Compare commits
	
		
			117 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| cb338129ca | |||
| 9e8a243439 | |||
| d3e0ee8c0d | |||
| 2e2c8ab2cb | |||
| 36474d3e9d | |||
| e6438503a5 | |||
| 58c7fe98b8 | |||
| 6867f48bf9 | |||
| 71942f7221 | |||
| c486ad1eb3 | |||
| 05e7cde8fa | |||
| 9adb593e8e | |||
| 073326f31b | |||
| dae324f86d | |||
| 2eec3372f3 | |||
| f6724c0948 | |||
| af8b688d94 | |||
| d21dba6a8f | |||
| 0e2d459d5a | |||
| 89ad302255 | |||
| 494f9442c4 | |||
| 68087a125c | |||
| 323fd7ea14 | |||
| 3167cfce9c | |||
| 8ea6f6d5c1 | |||
| 3b70116a15 | |||
| 397f5e126e | |||
| 14d7d5d4e0 | |||
| 6528879fed | |||
| 57aeeaa882 | |||
| bbceba7e9b | |||
| 5a210712f6 | |||
| bb8bba163e | |||
| 83b0d1553f | |||
| a1664630ed | |||
| 529ac89150 | |||
| 479f1befc9 | |||
| 29b30fbe22 | |||
| 1ccc663c48 | |||
| 7c43528ebf | |||
| 7f4c823c1e | |||
| d19050e06d | |||
| b5142ac765 | |||
| b456889fe9 | |||
| 3fdbcf905b | |||
| 8a2de2fdf2 | |||
| bd390894c5 | |||
| 04018a8c06 | |||
| b4cd5659cb | |||
| 59c3da0344 | |||
| c5eb41292c | |||
| c912b73c4b | |||
| 7b8ba7ab82 | |||
| dd2871b6bb | |||
| 216deecd33 | |||
| 22cc85b2e2 | |||
| 0b9350d19b | |||
| aad71116c5 | |||
| 16d6871422 | |||
| 78ff02e255 | |||
| a3f91701d0 | |||
| 697be64418 | |||
| a4b67c65ff | |||
| f040e708a4 | |||
| e6c19a1e6a | |||
| 98ecce518b | |||
| 500375dcf2 | |||
| 4e04bc306f | |||
| dfcb3ce020 | |||
| 5cf007f419 | |||
| 417fe35e91 | |||
| 3f598086b7 | |||
| dfe2c60646 | |||
| 8ec79428a9 | |||
| 3b0b8bea0d | |||
| ba00ec86a1 | |||
| f15f97d4c9 | |||
| d3eb68ed5a | |||
| 14a485deba | |||
| 236f7d4daf | |||
| f4f44a49ae | |||
| 1b72cbdfaa | |||
| ff3f7228b5 | |||
| b6ce4151bd | |||
| d49ce45de0 | |||
| a341fca43a | |||
| db6109b298 | |||
| 145d12d01a | |||
| 506df8cf15 | |||
| 21ecbb3ef3 | |||
| 29da31af20 | |||
| 23b35733cb | |||
| 55cd225c74 | |||
| e55ae67da6 | |||
| 79bc670ad0 | |||
| ebc2dd39f6 | |||
| 71768e27c0 | |||
| aaac755869 | |||
| 0430ba9213 | |||
| 0c17924c50 | |||
| 5286ff50a5 | |||
| 3ee2185714 | |||
| 7ea30819aa | |||
| 3647581cd7 | |||
| d76b385316 | |||
| 3240006516 | |||
| 2d0aa7aef1 | |||
| 4dd4c8c319 | |||
| 324438acac | |||
| a643b05f57 | |||
| 7adf325831 | |||
| b85903cb21 | |||
| 67d2f8d8e6 | |||
| 6979b6d08d | |||
| 44b9c8f869 | |||
| 6dae43b437 | |||
| 8eb1c9b4a7 | 
@ -1,15 +1,13 @@
 | 
				
			|||||||
image: debian:bullseye
 | 
					image: pureos/byzantium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
stages:
 | 
					stages:
 | 
				
			||||||
  - build
 | 
					  - build
 | 
				
			||||||
  - test
 | 
					  - test
 | 
				
			||||||
 | 
					  - deploy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
before_script:
 | 
					before_script:
 | 
				
			||||||
  - apt-get -y update
 | 
					  - apt-get -y update
 | 
				
			||||||
  - apt-get -y install wget ca-certificates gnupg
 | 
					  - apt-get -y install ca-certificates
 | 
				
			||||||
  - echo "deb [trusted=yes] http://ci.puri.sm/ bullseyeci main" > /etc/apt/sources.list.d/ci.list
 | 
					 | 
				
			||||||
  - wget -O- https://ci.puri.sm/ci-repo.key | apt-key add -
 | 
					 | 
				
			||||||
  - apt-get -y update
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
build_docs:
 | 
					build_docs:
 | 
				
			||||||
  stage: build
 | 
					  stage: build
 | 
				
			||||||
@ -56,6 +54,7 @@ build_deb:
 | 
				
			|||||||
    - cp ../*.deb .
 | 
					    - cp ../*.deb .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
build_deb:arm64:
 | 
					build_deb:arm64:
 | 
				
			||||||
 | 
					  image: pureos/byzantium
 | 
				
			||||||
  tags:
 | 
					  tags:
 | 
				
			||||||
    - aarch64
 | 
					    - aarch64
 | 
				
			||||||
  stage: build
 | 
					  stage: build
 | 
				
			||||||
@ -74,6 +73,44 @@ build_deb:arm64:
 | 
				
			|||||||
    - debuild -i -us -uc -b
 | 
					    - debuild -i -us -uc -b
 | 
				
			||||||
    - cp ../*.deb .
 | 
					    - cp ../*.deb .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					build_deb:future:
 | 
				
			||||||
 | 
					  image: debian:sid
 | 
				
			||||||
 | 
					  allow_failure: true
 | 
				
			||||||
 | 
					  tags:
 | 
				
			||||||
 | 
					    - aarch64
 | 
				
			||||||
 | 
					  stage: build
 | 
				
			||||||
 | 
					  artifacts:
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - '*.deb'
 | 
				
			||||||
 | 
					  script:
 | 
				
			||||||
 | 
					    - rm -f ../*.deb
 | 
				
			||||||
 | 
					    - mv debian/control-newer debian/control
 | 
				
			||||||
 | 
					    - apt-get -y build-dep .
 | 
				
			||||||
 | 
					    - apt-get -y install devscripts
 | 
				
			||||||
 | 
					    - REV=$(git log -1 --format=%h)
 | 
				
			||||||
 | 
					    - VER=$(dpkg-parsechangelog -SVersion)
 | 
				
			||||||
 | 
					    - DEBFULLNAME="Librem5 CI"
 | 
				
			||||||
 | 
					    - EMAIL="librem5-builds@lists.community.puri.sm"
 | 
				
			||||||
 | 
					    - dch -v"$VER+librem5ci$CI_PIPELINE_ID.$REV" "$MSG"
 | 
				
			||||||
 | 
					    - debuild -i -us -uc -b
 | 
				
			||||||
 | 
					    - cp ../*.deb .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					build_reference:
 | 
				
			||||||
 | 
					  stage: build
 | 
				
			||||||
 | 
					  needs:
 | 
				
			||||||
 | 
					    - job: build_meson
 | 
				
			||||||
 | 
					      artifacts: true
 | 
				
			||||||
 | 
					  artifacts:
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - _build/doc
 | 
				
			||||||
 | 
					  script:
 | 
				
			||||||
 | 
					    - apt-get -y install cargo
 | 
				
			||||||
 | 
					    - cd _build
 | 
				
			||||||
 | 
					    - ../cargo.sh doc --no-deps --document-private-items
 | 
				
			||||||
 | 
					  except:
 | 
				
			||||||
 | 
					    variables:
 | 
				
			||||||
 | 
					      - $PKG_ONLY == "1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_lintian:
 | 
					test_lintian:
 | 
				
			||||||
  stage: test
 | 
					  stage: test
 | 
				
			||||||
  needs:
 | 
					  needs:
 | 
				
			||||||
@ -122,3 +159,17 @@ check_release:
 | 
				
			|||||||
  except:
 | 
					  except:
 | 
				
			||||||
    variables:
 | 
					    variables:
 | 
				
			||||||
      - $PKG_ONLY == "1"
 | 
					      - $PKG_ONLY == "1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pages:
 | 
				
			||||||
 | 
					  stage: deploy
 | 
				
			||||||
 | 
					  needs:
 | 
				
			||||||
 | 
					    - build_docs
 | 
				
			||||||
 | 
					    - build_reference
 | 
				
			||||||
 | 
					  script:
 | 
				
			||||||
 | 
					    - mv _build/ public/
 | 
				
			||||||
 | 
					  artifacts:
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - public
 | 
				
			||||||
 | 
					  only:
 | 
				
			||||||
 | 
					    refs:
 | 
				
			||||||
 | 
					      - master
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								Cargo.deps
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								Cargo.deps
									
									
									
									
									
								
							@ -1,11 +1,17 @@
 | 
				
			|||||||
# Dependencies which change based on build flags
 | 
					# Dependencies which change based on build flags
 | 
				
			||||||
bitflags = "1.2.*"
 | 
					bitflags = "1.2.*"
 | 
				
			||||||
clap = { version = "2.33.*", default-features = false }
 | 
					clap = { version = "2.33.*", default-features = false }
 | 
				
			||||||
regex = { version = "1.3.*", default-features = false, features = ["std", "unicode-case"] }
 | 
					zbus = "1.0.*"
 | 
				
			||||||
 | 
					zvariant = "2.0.*"
 | 
				
			||||||
 | 
					# Newer versions seem to confuse the version of Cargo on Debian Bullseye
 | 
				
			||||||
 | 
					zvariant_derive = "2.0.*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies.cairo-rs]
 | 
					[dependencies.cairo-rs]
 | 
				
			||||||
version = "0.7.*"
 | 
					version = "0.7.*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.cairo-sys-rs]
 | 
				
			||||||
 | 
					version = "0.9"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies.gdk]
 | 
					[dependencies.gdk]
 | 
				
			||||||
version = "0.11.*"
 | 
					version = "0.11.*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -17,6 +23,14 @@ features = ["v2_44"]
 | 
				
			|||||||
version = "0.8.*"
 | 
					version = "0.8.*"
 | 
				
			||||||
features = ["v2_44"]
 | 
					features = ["v2_44"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.glib-sys]
 | 
				
			||||||
 | 
					version = "*"
 | 
				
			||||||
 | 
					features = ["v2_44"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies.gtk]
 | 
					[dependencies.gtk]
 | 
				
			||||||
version = "0.7.*"
 | 
					version = "0.7.*"
 | 
				
			||||||
features = ["v3_22"]
 | 
					features = ["v3_22"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.gtk-sys]
 | 
				
			||||||
 | 
					version = "0.9"
 | 
				
			||||||
 | 
					features = ["v3_22"]
 | 
				
			||||||
@ -1,22 +0,0 @@
 | 
				
			|||||||
# Dependencies which change based on build flags
 | 
					 | 
				
			||||||
bitflags = "1.0.*"
 | 
					 | 
				
			||||||
clap = { version = "2.32.*", default-features = false }
 | 
					 | 
				
			||||||
regex = { version = "1.1.*", default-features = false, features = ['use_std'] }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.cairo-rs]
 | 
					 | 
				
			||||||
version = "0.5.*"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.gdk]
 | 
					 | 
				
			||||||
version = "0.9.*"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.gio]
 | 
					 | 
				
			||||||
version = "0.5.*"
 | 
					 | 
				
			||||||
features = ["v2_44"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.glib]
 | 
					 | 
				
			||||||
version = "0.6.*"
 | 
					 | 
				
			||||||
features = ["v2_44"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.gtk]
 | 
					 | 
				
			||||||
version = "0.5.*"
 | 
					 | 
				
			||||||
features = ["v3_22"]
 | 
					 | 
				
			||||||
							
								
								
									
										37
									
								
								Cargo.deps.newer
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Cargo.deps.newer
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					# Dependencies which change based on build flags
 | 
				
			||||||
 | 
					# For the newer-than-Byzantium config
 | 
				
			||||||
 | 
					bitflags = "1.3.*"
 | 
				
			||||||
 | 
					clap = { version = "3.1.*", features=["std"], default-features = false }
 | 
				
			||||||
 | 
					zbus = "1.9.*"
 | 
				
			||||||
 | 
					zvariant = "2.10.*"
 | 
				
			||||||
 | 
					# Newer versions seem to confuse the version of Cargo on Debian Bullseye
 | 
				
			||||||
 | 
					zvariant_derive = "2.10.*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.cairo-rs]
 | 
				
			||||||
 | 
					version = "0.14.*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.cairo-sys-rs]
 | 
				
			||||||
 | 
					version = "0.14.*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.gdk]
 | 
				
			||||||
 | 
					version = "0.14.*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.gio]
 | 
				
			||||||
 | 
					version = "0.14.*"
 | 
				
			||||||
 | 
					features = ["v2_58"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.glib]
 | 
				
			||||||
 | 
					version = "0.14.*"
 | 
				
			||||||
 | 
					features = ["v2_58"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.glib-sys]
 | 
				
			||||||
 | 
					version = "0.14.*"
 | 
				
			||||||
 | 
					features = ["v2_58"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.gtk]
 | 
				
			||||||
 | 
					version = "0.14.*"
 | 
				
			||||||
 | 
					features = ["v3_22"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.gtk-sys]
 | 
				
			||||||
 | 
					version = "0.14.*"
 | 
				
			||||||
 | 
					features = ["v3_22"]
 | 
				
			||||||
							
								
								
									
										4
									
								
								Cargo.deps.online
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Cargo.deps.online
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +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" }
 | 
				
			||||||
							
								
								
									
										255
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										255
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -30,9 +30,9 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "autocfg"
 | 
					name = "autocfg"
 | 
				
			||||||
version = "1.0.1"
 | 
					version = "1.1.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 | 
					checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "bitflags"
 | 
					name = "bitflags"
 | 
				
			||||||
@ -40,6 +40,12 @@ version = "1.2.1"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 | 
					checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "byteorder"
 | 
				
			||||||
 | 
					version = "1.4.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "cairo-rs"
 | 
					name = "cairo-rs"
 | 
				
			||||||
version = "0.7.1"
 | 
					version = "0.7.1"
 | 
				
			||||||
@ -67,15 +73,27 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "cc"
 | 
					name = "cc"
 | 
				
			||||||
version = "1.0.72"
 | 
					version = "1.0.73"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
 | 
					checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cfg-if"
 | 
				
			||||||
 | 
					version = "0.1.10"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cfg-if"
 | 
				
			||||||
 | 
					version = "1.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "clap"
 | 
					name = "clap"
 | 
				
			||||||
version = "2.33.3"
 | 
					version = "2.33.4"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
 | 
					checksum = "826bf7bc84f9435630275cb8e802a4a0ec792b615969934bd16d42ffed10f207"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "bitflags",
 | 
					 "bitflags",
 | 
				
			||||||
 "textwrap",
 | 
					 "textwrap",
 | 
				
			||||||
@ -83,16 +101,50 @@ dependencies = [
 | 
				
			|||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "dtoa"
 | 
					name = "derivative"
 | 
				
			||||||
version = "0.4.8"
 | 
					version = "2.2.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
 | 
					checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "enumflags2"
 | 
				
			||||||
 | 
					version = "0.6.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "enumflags2_derive",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "enumflags2_derive"
 | 
				
			||||||
 | 
					version = "0.6.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "fastrand"
 | 
				
			||||||
 | 
					version = "1.7.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "instant",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "fragile"
 | 
					name = "fragile"
 | 
				
			||||||
version = "0.3.0"
 | 
					version = "0.3.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "git+https://source.puri.sm/dorota.czaplejewicz/fragile.git?tag=0.3.0#51048ca11824279c2114c77fef5bcb950838fc09"
 | 
				
			||||||
checksum = "05f8140122fa0d5dcb9fc8627cfce2b37cc1500f752636d46ea28bc26785c2f9"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "gdk"
 | 
					name = "gdk"
 | 
				
			||||||
@ -273,14 +325,23 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "indexmap"
 | 
					name = "indexmap"
 | 
				
			||||||
version = "1.7.0"
 | 
					version = "1.8.1"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
 | 
					checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "autocfg",
 | 
					 "autocfg",
 | 
				
			||||||
 "hashbrown",
 | 
					 "hashbrown",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "instant"
 | 
				
			||||||
 | 
					version = "0.1.12"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "cfg-if 1.0.0",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "lazy_static"
 | 
					name = "lazy_static"
 | 
				
			||||||
version = "1.4.0"
 | 
					version = "1.4.0"
 | 
				
			||||||
@ -289,9 +350,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "libc"
 | 
					name = "libc"
 | 
				
			||||||
version = "0.2.108"
 | 
					version = "0.2.124"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
 | 
					checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "linked-hash-map"
 | 
					name = "linked-hash-map"
 | 
				
			||||||
@ -315,6 +376,19 @@ dependencies = [
 | 
				
			|||||||
 "winapi",
 | 
					 "winapi",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "nix"
 | 
				
			||||||
 | 
					version = "0.17.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bitflags",
 | 
				
			||||||
 | 
					 "cc",
 | 
				
			||||||
 | 
					 "cfg-if 0.1.10",
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "void",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "pango"
 | 
					name = "pango"
 | 
				
			||||||
version = "0.7.0"
 | 
					version = "0.7.0"
 | 
				
			||||||
@ -344,43 +418,37 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "pkg-config"
 | 
					name = "pkg-config"
 | 
				
			||||||
version = "0.3.22"
 | 
					version = "0.3.25"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
 | 
					checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "proc-macro-crate"
 | 
				
			||||||
 | 
					version = "0.1.5"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "toml",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "proc-macro2"
 | 
					name = "proc-macro2"
 | 
				
			||||||
version = "1.0.32"
 | 
					version = "1.0.37"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
 | 
					checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "unicode-xid",
 | 
					 "unicode-xid",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "quote"
 | 
					name = "quote"
 | 
				
			||||||
version = "1.0.10"
 | 
					version = "1.0.18"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
 | 
					checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "proc-macro2",
 | 
					 "proc-macro2",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "regex"
 | 
					 | 
				
			||||||
version = "1.3.9"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "regex-syntax",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "regex-syntax"
 | 
					 | 
				
			||||||
version = "0.6.25"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "rs"
 | 
					name = "rs"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
@ -396,26 +464,51 @@ dependencies = [
 | 
				
			|||||||
 "gtk",
 | 
					 "gtk",
 | 
				
			||||||
 "gtk-sys",
 | 
					 "gtk-sys",
 | 
				
			||||||
 "maplit",
 | 
					 "maplit",
 | 
				
			||||||
 "regex",
 | 
					 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_yaml",
 | 
					 "serde_yaml",
 | 
				
			||||||
 "xkbcommon",
 | 
					 "xkbcommon",
 | 
				
			||||||
 | 
					 "zbus",
 | 
				
			||||||
 | 
					 "zvariant",
 | 
				
			||||||
 | 
					 "zvariant_derive",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "serde"
 | 
					name = "ryu"
 | 
				
			||||||
version = "1.0.130"
 | 
					version = "1.0.9"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
 | 
					checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "scoped-tls"
 | 
				
			||||||
 | 
					version = "1.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "serde"
 | 
				
			||||||
 | 
					version = "1.0.136"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "serde_derive",
 | 
					 "serde_derive",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "serde_derive"
 | 
					name = "serde_derive"
 | 
				
			||||||
version = "1.0.130"
 | 
					version = "1.0.136"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
 | 
					checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "serde_repr"
 | 
				
			||||||
 | 
					version = "0.1.7"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "proc-macro2",
 | 
					 "proc-macro2",
 | 
				
			||||||
 "quote",
 | 
					 "quote",
 | 
				
			||||||
@ -424,21 +517,21 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "serde_yaml"
 | 
					name = "serde_yaml"
 | 
				
			||||||
version = "0.8.21"
 | 
					version = "0.8.23"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af"
 | 
					checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "dtoa",
 | 
					 | 
				
			||||||
 "indexmap",
 | 
					 "indexmap",
 | 
				
			||||||
 | 
					 "ryu",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "yaml-rust",
 | 
					 "yaml-rust",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "syn"
 | 
					name = "syn"
 | 
				
			||||||
version = "1.0.82"
 | 
					version = "1.0.91"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
 | 
					checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "proc-macro2",
 | 
					 "proc-macro2",
 | 
				
			||||||
 "quote",
 | 
					 "quote",
 | 
				
			||||||
@ -454,6 +547,15 @@ dependencies = [
 | 
				
			|||||||
 "unicode-width",
 | 
					 "unicode-width",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "toml"
 | 
				
			||||||
 | 
					version = "0.5.9"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "unicode-width"
 | 
					name = "unicode-width"
 | 
				
			||||||
version = "0.1.9"
 | 
					version = "0.1.9"
 | 
				
			||||||
@ -466,6 +568,12 @@ version = "0.2.2"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 | 
					checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "void"
 | 
				
			||||||
 | 
					version = "1.0.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "winapi"
 | 
					name = "winapi"
 | 
				
			||||||
version = "0.3.9"
 | 
					version = "0.3.9"
 | 
				
			||||||
@ -506,3 +614,56 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
 | 
				
			|||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "linked-hash-map",
 | 
					 "linked-hash-map",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "zbus"
 | 
				
			||||||
 | 
					version = "1.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "1cb97c72cbfd5c7537ca730eeb810da7348f345ba67ab7673bcbe0d81c076427"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "byteorder",
 | 
				
			||||||
 | 
					 "derivative",
 | 
				
			||||||
 | 
					 "enumflags2",
 | 
				
			||||||
 | 
					 "fastrand",
 | 
				
			||||||
 | 
					 "nix",
 | 
				
			||||||
 | 
					 "scoped-tls",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 | 
					 "serde_repr",
 | 
				
			||||||
 | 
					 "zbus_macros",
 | 
				
			||||||
 | 
					 "zvariant",
 | 
				
			||||||
 | 
					 "zvariant_derive",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "zbus_macros"
 | 
				
			||||||
 | 
					version = "1.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "c0c1f2a20a4cb90922b44d3bebd232b246e52b3dd95ed5bea8aec83cde3a5a8a"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro-crate",
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "zvariant"
 | 
				
			||||||
 | 
					version = "2.0.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "f0bf85e67d1a3780cb1c56c80227532354f21907cba14805a773eb507b444580"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "byteorder",
 | 
				
			||||||
 | 
					 "enumflags2",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "zvariant_derive"
 | 
				
			||||||
 | 
					version = "2.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d68726e8c12757384a8d1485080527e263dea67d91f19e97cd71b9292f22d7c5"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
				
			|||||||
@ -17,22 +17,9 @@ name = "test_layout"
 | 
				
			|||||||
path = "@path@/examples/test_layout.rs"
 | 
					path = "@path@/examples/test_layout.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[features]
 | 
					[features]
 | 
				
			||||||
gio_v0_5 = []
 | 
					glib_v0_14 = []
 | 
				
			||||||
gtk_v0_5 = []
 | 
					 | 
				
			||||||
rustc_less_1_36 = []
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Dependencies which don't change based on build flags
 | 
					# Dependencies which don't change based on build flags
 | 
				
			||||||
[dependencies.cairo-sys-rs]
 | 
					 | 
				
			||||||
version = "*"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.glib-sys]
 | 
					 | 
				
			||||||
version = "*"
 | 
					 | 
				
			||||||
features = ["v2_44"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.gtk-sys]
 | 
					 | 
				
			||||||
version = "*"
 | 
					 | 
				
			||||||
features = ["v3_22"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
maplit = "1.0.*"
 | 
					maplit = "1.0.*"
 | 
				
			||||||
serde = { version = "1.0.*", features = ["derive"] }
 | 
					serde = { version = "1.0.*", features = ["derive"] }
 | 
				
			||||||
 | 
				
			|||||||
@ -86,4 +86,4 @@ It's strongly recommended to support:
 | 
				
			|||||||
Developing
 | 
					Developing
 | 
				
			||||||
----------
 | 
					----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
See [`doc/hacking.md`](doc/hacking.md) for this copy, or the [official documentation](https://developer.puri.sm/projects/squeekboard/) for the current release.
 | 
					See [`doc/hacking.md`](doc/hacking.md) for this copy, or the [official documentation](https://world.pages.gitlab.gnome.org/Phosh/squeekboard) for the current release.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,33 @@
 | 
				
			|||||||
/* Theme independent style */
 | 
					/* Theme independent styles */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sq_view {
 | 
				
			||||||
 | 
					    font-family: cantarell, sans-serif;
 | 
				
			||||||
 | 
					    font-size: 1.5em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sq_button {
 | 
				
			||||||
 | 
					    border-radius: 4px;
 | 
				
			||||||
 | 
					    margin: 2px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sq_view.wide sq_button {
 | 
				
			||||||
 | 
					    margin: 3px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sq_button.latched,
 | 
				
			||||||
 | 
					sq_button.locked {
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sq_button.action {
 | 
				
			||||||
 | 
					    font-size: 0.75em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sq_button.small {
 | 
				
			||||||
 | 
					    font-size: 0.5em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_view.pin sq_button {
 | 
					sq_view.pin sq_button {
 | 
				
			||||||
    border-radius: 0px;
 | 
					    border-radius: 0px;
 | 
				
			||||||
    margin: 1px 1px 1px 1px;
 | 
					    margin: 1px 1px 1px 1px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										326
									
								
								data/keyboards/gr+polytonic.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								data/keyboards/gr+polytonic.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,326 @@
 | 
				
			|||||||
 | 
					# Greek polytonic layout by Antonis Tsolomitis
 | 
				
			||||||
 | 
					# University of the Aegean, Department of Mathematics, atsol@aegean.gr
 | 
				
			||||||
 | 
					# March 2022
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					outlines:
 | 
				
			||||||
 | 
					    default:    { width: 40, height: 60 }
 | 
				
			||||||
 | 
					    altline:    { width: 52.67,    height: 60 }
 | 
				
			||||||
 | 
					    wide:       { width: 62,    height: 60 }
 | 
				
			||||||
 | 
					    extrawide:  { width: 66, height: 60 }
 | 
				
			||||||
 | 
					    spaceline:  { width: 140,   height: 60 }
 | 
				
			||||||
 | 
					    special:    { width: 44,    height: 60 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					views:
 | 
				
			||||||
 | 
					    base:
 | 
				
			||||||
 | 
					        - "semicolon ς ε ρ τ υ θ ι ο π"
 | 
				
			||||||
 | 
					        - "α σ δ φ γ η ξ κ λ show_accents"
 | 
				
			||||||
 | 
					        - "Shift_L ζ χ ψ ω β ν μ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space period comma Return"
 | 
				
			||||||
 | 
					    upper:
 | 
				
			||||||
 | 
					        - "colon EuroSign Ε Ρ Τ Υ Θ Ι Ο Π"
 | 
				
			||||||
 | 
					        - "Α Σ Δ Φ Γ Η Ξ Κ Λ show_accents"
 | 
				
			||||||
 | 
					        - "Shift_L Ζ Χ Ψ Ω Β Ν Μ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space exclam period_upper Return"
 | 
				
			||||||
 | 
					    accents:
 | 
				
			||||||
 | 
					        - "show_psiliordasiaandvaria show_psiliordasiaandoxia show_psiliordasia show_bariaorperispomeni show_oxia"
 | 
				
			||||||
 | 
					        - "show_PsiliOrDasiaAndVaria show_PsiliOrDasiaAndOxia show_PsiliOrDasia show_BariaOrPerispomeni show_Oxia show_base"
 | 
				
			||||||
 | 
					        - "show_PsiliOrDasiaAndPerispomeni show_psiliordasiaandperispomeni ᾿ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space Return"
 | 
				
			||||||
 | 
					    oxia:
 | 
				
			||||||
 | 
					        - "ά έ ή ί ϊ ΐ ό ύ ϋ ώ"
 | 
				
			||||||
 | 
					        - "show_Oxia ᾳ ᾴ ῃ ῄ ῳ ῴ show_base"
 | 
				
			||||||
 | 
					        - "Ϗ ϐ ϑ ϗ ϖ ΰ ϕ – — BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space eis_l eis_r Return"
 | 
				
			||||||
 | 
					    Oxia:
 | 
				
			||||||
 | 
					        - "Ά Έ Ή Ί Ϊ Ό Ύ Ϋ Ώ"
 | 
				
			||||||
 | 
					        - "show_oxia ᾼ ῌ ῼ show_base"
 | 
				
			||||||
 | 
					        - "Ϗ ϐ ϑ ϗ ϖ ϕ – — BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space eis_l eis_r Return"
 | 
				
			||||||
 | 
					    bariaorperispomeni:
 | 
				
			||||||
 | 
					        - "ὰ ὲ ὴ ὶ ῒ ὸ ὺ ὼ ῐ ῑ"
 | 
				
			||||||
 | 
					        - "show_BariaOrPerispomeni ᾳ ᾲ ῃ ῂ ῳ ῲ ῠ show_base"
 | 
				
			||||||
 | 
					        - "ᾶ ᾷ ῆ ῖ ῗ ῦ ῧ ῶ ῡ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space ῇ ῷ Return"
 | 
				
			||||||
 | 
					    BariaOrPerispomeni:
 | 
				
			||||||
 | 
					        - "Ὰ Ὲ Ὴ Ὶ Ὸ Ὺ Ὼ"
 | 
				
			||||||
 | 
					        - "show_bariaorperispomeni ᾼ ῌ ῼ show_base"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space BackSpace Return"
 | 
				
			||||||
 | 
					    psiliordasia:
 | 
				
			||||||
 | 
					        - "ἀ ἐ ἠ ἰ ὀ ὐ ὠ ᾀ ᾐ ᾠ"
 | 
				
			||||||
 | 
					        - "show_PsiliOrDasia ἁ ἑ ἡ ἱ ὁ ὑ ὡ show_base"
 | 
				
			||||||
 | 
					        - "ᾁ ᾑ ᾡ ῤ ῥ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space Return"
 | 
				
			||||||
 | 
					    PsiliOrDasia:
 | 
				
			||||||
 | 
					        - "Ἀ Ἐ Ἠ Ἰ Ὀ Ὠ ᾈ ᾘ ᾨ"
 | 
				
			||||||
 | 
					        - "show_psiliordasia Ἁ Ἑ Ἡ Ἱ Ὁ Ὑ Ὡ show_base"
 | 
				
			||||||
 | 
					        - "ᾉ ᾙ ᾩ Ῥ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space Return"
 | 
				
			||||||
 | 
					    psiliordasiaandoxia:
 | 
				
			||||||
 | 
					        - "ἄ ἔ ἤ ἴ ὄ ὔ ὤ ᾄ ᾔ ᾤ"
 | 
				
			||||||
 | 
					        - "show_PsiliOrDasiaAndOxia ἅ ἕ ἥ ἵ ὅ ὕ ὥ show_base"
 | 
				
			||||||
 | 
					        - "ᾅ ᾕ ᾥ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space Return"
 | 
				
			||||||
 | 
					    PsiliOrDasiaAndOxia:
 | 
				
			||||||
 | 
					        - "Ἄ Ἔ Ἤ Ἴ Ὄ Ὤ ᾌ ᾜ ᾬ"
 | 
				
			||||||
 | 
					        - "show_psiliordasiaandoxia Ἅ Ἕ Ἥ Ἵ Ὅ Ὕ Ὥ show_base"
 | 
				
			||||||
 | 
					        - "ᾍ ᾝ ᾭ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space Return"
 | 
				
			||||||
 | 
					    psiliordasiaandvaria:
 | 
				
			||||||
 | 
					        - "ἂ ἒ ἢ ἲ ὂ ὒ ὢ ᾂ ᾒ ᾢ"
 | 
				
			||||||
 | 
					        - "show_PsiliOrDasiaAndVaria ἃ ἓ ἣ ἳ ὃ ὓ ὣ show_base"
 | 
				
			||||||
 | 
					        - "ᾃ ᾓ ᾣ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space Return"
 | 
				
			||||||
 | 
					    PsiliOrDasiaAndVaria:
 | 
				
			||||||
 | 
					        - "Ἂ Ἒ Ἢ Ἲ Ὂ Ὢ ᾊ ᾚ ᾪ"
 | 
				
			||||||
 | 
					        - "show_psiliordasiaandvaria Ἃ Ἓ Ἣ Ἳ Ὃ Ὓ Ὣ show_base"
 | 
				
			||||||
 | 
					        - "ᾋ ᾛ ᾫ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space Return"
 | 
				
			||||||
 | 
					    psiliordasiaandperispomeni:
 | 
				
			||||||
 | 
					        - "ἆ ἦ ἶ ὖ ὦ ᾆ ᾖ ᾦ"
 | 
				
			||||||
 | 
					        - "show_PsiliOrDasiaAndPerispomeni ἇ ἧ ἷ ὗ ὧ show_base"
 | 
				
			||||||
 | 
					        - "ᾇ ᾗ ᾧ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space Return"
 | 
				
			||||||
 | 
					    PsiliOrDasiaAndPerispomeni:
 | 
				
			||||||
 | 
					        - "Ἆ Ἦ Ἶ Ὦ ᾎ ᾞ ᾮ"
 | 
				
			||||||
 | 
					        - "show_psiliordasiaandperispomeni Ἇ Ἧ Ἷ Ὗ Ὧ show_base"
 | 
				
			||||||
 | 
					        - "ᾏ ᾟ ᾯ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space Return"
 | 
				
			||||||
 | 
					    numbers:
 | 
				
			||||||
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
 | 
					        - "at numbersign dollar percent ampersand minus underscore plus parenleft parenright"
 | 
				
			||||||
 | 
					        - "show_symbols comma quotedbl quoteright colon semicolon exclam question BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences space period comma Return"
 | 
				
			||||||
 | 
					    symbols:
 | 
				
			||||||
 | 
					        - "asciitilde quoteleft bar U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
 | 
				
			||||||
 | 
					        - "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree asterisk braceleft braceright"
 | 
				
			||||||
 | 
					        - "show_numbers backslash slash less greater equal bracketleft bracketright  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences space period comma 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: "altline"
 | 
				
			||||||
 | 
					        icon: "keyboard-mode-symbolic"
 | 
				
			||||||
 | 
					    show_oxia:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "oxia"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "´ ΅"
 | 
				
			||||||
 | 
					    show_Oxia:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "Oxia"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "´¨↑"
 | 
				
			||||||
 | 
					    show_bariaorperispomeni:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "bariaorperispomeni"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "` ῀"
 | 
				
			||||||
 | 
					    show_BariaOrPerispomeni:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "BariaOrPerispomeni"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "`῀↑"
 | 
				
			||||||
 | 
					    show_psiliordasia:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "psiliordasia"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "᾿ ῾"
 | 
				
			||||||
 | 
					    show_PsiliOrDasia:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "PsiliOrDasia"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "᾿῾↑"
 | 
				
			||||||
 | 
					    show_psiliordasiaandoxia:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "psiliordasiaandoxia"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "῎ ῞"
 | 
				
			||||||
 | 
					    show_PsiliOrDasiaAndOxia:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "PsiliOrDasiaAndOxia"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "῎῞↑"
 | 
				
			||||||
 | 
					    show_psiliordasiaandvaria:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "psiliordasiaandvaria"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "῍ ῝"
 | 
				
			||||||
 | 
					    show_PsiliOrDasiaAndVaria:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "PsiliOrDasiaAndVaria"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "῍῝↑"
 | 
				
			||||||
 | 
					    show_psiliordasiaandperispomeni:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "psiliordasiaandperispomeni"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "῏ ῟"
 | 
				
			||||||
 | 
					    show_PsiliOrDasiaAndPerispomeni:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "PsiliOrDasiaAndPerispomeni"
 | 
				
			||||||
 | 
					        outline: "extrawide"
 | 
				
			||||||
 | 
					        label: "῏῟↑"
 | 
				
			||||||
 | 
					    show_numbers:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "numbers"
 | 
				
			||||||
 | 
					        outline: "wide"
 | 
				
			||||||
 | 
					        label: "123"
 | 
				
			||||||
 | 
					    show_letters:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "base"
 | 
				
			||||||
 | 
					        outline: "wide"
 | 
				
			||||||
 | 
					        label: "ΑΒΓ"
 | 
				
			||||||
 | 
					    show_symbols:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "symbols"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "*/="
 | 
				
			||||||
 | 
					    show_accents:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "accents"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "ᾦ"
 | 
				
			||||||
 | 
					    show_base:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "αι"
 | 
				
			||||||
 | 
					    space:
 | 
				
			||||||
 | 
					        outline: "spaceline"
 | 
				
			||||||
 | 
					        text: " "
 | 
				
			||||||
 | 
					    Return:
 | 
				
			||||||
 | 
					        outline: "wide"
 | 
				
			||||||
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
 | 
					    period:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "."
 | 
				
			||||||
 | 
					    period_upper:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "·"
 | 
				
			||||||
 | 
					    comma:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: ","
 | 
				
			||||||
 | 
					    colon:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: ":"
 | 
				
			||||||
 | 
					    semicolon:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: ";"
 | 
				
			||||||
 | 
					    exclam:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "!"
 | 
				
			||||||
 | 
					    eis_l:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "«"
 | 
				
			||||||
 | 
					    eis_r:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "»"
 | 
				
			||||||
 | 
					    aring:
 | 
				
			||||||
 | 
					        text: "å"
 | 
				
			||||||
 | 
					    Aring:
 | 
				
			||||||
 | 
					        text: "Å"
 | 
				
			||||||
 | 
					    oslash:
 | 
				
			||||||
 | 
					        text: "ø"
 | 
				
			||||||
 | 
					    Oslash:
 | 
				
			||||||
 | 
					        text: "Ø"
 | 
				
			||||||
 | 
					    ae:
 | 
				
			||||||
 | 
					        text: "æ"
 | 
				
			||||||
 | 
					    AE:
 | 
				
			||||||
 | 
					        text: "Æ"
 | 
				
			||||||
 | 
					    asterisk:
 | 
				
			||||||
 | 
					        text: "*"
 | 
				
			||||||
 | 
					    asciitilde:
 | 
				
			||||||
 | 
					        text: "~"
 | 
				
			||||||
 | 
					    quoteleft:
 | 
				
			||||||
 | 
					        text: "`"
 | 
				
			||||||
 | 
					    bar:
 | 
				
			||||||
 | 
					        text: "|"
 | 
				
			||||||
 | 
					    U00B7:
 | 
				
			||||||
 | 
					        text: "·"
 | 
				
			||||||
 | 
					    squareroot:
 | 
				
			||||||
 | 
					        text: "√"
 | 
				
			||||||
 | 
					    Greek_pi:
 | 
				
			||||||
 | 
					        text: "π"
 | 
				
			||||||
 | 
					    division:
 | 
				
			||||||
 | 
					        text: "÷"
 | 
				
			||||||
 | 
					    multiply:
 | 
				
			||||||
 | 
					        text: "×"
 | 
				
			||||||
 | 
					    paragraph:
 | 
				
			||||||
 | 
					        text: "¶"
 | 
				
			||||||
 | 
					    Greek_tau:
 | 
				
			||||||
 | 
					        text: "τ"
 | 
				
			||||||
 | 
					    copyright:
 | 
				
			||||||
 | 
					        text: "©"
 | 
				
			||||||
 | 
					    numbersign:
 | 
				
			||||||
 | 
					        text: "#"
 | 
				
			||||||
 | 
					    U00AE:
 | 
				
			||||||
 | 
					        text: "®"
 | 
				
			||||||
 | 
					    at:
 | 
				
			||||||
 | 
					        text: "@"
 | 
				
			||||||
 | 
					    dollar:
 | 
				
			||||||
 | 
					        text: "$"
 | 
				
			||||||
 | 
					    U00A3:
 | 
				
			||||||
 | 
					        text: "£"
 | 
				
			||||||
 | 
					    percent:
 | 
				
			||||||
 | 
					        text: "%"
 | 
				
			||||||
 | 
					    EuroSign:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "€"
 | 
				
			||||||
 | 
					    ampersand:
 | 
				
			||||||
 | 
					        text: "&"
 | 
				
			||||||
 | 
					    U00A5:
 | 
				
			||||||
 | 
					        text: "¥"
 | 
				
			||||||
 | 
					    minus:
 | 
				
			||||||
 | 
					        text: "-"
 | 
				
			||||||
 | 
					    asciicircum:
 | 
				
			||||||
 | 
					        text: "^"
 | 
				
			||||||
 | 
					    underscore:
 | 
				
			||||||
 | 
					        text: "_"
 | 
				
			||||||
 | 
					    degree:
 | 
				
			||||||
 | 
					        text: "°"
 | 
				
			||||||
 | 
					    plus:
 | 
				
			||||||
 | 
					        text: "+"
 | 
				
			||||||
 | 
					    equal:
 | 
				
			||||||
 | 
					        text: "="
 | 
				
			||||||
 | 
					    parenleft:
 | 
				
			||||||
 | 
					        text: "("
 | 
				
			||||||
 | 
					    parenright:
 | 
				
			||||||
 | 
					        text: ")"
 | 
				
			||||||
 | 
					    braceleft:
 | 
				
			||||||
 | 
					        text: "{"
 | 
				
			||||||
 | 
					    braceright:
 | 
				
			||||||
 | 
					        text: "}"
 | 
				
			||||||
 | 
					    backslash:
 | 
				
			||||||
 | 
					        text: "\\"
 | 
				
			||||||
 | 
					    slash:
 | 
				
			||||||
 | 
					        text: "/"
 | 
				
			||||||
 | 
					    quotedbl:
 | 
				
			||||||
 | 
					        text: "\""
 | 
				
			||||||
 | 
					    quoteright:
 | 
				
			||||||
 | 
					        text: "'"
 | 
				
			||||||
 | 
					    less:
 | 
				
			||||||
 | 
					        text: "<"
 | 
				
			||||||
 | 
					    greater:
 | 
				
			||||||
 | 
					        text: ">"
 | 
				
			||||||
 | 
					    question:
 | 
				
			||||||
 | 
					        text: "?"
 | 
				
			||||||
 | 
					    bracketleft:
 | 
				
			||||||
 | 
					        text: "["
 | 
				
			||||||
 | 
					    bracketright:
 | 
				
			||||||
 | 
					        text: "]"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,40 +1,41 @@
 | 
				
			|||||||
# Greek layout created by Antonis Tsolomitis
 | 
					# Greek layout originally created by Antonis Tsolomitis
 | 
				
			||||||
# University of the Aegean, Department of Mathematics, atsol@aegean.gr
 | 
					# University of the Aegean, Department of Mathematics, atsol@aegean.gr
 | 
				
			||||||
# Sep 2019
 | 
					# Sep 2019
 | 
				
			||||||
 | 
					# Edited by Sotiris Papadopoulos, sotirios.papadopoulos@inserm.fr
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
outlines:
 | 
					outlines:
 | 
				
			||||||
    default: { width: 32, height: 52 }
 | 
					    default:    { width: 40,    height: 60 }
 | 
				
			||||||
    altline: { width: 48.39024, height: 52 }
 | 
					    altline:    { width: 52.67, height: 60 }
 | 
				
			||||||
    wide: { width: 62, height: 52 }
 | 
					    wide:       { width: 62,    height: 60 }
 | 
				
			||||||
    outline7: { width: 88.97561, height: 52 }
 | 
					    spaceline:  { width: 140,   height: 60 }
 | 
				
			||||||
    spaceline: { width: 150.5853, height: 52 }
 | 
					    special:    { width: 44,    height: 60 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
views:
 | 
					views:
 | 
				
			||||||
    base:
 | 
					    base:
 | 
				
			||||||
        - "; ς ε ρ τ υ θ ι ο π !"
 | 
					        - "semicolon ς ε ρ τ υ θ ι ο π"
 | 
				
			||||||
        - "α σ δ φ γ η ξ κ λ show_accented"
 | 
					        - "α σ δ φ γ η ξ κ λ show_accented"
 | 
				
			||||||
        - "Shift_L ζ χ ψ ω β ν μ , BackSpace"
 | 
					        - "Shift_L ζ χ ψ ω β ν μ BackSpace"
 | 
				
			||||||
        - "show_numbers preferences space period Return"
 | 
					        - "show_numbers preferences space period comma Return"
 | 
				
			||||||
    upper:
 | 
					    upper:
 | 
				
			||||||
        - ": EuroSign Ε Ρ Τ Υ Θ Ι Ο Π"
 | 
					        - "colon exclam Ε Ρ Τ Υ Θ Ι Ο Π"
 | 
				
			||||||
        - "Α Σ Δ Φ Γ Η Ξ Κ Λ show_accented"
 | 
					        - "Α Σ Δ Φ Γ Η Ξ Κ Λ show_accented"
 | 
				
			||||||
        - "Shift_L Ζ Χ Ψ Ω Β Ν Μ · BackSpace"
 | 
					        - "Shift_L Ζ Χ Ψ Ω Β Ν Μ BackSpace"
 | 
				
			||||||
        - "show_numbers preferences space « » Return"
 | 
					        - "show_numbers preferences space period_upper apostrophe Return"
 | 
				
			||||||
    accented:
 | 
					    accented:
 | 
				
			||||||
        - "ά έ ή ί ό ύ ώ ϊ ϋ ΐ"
 | 
					        - "ά έ ή ί ϊ ΐ ό ύ ϋ ώ "
 | 
				
			||||||
        - "ΰ Ά Έ Ή Ί Ό Ύ Ώ Ϊ show_base"
 | 
					        - "Ά Έ Ή Ί Ϊ Ό Ύ Ϋ Ώ show_base"
 | 
				
			||||||
        - "Ϋ Ϗ ϐ ϑ ϕ ϖ ϗ – — BackSpace"
 | 
					        - "Ϗ ϐ ϑ ϗ ϖ ΰ ϕ – — BackSpace"
 | 
				
			||||||
        - "show_numbers preferences space quoteleft quoteright Return"
 | 
					        - "show_numbers preferences space eis_l eis_r Return"
 | 
				
			||||||
    numbers:
 | 
					    numbers:
 | 
				
			||||||
        - "1 2 3 4 5 6 7 8 9 0"
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
        - "at numbersign dollar percent ampersand minus underscore plus parenleft parenright"
 | 
					        - "at numbersign dollar percent ampersand minus underscore plus parenleft parenright"
 | 
				
			||||||
        - "show_symbols comma quotedbl quoteright colon semicolon exclam question BackSpace"
 | 
					        - "show_symbols comma quotedbl quoteright colon semicolon exclam question BackSpace"
 | 
				
			||||||
        - "show_letters preferences space period Return"
 | 
					        - "show_letters preferences space period comma Return"
 | 
				
			||||||
    symbols:
 | 
					    symbols:
 | 
				
			||||||
        - "asciitilde quoteleft bar U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
 | 
					        - "asciitilde quoteleft bar U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
 | 
				
			||||||
        - "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree asterisk braceleft braceright"
 | 
					        - "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree asterisk braceleft braceright"
 | 
				
			||||||
        - "show_numbers backslash slash less greater equal bracketleft bracketright  BackSpace"
 | 
					        - "show_numbers backslash slash less greater equal bracketleft bracketright  BackSpace"
 | 
				
			||||||
        - "show_letters preferences space period Return"
 | 
					        - "show_letters preferences space period comma Return"
 | 
				
			||||||
buttons:
 | 
					buttons:
 | 
				
			||||||
    Shift_L:
 | 
					    Shift_L:
 | 
				
			||||||
        action:
 | 
					        action:
 | 
				
			||||||
@ -54,12 +55,12 @@ buttons:
 | 
				
			|||||||
    show_numbers:
 | 
					    show_numbers:
 | 
				
			||||||
        action:
 | 
					        action:
 | 
				
			||||||
            set_view: "numbers"
 | 
					            set_view: "numbers"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "wide"
 | 
				
			||||||
        label: "123"
 | 
					        label: "123"
 | 
				
			||||||
    show_letters:
 | 
					    show_letters:
 | 
				
			||||||
        action:
 | 
					        action:
 | 
				
			||||||
            set_view: "base"
 | 
					            set_view: "base"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "wide"
 | 
				
			||||||
        label: "ΑΒΓ"
 | 
					        label: "ΑΒΓ"
 | 
				
			||||||
    show_symbols:
 | 
					    show_symbols:
 | 
				
			||||||
        action:
 | 
					        action:
 | 
				
			||||||
@ -78,16 +79,40 @@ buttons:
 | 
				
			|||||||
            set_view: "base"
 | 
					            set_view: "base"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        label: "αι"
 | 
					        label: "αι"
 | 
				
			||||||
    period:
 | 
					 | 
				
			||||||
        outline: "altline"
 | 
					 | 
				
			||||||
        text: "."
 | 
					 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: spaceline
 | 
					        outline: "spaceline"
 | 
				
			||||||
        text: " "
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "wide"
 | 
					        outline: "wide"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
        keysym: "Return"
 | 
					        keysym: "Return"
 | 
				
			||||||
 | 
					    period:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "."
 | 
				
			||||||
 | 
					    period_upper:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "·"
 | 
				
			||||||
 | 
					    comma:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: ","
 | 
				
			||||||
 | 
					    colon:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: ":"
 | 
				
			||||||
 | 
					    semicolon:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: ";"
 | 
				
			||||||
 | 
					    apostrophe:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "᾿"
 | 
				
			||||||
 | 
					    exclam:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "!"
 | 
				
			||||||
 | 
					    eis_l:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "«"
 | 
				
			||||||
 | 
					    eis_r:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "»"
 | 
				
			||||||
    aring:
 | 
					    aring:
 | 
				
			||||||
        text: "å"
 | 
					        text: "å"
 | 
				
			||||||
    Aring:
 | 
					    Aring:
 | 
				
			||||||
@ -162,8 +187,6 @@ buttons:
 | 
				
			|||||||
        text: "{"
 | 
					        text: "{"
 | 
				
			||||||
    braceright:
 | 
					    braceright:
 | 
				
			||||||
        text: "}"
 | 
					        text: "}"
 | 
				
			||||||
    comma:
 | 
					 | 
				
			||||||
        text: ","
 | 
					 | 
				
			||||||
    backslash:
 | 
					    backslash:
 | 
				
			||||||
        text: "\\"
 | 
					        text: "\\"
 | 
				
			||||||
    slash:
 | 
					    slash:
 | 
				
			||||||
@ -176,12 +199,6 @@ buttons:
 | 
				
			|||||||
        text: "<"
 | 
					        text: "<"
 | 
				
			||||||
    greater:
 | 
					    greater:
 | 
				
			||||||
        text: ">"
 | 
					        text: ">"
 | 
				
			||||||
    colon:
 | 
					 | 
				
			||||||
        text: ":"
 | 
					 | 
				
			||||||
    semicolon:
 | 
					 | 
				
			||||||
        text: ";"
 | 
					 | 
				
			||||||
    exclam:
 | 
					 | 
				
			||||||
        text: "!"
 | 
					 | 
				
			||||||
    question:
 | 
					    question:
 | 
				
			||||||
        text: "?"
 | 
					        text: "?"
 | 
				
			||||||
    bracketleft:
 | 
					    bracketleft:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										204
									
								
								data/keyboards/gr_wide.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								data/keyboards/gr_wide.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,204 @@
 | 
				
			|||||||
 | 
					# Creaed by Sotiris Papadopoulos, sotirios.papadopoulos@inserm.fr
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					outlines:
 | 
				
			||||||
 | 
					    default:    { width: 80,    height: 60 }
 | 
				
			||||||
 | 
					    altline:    { width: 110,    height: 60 }
 | 
				
			||||||
 | 
					    wide:       { width: 120,   height: 60 }
 | 
				
			||||||
 | 
					    spaceline:  { width: 250,   height: 60 }
 | 
				
			||||||
 | 
					    special:    { width: 75,    height: 60 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					views:
 | 
				
			||||||
 | 
					    base:
 | 
				
			||||||
 | 
					        - "semicolon ς ε ρ τ υ θ ι ο π"
 | 
				
			||||||
 | 
					        - "α σ δ φ γ η ξ κ λ show_accented"
 | 
				
			||||||
 | 
					        - "Shift_L ζ χ ψ ω β ν μ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space period comma Return"
 | 
				
			||||||
 | 
					    upper:
 | 
				
			||||||
 | 
					        - "colon exclam Ε Ρ Τ Υ Θ Ι Ο Π"
 | 
				
			||||||
 | 
					        - "Α Σ Δ Φ Γ Η Ξ Κ Λ show_accented"
 | 
				
			||||||
 | 
					        - "Shift_L Ζ Χ Ψ Ω Β Ν Μ BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space period_upper apostrophe Return"
 | 
				
			||||||
 | 
					    accented:
 | 
				
			||||||
 | 
					        - "ά έ ή ί ϊ ΐ ό ύ ϋ ώ "
 | 
				
			||||||
 | 
					        - "Ά Έ Ή Ί Ϊ Ό Ύ Ϋ Ώ show_base"
 | 
				
			||||||
 | 
					        - "Ϗ ϐ ϑ ϗ ΰ ϕ ϖ – — BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences space eis_l eis_r Return"
 | 
				
			||||||
 | 
					    numbers:
 | 
				
			||||||
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
 | 
					        - "at numbersign dollar percent ampersand minus underscore plus parenleft parenright"
 | 
				
			||||||
 | 
					        - "show_symbols comma quotedbl quoteright colon semicolon exclam question BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences space period comma Return"
 | 
				
			||||||
 | 
					    symbols:
 | 
				
			||||||
 | 
					        - "asciitilde quoteleft bar U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
 | 
				
			||||||
 | 
					        - "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree asterisk braceleft braceright"
 | 
				
			||||||
 | 
					        - "show_numbers backslash slash less greater equal bracketleft bracketright  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences space period comma 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_letters:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "base"
 | 
				
			||||||
 | 
					        outline: "wide"
 | 
				
			||||||
 | 
					        label: "ΑΒΓ"
 | 
				
			||||||
 | 
					    show_symbols:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "symbols"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "*/="
 | 
				
			||||||
 | 
					    show_accented:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "accented"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "άΐ"
 | 
				
			||||||
 | 
					    show_base:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "αι"
 | 
				
			||||||
 | 
					    space:
 | 
				
			||||||
 | 
					        outline: "spaceline"
 | 
				
			||||||
 | 
					        text: " "
 | 
				
			||||||
 | 
					    Return:
 | 
				
			||||||
 | 
					        outline: "wide"
 | 
				
			||||||
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
 | 
					    period:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "."
 | 
				
			||||||
 | 
					    period_upper:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "·"
 | 
				
			||||||
 | 
					    comma:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: ","
 | 
				
			||||||
 | 
					    colon:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: ":"
 | 
				
			||||||
 | 
					    semicolon:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: ";"
 | 
				
			||||||
 | 
					    apostrophe:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "᾿"
 | 
				
			||||||
 | 
					    exclam:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "!"
 | 
				
			||||||
 | 
					    eis_l:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "«"
 | 
				
			||||||
 | 
					    eis_r:
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        text: "»"
 | 
				
			||||||
 | 
					    aring:
 | 
				
			||||||
 | 
					        text: "å"
 | 
				
			||||||
 | 
					    Aring:
 | 
				
			||||||
 | 
					        text: "Å"
 | 
				
			||||||
 | 
					    oslash:
 | 
				
			||||||
 | 
					        text: "ø"
 | 
				
			||||||
 | 
					    Oslash:
 | 
				
			||||||
 | 
					        text: "Ø"
 | 
				
			||||||
 | 
					    ae:
 | 
				
			||||||
 | 
					        text: "æ"
 | 
				
			||||||
 | 
					    AE:
 | 
				
			||||||
 | 
					        text: "Æ"
 | 
				
			||||||
 | 
					    asterisk:
 | 
				
			||||||
 | 
					        text: "*"
 | 
				
			||||||
 | 
					    asciitilde:
 | 
				
			||||||
 | 
					        text: "~"
 | 
				
			||||||
 | 
					    quoteleft:
 | 
				
			||||||
 | 
					        text: "`"
 | 
				
			||||||
 | 
					    bar:
 | 
				
			||||||
 | 
					        text: "|"
 | 
				
			||||||
 | 
					    U00B7:
 | 
				
			||||||
 | 
					        text: "·"
 | 
				
			||||||
 | 
					    squareroot:
 | 
				
			||||||
 | 
					        text: "√"
 | 
				
			||||||
 | 
					    Greek_pi:
 | 
				
			||||||
 | 
					        text: "π"
 | 
				
			||||||
 | 
					    division:
 | 
				
			||||||
 | 
					        text: "÷"
 | 
				
			||||||
 | 
					    multiply:
 | 
				
			||||||
 | 
					        text: "×"
 | 
				
			||||||
 | 
					    paragraph:
 | 
				
			||||||
 | 
					        text: "¶"
 | 
				
			||||||
 | 
					    Greek_tau:
 | 
				
			||||||
 | 
					        text: "τ"
 | 
				
			||||||
 | 
					    copyright:
 | 
				
			||||||
 | 
					        text: "©"
 | 
				
			||||||
 | 
					    numbersign:
 | 
				
			||||||
 | 
					        text: "#"
 | 
				
			||||||
 | 
					    U00AE:
 | 
				
			||||||
 | 
					        text: "®"
 | 
				
			||||||
 | 
					    at:
 | 
				
			||||||
 | 
					        text: "@"
 | 
				
			||||||
 | 
					    dollar:
 | 
				
			||||||
 | 
					        text: "$"
 | 
				
			||||||
 | 
					    U00A3:
 | 
				
			||||||
 | 
					        text: "£"
 | 
				
			||||||
 | 
					    percent:
 | 
				
			||||||
 | 
					        text: "%"
 | 
				
			||||||
 | 
					    EuroSign:
 | 
				
			||||||
 | 
					        text: "€"
 | 
				
			||||||
 | 
					    ampersand:
 | 
				
			||||||
 | 
					        text: "&"
 | 
				
			||||||
 | 
					    U00A5:
 | 
				
			||||||
 | 
					        text: "¥"
 | 
				
			||||||
 | 
					    minus:
 | 
				
			||||||
 | 
					        text: "-"
 | 
				
			||||||
 | 
					    asciicircum:
 | 
				
			||||||
 | 
					        text: "^"
 | 
				
			||||||
 | 
					    underscore:
 | 
				
			||||||
 | 
					        text: "_"
 | 
				
			||||||
 | 
					    degree:
 | 
				
			||||||
 | 
					        text: "°"
 | 
				
			||||||
 | 
					    plus:
 | 
				
			||||||
 | 
					        text: "+"
 | 
				
			||||||
 | 
					    equal:
 | 
				
			||||||
 | 
					        text: "="
 | 
				
			||||||
 | 
					    parenleft:
 | 
				
			||||||
 | 
					        text: "("
 | 
				
			||||||
 | 
					    parenright:
 | 
				
			||||||
 | 
					        text: ")"
 | 
				
			||||||
 | 
					    braceleft:
 | 
				
			||||||
 | 
					        text: "{"
 | 
				
			||||||
 | 
					    braceright:
 | 
				
			||||||
 | 
					        text: "}"
 | 
				
			||||||
 | 
					    backslash:
 | 
				
			||||||
 | 
					        text: "\\"
 | 
				
			||||||
 | 
					    slash:
 | 
				
			||||||
 | 
					        text: "/"
 | 
				
			||||||
 | 
					    quotedbl:
 | 
				
			||||||
 | 
					        text: "\""
 | 
				
			||||||
 | 
					    quoteright:
 | 
				
			||||||
 | 
					        text: "'"
 | 
				
			||||||
 | 
					    less:
 | 
				
			||||||
 | 
					        text: "<"
 | 
				
			||||||
 | 
					    greater:
 | 
				
			||||||
 | 
					        text: ">"
 | 
				
			||||||
 | 
					    question:
 | 
				
			||||||
 | 
					        text: "?"
 | 
				
			||||||
 | 
					    bracketleft:
 | 
				
			||||||
 | 
					        text: "["
 | 
				
			||||||
 | 
					    bracketright:
 | 
				
			||||||
 | 
					        text: "]"
 | 
				
			||||||
							
								
								
									
										89
									
								
								data/keyboards/ro.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								data/keyboards/ro.yaml
									
									
									
									
									
										Normal 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: 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   , \" ' colon ; ! ?  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters show_eschars preferences         space        . Return"
 | 
				
			||||||
 | 
					    symbols:
 | 
				
			||||||
 | 
					        - "~ ` | · √ π τ ÷ × ¶"
 | 
				
			||||||
 | 
					        - "© ® £ $ ¥ ^ ° * { }"
 | 
				
			||||||
 | 
					        - "show_numbers_from_symbols   \\ / < > = [ ]  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters show_eschars preferences         space        , Return"
 | 
				
			||||||
 | 
					    eschars:
 | 
				
			||||||
 | 
					        - "ă â î ș ț á é í ó ü"
 | 
				
			||||||
 | 
					        - "Ă Â Î Ș Ț Á É Í Ó Ü"
 | 
				
			||||||
 | 
					        - "show_numbers_from_symbols „ ” « » ― { } 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: "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"
 | 
				
			||||||
							
								
								
									
										89
									
								
								data/keyboards/ro_wide.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								data/keyboards/ro_wide.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					outlines:
 | 
				
			||||||
 | 
					    default: { width: 54, height: 42 }
 | 
				
			||||||
 | 
					    altline: { width: 81, height: 42 }
 | 
				
			||||||
 | 
					    wide: { width: 108, height: 42 }
 | 
				
			||||||
 | 
					    spaceline: { width: 153, 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 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   , \" ' colon ; ! ?  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters show_eschars preferences         space        . Return"
 | 
				
			||||||
 | 
					    symbols:
 | 
				
			||||||
 | 
					        - "~ ` | · √ π τ ÷ × ¶"
 | 
				
			||||||
 | 
					        - "© ® £ $ ¥ ^ ° * { }"
 | 
				
			||||||
 | 
					        - "show_numbers_from_symbols   \\ / < > = [ ]  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters show_eschars preferences         space        , Return"
 | 
				
			||||||
 | 
					    eschars:
 | 
				
			||||||
 | 
					        - "ă â î ș ț á é í ó ü"
 | 
				
			||||||
 | 
					        - "Ă Â Î Ș Ț Á É Í Ó Ü"
 | 
				
			||||||
 | 
					        - "show_numbers_from_symbols „ ” « » ― { } 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: "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"
 | 
				
			||||||
@ -1,34 +1,22 @@
 | 
				
			|||||||
 | 
					/* Adwaita-dark style keyboard */
 | 
				
			||||||
sq_view {
 | 
					sq_view {
 | 
				
			||||||
    background-color: rgba(0, 0, 0, 255);
 | 
					    background-color: rgba(0, 0, 0, 255);
 | 
				
			||||||
    color: #ffffff;
 | 
					    color: #ffffff;
 | 
				
			||||||
    font-family: cantarell, sans-serif;
 | 
					 | 
				
			||||||
    font-size: 25px;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_view sq_button {
 | 
					sq_view sq_button {
 | 
				
			||||||
    color: #deddda;
 | 
					    color: #deddda;
 | 
				
			||||||
    background: #464448;
 | 
					    background: #464448;
 | 
				
			||||||
    border-style: solid;
 | 
					 | 
				
			||||||
    border-width: 1px;
 | 
					 | 
				
			||||||
    border-color: #5e5c64;
 | 
					 | 
				
			||||||
    border-radius: 3px;
 | 
					 | 
				
			||||||
    margin: 4px 2px 4px 2px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sq_view.wide sq_button {
 | 
					 | 
				
			||||||
    margin: 1px 1px 1px 1px;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button:active {
 | 
					sq_button:active {
 | 
				
			||||||
    background: #747077;
 | 
					    background: #747077;
 | 
				
			||||||
    border-color: #96949d;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button.altline,
 | 
					sq_button.altline,
 | 
				
			||||||
sq_button.special,
 | 
					sq_button.special,
 | 
				
			||||||
sq_button.wide {
 | 
					sq_button.wide {
 | 
				
			||||||
    background: #2b292f;
 | 
					    background: #2b292f;
 | 
				
			||||||
    border-color: #3e3a44;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button.latched {
 | 
					sq_button.latched {
 | 
				
			||||||
@ -41,22 +29,12 @@ sq_button.locked {
 | 
				
			|||||||
    color: #1c71d8;
 | 
					    color: #1c71d8;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button.action {
 | 
					 | 
				
			||||||
    font-size: 0.75em;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sq_button.small {
 | 
					 | 
				
			||||||
    font-size: 0.5em;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#Return {
 | 
					#Return {
 | 
				
			||||||
    background: #1c71d8;
 | 
					    background: #1c71d8;
 | 
				
			||||||
    border-color: #1a5fb4;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Return:active {
 | 
					#Return:active {
 | 
				
			||||||
    background: #1c71d8;
 | 
					    background: #1c71d8;
 | 
				
			||||||
    border-color: #3584e4;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@import url("resource:///sm/puri/squeekboard/common.css");
 | 
					@import url("resource:///sm/puri/squeekboard/common.css");
 | 
				
			||||||
 | 
				
			|||||||
@ -1,65 +1,47 @@
 | 
				
			|||||||
 | 
					/* Keyboard style */
 | 
				
			||||||
sq_view {
 | 
					sq_view {
 | 
				
			||||||
    background-color: @theme_base_color; /*rgba(0, 0, 0, 255);*/
 | 
					    background-color: mix(@theme_base_color, @theme_fg_color, 0.1);
 | 
				
			||||||
    color: @theme_text_color; /*#ffffff;*/
 | 
					    box-shadow:inset 0 1px 0 0 mix(@borders, @theme_base_color, 0.8);
 | 
				
			||||||
    font-family: cantarell, sans-serif;
 | 
					 | 
				
			||||||
    font-size: 25px;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_view sq_button {
 | 
					sq_button {
 | 
				
			||||||
    color: @theme_fg_color; /*#deddda;*/
 | 
					    color: @theme_fg_color;
 | 
				
			||||||
    background: mix(@theme_bg_color, @theme_base_color, -0.5); /* #464448; */
 | 
					    background: alpha(@theme_fg_color, 0.07); 
 | 
				
			||||||
    border-style: solid;
 | 
					    box-shadow: 0 1px 0 0 rgba(0,0,0,0.2); 
 | 
				
			||||||
    border-width: 1px;
 | 
					 | 
				
			||||||
    border-color: @borders; /* #5e5c64;*/
 | 
					 | 
				
			||||||
    border-radius: 3px;
 | 
					 | 
				
			||||||
    margin: 4px 2px 4px 2px;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_view.wide sq_button {
 | 
					sq_button:active {
 | 
				
			||||||
    margin: 1px 1px 1px 1px;
 | 
					    background: alpha(@theme_fg_color, 0.11);
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sq_button:active,
 | 
					 | 
				
			||||||
sq_button.altline:active,
 | 
					 | 
				
			||||||
sq_button.special:active,
 | 
					 | 
				
			||||||
sq_button.wide:active {
 | 
					 | 
				
			||||||
    background: mix(@theme_bg_color, @theme_selected_bg_color, 0.4);/* #747077; */
 | 
					 | 
				
			||||||
    border-color: mix(@borders, @theme_selected_fg_color, 0.5);/* #96949d; */
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button.altline,
 | 
					sq_button.altline,
 | 
				
			||||||
sq_button.special,
 | 
					sq_button.special {
 | 
				
			||||||
sq_button.wide {
 | 
					    background: alpha(@theme_fg_color, 0.15); 
 | 
				
			||||||
    background: mix(@theme_bg_color, @theme_base_color, 0.5); /*#2b292f;*/
 | 
					}
 | 
				
			||||||
    border-color: @borders; /* #3e3a44; */
 | 
					
 | 
				
			||||||
 | 
					sq_button.altline:active,
 | 
				
			||||||
 | 
					sq_button.special:active {
 | 
				
			||||||
 | 
					    background: alpha(@theme_fg_color, 0.2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button.latched {
 | 
					sq_button.latched {
 | 
				
			||||||
    background: @theme_fg_color; /*#ffffff;*/
 | 
					    background: alpha(@theme_fg_color, 0.2); 
 | 
				
			||||||
    color: @theme_bg_color; /*#2b292f;*/
 | 
					    color: alpha(@theme_fg_color, 0.8);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button.locked {
 | 
					sq_button.locked {
 | 
				
			||||||
    background: @theme_fg_color; /*#ffffff;*/
 | 
					    background: alpha(@theme_fg_color, 0.5);
 | 
				
			||||||
    color: mix(@theme_selected_bg_color, @theme_bg_color, 0.4); /*#2b292f;*/
 | 
					    color: @theme_base_color;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sq_button.action {
 | 
					 | 
				
			||||||
    font-size: 0.75em;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sq_button.small {
 | 
					 | 
				
			||||||
    font-size: 0.5em;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Return {
 | 
					#Return {
 | 
				
			||||||
    background: @theme_selected_bg_color; /* #1c71d8; */
 | 
					    background: @theme_selected_bg_color;
 | 
				
			||||||
    border-color: @borders; /*#1a5fb4;*/
 | 
					    color: @theme_selected_fg_color;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Return:active {
 | 
					#Return:active {
 | 
				
			||||||
    background: mix(@theme_selected_bg_color, @theme_bg_color, 0.4); /*#1c71d8;*/
 | 
					    background: mix(@theme_selected_bg_color, black, 0.2);
 | 
				
			||||||
    border-color: @borders; /*#3584e4;*/
 | 
					    color: mix(@theme_selected_fg_color, black, 0.2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@import url("resource:///sm/puri/squeekboard/common.css");
 | 
					@import url("resource:///sm/puri/squeekboard/common.css");
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								debian/cargo/config
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/cargo/config
									
									
									
									
										vendored
									
									
								
							@ -9,4 +9,3 @@ replace-with = 'vendored-sources'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[source.vendored-sources]
 | 
					[source.vendored-sources]
 | 
				
			||||||
directory = '/usr/share/cargo/registry'
 | 
					directory = '/usr/share/cargo/registry'
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										162
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										162
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,165 @@
 | 
				
			|||||||
 | 
					squeekboard (1.18.0-1) experimental; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Hugo Carvalho ]
 | 
				
			||||||
 | 
					  * Add Portuguese translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Мирослав Николић ]
 | 
				
			||||||
 | 
					  * Add Serbian translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ William Wold ]
 | 
				
			||||||
 | 
					  * Do not reset pending state on zwp_input_method_v2.done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Balázs Úr ]
 | 
				
			||||||
 | 
					  * Add Hungarian translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Emin Tufan Çetin ]
 | 
				
			||||||
 | 
					  * Add Turkish translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Piotr Drąg ]
 | 
				
			||||||
 | 
					  * Add Polish translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pablo Correa Gómez ]
 | 
				
			||||||
 | 
					  * Add Spanish translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vittorio Monti ]
 | 
				
			||||||
 | 
					  * Add Italian translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Dorota Czaplejewicz ]
 | 
				
			||||||
 | 
					  * build: Replace missing crates.io dependency with Purism-hosted one
 | 
				
			||||||
 | 
					  * ci: Allow failure on sid
 | 
				
			||||||
 | 
					  * build: Update clap on newer Debian
 | 
				
			||||||
 | 
					  * panel: Use scaling to set height
 | 
				
			||||||
 | 
					  * layouts: Add Greek Polytonic
 | 
				
			||||||
 | 
					  * debug: Add dbus interface to control debug prints
 | 
				
			||||||
 | 
					  * output: Store physical size
 | 
				
			||||||
 | 
					  * state: Derive panel size from physical click target size
 | 
				
			||||||
 | 
					  * Clean up size types
 | 
				
			||||||
 | 
					  * state: Add sizing unit test
 | 
				
			||||||
 | 
					  * layouts: Register gr_wide
 | 
				
			||||||
 | 
					  * CI: Build Rust code reference
 | 
				
			||||||
 | 
					  * CI: Add gitlab pages deployment
 | 
				
			||||||
 | 
					  * panel: Split away panel handling
 | 
				
			||||||
 | 
					  * cargo: Add zbus to newer Debian
 | 
				
			||||||
 | 
					  * docs: Update location
 | 
				
			||||||
 | 
					  * docs: Link to reference
 | 
				
			||||||
 | 
					  * docs: Make index more logical
 | 
				
			||||||
 | 
					  * Update Cargo lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Sotiris Papadopoulos ]
 | 
				
			||||||
 | 
					  * Update gr.yaml to take advantage of more space per symbol. Creation of a wide variant...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Arnaud Ferraris ]
 | 
				
			||||||
 | 
					  * state: fix "wide mode" detection in portrait orientation
 | 
				
			||||||
 | 
					  * layout: allow stretching the layout by a small amount
 | 
				
			||||||
 | 
					  * layout: fix build on i386
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Sungjoon Moon ]
 | 
				
			||||||
 | 
					  * Add Korean translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Quentin PAGÈS ]
 | 
				
			||||||
 | 
					  * Add Occitan translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Zurab Kargareteli ]
 | 
				
			||||||
 | 
					  * Add Georgian translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Mon, 25 Apr 2022 13:12:36 +0000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					squeekboard (1.17.0-1) experimental; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Dorota Czaplejewicz ]
 | 
				
			||||||
 | 
					  * docs: Detail the release process better
 | 
				
			||||||
 | 
					  * cleanup: Remove unused header lines
 | 
				
			||||||
 | 
					  * docstrings: Clarify the purpose of Receiver
 | 
				
			||||||
 | 
					  * wayland: Move initialization to the Rust side
 | 
				
			||||||
 | 
					  * ffi: Remove unnecessary pointers to InputMethod
 | 
				
			||||||
 | 
					  * outputs: Clean up for more Rust usage
 | 
				
			||||||
 | 
					  * outputs: Notify the state manager about changes
 | 
				
			||||||
 | 
					  * outputs: Handle removal
 | 
				
			||||||
 | 
					  * Save outputs state
 | 
				
			||||||
 | 
					  * Store preferred output
 | 
				
			||||||
 | 
					  * deps: Vendor assert_matches
 | 
				
			||||||
 | 
					  * Carry output information on visible command all the way to C
 | 
				
			||||||
 | 
					  * Don't reach for globals to choose output
 | 
				
			||||||
 | 
					  * visibility: Forward panel height information to window creation
 | 
				
			||||||
 | 
					  * outputs: Remove ui manager
 | 
				
			||||||
 | 
					  * output: Use new source of panel height information
 | 
				
			||||||
 | 
					  * panel: Apply a hard limit of 1/2 height
 | 
				
			||||||
 | 
					  * cargo: Update lockfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Cosmin Humeniuc ]
 | 
				
			||||||
 | 
					  * Add Romanian layout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Sam Hewitt ]
 | 
				
			||||||
 | 
					  * data: Update stylesheet with upstream design
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Tor ]
 | 
				
			||||||
 | 
					  * Make compatible with latest cargo deps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Luís Fernando Stürmer da Rosa ]
 | 
				
			||||||
 | 
					  * Update Brazilian Portuguese translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Fran Dieguez ]
 | 
				
			||||||
 | 
					  * Add Galician translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ William Wold ]
 | 
				
			||||||
 | 
					  * Check if dbus handler is null before using
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Yosef Or Boczko ]
 | 
				
			||||||
 | 
					  * Add Hebrew translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Tue, 25 Jan 2022 11:24:04 +0000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					squeekboard (1.16.0-1) experimental; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Dorota Czaplejewicz ]
 | 
				
			||||||
 | 
					  * build: Remove regex crate
 | 
				
			||||||
 | 
					  * ci: Use bookworm image
 | 
				
			||||||
 | 
					  * build: Pin transitive dependencies
 | 
				
			||||||
 | 
					  * cargo: Update Cargo.lock with pinned dependencies
 | 
				
			||||||
 | 
					  * CI: Use byzantium as the base
 | 
				
			||||||
 | 
					  * cargo: Bump dependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Guido Günther ]
 | 
				
			||||||
 | 
					  * po: Fix ui file name
 | 
				
			||||||
 | 
					  * entry: Mark as executable
 | 
				
			||||||
 | 
					  * entry: Only activate purpose timer when focused
 | 
				
			||||||
 | 
					  * entry: Add another input hint
 | 
				
			||||||
 | 
					  * Add entry test using GTK4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Rafael Fontenelle ]
 | 
				
			||||||
 | 
					  * Add Brazilian Portuguese translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Yuri Chornoivan ]
 | 
				
			||||||
 | 
					  * Add Ukrainian translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Luna Jernberg ]
 | 
				
			||||||
 | 
					  * Add Swedish Translation
 | 
				
			||||||
 | 
					  * Update sv.po
 | 
				
			||||||
 | 
					  * Update LINGUAS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Fabio Tomat ]
 | 
				
			||||||
 | 
					  * Add Friulian translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Daniel Șerbănescu ]
 | 
				
			||||||
 | 
					  * Add Romanian translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Matej Urbančič ]
 | 
				
			||||||
 | 
					  * Add Slovenian translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Nathan Follens ]
 | 
				
			||||||
 | 
					  * Add Dutch translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Jiri Grönroos ]
 | 
				
			||||||
 | 
					  * Add Finnish translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Danial Behzadi ]
 | 
				
			||||||
 | 
					  * Add Persian translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Jordi Mas i Hernandez ]
 | 
				
			||||||
 | 
					  * Add Catalan translation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Tue, 25 Jan 2022 11:24:04 +0000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
squeekboard (1.15.0-1) experimental; urgency=medium
 | 
					squeekboard (1.15.0-1) experimental; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [ Khaled Eldoheiri ]
 | 
					  [ Khaled Eldoheiri ]
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@ -20,10 +20,10 @@ Build-Depends:
 | 
				
			|||||||
 librust-gtk+v3-22-dev (>= 0.5),
 | 
					 librust-gtk+v3-22-dev (>= 0.5),
 | 
				
			||||||
 librust-gtk-sys-dev,
 | 
					 librust-gtk-sys-dev,
 | 
				
			||||||
 librust-maplit-1-dev (>= 1.0),
 | 
					 librust-maplit-1-dev (>= 1.0),
 | 
				
			||||||
 librust-regex-1-dev (>= 1.1),
 | 
					 | 
				
			||||||
 librust-serde-derive-1-dev (>= 1.0),
 | 
					 librust-serde-derive-1-dev (>= 1.0),
 | 
				
			||||||
 librust-serde-yaml-0.8-dev (>= 0.8),
 | 
					 librust-serde-yaml-0.8-dev (>= 0.8),
 | 
				
			||||||
 librust-xkbcommon-0.4+wayland-dev (>= 0.4),
 | 
					 librust-xkbcommon-0.4+wayland-dev (>= 0.4),
 | 
				
			||||||
 | 
					 librust-zbus-dev (>=1.0),
 | 
				
			||||||
 libwayland-dev (>= 1.16),
 | 
					 libwayland-dev (>= 1.16),
 | 
				
			||||||
 lsb-release,
 | 
					 lsb-release,
 | 
				
			||||||
 python3,
 | 
					 python3,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										59
									
								
								debian/control-newer
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								debian/control-newer
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					Source: squeekboard
 | 
				
			||||||
 | 
					Section: x11
 | 
				
			||||||
 | 
					Priority: optional
 | 
				
			||||||
 | 
					Maintainer: Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>
 | 
				
			||||||
 | 
					Build-Depends:
 | 
				
			||||||
 | 
					 cargo,
 | 
				
			||||||
 | 
					 debhelper-compat (= 13),
 | 
				
			||||||
 | 
					 meson (>=0.51.0),
 | 
				
			||||||
 | 
					 ninja-build,
 | 
				
			||||||
 | 
					 pkg-config,
 | 
				
			||||||
 | 
					 libglib2.0-dev,
 | 
				
			||||||
 | 
					 libgnome-desktop-3-dev,
 | 
				
			||||||
 | 
					 libgtk-3-dev,
 | 
				
			||||||
 | 
					 libfeedback-dev,
 | 
				
			||||||
 | 
					 librust-bitflags-dev (>= 1.0),
 | 
				
			||||||
 | 
					 librust-clap-dev (>= 2.32),
 | 
				
			||||||
 | 
					 librust-gio+v2-58-dev,
 | 
				
			||||||
 | 
					 librust-glib+v2-58-dev,
 | 
				
			||||||
 | 
					 librust-glib-sys-dev,
 | 
				
			||||||
 | 
					 librust-gtk+v3-22-dev (>= 0.5),
 | 
				
			||||||
 | 
					 librust-gtk-sys-dev,
 | 
				
			||||||
 | 
					 librust-maplit-1-dev (>= 1.0),
 | 
				
			||||||
 | 
					 librust-serde-derive-1-dev (>= 1.0),
 | 
				
			||||||
 | 
					 librust-serde-yaml-0.8-dev (>= 0.8),
 | 
				
			||||||
 | 
					 librust-xkbcommon-0.4+wayland-dev (>= 0.4),
 | 
				
			||||||
 | 
					 librust-zbus-dev (>= 1.9),
 | 
				
			||||||
 | 
					 libwayland-dev (>= 1.16),
 | 
				
			||||||
 | 
					 lsb-release,
 | 
				
			||||||
 | 
					 python3,
 | 
				
			||||||
 | 
					 python3-ruamel.yaml,
 | 
				
			||||||
 | 
					 rustc,
 | 
				
			||||||
 | 
					 wayland-protocols (>= 1.14),
 | 
				
			||||||
 | 
					Standards-Version: 4.1.3
 | 
				
			||||||
 | 
					Homepage: https://source.puri.sm/Librem5/squeekboard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Package: squeekboard
 | 
				
			||||||
 | 
					Architecture: linux-any
 | 
				
			||||||
 | 
					Depends:
 | 
				
			||||||
 | 
					# for the Adwaita-dark theme
 | 
				
			||||||
 | 
					 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Package: squeekboard-devel
 | 
				
			||||||
 | 
					Architecture: linux-any
 | 
				
			||||||
 | 
					Depends:
 | 
				
			||||||
 | 
					 python3,
 | 
				
			||||||
 | 
					 python3-gi,
 | 
				
			||||||
 | 
					 ${shlibs:Depends},
 | 
				
			||||||
 | 
					 ${misc:Depends},
 | 
				
			||||||
 | 
					Description: Resources for making Squeekboard layouts
 | 
				
			||||||
 | 
					 Tools for creating and testing Squeekboard layouts:
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					  * squeekboard-entry
 | 
				
			||||||
 | 
					  * squeekboard-test-layout
 | 
				
			||||||
							
								
								
									
										8
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@ -25,10 +25,10 @@ export RUSTFLAGS = --remap-path-prefix=$(CURDIR)=/remap-pwd $(xgot)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
distrel := $(shell lsb_release --codename --short)
 | 
					distrel := $(shell lsb_release --codename --short)
 | 
				
			||||||
ifneq (,$(filter $(distrel),buster amber))
 | 
					ifneq (,$(filter $(distrel),sid))
 | 
				
			||||||
	legacy = true
 | 
						newer = true
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
	legacy = false
 | 
						newer = false
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%:
 | 
					%:
 | 
				
			||||||
@ -38,6 +38,6 @@ endif
 | 
				
			|||||||
# causing Cargo to refuse to build with a crates.io copy
 | 
					# causing Cargo to refuse to build with a crates.io copy
 | 
				
			||||||
override_dh_auto_configure:
 | 
					override_dh_auto_configure:
 | 
				
			||||||
	[ ! -f Cargo.lock ] || rm Cargo.lock
 | 
						[ ! -f Cargo.lock ] || rm Cargo.lock
 | 
				
			||||||
	dh_auto_configure -- -Dlegacy=$(legacy)
 | 
						dh_auto_configure -- -Dnewer=$(newer) -Donline=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
override_dh_autoreconf:
 | 
					override_dh_autoreconf:
 | 
				
			||||||
 | 
				
			|||||||
@ -102,6 +102,17 @@ contain a comma separated list of:
 | 
				
			|||||||
Coding
 | 
					Coding
 | 
				
			||||||
------
 | 
					------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Reference docs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Reference documentation can be generated using:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					cd squeekboard_build/ 
 | 
				
			||||||
 | 
					../squeekboard_source/cargo.sh doc --no-deps --document-private-items
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					as well as found [online](https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Project structure
 | 
					### Project structure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Rust modules should be split into 2 categories: libraries, and user interface. They differ in the way they do error handling.
 | 
					Rust modules should be split into 2 categories: libraries, and user interface. They differ in the way they do error handling.
 | 
				
			||||||
@ -205,6 +216,7 @@ While the file is not actually used, it's a good idea to save the config in case
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
cd squeekboard-build
 | 
					cd squeekboard-build
 | 
				
			||||||
 | 
					.../squeekboard-source/cargo.sh update
 | 
				
			||||||
ninja test
 | 
					ninja test
 | 
				
			||||||
cp ./Cargo.lock .../squeekboard-source
 | 
					cp ./Cargo.lock .../squeekboard-source
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								doc/index.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								doc/index.md
									
									
									
									
									
								
							@ -1,13 +1,6 @@
 | 
				
			|||||||
Welcome to squeekboard's documentation!
 | 
					Welcome to squeekboard's documentation!
 | 
				
			||||||
=======================================
 | 
					=======================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Contents
 | 
					 | 
				
			||||||
--------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* [Tutorial](tutorial.md)
 | 
					 | 
				
			||||||
* [Contributing](hacking.md)
 | 
					 | 
				
			||||||
* [Switching views](views.md)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Introduction
 | 
					Introduction
 | 
				
			||||||
------------
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -22,9 +15,15 @@ Layouts are created using a text-based format, based on YAML.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
TODO: Provide a description of the format.
 | 
					TODO: Provide a description of the format.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Views
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Squeekboard layouts are separated into *views* and use a *room metaphor* to [switch views](views.md).
 | 
					Squeekboard layouts are separated into *views* and use a *room metaphor* to [switch views](views.md).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Contributions
 | 
					Contributions
 | 
				
			||||||
-------------
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Anyone is free to modify *squeekboard*. See the [contributing document](hacking.md).
 | 
					Anyone is free to modify *squeekboard*. See the [contributing document](hacking.md).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Code documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To expose the structure of Squeekboard in detail, there's a [code reference](doc/rs).
 | 
				
			||||||
@ -55,6 +55,8 @@ typedef struct _EekGtkKeyboardPrivate
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    GdkEventSequence *sequence; // unowned reference
 | 
					    GdkEventSequence *sequence; // unowned reference
 | 
				
			||||||
    LfbEvent *event;
 | 
					    LfbEvent *event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gulong kb_signal;
 | 
				
			||||||
} EekGtkKeyboardPrivate;
 | 
					} EekGtkKeyboardPrivate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
 | 
					G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
 | 
				
			||||||
@ -307,12 +309,19 @@ eek_gtk_keyboard_set_property (GObject      *object,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This may actually get called multiple times in a row
 | 
				
			||||||
 | 
					// if both a parent object and its parent get destroyed
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
eek_gtk_keyboard_dispose (GObject *object)
 | 
					eek_gtk_keyboard_dispose (GObject *object)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekGtkKeyboard        *self = EEK_GTK_KEYBOARD (object);
 | 
					    EekGtkKeyboard        *self = EEK_GTK_KEYBOARD (object);
 | 
				
			||||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
					    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (priv->kb_signal != 0) {
 | 
				
			||||||
 | 
					        g_signal_handler_disconnect(priv->eekboard_context, priv->kb_signal);
 | 
				
			||||||
 | 
					        priv->kb_signal = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (priv->renderer) {
 | 
					    if (priv->renderer) {
 | 
				
			||||||
        eek_renderer_free(priv->renderer);
 | 
					        eek_renderer_free(priv->renderer);
 | 
				
			||||||
        priv->renderer = NULL;
 | 
					        priv->renderer = NULL;
 | 
				
			||||||
@ -418,12 +427,13 @@ eek_gtk_keyboard_new (EekboardContextService *eekservice,
 | 
				
			|||||||
        .widget_to_layout = {
 | 
					        .widget_to_layout = {
 | 
				
			||||||
            .origin_x = 0,
 | 
					            .origin_x = 0,
 | 
				
			||||||
            .origin_y = 0,
 | 
					            .origin_y = 0,
 | 
				
			||||||
            .scale = 1,
 | 
					            .scale_x = 1,
 | 
				
			||||||
 | 
					            .scale_y = 1,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    priv->render_geometry = initial_geometry;
 | 
					    priv->render_geometry = initial_geometry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_signal_connect (eekservice,
 | 
					    priv->kb_signal = g_signal_connect (eekservice,
 | 
				
			||||||
                      "notify::keyboard",
 | 
					                      "notify::keyboard",
 | 
				
			||||||
                      G_CALLBACK(on_notify_keyboard),
 | 
					                      G_CALLBACK(on_notify_keyboard),
 | 
				
			||||||
                      ret);
 | 
					                      ret);
 | 
				
			||||||
 | 
				
			|||||||
@ -219,7 +219,7 @@ eek_renderer_render_keyboard (EekRenderer *self,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    cairo_save(cr);
 | 
					    cairo_save(cr);
 | 
				
			||||||
    cairo_translate (cr, geometry.widget_to_layout.origin_x, geometry.widget_to_layout.origin_y);
 | 
					    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);
 | 
					    cairo_scale (cr, geometry.widget_to_layout.scale_x, geometry.widget_to_layout.scale_y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    squeek_draw_layout_base_view(keyboard->layout, self, cr);
 | 
					    squeek_draw_layout_base_view(keyboard->layout, self, cr);
 | 
				
			||||||
    squeek_layout_draw_all_changed(keyboard->layout, self, cr, submission);
 | 
					    squeek_layout_draw_all_changed(keyboard->layout, self, cr, submission);
 | 
				
			||||||
 | 
				
			|||||||
@ -87,7 +87,8 @@ void       eek_bounds_free     (EekBounds       *bounds);
 | 
				
			|||||||
struct transformation {
 | 
					struct transformation {
 | 
				
			||||||
    gdouble origin_x;
 | 
					    gdouble origin_x;
 | 
				
			||||||
    gdouble origin_y;
 | 
					    gdouble origin_y;
 | 
				
			||||||
    gdouble scale;
 | 
					    gdouble scale_x;
 | 
				
			||||||
 | 
					    gdouble scale_y;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_END_DECLS
 | 
					G_END_DECLS
 | 
				
			||||||
 | 
				
			|||||||
@ -60,10 +60,10 @@ struct _EekboardContextService {
 | 
				
			|||||||
    LevelKeyboard *keyboard; // currently used keyboard
 | 
					    LevelKeyboard *keyboard; // currently used keyboard
 | 
				
			||||||
    GSettings *settings; // Owned reference
 | 
					    GSettings *settings; // Owned reference
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Maybe TODO: it's used only for fetching layout type.
 | 
					    /// Needed for keymap changes after keyboard updates.
 | 
				
			||||||
    // Maybe let UI push the type to this structure?
 | 
					    // TODO: can the main loop access submission to change the key maps instead?
 | 
				
			||||||
    ServerContextService *ui; // unowned reference
 | 
					    // This should probably land together with passing buttons through state,
 | 
				
			||||||
    /// Needed for keymap changes after keyboard updates
 | 
					    // to avoid race conditions between setting buttons and key maps.
 | 
				
			||||||
    struct submission *submission; // unowned
 | 
					    struct submission *submission; // unowned
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -297,6 +297,8 @@ eekboard_context_service_get_keyboard (EekboardContextService *context)
 | 
				
			|||||||
    return context->keyboard;
 | 
					    return context->keyboard;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Used from Rust.
 | 
				
			||||||
 | 
					// TODO: move hint management to Rust entirely
 | 
				
			||||||
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
 | 
					void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
 | 
				
			||||||
                                               uint32_t hint, uint32_t purpose)
 | 
					                                               uint32_t hint, uint32_t purpose)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -340,7 +342,3 @@ void eekboard_context_service_set_submission(EekboardContextService *context, st
 | 
				
			|||||||
        submission_use_layout(context->submission, context->keyboard->layout, time);
 | 
					        submission_use_layout(context->submission, context->keyboard->layout, time);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
void eekboard_context_service_set_ui(EekboardContextService *context, ServerContextService *ui) {
 | 
					 | 
				
			||||||
    context->ui = ui;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -39,16 +39,12 @@ G_DECLARE_FINAL_TYPE(EekboardContextService, eekboard_context_service, EEKBOARD,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
EekboardContextService *eekboard_context_service_new(struct squeek_layout_state *state);
 | 
					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_submission(EekboardContextService *context, struct submission *submission);
 | 
				
			||||||
void eekboard_context_service_set_ui(EekboardContextService *context, ServerContextService *ui);
 | 
					 | 
				
			||||||
void          eekboard_context_service_destroy (EekboardContextService *context);
 | 
					void          eekboard_context_service_destroy (EekboardContextService *context);
 | 
				
			||||||
LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
 | 
					LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void eekboard_context_service_set_keymap(EekboardContextService *context,
 | 
					void eekboard_context_service_set_keymap(EekboardContextService *context,
 | 
				
			||||||
                                         const LevelKeyboard *keyboard);
 | 
					                                         const LevelKeyboard *keyboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
 | 
					 | 
				
			||||||
                                               uint32_t hint,
 | 
					 | 
				
			||||||
                                               uint32_t purpose);
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *layout, uint32_t timestamp);
 | 
					eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *layout, uint32_t timestamp);
 | 
				
			||||||
G_END_DECLS
 | 
					G_END_DECLS
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								meson.build
									
									
									
									
									
								
							@ -1,7 +1,7 @@
 | 
				
			|||||||
project(
 | 
					project(
 | 
				
			||||||
    'squeekboard',
 | 
					    'squeekboard',
 | 
				
			||||||
    'c', 'rust',
 | 
					    'c', 'rust',
 | 
				
			||||||
    version: '1.15.0',
 | 
					    version: '1.18.0',
 | 
				
			||||||
    license: 'GPLv3',
 | 
					    license: 'GPLv3',
 | 
				
			||||||
    meson_version: '>=0.51.0',
 | 
					    meson_version: '>=0.51.0',
 | 
				
			||||||
    default_options: [
 | 
					    default_options: [
 | 
				
			||||||
@ -96,19 +96,23 @@ cargo_toml_base = configure_file(
 | 
				
			|||||||
    configuration: path_data,
 | 
					    configuration: path_data,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cargo_patch = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cargo_deps = files('Cargo.deps')
 | 
					if get_option('newer') == true
 | 
				
			||||||
 | 
					    cargo_build_flags += ['--features', 'glib_v0_14']
 | 
				
			||||||
if get_option('legacy') == true
 | 
					    cargo_deps = files('Cargo.deps.newer')
 | 
				
			||||||
    cargo_build_flags += ['--features', 'gtk_v0_5,gio_v0_5,rustc_less_1_36']
 | 
					else
 | 
				
			||||||
    cargo_deps = files('Cargo.deps.legacy')
 | 
					    cargo_deps = files('Cargo.deps')
 | 
				
			||||||
 | 
					    if get_option('online') == true
 | 
				
			||||||
 | 
					        cargo_patch = [files('Cargo.deps.online')]
 | 
				
			||||||
 | 
					    endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
cat = find_program('cat')
 | 
					cat = find_program('cat')
 | 
				
			||||||
cargo_toml = custom_target(
 | 
					cargo_toml = custom_target(
 | 
				
			||||||
    'Cargo.toml',
 | 
					    'Cargo.toml',
 | 
				
			||||||
    output: 'Cargo.toml',
 | 
					    output: 'Cargo.toml',
 | 
				
			||||||
    command: [cat, cargo_toml_base, cargo_deps],
 | 
					    command: [cat, cargo_toml_base, cargo_deps] + cargo_patch,
 | 
				
			||||||
    capture: true,
 | 
					    capture: true,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,10 +7,14 @@ option('tests',
 | 
				
			|||||||
       type: 'boolean', value: true,
 | 
					       type: 'boolean', value: true,
 | 
				
			||||||
       description: 'Whether to compile unit tests')
 | 
					       description: 'Whether to compile unit tests')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option('legacy',
 | 
					option('newer',
 | 
				
			||||||
       type: 'boolean', value: false,
 | 
					       type: 'boolean', value: false,
 | 
				
			||||||
       description: 'Build with Deban Buster versions of dependencies')
 | 
					       description: 'Build with dependencies newer than those of Byzantium')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					option('online',
 | 
				
			||||||
 | 
					       type: 'boolean', value: true,
 | 
				
			||||||
 | 
					       description: 'Pull packages from the internet while building, as opposed to a local regstry.')
 | 
				
			||||||
 | 
					       
 | 
				
			||||||
option('strict',
 | 
					option('strict',
 | 
				
			||||||
       type: 'boolean', value: true,
 | 
					       type: 'boolean', value: true,
 | 
				
			||||||
       description: 'Turn more warnings into errors')
 | 
					       description: 'Turn more warnings into errors')
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								po/LINGUAS
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								po/LINGUAS
									
									
									
									
									
								
							@ -1 +1,23 @@
 | 
				
			|||||||
 | 
					ca
 | 
				
			||||||
de
 | 
					de
 | 
				
			||||||
 | 
					es
 | 
				
			||||||
 | 
					fa
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					fur
 | 
				
			||||||
 | 
					gl
 | 
				
			||||||
 | 
					he
 | 
				
			||||||
 | 
					hu
 | 
				
			||||||
 | 
					it
 | 
				
			||||||
 | 
					ka
 | 
				
			||||||
 | 
					ko
 | 
				
			||||||
 | 
					nl
 | 
				
			||||||
 | 
					oc
 | 
				
			||||||
 | 
					pl
 | 
				
			||||||
 | 
					pt
 | 
				
			||||||
 | 
					pt_BR
 | 
				
			||||||
 | 
					ro
 | 
				
			||||||
 | 
					sl
 | 
				
			||||||
 | 
					sr
 | 
				
			||||||
 | 
					tr
 | 
				
			||||||
 | 
					uk
 | 
				
			||||||
 | 
					sv
 | 
				
			||||||
 | 
				
			|||||||
@ -1,2 +1,2 @@
 | 
				
			|||||||
data/popup.ui
 | 
					data/popover.ui
 | 
				
			||||||
data/sm.puri.Squeekboard.desktop.in.in
 | 
					data/sm.puri.Squeekboard.desktop.in.in
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										45
									
								
								po/ca.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								po/ca.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					# Catalan translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# maite <maite.guix@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-01-11 14:31+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-01-20 10:53+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: maite guix <maite.guix@me.com>\n"
 | 
				
			||||||
 | 
					"Language-Team: Catalan <gnome@llistes.softcatala.org>\n"
 | 
				
			||||||
 | 
					"Language: ca\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 "Terminal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Configuració del teclat"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:3
 | 
				
			||||||
 | 
					msgid "Squeekboard"
 | 
				
			||||||
 | 
					msgstr "Teclat virtual"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:4
 | 
				
			||||||
 | 
					msgid "On Screen Keyboard"
 | 
				
			||||||
 | 
					msgstr "Teclat en pantalla"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Un teclat virtual en pantalla"
 | 
				
			||||||
							
								
								
									
										47
									
								
								po/es.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								po/es.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					# Spanish translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
				
			||||||
 | 
					# Pablo Correa Gómez <ablocorrea@hotmail.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-03-20 13:14+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-03-22 21:33+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: Pablo Correa Gómez <ablocorrea@hotmail.com>\n"
 | 
				
			||||||
 | 
					"Language-Team: Spanish; Castilian <gnome-es-list@gnome.org>\n"
 | 
				
			||||||
 | 
					"Language: es\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 3.36.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 "Ajustes de teclado"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Teclado en pantala"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Un teclado virtual en pantalla"
 | 
				
			||||||
							
								
								
									
										45
									
								
								po/fa.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								po/fa.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					# Persian translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Danial Behzadi <dani.behzi@ubuntu.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: 2021-12-26 15:15+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-01-11 18:01+0330\n"
 | 
				
			||||||
 | 
					"Language-Team: Persian <fa@li.org>\n"
 | 
				
			||||||
 | 
					"Language: fa\n"
 | 
				
			||||||
 | 
					"MIME-Version: 1.0\n"
 | 
				
			||||||
 | 
					"Content-Type: text/plain; charset=UTF-8\n"
 | 
				
			||||||
 | 
					"Content-Transfer-Encoding: 8bit\n"
 | 
				
			||||||
 | 
					"Last-Translator: Danial Behzadi <dani.behzi@ubuntu.com>\n"
 | 
				
			||||||
 | 
					"X-Generator: Poedit 3.0\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 "اسکوییکبرد"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "یک صفحهٔ کلید لمسی مجازی"
 | 
				
			||||||
							
								
								
									
										46
									
								
								po/fi.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								po/fi.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					# Finnish translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2021 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Jiri Grönroos <jiri.gronroos@iki.fi>, 2021.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: squeekboard master\n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2021-12-25 13:55+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2021-12-26 17:15+0200\n"
 | 
				
			||||||
 | 
					"Last-Translator: Jiri Grönroos <jiri.gronroos+l10n@iki.fi>\n"
 | 
				
			||||||
 | 
					"Language-Team: Finnish <lokalisointi-lista@googlegroups.com>\n"
 | 
				
			||||||
 | 
					"Language: fi\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: 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 "Pääte"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Näppäimistön asetukset"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Näyttönäppäimistö"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Virtuaalinen näyttönäppäimistö"
 | 
				
			||||||
							
								
								
									
										45
									
								
								po/fur.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								po/fur.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					# Friulian translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2021 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Fabio Tomat <f.t.public@gmail.com>, 2021.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: squeekboard master\n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2021-12-22 13:33+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2021-12-22 15:06+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
 | 
				
			||||||
 | 
					"Language-Team: Friulian <fur@li.org>\n"
 | 
				
			||||||
 | 
					"Language: fur\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 "Terminâl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Impostazions tastiere"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Tastiere a visôr"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Une tastiere virtuâl a visôr"
 | 
				
			||||||
							
								
								
									
										52
									
								
								po/gl.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								po/gl.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					# Galician translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
				
			||||||
 | 
					# Fran Diéguez <frandieguez@gnome.org>, 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-02-02 17:41+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-02-04 16:18+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: Fran Diéguez <frandieguez@gnome.org>\n"
 | 
				
			||||||
 | 
					"Language-Team: Galician <proxecto@trasno.gal>\n"
 | 
				
			||||||
 | 
					"Language: gl\n"
 | 
				
			||||||
 | 
					"MIME-Version: 1.0\n"
 | 
				
			||||||
 | 
					"Content-Type: text/plain; charset=UTF-8\n"
 | 
				
			||||||
 | 
					"Content-Transfer-Encoding: 8bit\n"
 | 
				
			||||||
 | 
					"X-DL-Team: gl\n"
 | 
				
			||||||
 | 
					"X-DL-Module: squeekboard\n"
 | 
				
			||||||
 | 
					"X-DL-Branch: master\n"
 | 
				
			||||||
 | 
					"X-DL-Domain: po\n"
 | 
				
			||||||
 | 
					"X-DL-State: Translating\n"
 | 
				
			||||||
 | 
					"Plural-Forms: nplurals=2; plural=(n != 1)\n"
 | 
				
			||||||
 | 
					"X-Generator: Gtranslator 41.0\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#. translators: This is a emmoji keyboard layout
 | 
				
			||||||
 | 
					#: data/popover.ui:6
 | 
				
			||||||
 | 
					msgid "Emoji"
 | 
				
			||||||
 | 
					msgstr "Emoticono"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#. translators: This is a terminal keyboard layout
 | 
				
			||||||
 | 
					#: data/popover.ui:12
 | 
				
			||||||
 | 
					msgid "Terminal"
 | 
				
			||||||
 | 
					msgstr "Terminal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Preferencias de teclado"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Teclado en pantalla"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Un teclado en pantalla virtual"
 | 
				
			||||||
							
								
								
									
										46
									
								
								po/he.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								po/he.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					# Hebrew translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Yosef Or Boczko <yoseforb@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-02-04 15:22+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-02-14 18:05+0200\n"
 | 
				
			||||||
 | 
					"Last-Translator: Yosef Or Boczko <yoseforb@gmail.com>\n"
 | 
				
			||||||
 | 
					"Language-Team: Hebrew <>\n"
 | 
				
			||||||
 | 
					"Language: he\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 "רגשון"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#. 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 "מקלדת מדומה על המסך"
 | 
				
			||||||
							
								
								
									
										46
									
								
								po/hu.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								po/hu.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					# Hungarian translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 Free Software Foundation, Inc.
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Balázs Úr <ur.balazs at fsf dot hu>, 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-03-12 12:04+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-03-16 01:55+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: Balázs Úr <ur.balazs at fsf dot hu>\n"
 | 
				
			||||||
 | 
					"Language-Team: Hungarian <gnome-hu-list at gnome dot org>\n"
 | 
				
			||||||
 | 
					"Language: hu\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: Lokalize 19.12.3\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#. translators: This is a emmoji keyboard layout
 | 
				
			||||||
 | 
					#: data/popover.ui:6
 | 
				
			||||||
 | 
					msgid "Emoji"
 | 
				
			||||||
 | 
					msgstr "Emodzsi"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#. translators: This is a terminal keyboard layout
 | 
				
			||||||
 | 
					#: data/popover.ui:12
 | 
				
			||||||
 | 
					msgid "Terminal"
 | 
				
			||||||
 | 
					msgstr "Terminál"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Billentyűzetbeállítások"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Képernyő-billentyűzet"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Egy virtuális képernyő-billentyűzet"
 | 
				
			||||||
							
								
								
									
										47
									
								
								po/it.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								po/it.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					# Italian translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2021 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Vittorio <postav@pm.me>, 2021.
 | 
				
			||||||
 | 
					# Vittorio Monti <postav@pm.me>, 2021.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: squeekboard master\n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2021-12-22 19:14+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2021-12-22 20:37+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: Vittorio Monti <postav@pm.me>\n"
 | 
				
			||||||
 | 
					"Language-Team: Italian <gnome-it-list@gnome.org>\n"
 | 
				
			||||||
 | 
					"Language: it\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 3.30.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 "Terminale"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Impostazioni tastiera"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Tastiera su schermo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Una tastiera virtuale su schermo"
 | 
				
			||||||
							
								
								
									
										46
									
								
								po/ka.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								po/ka.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					# SOME DESCRIPTIVE TITLE.
 | 
				
			||||||
 | 
					# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the PACKAGE package.
 | 
				
			||||||
 | 
					# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: \n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2022-02-04 15:22+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-02-08 03:15+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n"
 | 
				
			||||||
 | 
					"Language-Team: \n"
 | 
				
			||||||
 | 
					"Language: ka\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: 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 "ეკრანზე ვირტუალური კლავიატურის ჩვენება"
 | 
				
			||||||
							
								
								
									
										46
									
								
								po/ko.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								po/ko.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					# Korean translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 squeekboard'S COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Moon Sungjoon <sumoon@seoulsaram.org>, 2022.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: \n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2022-04-09 18:43+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-04-11 19:23+0900\n"
 | 
				
			||||||
 | 
					"Last-Translator: Moon Sungjoon <sumoon@seoulsaram.org>\n"
 | 
				
			||||||
 | 
					"Language-Team: \n"
 | 
				
			||||||
 | 
					"Language: ko\n"
 | 
				
			||||||
 | 
					"MIME-Version: 1.0\n"
 | 
				
			||||||
 | 
					"Content-Type: text/plain; charset=UTF-8\n"
 | 
				
			||||||
 | 
					"Content-Transfer-Encoding: 8bit\n"
 | 
				
			||||||
 | 
					"Plural-Forms: nplurals=1; plural=0;\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 "스퀴크 보드"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "가상 키보드"
 | 
				
			||||||
							
								
								
									
										48
									
								
								po/nl.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								po/nl.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					# Dutch translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2021 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Jan Jasper de Kroon <jajadekroon@gmail.com>, 2021.
 | 
				
			||||||
 | 
					# Nathan Follens <nfollens@gnome.org>, 2021.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: squeekboard master\n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2021-12-23 15:18+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2021-12-25 14:04+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: Nathan Follens <nfollens@gnome.org>\n"
 | 
				
			||||||
 | 
					"Language-Team: Dutch <gnome-nl-list@gnome.org>\n"
 | 
				
			||||||
 | 
					"Language: nl\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: 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 "Terminal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Toetsenbordinstellingen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Dit is de naam van de applicatie
 | 
				
			||||||
 | 
					#: 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 "Schermtoetsenbord"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Een virtueel schermtoetsenbord"
 | 
				
			||||||
							
								
								
									
										45
									
								
								po/oc.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								po/oc.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					# Occitan translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Quentin PAGÈS <pages_quentin@hotmail.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-17 06:24+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-04-17 09:17+0200\n"
 | 
				
			||||||
 | 
					"Last-Translator: Quentin PAGÈS\n"
 | 
				
			||||||
 | 
					"Language-Team: Occitan <totenoc@gmail.com>\n"
 | 
				
			||||||
 | 
					"Language: oc\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 "Terminal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Paramètres del clavièr"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Clavièr visual"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Un clavièr virtual sus l’ecran"
 | 
				
			||||||
							
								
								
									
										47
									
								
								po/pl.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								po/pl.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					# Polish translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright © 2022 the squeekboard authors.
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Piotr Drąg <piotrdrag@gmail.com>, 2022.
 | 
				
			||||||
 | 
					# Aviary.pl <community-poland@mozilla.org>, 2022.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: squeekboard\n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2022-03-19 09:34+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-03-20 14:12+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
 | 
				
			||||||
 | 
					"Language-Team: Polish <community-poland@mozilla.org>\n"
 | 
				
			||||||
 | 
					"Language: pl\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==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
 | 
				
			||||||
 | 
					"|| n%100>=20) ? 1 : 2);\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 "Ustawienia klawiatury"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Klawiatura ekranowa"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Wirtualna klawiatura ekranowa"
 | 
				
			||||||
							
								
								
									
										46
									
								
								po/pt.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								po/pt.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					# Portuguese translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Hugo Carvalho <hugokarvalho@hotmail.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-02-26 10:49+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-02-26 18:27+0000\n"
 | 
				
			||||||
 | 
					"Last-Translator: Hugo Carvalho <hugokarvalho@hotmail.com>\n"
 | 
				
			||||||
 | 
					"Language-Team: Portuguese <pt@li.org>\n"
 | 
				
			||||||
 | 
					"Language: pt\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: 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 "Terminal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Definições do teclado"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Teclado no ecrã"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Um teclado virtual no ecrã"
 | 
				
			||||||
							
								
								
									
										47
									
								
								po/pt_BR.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								po/pt_BR.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					# Brazilian Portuguese translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2021 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Rafael Fontenelle <rafaelff@gnome.org>, 2021.
 | 
				
			||||||
 | 
					# Luís Fernando Stürmer da Rosa <luisfsr@dismail.de>, 2021.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: squeekboard master\n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2021-12-22 12:39+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-01-30 12:34-0300\n"
 | 
				
			||||||
 | 
					"Last-Translator: Luís Fernando Stürmer da Rosa <luisfsr@dismail.de>\n"
 | 
				
			||||||
 | 
					"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n"
 | 
				
			||||||
 | 
					"Language: pt_BR\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: Poedit 3.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 "Configurações do teclado"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Teclado virtual"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Um teclado virtual"
 | 
				
			||||||
							
								
								
									
										47
									
								
								po/ro.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								po/ro.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					# Romanian translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2021 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# libre <eposta1@pm.me>, 2021.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: squeekboard master\n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2021-12-22 14:45+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2021-12-22 20:05+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: libre <eposta1@pm.me>\n"
 | 
				
			||||||
 | 
					"Language-Team: Romanian <gnomero-list@lists.sourceforge.net>\n"
 | 
				
			||||||
 | 
					"Language: ro\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==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
 | 
				
			||||||
 | 
					"20)) ? 1 : 2);;\n"
 | 
				
			||||||
 | 
					"X-Generator: Gtranslator 3.30.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 "Terminal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Opțiuni tastatură"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Tastatură pe ecran"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "O tastatură virtuală pe ecran"
 | 
				
			||||||
							
								
								
									
										49
									
								
								po/sl.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								po/sl.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					# Slovenian translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2021 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Matej Urbančič <mateju@src.gnome.org>, 2021.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: squeekboard master\n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2021-12-22 19:14+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2021-12-23 16:17+0100\n"
 | 
				
			||||||
 | 
					"Last-Translator: Matej Urbančič <mateju@svn.gnome.org>\n"
 | 
				
			||||||
 | 
					"Language-Team: Slovenian GNOME Translation Team <gnome-si@googlegroups.com>\n"
 | 
				
			||||||
 | 
					"Language: sl_SI\n"
 | 
				
			||||||
 | 
					"MIME-Version: 1.0\n"
 | 
				
			||||||
 | 
					"Content-Type: text/plain; charset=UTF-8\n"
 | 
				
			||||||
 | 
					"Content-Transfer-Encoding: 8bit\n"
 | 
				
			||||||
 | 
					"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n"
 | 
				
			||||||
 | 
					"%100==4 ? 3 : 0);\n"
 | 
				
			||||||
 | 
					"X-Poedit-SourceCharset: utf-8\n"
 | 
				
			||||||
 | 
					"X-Generator: Poedit 3.0.1\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#. translators: This is a emmoji keyboard layout
 | 
				
			||||||
 | 
					#: data/popover.ui:6
 | 
				
			||||||
 | 
					msgid "Emoji"
 | 
				
			||||||
 | 
					msgstr "Izrazne ikone"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#. translators: This is a terminal keyboard layout
 | 
				
			||||||
 | 
					#: data/popover.ui:12
 | 
				
			||||||
 | 
					msgid "Terminal"
 | 
				
			||||||
 | 
					msgstr "Terminal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Nastavitve tipkovnice"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:3
 | 
				
			||||||
 | 
					msgid "Squeekboard"
 | 
				
			||||||
 | 
					msgstr "Cvilkovnica"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:4
 | 
				
			||||||
 | 
					msgid "On Screen Keyboard"
 | 
				
			||||||
 | 
					msgstr "Zaslonska tipkovnica"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Navidezna zaslonska tipkovnica"
 | 
				
			||||||
							
								
								
									
										45
									
								
								po/sr.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								po/sr.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					# Serbian translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright © 2022 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Мирослав Николић <miroslavnikolic@rocketmail.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-03-08 10:15+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-03-12 13:00+0200\n"
 | 
				
			||||||
 | 
					"Last-Translator: Мирослав Николић <miroslavnikolic@rocketmail.com>\n"
 | 
				
			||||||
 | 
					"Language-Team: Serbian <(nothing)>\n"
 | 
				
			||||||
 | 
					"Language: sr\n"
 | 
				
			||||||
 | 
					"MIME-Version: 1.0\n"
 | 
				
			||||||
 | 
					"Content-Type: text/plain; charset=UTF-8\n"
 | 
				
			||||||
 | 
					"Content-Transfer-Encoding: 8bit\n"
 | 
				
			||||||
 | 
					"Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : n"
 | 
				
			||||||
 | 
					"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\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 "Сквик-табла"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Виртуелна тастатура на екрану"
 | 
				
			||||||
							
								
								
									
										48
									
								
								po/sv.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								po/sv.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					# Swedish translations for squeekboard package.
 | 
				
			||||||
 | 
					# Copyright (C) 2021 THE squeekboard'S COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Automatically generated, 2021.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Luna Jernberg <droidbittin@gmail.com>, 2021.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: \n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
 | 
				
			||||||
 | 
					"issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2021-12-22 12:47+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2021-12-22 14:15+0100\n"
 | 
				
			||||||
 | 
					"Language-Team: \n"
 | 
				
			||||||
 | 
					"MIME-Version: 1.0\n"
 | 
				
			||||||
 | 
					"Content-Type: text/plain; charset=UTF-8\n"
 | 
				
			||||||
 | 
					"Content-Transfer-Encoding: 8bit\n"
 | 
				
			||||||
 | 
					"X-Generator: Poedit 3.0\n"
 | 
				
			||||||
 | 
					"Last-Translator: \n"
 | 
				
			||||||
 | 
					"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
				
			||||||
 | 
					"Language: sv\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 "Tangentbordsinställningar"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Skärmtangentbord"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Ett virtuellt skärmtangentbord"
 | 
				
			||||||
							
								
								
									
										46
									
								
								po/tr.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								po/tr.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					# Turkish translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					# Emin Tufan Çetin <etcetin@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-03-16 00:57+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2022-03-19 12:33+0300\n"
 | 
				
			||||||
 | 
					"Last-Translator: Emin Tufan Çetin <etcetin@gmail.com>\n"
 | 
				
			||||||
 | 
					"Language-Team: Turkish <gnometurk@gnome.org>\n"
 | 
				
			||||||
 | 
					"Language: tr\n"
 | 
				
			||||||
 | 
					"MIME-Version: 1.0\n"
 | 
				
			||||||
 | 
					"Content-Type: text/plain; charset=UTF-8\n"
 | 
				
			||||||
 | 
					"Content-Transfer-Encoding: 8bit\n"
 | 
				
			||||||
 | 
					"Plural-Forms: nplurals=1; plural=0;\n"
 | 
				
			||||||
 | 
					"X-Generator: Poedit 2.4.3\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 "Uçbirim"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/popover.ui:18
 | 
				
			||||||
 | 
					msgid "Keyboard Settings"
 | 
				
			||||||
 | 
					msgstr "Klavye Ayarları"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: 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 "Ekran Klavyesi"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: data/sm.puri.Squeekboard.desktop.in.in:5
 | 
				
			||||||
 | 
					msgid "An on screen virtual keyboard"
 | 
				
			||||||
 | 
					msgstr "Sanal ekran klavyesi"
 | 
				
			||||||
							
								
								
									
										51
									
								
								po/uk.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								po/uk.po
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					# Ukrainian translation for squeekboard.
 | 
				
			||||||
 | 
					# Copyright (C) 2021 squeekboard's COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					# This file is distributed under the same license as the squeekboard package.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Yuri Chornoivan <yurchor@ukr.net>, 2021.
 | 
				
			||||||
 | 
					msgid ""
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Project-Id-Version: squeekboard master\n"
 | 
				
			||||||
 | 
					"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/issues\n"
 | 
				
			||||||
 | 
					"POT-Creation-Date: 2021-12-22 10:36+0000\n"
 | 
				
			||||||
 | 
					"PO-Revision-Date: 2021-12-22 14:46+0200\n"
 | 
				
			||||||
 | 
					"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
 | 
				
			||||||
 | 
					"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n"
 | 
				
			||||||
 | 
					"Language: uk\n"
 | 
				
			||||||
 | 
					"MIME-Version: 1.0\n"
 | 
				
			||||||
 | 
					"Content-Type: text/plain; charset=UTF-8\n"
 | 
				
			||||||
 | 
					"Content-Transfer-Encoding: 8bit\n"
 | 
				
			||||||
 | 
					"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
 | 
				
			||||||
 | 
					"X-Generator: Lokalize 20.12.0\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 ""
 | 
				
			||||||
 | 
					"Екранна віртуальна клавіатура"
 | 
				
			||||||
@ -6,12 +6,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use std::time::Duration;
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::outputs::OutputId;
 | 
				
			||||||
 | 
					use crate::panel::PixelSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The keyboard should hide after this has elapsed to prevent flickering.
 | 
					/// The keyboard should hide after this has elapsed to prevent flickering.
 | 
				
			||||||
pub const HIDING_TIMEOUT: Duration = Duration::from_millis(200);
 | 
					pub const HIDING_TIMEOUT: Duration = Duration::from_millis(200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The outwardly visible state of visibility
 | 
					/// The outwardly visible state of visibility
 | 
				
			||||||
#[derive(PartialEq, Debug, Clone)]
 | 
					#[derive(PartialEq, Debug, Clone)]
 | 
				
			||||||
pub enum Outcome {
 | 
					pub enum Outcome {
 | 
				
			||||||
    Visible,
 | 
					    Visible {
 | 
				
			||||||
 | 
					        output: OutputId,
 | 
				
			||||||
 | 
					        height: PixelSize,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    Hidden,
 | 
					    Hidden,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										358
									
								
								src/assert_matches.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										358
									
								
								src/assert_matches.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,358 @@
 | 
				
			|||||||
 | 
					/* Taken from https://github.com/murarth/assert_matches
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * git commit: 26b8b40a12823c068a829ba475d0eccc13dfc221
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * assert_matches is distributed under the terms of both the MIT license and the Apache License (Version 2.0).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					Copyright (c) 2016 Murarth
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any
 | 
				
			||||||
 | 
					person obtaining a copy of this software and associated
 | 
				
			||||||
 | 
					documentation files (the "Software"), to deal in the
 | 
				
			||||||
 | 
					Software without restriction, including without
 | 
				
			||||||
 | 
					limitation the rights to use, copy, modify, merge,
 | 
				
			||||||
 | 
					publish, distribute, sublicense, and/or sell copies of
 | 
				
			||||||
 | 
					the Software, and to permit persons to whom the Software
 | 
				
			||||||
 | 
					is furnished to do so, subject to the following
 | 
				
			||||||
 | 
					conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice
 | 
				
			||||||
 | 
					shall be included in all copies or substantial portions
 | 
				
			||||||
 | 
					of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
 | 
				
			||||||
 | 
					ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 | 
				
			||||||
 | 
					TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 | 
				
			||||||
 | 
					PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 | 
				
			||||||
 | 
					SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
				
			||||||
 | 
					CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | 
				
			||||||
 | 
					OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
 | 
				
			||||||
 | 
					IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
				
			||||||
 | 
					DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! Provides a macro, `assert_matches!`, which tests whether a value
 | 
				
			||||||
 | 
					//! matches a given pattern, causing a panic if the match fails.
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! See the macro [`assert_matches!`] documentation for more information.
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! Also provides a debug-only counterpart, [`debug_assert_matches!`].
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! See the macro [`debug_assert_matches!`] documentation for more information
 | 
				
			||||||
 | 
					//! about this macro.
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! [`assert_matches!`]: macro.assert_matches.html
 | 
				
			||||||
 | 
					//! [`debug_assert_matches!`]: macro.debug_assert_matches.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#![deny(missing_docs)]
 | 
				
			||||||
 | 
					#![cfg_attr(not(test), no_std)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Asserts that an expression matches a given pattern.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// A guard expression may be supplied to add further restrictions to the
 | 
				
			||||||
 | 
					/// expected value of the expression.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// A `match` arm may be supplied to perform additional assertions or to yield
 | 
				
			||||||
 | 
					/// a value from the macro invocation.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Examples
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					/// #[macro_use] extern crate assert_matches;
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// #[derive(Debug)]
 | 
				
			||||||
 | 
					/// enum Foo {
 | 
				
			||||||
 | 
					///     A(i32),
 | 
				
			||||||
 | 
					///     B(&'static str),
 | 
				
			||||||
 | 
					/// }
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # fn main() {
 | 
				
			||||||
 | 
					/// let a = Foo::A(1);
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // Assert that `a` matches the pattern `Foo::A(_)`.
 | 
				
			||||||
 | 
					/// assert_matches!(a, Foo::A(_));
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // Assert that `a` matches the pattern and
 | 
				
			||||||
 | 
					/// // that the contained value meets the condition `i > 0`.
 | 
				
			||||||
 | 
					/// assert_matches!(a, Foo::A(i) if i > 0);
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// let b = Foo::B("foobar");
 | 
				
			||||||
 | 
					/// 
 | 
				
			||||||
 | 
					/// // Assert that `b` matches the pattern `Foo::B(_)`.
 | 
				
			||||||
 | 
					/// assert_matches!(b, Foo::B(s) => {
 | 
				
			||||||
 | 
					///     // Perform additional assertions on the variable binding `s`.
 | 
				
			||||||
 | 
					///     assert!(s.starts_with("foo"));
 | 
				
			||||||
 | 
					///     assert!(s.ends_with("bar"));
 | 
				
			||||||
 | 
					/// });
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // Assert that `b` matches the pattern and yield the string `s`.
 | 
				
			||||||
 | 
					/// let s = assert_matches!(b, Foo::B(s) => s);
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // Perform an assertion on the value `s`.
 | 
				
			||||||
 | 
					/// assert_eq!(s, "foobar");
 | 
				
			||||||
 | 
					/// # }
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					#[macro_export]
 | 
				
			||||||
 | 
					macro_rules! assert_matches {
 | 
				
			||||||
 | 
					    ( $e:expr , $($pat:pat)|+ ) => {
 | 
				
			||||||
 | 
					        match $e {
 | 
				
			||||||
 | 
					            $($pat)|+ => (),
 | 
				
			||||||
 | 
					            ref e => panic!("assertion failed: `{:?}` does not match `{}`",
 | 
				
			||||||
 | 
					                e, stringify!($($pat)|+))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ( $e:expr , $($pat:pat)|+ if $cond:expr ) => {
 | 
				
			||||||
 | 
					        match $e {
 | 
				
			||||||
 | 
					            $($pat)|+ if $cond => (),
 | 
				
			||||||
 | 
					            ref e => panic!("assertion failed: `{:?}` does not match `{}`",
 | 
				
			||||||
 | 
					                e, stringify!($($pat)|+ if $cond))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ( $e:expr , $($pat:pat)|+ => $arm:expr ) => {
 | 
				
			||||||
 | 
					        match $e {
 | 
				
			||||||
 | 
					            $($pat)|+ => $arm,
 | 
				
			||||||
 | 
					            ref e => panic!("assertion failed: `{:?}` does not match `{}`",
 | 
				
			||||||
 | 
					                e, stringify!($($pat)|+))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ( $e:expr , $($pat:pat)|+ if $cond:expr => $arm:expr ) => {
 | 
				
			||||||
 | 
					        match $e {
 | 
				
			||||||
 | 
					            $($pat)|+ if $cond => $arm,
 | 
				
			||||||
 | 
					            ref e => panic!("assertion failed: `{:?}` does not match `{}`",
 | 
				
			||||||
 | 
					                e, stringify!($($pat)|+ if $cond))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ( $e:expr , $($pat:pat)|+ , $($arg:tt)* ) => {
 | 
				
			||||||
 | 
					        match $e {
 | 
				
			||||||
 | 
					            $($pat)|+ => (),
 | 
				
			||||||
 | 
					            ref e => panic!("assertion failed: `{:?}` does not match `{}`: {}",
 | 
				
			||||||
 | 
					                e, stringify!($($pat)|+), format_args!($($arg)*))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ( $e:expr , $($pat:pat)|+ if $cond:expr , $($arg:tt)* ) => {
 | 
				
			||||||
 | 
					        match $e {
 | 
				
			||||||
 | 
					            $($pat)|+ if $cond => (),
 | 
				
			||||||
 | 
					            ref e => panic!("assertion failed: `{:?}` does not match `{}`: {}",
 | 
				
			||||||
 | 
					                e, stringify!($($pat)|+ if $cond), format_args!($($arg)*))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ( $e:expr , $($pat:pat)|+ => $arm:expr , $($arg:tt)* ) => {
 | 
				
			||||||
 | 
					        match $e {
 | 
				
			||||||
 | 
					            $($pat)|+ => $arm,
 | 
				
			||||||
 | 
					            ref e => panic!("assertion failed: `{:?}` does not match `{}`: {}",
 | 
				
			||||||
 | 
					                e, stringify!($($pat)|+), format_args!($($arg)*))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ( $e:expr , $($pat:pat)|+ if $cond:expr => $arm:expr , $($arg:tt)* ) => {
 | 
				
			||||||
 | 
					        match $e {
 | 
				
			||||||
 | 
					            $($pat)|+ if $cond => $arm,
 | 
				
			||||||
 | 
					            ref e => panic!("assertion failed: `{:?}` does not match `{}`: {}",
 | 
				
			||||||
 | 
					                e, stringify!($($pat)|+ if $cond), format_args!($($arg)*))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Asserts that an expression matches a given pattern.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Unlike [`assert_matches!`], `debug_assert_matches!` statements are only enabled
 | 
				
			||||||
 | 
					/// in non-optimized builds by default. An optimized build will omit all
 | 
				
			||||||
 | 
					/// `debug_assert_matches!` statements unless `-C debug-assertions` is passed
 | 
				
			||||||
 | 
					/// to the compiler.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// See the macro [`assert_matches!`] documentation for more information.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// [`assert_matches!`]: macro.assert_matches.html
 | 
				
			||||||
 | 
					#[macro_export(local_inner_macros)]
 | 
				
			||||||
 | 
					macro_rules! debug_assert_matches {
 | 
				
			||||||
 | 
					    ( $($tt:tt)* ) => { {
 | 
				
			||||||
 | 
					        if _assert_matches_cfg!(debug_assertions) {
 | 
				
			||||||
 | 
					            assert_matches!($($tt)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[doc(hidden)]
 | 
				
			||||||
 | 
					#[macro_export]
 | 
				
			||||||
 | 
					macro_rules! _assert_matches_cfg {
 | 
				
			||||||
 | 
					    ( $($tt:tt)* ) => { cfg!($($tt)*) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod test {
 | 
				
			||||||
 | 
					    use std::panic::{catch_unwind, UnwindSafe};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[derive(Debug)]
 | 
				
			||||||
 | 
					    enum Foo {
 | 
				
			||||||
 | 
					        A(i32),
 | 
				
			||||||
 | 
					        B(&'static str),
 | 
				
			||||||
 | 
					        C(&'static str),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_assert_succeed() {
 | 
				
			||||||
 | 
					        let a = Foo::A(123);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(_));
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(123));
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(i) if i == 123);
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(42) | Foo::A(123));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let b = Foo::B("foo");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(_));
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B("foo"));
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) if s == "foo");
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) => assert_eq!(s, "foo"));
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) => { assert_eq!(s, "foo"); assert!(true) });
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) if s == "foo" => assert_eq!(s, "foo"));
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) if s == "foo" => { assert_eq!(s, "foo"); assert!(true) });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let c = Foo::C("foo");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(c, Foo::B(_) | Foo::C(_));
 | 
				
			||||||
 | 
					        assert_matches!(c, Foo::B("foo") | Foo::C("foo"));
 | 
				
			||||||
 | 
					        assert_matches!(c, Foo::B(s) | Foo::C(s) if s == "foo");
 | 
				
			||||||
 | 
					        assert_matches!(c, Foo::B(s) | Foo::C(s) => assert_eq!(s, "foo"));
 | 
				
			||||||
 | 
					        assert_matches!(c, Foo::B(s) | Foo::C(s) => { assert_eq!(s, "foo"); assert!(true) });
 | 
				
			||||||
 | 
					        assert_matches!(c, Foo::B(s) | Foo::C(s) if s == "foo" => assert_eq!(s, "foo"));
 | 
				
			||||||
 | 
					        assert_matches!(c, Foo::B(s) | Foo::C(s) if s == "foo" => { assert_eq!(s, "foo"); assert!(true) });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[should_panic]
 | 
				
			||||||
 | 
					    fn test_assert_panic_0() {
 | 
				
			||||||
 | 
					        let a = Foo::A(123);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::B(_));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[should_panic]
 | 
				
			||||||
 | 
					    fn test_assert_panic_1() {
 | 
				
			||||||
 | 
					        let b = Foo::B("foo");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B("bar"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[should_panic]
 | 
				
			||||||
 | 
					    fn test_assert_panic_2() {
 | 
				
			||||||
 | 
					        let b = Foo::B("foo");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) if s == "bar");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[should_panic]
 | 
				
			||||||
 | 
					    fn test_assert_panic_3() {
 | 
				
			||||||
 | 
					        let b = Foo::B("foo");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) => assert_eq!(s, "bar"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[should_panic]
 | 
				
			||||||
 | 
					    fn test_assert_panic_4() {
 | 
				
			||||||
 | 
					        let b = Foo::B("foo");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) if s == "bar" => assert_eq!(s, "foo"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[should_panic]
 | 
				
			||||||
 | 
					    fn test_assert_panic_5() {
 | 
				
			||||||
 | 
					        let b = Foo::B("foo");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) if s == "foo" => assert_eq!(s, "bar"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[should_panic]
 | 
				
			||||||
 | 
					    fn test_assert_panic_6() {
 | 
				
			||||||
 | 
					        let b = Foo::B("foo");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(b, Foo::B(s) if s == "foo" => { assert_eq!(s, "foo"); assert!(false) });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_assert_no_move() {
 | 
				
			||||||
 | 
					        let b = &mut Foo::A(0);
 | 
				
			||||||
 | 
					        assert_matches!(*b, Foo::A(0));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn assert_with_message() {
 | 
				
			||||||
 | 
					        let a = Foo::A(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(_), "o noes");
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) if n == 0, "o noes");
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) => assert_eq!(n, 0), "o noes");
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) => { assert_eq!(n, 0); assert!(n < 1) }, "o noes");
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) if n == 0 => assert_eq!(n, 0), "o noes");
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) if n == 0 => { assert_eq!(n, 0); assert!(n < 1) }, "o noes");
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(_), "o noes {:?}", a);
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) if n == 0, "o noes {:?}", a);
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) => assert_eq!(n, 0), "o noes {:?}", a);
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) => { assert_eq!(n, 0); assert!(n < 1) }, "o noes {:?}", a);
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(_), "o noes {value:?}", value=a);
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) if n == 0, "o noes {value:?}", value=a);
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) => assert_eq!(n, 0), "o noes {value:?}", value=a);
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) => { assert_eq!(n, 0); assert!(n < 1) }, "o noes {value:?}", value=a);
 | 
				
			||||||
 | 
					        assert_matches!(a, Foo::A(n) if n == 0 => assert_eq!(n, 0), "o noes {value:?}", value=a);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn panic_message<F>(f: F) -> String
 | 
				
			||||||
 | 
					            where F: FnOnce() + UnwindSafe {
 | 
				
			||||||
 | 
					        let err = catch_unwind(f)
 | 
				
			||||||
 | 
					            .expect_err("function did not panic");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        *err.downcast::<String>()
 | 
				
			||||||
 | 
					            .expect("function panicked with non-String value")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_panic_message() {
 | 
				
			||||||
 | 
					        let a = Foo::A(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // expr, pat
 | 
				
			||||||
 | 
					        assert_eq!(panic_message(|| {
 | 
				
			||||||
 | 
					            assert_matches!(a, Foo::B(_));
 | 
				
			||||||
 | 
					        }), r#"assertion failed: `A(1)` does not match `Foo::B(_)`"#);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // expr, pat if cond
 | 
				
			||||||
 | 
					        assert_eq!(panic_message(|| {
 | 
				
			||||||
 | 
					            assert_matches!(a, Foo::B(s) if s == "foo");
 | 
				
			||||||
 | 
					        }), r#"assertion failed: `A(1)` does not match `Foo::B(s) if s == "foo"`"#);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // expr, pat => arm
 | 
				
			||||||
 | 
					        assert_eq!(panic_message(|| {
 | 
				
			||||||
 | 
					            assert_matches!(a, Foo::B(_) => {});
 | 
				
			||||||
 | 
					        }), r#"assertion failed: `A(1)` does not match `Foo::B(_)`"#);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // expr, pat if cond => arm
 | 
				
			||||||
 | 
					        assert_eq!(panic_message(|| {
 | 
				
			||||||
 | 
					            assert_matches!(a, Foo::B(s) if s == "foo" => {});
 | 
				
			||||||
 | 
					        }), r#"assertion failed: `A(1)` does not match `Foo::B(s) if s == "foo"`"#);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // expr, pat, args
 | 
				
			||||||
 | 
					        assert_eq!(panic_message(|| {
 | 
				
			||||||
 | 
					            assert_matches!(a, Foo::B(_), "msg");
 | 
				
			||||||
 | 
					        }), r#"assertion failed: `A(1)` does not match `Foo::B(_)`: msg"#);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // expr, pat if cond, args
 | 
				
			||||||
 | 
					        assert_eq!(panic_message(|| {
 | 
				
			||||||
 | 
					            assert_matches!(a, Foo::B(s) if s == "foo", "msg");
 | 
				
			||||||
 | 
					        }), r#"assertion failed: `A(1)` does not match `Foo::B(s) if s == "foo"`: msg"#);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // expr, pat => arm, args
 | 
				
			||||||
 | 
					        assert_eq!(panic_message(|| {
 | 
				
			||||||
 | 
					            assert_matches!(a, Foo::B(_) => {}, "msg");
 | 
				
			||||||
 | 
					        }), r#"assertion failed: `A(1)` does not match `Foo::B(_)`: msg"#);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // expr, pat if cond => arm, args
 | 
				
			||||||
 | 
					        assert_eq!(panic_message(|| {
 | 
				
			||||||
 | 
					            assert_matches!(a, Foo::B(s) if s == "foo" => {}, "msg");
 | 
				
			||||||
 | 
					        }), r#"assertion failed: `A(1)` does not match `Foo::B(s) if s == "foo"`: msg"#);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										71
									
								
								src/debug.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/debug.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2022 Purism SPC
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					use std::thread;
 | 
				
			||||||
 | 
					use zbus::{Connection, ObjectServer, dbus_interface, fdo};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::event_loop;
 | 
				
			||||||
 | 
					use crate::state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::convert::TryInto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Accepts commands controlling the debug mode
 | 
				
			||||||
 | 
					struct Manager {
 | 
				
			||||||
 | 
					    sender: event_loop::driver::Threaded,
 | 
				
			||||||
 | 
					    enabled: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[dbus_interface(name = "sm.puri.SqueekDebug")]
 | 
				
			||||||
 | 
					impl Manager {
 | 
				
			||||||
 | 
					    #[dbus_interface(property, name = "Enabled")]
 | 
				
			||||||
 | 
					    fn get_enabled(&self) -> bool {
 | 
				
			||||||
 | 
					        self.enabled
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[dbus_interface(property, name = "Enabled")]
 | 
				
			||||||
 | 
					    fn set_enabled(&mut self, enabled: bool) {
 | 
				
			||||||
 | 
					        self.enabled = enabled;
 | 
				
			||||||
 | 
					        self.sender
 | 
				
			||||||
 | 
					            .send(state::Event::Debug(
 | 
				
			||||||
 | 
					                if enabled { Event::Enable }
 | 
				
			||||||
 | 
					                else { Event::Disable }
 | 
				
			||||||
 | 
					            ))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn start(mgr: Manager) -> Result<(), Box<dyn std::error::Error>> {
 | 
				
			||||||
 | 
					    let connection = Connection::new_session()?;
 | 
				
			||||||
 | 
					    fdo::DBusProxy::new(&connection)?.request_name(
 | 
				
			||||||
 | 
					        "sm.puri.SqueekDebug",
 | 
				
			||||||
 | 
					        fdo::RequestNameFlags::ReplaceExisting.into(),
 | 
				
			||||||
 | 
					    )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut object_server = ObjectServer::new(&connection);
 | 
				
			||||||
 | 
					    object_server.at(&"/sm/puri/SqueekDebug".try_into()?, mgr)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        if let Err(err) = object_server.try_handle_next() {
 | 
				
			||||||
 | 
					            eprintln!("{}", err);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn init(sender: event_loop::driver::Threaded) {
 | 
				
			||||||
 | 
					    let mgr = Manager {
 | 
				
			||||||
 | 
					        sender,
 | 
				
			||||||
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    thread::spawn(move || {
 | 
				
			||||||
 | 
					        start(mgr).unwrap();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum Event {
 | 
				
			||||||
 | 
					    Enable,
 | 
				
			||||||
 | 
					    Disable,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -10,7 +10,7 @@ use ::layout::c::{ Bounds, EekGtkKeyboard, Point };
 | 
				
			|||||||
use ::submission::c::Submission as CSubmission;
 | 
					use ::submission::c::Submission as CSubmission;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use glib::translate::FromGlibPtrNone;
 | 
					use glib::translate::FromGlibPtrNone;
 | 
				
			||||||
use gtk::WidgetExt;
 | 
					use gtk::prelude::WidgetExt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::collections::HashSet;
 | 
					use std::collections::HashSet;
 | 
				
			||||||
use std::ffi::CStr;
 | 
					use std::ffi::CStr;
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,9 @@ use std::time::Instant;
 | 
				
			|||||||
use crate::logging::Warn;
 | 
					use crate::logging::Warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Type of the sender that waits for external events
 | 
				
			||||||
type Sender = mpsc::Sender<Event>;
 | 
					type Sender = mpsc::Sender<Event>;
 | 
				
			||||||
 | 
					/// Type of the sender that waits for internal state changes
 | 
				
			||||||
type UISender = glib::Sender<Commands>;
 | 
					type UISender = glib::Sender<Commands>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// This loop driver spawns a new thread which updates the state in a loop,
 | 
					/// This loop driver spawns a new thread which updates the state in a loop,
 | 
				
			||||||
 | 
				
			|||||||
@ -151,8 +151,9 @@ mod test {
 | 
				
			|||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use crate::animation;
 | 
					    use crate::animation;
 | 
				
			||||||
    use crate::imservice::{ ContentHint, ContentPurpose };
 | 
					    use crate::imservice::{ ContentHint, ContentPurpose };
 | 
				
			||||||
    use crate::main::PanelCommand;
 | 
					    use crate::panel;
 | 
				
			||||||
    use crate::state::{ Application, InputMethod, InputMethodDetails, Presence, visibility };
 | 
					    use crate::state::{ Application, InputMethod, InputMethodDetails, Presence, visibility };
 | 
				
			||||||
 | 
					    use crate::state::test::application_with_fake_output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn imdetails_new() -> InputMethodDetails {
 | 
					    fn imdetails_new() -> InputMethodDetails {
 | 
				
			||||||
        InputMethodDetails {
 | 
					        InputMethodDetails {
 | 
				
			||||||
@ -170,17 +171,18 @@ mod test {
 | 
				
			|||||||
            im: InputMethod::Active(imdetails_new()),
 | 
					            im: InputMethod::Active(imdetails_new()),
 | 
				
			||||||
            physical_keyboard: Presence::Missing,
 | 
					            physical_keyboard: Presence::Missing,
 | 
				
			||||||
            visibility_override: visibility::State::NotForced,
 | 
					            visibility_override: visibility::State::NotForced,
 | 
				
			||||||
 | 
					            ..application_with_fake_output(start)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        let l = State::new(state, now);
 | 
					        let l = State::new(state, now);
 | 
				
			||||||
        let (l, commands) = handle_event(l, InputMethod::InactiveSince(now).into(), now);
 | 
					        let (l, commands) = handle_event(l, InputMethod::InactiveSince(now).into(), now);
 | 
				
			||||||
        assert_eq!(commands.panel_visibility, Some(PanelCommand::Show));
 | 
					        assert_matches!(commands.panel_visibility, Some(panel::Command::Show{..}));
 | 
				
			||||||
        assert_eq!(l.scheduled_wakeup, Some(now + animation::HIDING_TIMEOUT));
 | 
					        assert_eq!(l.scheduled_wakeup, Some(now + animation::HIDING_TIMEOUT));
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        now += animation::HIDING_TIMEOUT;
 | 
					        now += animation::HIDING_TIMEOUT;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        let (l, commands) = handle_event(l, Event::TimeoutReached(now), now);
 | 
					        let (l, commands) = handle_event(l, Event::TimeoutReached(now), now);
 | 
				
			||||||
        assert_eq!(commands.panel_visibility, Some(PanelCommand::Hide));
 | 
					        assert_eq!(commands.panel_visibility, Some(panel::Command::Hide));
 | 
				
			||||||
        assert_eq!(l.scheduled_wakeup, None);
 | 
					        assert_eq!(l.scheduled_wakeup, None);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "submission.h"
 | 
					#include "input-method-unstable-v2-client-protocol.h"
 | 
				
			||||||
 | 
					#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <glib.h>
 | 
					#include "submission.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct imservice;
 | 
					struct imservice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -26,21 +26,32 @@ pub mod c {
 | 
				
			|||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use std::os::raw::{c_char, c_void};
 | 
					    use std::os::raw::{c_char, c_void};
 | 
				
			||||||
 | 
					    use std::ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // The following defined in C
 | 
					    // The following defined in C
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    /// struct zwp_input_method_v2*
 | 
					    /// struct zwp_input_method_v2*
 | 
				
			||||||
    #[repr(transparent)]
 | 
					    #[repr(transparent)]
 | 
				
			||||||
 | 
					    #[derive(PartialEq, Clone, Copy)]
 | 
				
			||||||
    pub struct InputMethod(*const c_void);
 | 
					    pub struct InputMethod(*const c_void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    impl InputMethod {
 | 
				
			||||||
 | 
					        pub fn is_null(&self) -> bool {
 | 
				
			||||||
 | 
					            self.0.is_null()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        pub fn null() -> Self {
 | 
				
			||||||
 | 
					            Self(ptr::null())
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    extern "C" {
 | 
					    extern "C" {
 | 
				
			||||||
        fn imservice_destroy_im(im: *mut c::InputMethod);
 | 
					        fn imservice_destroy_im(im: InputMethod);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #[allow(improper_ctypes)] // IMService will never be dereferenced in C
 | 
					        #[allow(improper_ctypes)] // IMService will never be dereferenced in C
 | 
				
			||||||
        pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService);
 | 
					        pub fn imservice_connect_listeners(im: InputMethod, imservice: *const IMService);
 | 
				
			||||||
        pub fn eek_input_method_commit_string(im: *mut InputMethod, text: *const c_char);
 | 
					        pub fn eek_input_method_commit_string(im: 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_delete_surrounding_text(im: InputMethod, before: u32, after: u32);
 | 
				
			||||||
        pub fn eek_input_method_commit(im: *mut InputMethod, serial: u32);
 | 
					        pub fn eek_input_method_commit(im: InputMethod, serial: u32);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
					    // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
				
			||||||
@ -49,7 +60,7 @@ pub mod c {
 | 
				
			|||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn imservice_handle_input_method_activate(imservice: *mut IMService,
 | 
					    fn imservice_handle_input_method_activate(imservice: *mut IMService,
 | 
				
			||||||
        im: *const InputMethod)
 | 
					        im: InputMethod)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
					        let imservice = check_imservice(imservice, im).unwrap();
 | 
				
			||||||
        imservice.preedit_string = String::new();
 | 
					        imservice.preedit_string = String::new();
 | 
				
			||||||
@ -62,7 +73,7 @@ pub mod c {
 | 
				
			|||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn imservice_handle_input_method_deactivate(imservice: *mut IMService,
 | 
					    fn imservice_handle_input_method_deactivate(imservice: *mut IMService,
 | 
				
			||||||
        im: *const InputMethod)
 | 
					        im: InputMethod)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
					        let imservice = check_imservice(imservice, im).unwrap();
 | 
				
			||||||
        imservice.pending = IMProtocolState {
 | 
					        imservice.pending = IMProtocolState {
 | 
				
			||||||
@ -74,7 +85,7 @@ pub mod c {
 | 
				
			|||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn imservice_handle_surrounding_text(imservice: *mut IMService,
 | 
					    fn imservice_handle_surrounding_text(imservice: *mut IMService,
 | 
				
			||||||
        im: *const InputMethod,
 | 
					        im: InputMethod,
 | 
				
			||||||
        text: *const c_char, cursor: u32, _anchor: u32)
 | 
					        text: *const c_char, cursor: u32, _anchor: u32)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
					        let imservice = check_imservice(imservice, im).unwrap();
 | 
				
			||||||
@ -90,7 +101,7 @@ pub mod c {
 | 
				
			|||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn imservice_handle_content_type(imservice: *mut IMService,
 | 
					    fn imservice_handle_content_type(imservice: *mut IMService,
 | 
				
			||||||
        im: *const InputMethod,
 | 
					        im: InputMethod,
 | 
				
			||||||
        hint: u32, purpose: u32)
 | 
					        hint: u32, purpose: u32)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
					        let imservice = check_imservice(imservice, im).unwrap();
 | 
				
			||||||
@ -118,7 +129,7 @@ pub mod c {
 | 
				
			|||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn imservice_handle_text_change_cause(imservice: *mut IMService,
 | 
					    fn imservice_handle_text_change_cause(imservice: *mut IMService,
 | 
				
			||||||
        im: *const InputMethod,
 | 
					        im: InputMethod,
 | 
				
			||||||
        cause: u32)
 | 
					        cause: u32)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
					        let imservice = check_imservice(imservice, im).unwrap();
 | 
				
			||||||
@ -138,16 +149,11 @@ pub mod c {
 | 
				
			|||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn imservice_handle_done(imservice: *mut IMService,
 | 
					    fn imservice_handle_done(imservice: *mut IMService,
 | 
				
			||||||
        im: *const InputMethod)
 | 
					        im: InputMethod)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
					        let imservice = check_imservice(imservice, im).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        imservice.current = imservice.pending.clone();
 | 
					        imservice.current = imservice.pending.clone();
 | 
				
			||||||
        imservice.pending = IMProtocolState {
 | 
					 | 
				
			||||||
            active: imservice.current.active,
 | 
					 | 
				
			||||||
            ..IMProtocolState::default()
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        imservice.serial += Wrapping(1u32);
 | 
					        imservice.serial += Wrapping(1u32);
 | 
				
			||||||
        imservice.send_event();
 | 
					        imservice.send_event();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -156,7 +162,7 @@ pub mod c {
 | 
				
			|||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn imservice_handle_unavailable(imservice: *mut IMService,
 | 
					    fn imservice_handle_unavailable(imservice: *mut IMService,
 | 
				
			||||||
        im: *mut InputMethod)
 | 
					        im: InputMethod)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
					        let imservice = check_imservice(imservice, im).unwrap();
 | 
				
			||||||
        unsafe { imservice_destroy_im(im); }
 | 
					        unsafe { imservice_destroy_im(im); }
 | 
				
			||||||
@ -181,7 +187,7 @@ pub mod c {
 | 
				
			|||||||
    /// Care must be take
 | 
					    /// Care must be take
 | 
				
			||||||
    /// not to exceed the lifetime of the pointer with the reference,
 | 
					    /// not to exceed the lifetime of the pointer with the reference,
 | 
				
			||||||
    /// especially not to store it.
 | 
					    /// especially not to store it.
 | 
				
			||||||
    fn check_imservice(imservice: *mut IMService, im: *const InputMethod)
 | 
					    fn check_imservice(imservice: *mut IMService, im: InputMethod)
 | 
				
			||||||
        -> Result<&'static mut IMService, &'static str>
 | 
					        -> Result<&'static mut IMService, &'static str>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if imservice.is_null() {
 | 
					        if imservice.is_null() {
 | 
				
			||||||
@ -315,7 +321,7 @@ impl Default for IMProtocolState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub struct IMService {
 | 
					pub struct IMService {
 | 
				
			||||||
    /// Owned reference (still created and destroyed in C)
 | 
					    /// Owned reference (still created and destroyed in C)
 | 
				
			||||||
    pub im: *mut c::InputMethod,
 | 
					    pub im: c::InputMethod,
 | 
				
			||||||
    sender: driver::Threaded,
 | 
					    sender: driver::Threaded,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pending: IMProtocolState,
 | 
					    pending: IMProtocolState,
 | 
				
			||||||
@ -331,7 +337,7 @@ pub enum SubmitError {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
impl IMService {
 | 
					impl IMService {
 | 
				
			||||||
    pub fn new(
 | 
					    pub fn new(
 | 
				
			||||||
        im: *mut c::InputMethod,
 | 
					        im: c::InputMethod,
 | 
				
			||||||
        sender: driver::Threaded,
 | 
					        sender: driver::Threaded,
 | 
				
			||||||
    ) -> Box<IMService> {
 | 
					    ) -> Box<IMService> {
 | 
				
			||||||
        // IMService will be referenced to by C,
 | 
					        // IMService will be referenced to by C,
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::cell::RefCell;
 | 
					use std::cell::RefCell;
 | 
				
			||||||
 | 
					use std::cmp;
 | 
				
			||||||
use std::collections::{ HashMap, HashSet };
 | 
					use std::collections::{ HashMap, HashSet };
 | 
				
			||||||
use std::ffi::CString;
 | 
					use std::ffi::CString;
 | 
				
			||||||
use std::fmt;
 | 
					use std::fmt;
 | 
				
			||||||
@ -26,6 +27,7 @@ use std::vec::Vec;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use ::action::Action;
 | 
					use ::action::Action;
 | 
				
			||||||
use ::drawing;
 | 
					use ::drawing;
 | 
				
			||||||
 | 
					use ::float_ord::FloatOrd;
 | 
				
			||||||
use ::keyboard::KeyState;
 | 
					use ::keyboard::KeyState;
 | 
				
			||||||
use ::logging;
 | 
					use ::logging;
 | 
				
			||||||
use ::manager;
 | 
					use ::manager;
 | 
				
			||||||
@ -117,28 +119,30 @@ pub mod c {
 | 
				
			|||||||
    pub struct Transformation {
 | 
					    pub struct Transformation {
 | 
				
			||||||
        pub origin_x: f64,
 | 
					        pub origin_x: f64,
 | 
				
			||||||
        pub origin_y: f64,
 | 
					        pub origin_y: f64,
 | 
				
			||||||
        pub scale: f64,
 | 
					        pub scale_x: f64,
 | 
				
			||||||
 | 
					        pub scale_y: f64,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    impl Transformation {
 | 
					    impl Transformation {
 | 
				
			||||||
        /// Applies the new transformation after this one
 | 
					        /// Applies the new transformation after this one
 | 
				
			||||||
        pub fn chain(self, next: Transformation) -> Transformation {
 | 
					        pub fn chain(self, next: Transformation) -> Transformation {
 | 
				
			||||||
            Transformation {
 | 
					            Transformation {
 | 
				
			||||||
                origin_x: self.origin_x + self.scale * next.origin_x,
 | 
					                origin_x: self.origin_x + self.scale_x * next.origin_x,
 | 
				
			||||||
                origin_y: self.origin_y + self.scale * next.origin_y,
 | 
					                origin_y: self.origin_y + self.scale_y * next.origin_y,
 | 
				
			||||||
                scale: self.scale * next.scale,
 | 
					                scale_x: self.scale_x * next.scale_x,
 | 
				
			||||||
 | 
					                scale_y: self.scale_y * next.scale_y,
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        fn forward(&self, p: Point) -> Point {
 | 
					        fn forward(&self, p: Point) -> Point {
 | 
				
			||||||
            Point {
 | 
					            Point {
 | 
				
			||||||
                x: (p.x - self.origin_x) / self.scale,
 | 
					                x: (p.x - self.origin_x) / self.scale_x,
 | 
				
			||||||
                y: (p.y - self.origin_y) / self.scale,
 | 
					                y: (p.y - self.origin_y) / self.scale_y,
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        fn reverse(&self, p: Point) -> Point {
 | 
					        fn reverse(&self, p: Point) -> Point {
 | 
				
			||||||
            Point {
 | 
					            Point {
 | 
				
			||||||
                x: p.x * self.scale + self.origin_x,
 | 
					                x: p.x * self.scale_x + self.origin_x,
 | 
				
			||||||
                y: p.y * self.scale + self.origin_y,
 | 
					                y: p.y * self.scale_y + self.origin_y,
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        pub fn reverse_bounds(&self, b: Bounds) -> Bounds {
 | 
					        pub fn reverse_bounds(&self, b: Bounds) -> Bounds {
 | 
				
			||||||
@ -394,7 +398,8 @@ pub mod c {
 | 
				
			|||||||
                let transform = Transformation {
 | 
					                let transform = Transformation {
 | 
				
			||||||
                    origin_x: 10f64,
 | 
					                    origin_x: 10f64,
 | 
				
			||||||
                    origin_y: 11f64,
 | 
					                    origin_y: 11f64,
 | 
				
			||||||
                    scale: 12f64,
 | 
					                    scale_x: 12f64,
 | 
				
			||||||
 | 
					                    scale_y: 13f64,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                let point = Point { x: 1f64, y: 1f64 };
 | 
					                let point = Point { x: 1f64, y: 1f64 };
 | 
				
			||||||
                let transformed = transform.reverse(transform.forward(point.clone()));
 | 
					                let transformed = transform.reverse(transform.forward(point.clone()));
 | 
				
			||||||
@ -755,16 +760,20 @@ impl Layout {
 | 
				
			|||||||
        let size = self.calculate_size();
 | 
					        let size = self.calculate_size();
 | 
				
			||||||
        let h_scale = available.width / size.width;
 | 
					        let h_scale = available.width / size.width;
 | 
				
			||||||
        let v_scale = available.height / size.height;
 | 
					        let v_scale = available.height / size.height;
 | 
				
			||||||
        let scale = if h_scale < v_scale { h_scale } else { v_scale };
 | 
					        // Allow up to 5% (and a bit more) horizontal stretching for filling up available space
 | 
				
			||||||
 | 
					        let scale_x = if (h_scale / v_scale) < 1.055 { h_scale } else { v_scale };
 | 
				
			||||||
 | 
					        let scale_y = cmp::min(FloatOrd(h_scale), FloatOrd(v_scale)).0;
 | 
				
			||||||
        let outside_margins = c::Transformation {
 | 
					        let outside_margins = c::Transformation {
 | 
				
			||||||
            origin_x: (available.width - (scale * size.width)) / 2.0,
 | 
					            origin_x: (available.width - (scale_x * size.width)) / 2.0,
 | 
				
			||||||
            origin_y: (available.height - (scale * size.height)) / 2.0,
 | 
					            origin_y: (available.height - (scale_y * size.height)) / 2.0,
 | 
				
			||||||
            scale: scale,
 | 
					            scale_x: scale_x,
 | 
				
			||||||
 | 
					            scale_y: scale_y,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        outside_margins.chain(c::Transformation {
 | 
					        outside_margins.chain(c::Transformation {
 | 
				
			||||||
            origin_x: self.margins.left,
 | 
					            origin_x: self.margins.left,
 | 
				
			||||||
            origin_y: self.margins.top,
 | 
					            origin_y: self.margins.top,
 | 
				
			||||||
            scale: 1.0,
 | 
					            scale_x: 1.0,
 | 
				
			||||||
 | 
					            scale_y: 1.0,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1471,8 +1480,63 @@ mod test {
 | 
				
			|||||||
        let transformation = layout.calculate_transformation(
 | 
					        let transformation = layout.calculate_transformation(
 | 
				
			||||||
            Size { width: 2.0, height: 2.0 }
 | 
					            Size { width: 2.0, height: 2.0 }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        assert_eq!(transformation.scale, 1.0);
 | 
					        assert_eq!(transformation.scale_x, 1.0);
 | 
				
			||||||
 | 
					        assert_eq!(transformation.scale_y, 1.0);
 | 
				
			||||||
        assert_eq!(transformation.origin_x, 0.5);
 | 
					        assert_eq!(transformation.origin_x, 0.5);
 | 
				
			||||||
        assert_eq!(transformation.origin_y, 0.0);
 | 
					        assert_eq!(transformation.origin_y, 0.0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn check_stretching() {
 | 
				
			||||||
 | 
					        // just one button
 | 
				
			||||||
 | 
					        let view = View::new(vec![
 | 
				
			||||||
 | 
					            (
 | 
				
			||||||
 | 
					                0.0,
 | 
				
			||||||
 | 
					                Row::new(vec![(
 | 
				
			||||||
 | 
					                    0.0,
 | 
				
			||||||
 | 
					                    Box::new(Button {
 | 
				
			||||||
 | 
					                        size: Size { width: 1.0, height: 1.0 },
 | 
				
			||||||
 | 
					                        ..*make_button_with_state("foo".into(), make_state())
 | 
				
			||||||
 | 
					                    }),
 | 
				
			||||||
 | 
					                )]),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					        let layout = Layout {
 | 
				
			||||||
 | 
					            current_view: String::new(),
 | 
				
			||||||
 | 
					            view_latched: LatchedState::Not,
 | 
				
			||||||
 | 
					            keymaps: Vec::new(),
 | 
				
			||||||
 | 
					            kind: ArrangementKind::Base,
 | 
				
			||||||
 | 
					            pressed_keys: HashSet::new(),
 | 
				
			||||||
 | 
					            margins: Margins {
 | 
				
			||||||
 | 
					                top: 0.0,
 | 
				
			||||||
 | 
					                left: 0.0,
 | 
				
			||||||
 | 
					                right: 0.0,
 | 
				
			||||||
 | 
					                bottom: 0.0,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            views: hashmap! {
 | 
				
			||||||
 | 
					                String::new() => (c::Point { x: 0.0, y: 0.0 }, view),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            purpose: ContentPurpose::Normal,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let transformation = layout.calculate_transformation(
 | 
				
			||||||
 | 
					            Size { width: 100.0, height: 100.0 }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        assert_eq!(transformation.scale_x, 100.0);
 | 
				
			||||||
 | 
					        assert_eq!(transformation.scale_y, 100.0);
 | 
				
			||||||
 | 
					        let transformation = layout.calculate_transformation(
 | 
				
			||||||
 | 
					            Size { width: 95.0, height: 100.0 }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        assert_eq!(transformation.scale_x, 95.0);
 | 
				
			||||||
 | 
					        assert_eq!(transformation.scale_y, 95.0);
 | 
				
			||||||
 | 
					        let transformation = layout.calculate_transformation(
 | 
				
			||||||
 | 
					            Size { width: 105.0, height: 100.0 }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        assert_eq!(transformation.scale_x, 105.0);
 | 
				
			||||||
 | 
					        assert_eq!(transformation.scale_y, 100.0);
 | 
				
			||||||
 | 
					        let transformation = layout.calculate_transformation(
 | 
				
			||||||
 | 
					            Size { width: 106.0, height: 100.0 }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        assert_eq!(transformation.scale_x, 100.0);
 | 
				
			||||||
 | 
					        assert_eq!(transformation.scale_y, 100.0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -11,16 +11,21 @@ extern crate gtk_sys;
 | 
				
			|||||||
#[allow(unused_imports)]
 | 
					#[allow(unused_imports)]
 | 
				
			||||||
#[macro_use] // only for tests
 | 
					#[macro_use] // only for tests
 | 
				
			||||||
extern crate maplit;
 | 
					extern crate maplit;
 | 
				
			||||||
extern crate regex;
 | 
					 | 
				
			||||||
extern crate serde;
 | 
					extern crate serde;
 | 
				
			||||||
extern crate xkbcommon;
 | 
					extern crate xkbcommon;
 | 
				
			||||||
 | 
					extern crate zbus;
 | 
				
			||||||
 | 
					extern crate zvariant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					#[macro_use]
 | 
				
			||||||
 | 
					mod assert_matches;
 | 
				
			||||||
#[macro_use]
 | 
					#[macro_use]
 | 
				
			||||||
mod logging;
 | 
					mod logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod action;
 | 
					mod action;
 | 
				
			||||||
mod animation;
 | 
					mod animation;
 | 
				
			||||||
pub mod data;
 | 
					pub mod data;
 | 
				
			||||||
 | 
					mod debug;
 | 
				
			||||||
mod drawing;
 | 
					mod drawing;
 | 
				
			||||||
mod event_loop;
 | 
					mod event_loop;
 | 
				
			||||||
pub mod float_ord;
 | 
					pub mod float_ord;
 | 
				
			||||||
@ -31,6 +36,7 @@ mod locale;
 | 
				
			|||||||
mod main;
 | 
					mod main;
 | 
				
			||||||
mod manager;
 | 
					mod manager;
 | 
				
			||||||
mod outputs;
 | 
					mod outputs;
 | 
				
			||||||
 | 
					mod panel;
 | 
				
			||||||
mod popover;
 | 
					mod popover;
 | 
				
			||||||
mod resources;
 | 
					mod resources;
 | 
				
			||||||
mod state;
 | 
					mod state;
 | 
				
			||||||
@ -38,6 +44,5 @@ mod style;
 | 
				
			|||||||
mod submission;
 | 
					mod submission;
 | 
				
			||||||
pub mod tests;
 | 
					pub mod tests;
 | 
				
			||||||
pub mod util;
 | 
					pub mod util;
 | 
				
			||||||
mod ui_manager;
 | 
					 | 
				
			||||||
mod vkeyboard;
 | 
					mod vkeyboard;
 | 
				
			||||||
mod xdg;
 | 
					mod xdg;
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "eek/eek-types.h"
 | 
					#include "eek/eek-types.h"
 | 
				
			||||||
#include "dbus.h"
 | 
					#include "dbus.h"
 | 
				
			||||||
 | 
					#include "panel.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct receiver;
 | 
					struct receiver;
 | 
				
			||||||
@ -21,11 +22,12 @@ struct rsobjects {
 | 
				
			|||||||
    struct receiver *receiver;
 | 
					    struct receiver *receiver;
 | 
				
			||||||
    struct squeek_state_manager *state_manager;
 | 
					    struct squeek_state_manager *state_manager;
 | 
				
			||||||
    struct submission *submission;
 | 
					    struct submission *submission;
 | 
				
			||||||
 | 
					    struct squeek_wayland *wayland;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void register_ui_loop_handler(struct receiver *receiver, ServerContextService *ui, DBusHandler *dbus_handler);
 | 
					void register_ui_loop_handler(struct receiver *receiver, struct panel_manager *panel, EekboardContextService *hint_manager, DBusHandler *dbus_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rsobjects squeek_rsobjects_new(struct zwp_input_method_v2 *im, struct zwp_virtual_keyboard_v1 *vk);
 | 
					struct rsobjects squeek_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void squeek_state_send_force_visible(struct squeek_state_manager *state);
 | 
					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_force_hidden(struct squeek_state_manager *state);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										116
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								src/main.rs
									
									
									
									
									
								
							@ -1,9 +1,10 @@
 | 
				
			|||||||
/* Copyright (C) 2020 Purism SPC
 | 
					/* Copyright (C) 2020,2022 Purism SPC
 | 
				
			||||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
					 * SPDX-License-Identifier: GPL-3.0+
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Glue for the main loop. */
 | 
					/*! Glue for the main loop. */
 | 
				
			||||||
 | 
					use crate::panel;
 | 
				
			||||||
 | 
					use crate::debug;
 | 
				
			||||||
use crate::state;
 | 
					use crate::state;
 | 
				
			||||||
use glib::{Continue, MainContext, PRIORITY_DEFAULT, Receiver};
 | 
					use glib::{Continue, MainContext, PRIORITY_DEFAULT, Receiver};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -11,37 +12,73 @@ use glib::{Continue, MainContext, PRIORITY_DEFAULT, Receiver};
 | 
				
			|||||||
mod c {
 | 
					mod c {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use std::os::raw::c_void;
 | 
					    use std::os::raw::c_void;
 | 
				
			||||||
 | 
					    use std::ptr;
 | 
				
			||||||
    use std::rc::Rc;
 | 
					    use std::rc::Rc;
 | 
				
			||||||
    use std::time::Instant;
 | 
					    use std::time::Instant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use crate::event_loop::driver;
 | 
					    use crate::event_loop::driver;
 | 
				
			||||||
    use crate::imservice::IMService;
 | 
					    use crate::imservice::IMService;
 | 
				
			||||||
    use crate::imservice::c::InputMethod;
 | 
					    use crate::imservice::c::InputMethod;
 | 
				
			||||||
 | 
					    use crate::outputs::Outputs;
 | 
				
			||||||
    use crate::state;
 | 
					    use crate::state;
 | 
				
			||||||
    use crate::submission::Submission;
 | 
					    use crate::submission::Submission;
 | 
				
			||||||
    use crate::util::c::Wrapped;
 | 
					    use crate::util::c::Wrapped;
 | 
				
			||||||
    use crate::vkeyboard::c::ZwpVirtualKeyboardV1;
 | 
					    use crate::vkeyboard::c::ZwpVirtualKeyboardV1;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /// ServerContextService*
 | 
					 | 
				
			||||||
    #[repr(transparent)]
 | 
					 | 
				
			||||||
    pub struct UIManager(*const c_void);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /// DbusHandler*
 | 
					    /// DbusHandler*
 | 
				
			||||||
    #[repr(transparent)]
 | 
					    #[repr(transparent)]
 | 
				
			||||||
    pub struct DBusHandler(*const c_void);
 | 
					    pub struct DBusHandler(*const c_void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// EekboardContextService* in the role of a hint receiver
 | 
				
			||||||
 | 
					    // The clone/copy is a concession to C style of programming.
 | 
				
			||||||
 | 
					    // It would be hard to get rid of it.
 | 
				
			||||||
 | 
					    #[repr(transparent)]
 | 
				
			||||||
 | 
					    #[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					    pub struct HintManager(*const c_void);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /// Holds the Rust structures that are interesting from C.
 | 
					    /// Holds the Rust structures that are interesting from C.
 | 
				
			||||||
    #[repr(C)]
 | 
					    #[repr(C)]
 | 
				
			||||||
    pub struct RsObjects {
 | 
					    pub struct RsObjects {
 | 
				
			||||||
 | 
					        /// The handle to which Commands should be sent
 | 
				
			||||||
 | 
					        /// for processing in the main loop.
 | 
				
			||||||
        receiver: Wrapped<Receiver<Commands>>,
 | 
					        receiver: Wrapped<Receiver<Commands>>,
 | 
				
			||||||
        state_manager: Wrapped<driver::Threaded>,
 | 
					        state_manager: Wrapped<driver::Threaded>,
 | 
				
			||||||
        submission: Wrapped<Submission>,
 | 
					        submission: Wrapped<Submission>,
 | 
				
			||||||
 | 
					        /// Not wrapped, because C needs to access this.
 | 
				
			||||||
 | 
					        wayland: *mut Wayland,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Corresponds to wayland.h::squeek_wayland.
 | 
				
			||||||
 | 
					    /// Fields unused by Rust are marked as generic data types.
 | 
				
			||||||
 | 
					    #[repr(C)]
 | 
				
			||||||
 | 
					    pub struct Wayland {
 | 
				
			||||||
 | 
					        layer_shell: *const c_void,
 | 
				
			||||||
 | 
					        virtual_keyboard_manager: *const c_void,
 | 
				
			||||||
 | 
					        input_method_manager: *const c_void,
 | 
				
			||||||
 | 
					        outputs: Wrapped<Outputs>,
 | 
				
			||||||
 | 
					        seat: *const c_void,
 | 
				
			||||||
 | 
					        input_method: InputMethod,
 | 
				
			||||||
 | 
					        virtual_keyboard: ZwpVirtualKeyboardV1,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    impl Wayland {
 | 
				
			||||||
 | 
					        fn new(outputs_manager: Outputs) -> Self {
 | 
				
			||||||
 | 
					            Wayland {
 | 
				
			||||||
 | 
					                layer_shell: ptr::null(),
 | 
				
			||||||
 | 
					                virtual_keyboard_manager: ptr::null(),
 | 
				
			||||||
 | 
					                input_method_manager: ptr::null(),
 | 
				
			||||||
 | 
					                outputs: Wrapped::new(outputs_manager),
 | 
				
			||||||
 | 
					                seat: ptr::null(),
 | 
				
			||||||
 | 
					                input_method: InputMethod::null(),
 | 
				
			||||||
 | 
					                virtual_keyboard: ZwpVirtualKeyboardV1::null(),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    extern "C" {
 | 
					    extern "C" {
 | 
				
			||||||
        fn server_context_service_real_show_keyboard(service: *const UIManager);
 | 
					        #[allow(improper_ctypes)]
 | 
				
			||||||
        fn server_context_service_real_hide_keyboard(service: *const UIManager);
 | 
					        fn init_wayland(wayland: *mut Wayland);
 | 
				
			||||||
        fn server_context_service_set_hint_purpose(service: *const UIManager, hint: u32, purpose: u32);
 | 
					        fn eekboard_context_service_set_hint_purpose(service: HintManager, hint: u32, purpose: u32);
 | 
				
			||||||
        // This should probably only get called from the gtk main loop,
 | 
					        // This should probably only get called from the gtk main loop,
 | 
				
			||||||
        // given that dbus handler is using glib.
 | 
					        // given that dbus handler is using glib.
 | 
				
			||||||
        fn dbus_handler_set_visible(dbus: *const DBusHandler, visible: u8);
 | 
					        fn dbus_handler_set_visible(dbus: *const DBusHandler, visible: u8);
 | 
				
			||||||
@ -52,19 +89,25 @@ mod c {
 | 
				
			|||||||
    /// and that leads to suffering.
 | 
					    /// and that leads to suffering.
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_rsobjects_new(
 | 
					    fn squeek_init() -> RsObjects {
 | 
				
			||||||
        im: *mut InputMethod,
 | 
					        // Set up channels
 | 
				
			||||||
        vk: ZwpVirtualKeyboardV1,
 | 
					 | 
				
			||||||
    ) -> RsObjects {
 | 
					 | 
				
			||||||
        let (sender, receiver) = MainContext::channel(PRIORITY_DEFAULT);
 | 
					        let (sender, receiver) = MainContext::channel(PRIORITY_DEFAULT);
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        let now = Instant::now();
 | 
					        let now = Instant::now();
 | 
				
			||||||
        let state_manager = driver::Threaded::new(sender, state::Application::new(now));
 | 
					        let state_manager = driver::Threaded::new(sender, state::Application::new(now));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let imservice = if im.is_null() {
 | 
					        debug::init(state_manager.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let outputs = Outputs::new(state_manager.clone());
 | 
				
			||||||
 | 
					        let mut wayland = Box::new(Wayland::new(outputs));
 | 
				
			||||||
 | 
					        let wayland_raw = &mut *wayland as *mut _;
 | 
				
			||||||
 | 
					        unsafe { init_wayland(wayland_raw); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let vk = wayland.virtual_keyboard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let imservice = if wayland.input_method.is_null() {
 | 
				
			||||||
            None
 | 
					            None
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            Some(IMService::new(im, state_manager.clone()))
 | 
					            Some(IMService::new(wayland.input_method, state_manager.clone()))
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let submission = Submission::new(vk, imservice);
 | 
					        let submission = Submission::new(vk, imservice);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -72,6 +115,7 @@ mod c {
 | 
				
			|||||||
            submission: Wrapped::new(submission),
 | 
					            submission: Wrapped::new(submission),
 | 
				
			||||||
            state_manager: Wrapped::new(state_manager),
 | 
					            state_manager: Wrapped::new(state_manager),
 | 
				
			||||||
            receiver: Wrapped::new(receiver),
 | 
					            receiver: Wrapped::new(receiver),
 | 
				
			||||||
 | 
					            wayland: Box::into_raw(wayland),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -80,21 +124,24 @@ mod c {
 | 
				
			|||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn register_ui_loop_handler(
 | 
					    fn register_ui_loop_handler(
 | 
				
			||||||
        receiver: Wrapped<Receiver<Commands>>,
 | 
					        receiver: Wrapped<Receiver<Commands>>,
 | 
				
			||||||
        ui_manager: *const UIManager,
 | 
					        panel_manager: panel::c::PanelManager,
 | 
				
			||||||
 | 
					        hint_manager: HintManager,
 | 
				
			||||||
        dbus_handler: *const DBusHandler,
 | 
					        dbus_handler: *const DBusHandler,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        let receiver = unsafe { receiver.unwrap() };
 | 
					        let receiver = unsafe { receiver.unwrap() };
 | 
				
			||||||
        let receiver = Rc::try_unwrap(receiver).expect("References still present");
 | 
					        let receiver = Rc::try_unwrap(receiver).expect("References still present");
 | 
				
			||||||
        let receiver = receiver.into_inner();
 | 
					        let receiver = receiver.into_inner();
 | 
				
			||||||
 | 
					        let panel_manager = Wrapped::new(panel::Manager::new(panel_manager));
 | 
				
			||||||
        let ctx = MainContext::default();
 | 
					        let ctx = MainContext::default();
 | 
				
			||||||
        ctx.acquire();
 | 
					        let _acqu = ctx.acquire();
 | 
				
			||||||
        receiver.attach(
 | 
					        receiver.attach(
 | 
				
			||||||
            Some(&ctx),
 | 
					            Some(&ctx),
 | 
				
			||||||
            move |msg| {
 | 
					            move |msg| {
 | 
				
			||||||
                main_loop_handle_message(msg, ui_manager, dbus_handler);
 | 
					                main_loop_handle_message(msg, panel_manager.clone(), hint_manager, dbus_handler);
 | 
				
			||||||
                Continue(true)
 | 
					                Continue(true)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					        #[cfg(not(feature = "glib_v0_14"))]
 | 
				
			||||||
        ctx.release();
 | 
					        ctx.release();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -104,27 +151,24 @@ mod c {
 | 
				
			|||||||
    /// and doesn't lend itself to testing other than integration.
 | 
					    /// and doesn't lend itself to testing other than integration.
 | 
				
			||||||
    fn main_loop_handle_message(
 | 
					    fn main_loop_handle_message(
 | 
				
			||||||
        msg: Commands,
 | 
					        msg: Commands,
 | 
				
			||||||
        ui_manager: *const UIManager,
 | 
					        panel_manager: Wrapped<panel::Manager>,
 | 
				
			||||||
 | 
					        hint_manager: HintManager,
 | 
				
			||||||
        dbus_handler: *const DBusHandler,
 | 
					        dbus_handler: *const DBusHandler,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        match msg.panel_visibility {
 | 
					        if let Some(visibility) = msg.panel_visibility {
 | 
				
			||||||
            Some(PanelCommand::Show) => unsafe {
 | 
					            panel::Manager::update(panel_manager, visibility);
 | 
				
			||||||
                server_context_service_real_show_keyboard(ui_manager);
 | 
					        }
 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            Some(PanelCommand::Hide) => unsafe {
 | 
					 | 
				
			||||||
                server_context_service_real_hide_keyboard(ui_manager);
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            None => {},
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(visible) = msg.dbus_visible_set {
 | 
					        if let Some(visible) = msg.dbus_visible_set {
 | 
				
			||||||
            unsafe { dbus_handler_set_visible(dbus_handler, visible as u8) };
 | 
					            if dbus_handler != std::ptr::null() {
 | 
				
			||||||
 | 
					                unsafe { dbus_handler_set_visible(dbus_handler, visible as u8) };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(hints) = msg.layout_hint_set {
 | 
					        if let Some(hints) = msg.layout_hint_set {
 | 
				
			||||||
            unsafe {
 | 
					            unsafe {
 | 
				
			||||||
                server_context_service_set_hint_purpose(
 | 
					                eekboard_context_service_set_hint_purpose(
 | 
				
			||||||
                    ui_manager,
 | 
					                    hint_manager,
 | 
				
			||||||
                    hints.hint.bits(),
 | 
					                    hints.hint.bits(),
 | 
				
			||||||
                    hints.purpose.clone() as u32,
 | 
					                    hints.purpose.clone() as u32,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
@ -133,17 +177,11 @@ mod c {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, PartialEq, Debug)]
 | 
					 | 
				
			||||||
pub enum PanelCommand {
 | 
					 | 
				
			||||||
    Show,
 | 
					 | 
				
			||||||
    Hide,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The commands consumed by the main loop,
 | 
					/// The commands consumed by the main loop,
 | 
				
			||||||
/// to be sent out to external components.
 | 
					/// to be sent out to external components.
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone)]
 | 
				
			||||||
pub struct Commands {
 | 
					pub struct Commands {
 | 
				
			||||||
    pub panel_visibility: Option<PanelCommand>,
 | 
					    pub panel_visibility: Option<panel::Command>,
 | 
				
			||||||
    pub layout_hint_set: Option<state::InputMethodDetails>,
 | 
					    pub layout_hint_set: Option<state::InputMethodDetails>,
 | 
				
			||||||
    pub dbus_visible_set: Option<bool>,
 | 
					    pub dbus_visible_set: Option<bool>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ sources = [
 | 
				
			|||||||
  config_h,
 | 
					  config_h,
 | 
				
			||||||
  'dbus.c',
 | 
					  'dbus.c',
 | 
				
			||||||
  'imservice.c',
 | 
					  'imservice.c',
 | 
				
			||||||
 | 
					  'panel.c',
 | 
				
			||||||
  'popover.c',
 | 
					  'popover.c',
 | 
				
			||||||
  'server-context-service.c',
 | 
					  'server-context-service.c',
 | 
				
			||||||
  'wayland.c',
 | 
					  'wayland.c',
 | 
				
			||||||
 | 
				
			|||||||
@ -11,7 +11,8 @@ struct squeek_output_handle {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct squeek_outputs *squeek_outputs_new(void);
 | 
					struct squeek_outputs *squeek_outputs_new(void);
 | 
				
			||||||
void squeek_outputs_free(struct squeek_outputs*);
 | 
					void squeek_outputs_free(struct squeek_outputs*);
 | 
				
			||||||
void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output);
 | 
					void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output, uint32_t id);
 | 
				
			||||||
 | 
					struct wl_output *squeek_outputs_try_unregister(struct squeek_outputs*, uint32_t id);
 | 
				
			||||||
struct squeek_output_handle squeek_outputs_get_current(struct squeek_outputs*);
 | 
					struct squeek_output_handle squeek_outputs_get_current(struct squeek_outputs*);
 | 
				
			||||||
int32_t squeek_outputs_get_perceptual_width(struct squeek_outputs*, struct wl_output *output);
 | 
					int32_t squeek_outputs_get_perceptual_width(struct squeek_outputs*, struct wl_output *output);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										339
									
								
								src/outputs.rs
									
									
									
									
									
								
							
							
						
						
									
										339
									
								
								src/outputs.rs
									
									
									
									
									
								
							@ -1,7 +1,14 @@
 | 
				
			|||||||
 | 
					/* Copyright (C) 2019-2022 Purism SPC
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: GPL-3.0+
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Managing Wayland outputs */
 | 
					/*! Managing Wayland outputs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::ops;
 | 
				
			||||||
use std::vec::Vec;
 | 
					use std::vec::Vec;
 | 
				
			||||||
 | 
					use crate::event_loop;
 | 
				
			||||||
use ::logging;
 | 
					use ::logging;
 | 
				
			||||||
 | 
					use crate::util::DivCeil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// traits
 | 
					// traits
 | 
				
			||||||
use ::logging::Warn;
 | 
					use ::logging::Warn;
 | 
				
			||||||
@ -11,15 +18,22 @@ pub mod c {
 | 
				
			|||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    use std::os::raw::{ c_char, c_void };
 | 
					    use std::os::raw::{ c_char, c_void };
 | 
				
			||||||
 | 
					    use std::ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use ::util::c::COpaquePtr;
 | 
					    use ::util::c::{COpaquePtr, Wrapped};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Defined in C
 | 
					    // Defined in C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[repr(transparent)]
 | 
					    #[repr(transparent)]
 | 
				
			||||||
    #[derive(Clone, PartialEq, Copy)]
 | 
					    #[derive(Clone, PartialEq, Copy, Debug, Eq, Hash)]
 | 
				
			||||||
    pub struct WlOutput(*const c_void);
 | 
					    pub struct WlOutput(*const c_void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    impl WlOutput {
 | 
				
			||||||
 | 
					        fn null() -> Self {
 | 
				
			||||||
 | 
					            Self(ptr::null())
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[repr(C)]
 | 
					    #[repr(C)]
 | 
				
			||||||
    struct WlOutputListener<T: COpaquePtr> {
 | 
					    struct WlOutputListener<T: COpaquePtr> {
 | 
				
			||||||
        geometry: extern fn(
 | 
					        geometry: extern fn(
 | 
				
			||||||
@ -63,7 +77,7 @@ pub mod c {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Map to `wl_output.transform` values
 | 
					    /// Map to `wl_output.transform` values
 | 
				
			||||||
    #[derive(Clone)]
 | 
					    #[derive(Clone, Copy, Debug)]
 | 
				
			||||||
    pub enum Transform {
 | 
					    pub enum Transform {
 | 
				
			||||||
        Normal = 0,
 | 
					        Normal = 0,
 | 
				
			||||||
        Rotated90 = 1,
 | 
					        Rotated90 = 1,
 | 
				
			||||||
@ -103,33 +117,18 @@ pub mod c {
 | 
				
			|||||||
        ) -> i32;
 | 
					        ) -> i32;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type COutputs = ::util::c::Wrapped<Outputs>;
 | 
					    /// Wrapping Outputs is required for calling its methods from C
 | 
				
			||||||
 | 
					    type COutputs = Wrapped<Outputs>;
 | 
				
			||||||
    /// A stable reference to an output.
 | 
					 | 
				
			||||||
    #[derive(Clone)]
 | 
					 | 
				
			||||||
    #[repr(C)]
 | 
					 | 
				
			||||||
    pub struct OutputHandle {
 | 
					 | 
				
			||||||
        wl_output: WlOutput,
 | 
					 | 
				
			||||||
        outputs: COutputs,
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    impl OutputHandle {
 | 
					 | 
				
			||||||
        // Cannot return an Output reference
 | 
					 | 
				
			||||||
        // because COutputs is too deeply wrapped
 | 
					 | 
				
			||||||
        pub fn get_state(&self) -> Option<OutputState> {
 | 
					 | 
				
			||||||
            let outputs = self.outputs.clone_ref();
 | 
					 | 
				
			||||||
            let outputs = outputs.borrow();
 | 
					 | 
				
			||||||
            find_output(&outputs, self.wl_output.clone()).map(|o| o.current.clone())
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Defined in Rust
 | 
					    // Defined in Rust
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Callbacks from the output listener follow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    extern fn outputs_handle_geometry(
 | 
					    extern fn outputs_handle_geometry(
 | 
				
			||||||
        outputs: COutputs,
 | 
					        outputs: COutputs,
 | 
				
			||||||
        wl_output: WlOutput,
 | 
					        wl_output: WlOutput,
 | 
				
			||||||
        _x: i32, _y: i32,
 | 
					        _x: i32, _y: i32,
 | 
				
			||||||
        _phys_width: i32, _phys_height: i32,
 | 
					        phys_width: i32, phys_height: i32,
 | 
				
			||||||
        _subpixel: i32,
 | 
					        _subpixel: i32,
 | 
				
			||||||
        _make: *const c_char, _model: *const c_char,
 | 
					        _make: *const c_char, _model: *const c_char,
 | 
				
			||||||
        transform: i32,
 | 
					        transform: i32,
 | 
				
			||||||
@ -143,10 +142,23 @@ pub mod c {
 | 
				
			|||||||
        let outputs = outputs.clone_ref();
 | 
					        let outputs = outputs.clone_ref();
 | 
				
			||||||
        let mut collection = outputs.borrow_mut();
 | 
					        let mut collection = outputs.borrow_mut();
 | 
				
			||||||
        let output_state: Option<&mut OutputState>
 | 
					        let output_state: Option<&mut OutputState>
 | 
				
			||||||
            = find_output_mut(&mut collection, wl_output)
 | 
					            = collection
 | 
				
			||||||
 | 
					                .find_output_mut(wl_output)
 | 
				
			||||||
                .map(|o| &mut o.pending);
 | 
					                .map(|o| &mut o.pending);
 | 
				
			||||||
        match output_state {
 | 
					        match output_state {
 | 
				
			||||||
            Some(state) => { state.transform = Some(transform) },
 | 
					            Some(state) => {
 | 
				
			||||||
 | 
					                fn maybe_mm(value: i32) -> Option<Millimeter> {
 | 
				
			||||||
 | 
					                    if value == 0 { None }
 | 
				
			||||||
 | 
					                    else { Some(Millimeter(value)) }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                state.geometry = Some(Geometry {
 | 
				
			||||||
 | 
					                    phys_size: Size {
 | 
				
			||||||
 | 
					                        width: maybe_mm(phys_width),
 | 
				
			||||||
 | 
					                        height: maybe_mm(phys_height),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    transform,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            None => log_print!(
 | 
					            None => log_print!(
 | 
				
			||||||
                logging::Level::Warning,
 | 
					                logging::Level::Warning,
 | 
				
			||||||
                "Got geometry on unknown output",
 | 
					                "Got geometry on unknown output",
 | 
				
			||||||
@ -171,7 +183,8 @@ pub mod c {
 | 
				
			|||||||
        let outputs = outputs.clone_ref();
 | 
					        let outputs = outputs.clone_ref();
 | 
				
			||||||
        let mut collection = outputs.borrow_mut();
 | 
					        let mut collection = outputs.borrow_mut();
 | 
				
			||||||
        let output_state: Option<&mut OutputState>
 | 
					        let output_state: Option<&mut OutputState>
 | 
				
			||||||
            = find_output_mut(&mut collection, wl_output)
 | 
					            = collection
 | 
				
			||||||
 | 
					                .find_output_mut(wl_output)
 | 
				
			||||||
                .map(|o| &mut o.pending);
 | 
					                .map(|o| &mut o.pending);
 | 
				
			||||||
        match output_state {
 | 
					        match output_state {
 | 
				
			||||||
            Some(state) => {
 | 
					            Some(state) => {
 | 
				
			||||||
@ -192,14 +205,27 @@ pub mod c {
 | 
				
			|||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        let outputs = outputs.clone_ref();
 | 
					        let outputs = outputs.clone_ref();
 | 
				
			||||||
        let mut collection = outputs.borrow_mut();
 | 
					        let mut collection = outputs.borrow_mut();
 | 
				
			||||||
        let output = find_output_mut(&mut collection, wl_output);
 | 
					        let output = collection
 | 
				
			||||||
        match output {
 | 
					            .find_output_mut(wl_output);
 | 
				
			||||||
            Some(output) => { output.current = output.pending.clone(); }
 | 
					        let event = match output {
 | 
				
			||||||
            None => log_print!(
 | 
					            Some(output) => {
 | 
				
			||||||
                logging::Level::Warning,
 | 
					                output.current = output.pending.clone();
 | 
				
			||||||
                "Got done on unknown output",
 | 
					                Some(Event {
 | 
				
			||||||
            ),
 | 
					                    output: OutputId(wl_output),
 | 
				
			||||||
 | 
					                    change: ChangeType::Altered(output.current),
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            None => {
 | 
				
			||||||
 | 
					                log_print!(
 | 
				
			||||||
 | 
					                    logging::Level::Warning,
 | 
				
			||||||
 | 
					                    "Got done on unknown output",
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                None
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					        if let Some(event) = event {
 | 
				
			||||||
 | 
					            collection.send_event(event);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    extern fn outputs_handle_scale(
 | 
					    extern fn outputs_handle_scale(
 | 
				
			||||||
@ -210,7 +236,8 @@ pub mod c {
 | 
				
			|||||||
        let outputs = outputs.clone_ref();
 | 
					        let outputs = outputs.clone_ref();
 | 
				
			||||||
        let mut collection = outputs.borrow_mut();
 | 
					        let mut collection = outputs.borrow_mut();
 | 
				
			||||||
        let output_state: Option<&mut OutputState>
 | 
					        let output_state: Option<&mut OutputState>
 | 
				
			||||||
            = find_output_mut(&mut collection, wl_output)
 | 
					            = collection
 | 
				
			||||||
 | 
					                .find_output_mut(wl_output)
 | 
				
			||||||
                .map(|o| &mut o.pending);
 | 
					                .map(|o| &mut o.pending);
 | 
				
			||||||
        match output_state {
 | 
					        match output_state {
 | 
				
			||||||
            Some(state) => { state.scale = factor; }
 | 
					            Some(state) => { state.scale = factor; }
 | 
				
			||||||
@ -221,11 +248,7 @@ pub mod c {
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[no_mangle]
 | 
					    // End callbacks
 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_outputs_new() -> COutputs {
 | 
					 | 
				
			||||||
        COutputs::new(Outputs { outputs: Vec::new() })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
@ -235,14 +258,17 @@ pub mod c {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput) {
 | 
					    fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput, id: u32) {
 | 
				
			||||||
        let collection = raw_collection.clone_ref();
 | 
					        let collection = raw_collection.clone_ref();
 | 
				
			||||||
        let mut collection = collection.borrow_mut();
 | 
					        let mut collection = collection.borrow_mut();
 | 
				
			||||||
        collection.outputs.push(Output {
 | 
					        collection.outputs.push((
 | 
				
			||||||
            output: output.clone(),
 | 
					            Output {
 | 
				
			||||||
            pending: OutputState::uninitialized(),
 | 
					                output: output.clone(),
 | 
				
			||||||
            current: OutputState::uninitialized(),
 | 
					                pending: OutputState::uninitialized(),
 | 
				
			||||||
        });
 | 
					                current: OutputState::uninitialized(),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            id,
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        unsafe { squeek_output_add_listener(
 | 
					        unsafe { squeek_output_add_listener(
 | 
				
			||||||
            output,
 | 
					            output,
 | 
				
			||||||
@ -255,61 +281,70 @@ pub mod c {
 | 
				
			|||||||
            raw_collection,
 | 
					            raw_collection,
 | 
				
			||||||
        )};
 | 
					        )};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
 | 
					    /// This will try to unregister the output, if the id matches a registered one.
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_outputs_get_current(raw_collection: COutputs) -> OutputHandle {
 | 
					    fn squeek_outputs_try_unregister(raw_collection: COutputs, id: u32) -> WlOutput {
 | 
				
			||||||
        let collection = raw_collection.clone_ref();
 | 
					        let collection = raw_collection.clone_ref();
 | 
				
			||||||
        let collection = collection.borrow();
 | 
					        let mut collection = collection.borrow_mut();
 | 
				
			||||||
        OutputHandle {
 | 
					        collection.remove_output_by_global(id)
 | 
				
			||||||
            wl_output: collection.outputs[0].output.clone(),
 | 
					            .map_err(|e| log_print!(
 | 
				
			||||||
            outputs: raw_collection.clone(),
 | 
					                logging::Level::Debug,
 | 
				
			||||||
        }
 | 
					                "Tried to remove global {:x} but it is not registered as an output: {:?}",
 | 
				
			||||||
 | 
					                id, e,
 | 
				
			||||||
 | 
					            ))
 | 
				
			||||||
 | 
					            .unwrap_or(WlOutput::null())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO: handle unregistration
 | 
					    // TODO: handle unregistration
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    fn find_output(
 | 
					 | 
				
			||||||
        collection: &Outputs,
 | 
					 | 
				
			||||||
        wl_output: WlOutput,
 | 
					 | 
				
			||||||
    ) -> Option<&Output> {
 | 
					 | 
				
			||||||
        collection.outputs
 | 
					 | 
				
			||||||
            .iter()
 | 
					 | 
				
			||||||
            .find_map(|o|
 | 
					 | 
				
			||||||
                if o.output == wl_output { Some(o) } else { None }
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn find_output_mut(
 | 
					 | 
				
			||||||
        collection: &mut Outputs,
 | 
					 | 
				
			||||||
        wl_output: WlOutput,
 | 
					 | 
				
			||||||
    ) -> Option<&mut Output> {
 | 
					 | 
				
			||||||
        collection.outputs
 | 
					 | 
				
			||||||
            .iter_mut()
 | 
					 | 
				
			||||||
            .find_map(|o|
 | 
					 | 
				
			||||||
                if o.output == wl_output { Some(o) } else { None }
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generic size
 | 
					/// Generic size
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
pub struct Size {
 | 
					pub struct Size<Unit> {
 | 
				
			||||||
    pub width: u32,
 | 
					    pub width: Unit,
 | 
				
			||||||
    pub height: u32,
 | 
					    pub height: Unit,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub type PixelSize = Size<u32>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// wl_output mode
 | 
					/// wl_output mode
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
struct Mode {
 | 
					pub struct Mode {
 | 
				
			||||||
    width: i32,
 | 
					    pub width: i32,
 | 
				
			||||||
    height: i32,
 | 
					    pub height: i32,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
 | 
					pub struct Millimeter(pub i32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl DivCeil<i32> for Millimeter {
 | 
				
			||||||
 | 
					    type Output = Millimeter;
 | 
				
			||||||
 | 
					    fn div_ceil(self, other: i32) -> Self {
 | 
				
			||||||
 | 
					        Self(self.0.div_ceil(other))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ops::Mul<i32> for Millimeter {
 | 
				
			||||||
 | 
					    type Output = Self;
 | 
				
			||||||
 | 
					    fn mul(self, m: i32) -> Self {
 | 
				
			||||||
 | 
					        Self(self.0 * m as i32)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// All geometry parameters
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
 | 
					pub struct Geometry {
 | 
				
			||||||
 | 
					    pub transform: c::Transform,
 | 
				
			||||||
 | 
					    pub phys_size: Size<Option<Millimeter>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
pub struct OutputState {
 | 
					pub struct OutputState {
 | 
				
			||||||
    current_mode: Option<Mode>,
 | 
					    pub current_mode: Option<Mode>,
 | 
				
			||||||
    transform: Option<c::Transform>,
 | 
					    pub geometry: Option<Geometry>,
 | 
				
			||||||
    pub scale: i32,
 | 
					    pub scale: i32,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -323,44 +358,138 @@ impl OutputState {
 | 
				
			|||||||
    fn uninitialized() -> OutputState {
 | 
					    fn uninitialized() -> OutputState {
 | 
				
			||||||
        OutputState {
 | 
					        OutputState {
 | 
				
			||||||
            current_mode: None,
 | 
					            current_mode: None,
 | 
				
			||||||
            transform: None,
 | 
					            geometry: None,
 | 
				
			||||||
            scale: 1,
 | 
					            scale: 1,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn get_pixel_size(&self) -> Option<Size> {
 | 
					    fn transform_size<T>(
 | 
				
			||||||
 | 
					        width: T,
 | 
				
			||||||
 | 
					        height: T,
 | 
				
			||||||
 | 
					        transform: self::c::Transform,
 | 
				
			||||||
 | 
					    ) -> Size<T> {
 | 
				
			||||||
        use self::c::Transform;
 | 
					        use self::c::Transform;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match transform {
 | 
				
			||||||
 | 
					            Transform::Normal
 | 
				
			||||||
 | 
					            | Transform::Rotated180
 | 
				
			||||||
 | 
					            | Transform::Flipped
 | 
				
			||||||
 | 
					            | Transform::FlippedRotated180 => Size {
 | 
				
			||||||
 | 
					                width,
 | 
				
			||||||
 | 
					                height,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            _ => Size {
 | 
				
			||||||
 | 
					                width: height,
 | 
				
			||||||
 | 
					                height: width,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Return resolution adjusted for current transform
 | 
				
			||||||
 | 
					    pub fn get_pixel_size(&self) -> Option<PixelSize> {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            OutputState {
 | 
					            OutputState {
 | 
				
			||||||
                current_mode: Some(Mode { width, height } ),
 | 
					                current_mode: Some(Mode { width, height } ),
 | 
				
			||||||
                transform: Some(transform),
 | 
					                geometry: Some(Geometry { transform, .. } ),
 | 
				
			||||||
                scale: _,
 | 
					                scale: _,
 | 
				
			||||||
            } => Some(
 | 
					            } => Some(Self::transform_size(*width as u32, *height as u32, *transform)),
 | 
				
			||||||
                match transform {
 | 
					            OutputState {
 | 
				
			||||||
                    Transform::Normal
 | 
					                current_mode: Some(Mode { width, height } ),
 | 
				
			||||||
                    | Transform::Rotated180
 | 
					                ..
 | 
				
			||||||
                    | Transform::Flipped
 | 
					            } => Some(PixelSize { width: *width as u32, height: *height as u32 } ),
 | 
				
			||||||
                    | Transform::FlippedRotated180 => Size {
 | 
					            _ => None,
 | 
				
			||||||
                        width: *width as u32,
 | 
					        }
 | 
				
			||||||
                        height: *height as u32,
 | 
					    }
 | 
				
			||||||
                    },
 | 
					
 | 
				
			||||||
                    _ => Size {
 | 
					    /// Return physical dimensions adjusted for current transform
 | 
				
			||||||
                        width: *height as u32,
 | 
					    pub fn get_physical_size(&self) -> Option<Size<Option<Millimeter>>> {
 | 
				
			||||||
                        height: *width as u32,
 | 
					        match self {
 | 
				
			||||||
                    },
 | 
					            OutputState {
 | 
				
			||||||
                }
 | 
					                geometry: Some(Geometry { transform, phys_size } ),
 | 
				
			||||||
            ),
 | 
					                ..
 | 
				
			||||||
 | 
					            } => Some(Self::transform_size(phys_size.width, phys_size.height, *transform)),
 | 
				
			||||||
            _ => None,
 | 
					            _ => None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Output {
 | 
					/// Not guaranteed to exist,
 | 
				
			||||||
 | 
					/// but can be used to look up state.
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash)]
 | 
				
			||||||
 | 
					pub struct OutputId(pub c::WlOutput);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WlOutput is a pointer,
 | 
				
			||||||
 | 
					// but in the public interface,
 | 
				
			||||||
 | 
					// we're only using it as a lookup key.
 | 
				
			||||||
 | 
					unsafe impl Send for OutputId {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Output {
 | 
				
			||||||
    output: c::WlOutput,
 | 
					    output: c::WlOutput,
 | 
				
			||||||
    pending: OutputState,
 | 
					    pending: OutputState,
 | 
				
			||||||
    current: OutputState,
 | 
					    current: OutputState,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					struct NotFound;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Wayland global ID type
 | 
				
			||||||
 | 
					type GlobalId = u32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The outputs manager
 | 
				
			||||||
pub struct Outputs {
 | 
					pub struct Outputs {
 | 
				
			||||||
    outputs: Vec<Output>,
 | 
					    outputs: Vec<(Output, GlobalId)>,
 | 
				
			||||||
 | 
					    sender: event_loop::driver::Threaded,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Outputs {
 | 
				
			||||||
 | 
					    pub fn new(sender: event_loop::driver::Threaded) -> Outputs {
 | 
				
			||||||
 | 
					        Outputs {
 | 
				
			||||||
 | 
					            outputs: Vec::new(),
 | 
				
			||||||
 | 
					            sender,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn send_event(&self, event: Event) {
 | 
				
			||||||
 | 
					        self.sender.send(event.into()).unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn remove_output_by_global(&mut self, id: GlobalId)
 | 
				
			||||||
 | 
					        -> Result<c::WlOutput, NotFound>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let index = self.outputs.iter()
 | 
				
			||||||
 | 
					            .position(|(_o, global_id)| *global_id == id);
 | 
				
			||||||
 | 
					        if let Some(index) = index {
 | 
				
			||||||
 | 
					            let (output, _id) = self.outputs.remove(index);
 | 
				
			||||||
 | 
					            self.send_event(Event {
 | 
				
			||||||
 | 
					                change: ChangeType::Removed,
 | 
				
			||||||
 | 
					                output: OutputId(output.output),
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            Ok(output.output)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Err(NotFound)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn find_output_mut(&mut self, wl_output: c::WlOutput)
 | 
				
			||||||
 | 
					        -> Option<&mut Output>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        self.outputs
 | 
				
			||||||
 | 
					            .iter_mut()
 | 
				
			||||||
 | 
					            .find_map(|(o, _global)|
 | 
				
			||||||
 | 
					                if o.output == wl_output { Some(o) } else { None }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
 | 
					pub enum ChangeType {
 | 
				
			||||||
 | 
					    /// Added or changed
 | 
				
			||||||
 | 
					    Altered(OutputState),
 | 
				
			||||||
 | 
					    Removed,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
 | 
					pub struct Event {
 | 
				
			||||||
 | 
					    pub output: OutputId,
 | 
				
			||||||
 | 
					    pub change: ChangeType,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										130
									
								
								src/panel.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/panel.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					#include "eekboard/eekboard-context-service.h"
 | 
				
			||||||
 | 
					#include "wayland.h"
 | 
				
			||||||
 | 
					#include "panel.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Called from rust
 | 
				
			||||||
 | 
					/// Destroys the widget
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					panel_manager_hide(struct panel_manager *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (self->window) {
 | 
				
			||||||
 | 
					        gtk_widget_destroy (GTK_WIDGET (self->window));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (self->widget) {
 | 
				
			||||||
 | 
					        gtk_widget_destroy (GTK_WIDGET (self->widget));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    self->window = NULL;
 | 
				
			||||||
 | 
					    self->widget = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_destroy (struct panel_manager *self, GtkWidget *widget)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    g_assert (widget == GTK_WIDGET(self->window));
 | 
				
			||||||
 | 
					    panel_manager_hide(self);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// panel::Manager. Only needed for this callback
 | 
				
			||||||
 | 
					struct squeek_panel_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Calls back into Rust
 | 
				
			||||||
 | 
					void squeek_panel_manager_configured(struct squeek_panel_manager *mgr, uint32_t width, uint32_t height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_surface_configure(struct squeek_panel_manager *self, PhoshLayerSurface *surface)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gint width;
 | 
				
			||||||
 | 
					    gint height;
 | 
				
			||||||
 | 
					    g_return_if_fail (PHOSH_IS_LAYER_SURFACE (surface));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_object_get(G_OBJECT(surface),
 | 
				
			||||||
 | 
					                 "configured-width", &width,
 | 
				
			||||||
 | 
					                 "configured-height", &height,
 | 
				
			||||||
 | 
					                 NULL);
 | 
				
			||||||
 | 
					    squeek_panel_manager_configured(self, width, height);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gtk_widget_set_has_tooltip (self->widget, TRUE);
 | 
				
			||||||
 | 
					    gtk_container_add (GTK_CONTAINER(self->window), self->widget);
 | 
				
			||||||
 | 
					    gtk_widget_show_all(self->widget);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Called from rust
 | 
				
			||||||
 | 
					/// Creates a new panel widget
 | 
				
			||||||
 | 
					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");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gtk_widget_show (GTK_WIDGET(self->window));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Called from rust
 | 
				
			||||||
 | 
					/// Updates the size
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					panel_manager_resize (struct panel_manager *self, uint32_t height)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    phosh_layer_surface_set_size(self->window, 0, height);
 | 
				
			||||||
 | 
					    phosh_layer_surface_set_exclusive_zone(self->window, height);
 | 
				
			||||||
 | 
					    phosh_layer_surface_wl_surface_commit(self->window);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct panel_manager mgr = {
 | 
				
			||||||
 | 
					        .state = state,
 | 
				
			||||||
 | 
					        .submission = submission,
 | 
				
			||||||
 | 
					        .layout = layout,
 | 
				
			||||||
 | 
					        .window = NULL,
 | 
				
			||||||
 | 
					        .widget = NULL,
 | 
				
			||||||
 | 
					        .current_output = NULL,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return mgr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/panel.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/panel.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "eek/layersurface.h"
 | 
				
			||||||
 | 
					#include "src/layout.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 submission *submission; // unowned
 | 
				
			||||||
 | 
					    struct squeek_layout_state *layout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PhoshLayerSurface *window;
 | 
				
			||||||
 | 
					    GtkWidget *widget; // nullable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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);
 | 
				
			||||||
							
								
								
									
										248
									
								
								src/panel.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								src/panel.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,248 @@
 | 
				
			|||||||
 | 
					/* Copyright (C) 2022 Purism SPC
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: GPL-3.0+
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Panel state management.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is effectively a mirror of the previous C code,
 | 
				
			||||||
 | 
					 * with an explicit state machine managing the panel size.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It still relies on a callback from Wayland to accept the panel size,
 | 
				
			||||||
 | 
					 * which makes this code somewhat prone to mistakes.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * An alternative to the callback would be
 | 
				
			||||||
 | 
					 * to send a message all the way to `state::State`
 | 
				
			||||||
 | 
					 * every time the allocated size changes.
 | 
				
			||||||
 | 
					 * That would allow for a more holistic view
 | 
				
			||||||
 | 
					 * of interactions of different pieces of state.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * However, `state::State` already has the potential to become a ball of mud,
 | 
				
			||||||
 | 
					 * tightly coupling different functionality and making it difficult to see independent units.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * For this reason, I'm taking a light touch approach with the panel manager,
 | 
				
			||||||
 | 
					 * and moving it just a bit closer to `state::State`.
 | 
				
			||||||
 | 
					 * Hopefully ths still allows us to expose assumptions that were not stated yet
 | 
				
			||||||
 | 
					 * (e.g. can the output disappear between size request andallocation?).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Tight coupling, e.g. a future one between presented hints and layout size,
 | 
				
			||||||
 | 
					 * will have to be taken into account later.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::logging;
 | 
				
			||||||
 | 
					use crate::outputs::OutputId;
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// struct panel_manager*
 | 
				
			||||||
 | 
					    #[repr(transparent)]
 | 
				
			||||||
 | 
					    #[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					    pub struct PanelManager(*const c_void);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    extern "C" {
 | 
				
			||||||
 | 
					        #[allow(improper_ctypes)]
 | 
				
			||||||
 | 
					        pub fn panel_manager_request_widget(
 | 
				
			||||||
 | 
					            service: PanelManager,
 | 
				
			||||||
 | 
					            output: WlOutput,
 | 
				
			||||||
 | 
					            height: u32,
 | 
				
			||||||
 | 
					            // for callbacks
 | 
				
			||||||
 | 
					            panel: Wrapped<Manager>,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        pub fn panel_manager_resize(service: PanelManager, height: u32);
 | 
				
			||||||
 | 
					        pub fn panel_manager_hide(service: PanelManager);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_panel_manager_configured(panel: Wrapped<Manager>, width: u32, height: u32) {
 | 
				
			||||||
 | 
					        // This is why this needs to be moved into state::State:
 | 
				
			||||||
 | 
					        // it's getting too coupled to glib.
 | 
				
			||||||
 | 
					        glib::idle_add_local(move || {
 | 
				
			||||||
 | 
					            let panel = panel.clone_ref();
 | 
				
			||||||
 | 
					            panel.borrow_mut().set_configured(Size{width, height});
 | 
				
			||||||
 | 
					            Continue(false)
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Size in pixels that is aware of scaling
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, PartialEq, Debug)]
 | 
				
			||||||
 | 
					pub struct PixelSize {
 | 
				
			||||||
 | 
					    pub pixels: u32,
 | 
				
			||||||
 | 
					    pub scale_factor: u32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn div_ceil(a: u32, b: u32) -> u32 {
 | 
				
			||||||
 | 
					    // Given that it's for pixels on a screen, an overflow is unlikely.
 | 
				
			||||||
 | 
					    (a + b - 1) / b
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl PixelSize {
 | 
				
			||||||
 | 
					    pub fn as_scaled_floor(&self) -> u32 {
 | 
				
			||||||
 | 
					        self.pixels / self.scale_factor
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn as_scaled_ceiling(&self) -> u32 {
 | 
				
			||||||
 | 
					        div_ceil(self.pixels, self.scale_factor)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					struct Size {
 | 
				
			||||||
 | 
					    width: u32,
 | 
				
			||||||
 | 
					    height: u32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// This state requests the Wayland layer shell protocol synchronization:
 | 
				
			||||||
 | 
					/// the application asks for some size,
 | 
				
			||||||
 | 
					/// and then receives a size that the compositor thought appropriate.
 | 
				
			||||||
 | 
					/// Stores raw values passed to Wayland, i.e. scaled dimensions.
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					enum State {
 | 
				
			||||||
 | 
					    Hidden,
 | 
				
			||||||
 | 
					    SizeRequested {
 | 
				
			||||||
 | 
					        output: OutputId,
 | 
				
			||||||
 | 
					        height: u32,
 | 
				
			||||||
 | 
					        //width: u32,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    SizeAllocated {
 | 
				
			||||||
 | 
					        output: OutputId,
 | 
				
			||||||
 | 
					        wanted_height: u32,
 | 
				
			||||||
 | 
					        allocated: Size,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, PartialEq, Debug)]
 | 
				
			||||||
 | 
					pub enum Command {
 | 
				
			||||||
 | 
					    Show {
 | 
				
			||||||
 | 
					        output: OutputId,
 | 
				
			||||||
 | 
					        height: PixelSize,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    Hide,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Tries to contain all the panel sizing duties.
 | 
				
			||||||
 | 
					pub struct Manager {
 | 
				
			||||||
 | 
					    panel: c::PanelManager,
 | 
				
			||||||
 | 
					    state: State,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Manager {
 | 
				
			||||||
 | 
					    pub fn new(panel: c::PanelManager) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            panel,
 | 
				
			||||||
 | 
					            state: State::Hidden,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // TODO: mabe send the allocated size back to state::State,
 | 
				
			||||||
 | 
					    // to perform layout adjustments
 | 
				
			||||||
 | 
					    fn set_configured(&mut self, size: Size) {
 | 
				
			||||||
 | 
					        self.state = match self.state.clone() {
 | 
				
			||||||
 | 
					            State::Hidden => {
 | 
				
			||||||
 | 
					                // This may happen if a hide is scheduled immediately after a show.
 | 
				
			||||||
 | 
					                log_print!(
 | 
				
			||||||
 | 
					                    logging::Level::Surprise,
 | 
				
			||||||
 | 
					                    "Panel has been configured, but no request is pending. Ignoring",
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                State::Hidden
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            State::SizeAllocated{output, wanted_height, ..} => {
 | 
				
			||||||
 | 
					                log_print!(
 | 
				
			||||||
 | 
					                    logging::Level::Surprise,
 | 
				
			||||||
 | 
					                    "Panel received new configuration without asking",
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                State::SizeAllocated{output, wanted_height, allocated: size}
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            State::SizeRequested{output, height} => State::SizeAllocated {
 | 
				
			||||||
 | 
					                output,
 | 
				
			||||||
 | 
					                wanted_height: height,
 | 
				
			||||||
 | 
					                allocated: size,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn update(mgr: Wrapped<Manager>, cmd: Command) {
 | 
				
			||||||
 | 
					        let copied = mgr.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mgr = mgr.clone_ref();
 | 
				
			||||||
 | 
					        let mut mgr = mgr.borrow_mut();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        (*mgr).state = match (cmd, mgr.state.clone()) {
 | 
				
			||||||
 | 
					            (Command::Hide, State::Hidden) => State::Hidden,
 | 
				
			||||||
 | 
					            (Command::Hide, State::SizeAllocated{..}) => {
 | 
				
			||||||
 | 
					                unsafe { c::panel_manager_hide(mgr.panel); }
 | 
				
			||||||
 | 
					                State::Hidden
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            (Command::Hide, State::SizeRequested{..}) => {
 | 
				
			||||||
 | 
					                unsafe { c::panel_manager_hide(mgr.panel); }
 | 
				
			||||||
 | 
					                State::Hidden
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            (Command::Show{output, height}, State::Hidden) => {
 | 
				
			||||||
 | 
					                let height = height.as_scaled_ceiling();
 | 
				
			||||||
 | 
					                unsafe { c::panel_manager_request_widget(mgr.panel, output.0, height, copied); }
 | 
				
			||||||
 | 
					                State::SizeRequested{output, height}
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            (
 | 
				
			||||||
 | 
					                Command::Show{output, height},
 | 
				
			||||||
 | 
					                State::SizeRequested{output: req_output, height: req_height},
 | 
				
			||||||
 | 
					            ) => {
 | 
				
			||||||
 | 
					                let height = height.as_scaled_ceiling();
 | 
				
			||||||
 | 
					                if output == req_output && height == req_height {
 | 
				
			||||||
 | 
					                    State::SizeRequested{output: req_output, height: req_height}
 | 
				
			||||||
 | 
					                } else if output == req_output {
 | 
				
			||||||
 | 
					                    // I'm not sure about that.
 | 
				
			||||||
 | 
					                    // This could cause a busy loop,
 | 
				
			||||||
 | 
					                    // when two requests are being processed at the same time:
 | 
				
			||||||
 | 
					                    // one message in the compositor to allocate size A,
 | 
				
			||||||
 | 
					                    // causing the state to update to height A'
 | 
				
			||||||
 | 
					                    // the other from the state wanting height B',
 | 
				
			||||||
 | 
					                    // causing the compositor to change size to B.
 | 
				
			||||||
 | 
					                    // So better cut this short here, despite artifacts.
 | 
				
			||||||
 | 
					                    // Out of simplicty, just ignore the new request.
 | 
				
			||||||
 | 
					                    // If that causes problems, the request in flight could be stored
 | 
				
			||||||
 | 
					                    // for the purpose of handling it better somehow.
 | 
				
			||||||
 | 
					                    State::SizeRequested{output: req_output, height: req_height}
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    // This looks weird, but should be safe.
 | 
				
			||||||
 | 
					                    // The stack seems to handle
 | 
				
			||||||
 | 
					                    // configure events on a dead surface.
 | 
				
			||||||
 | 
					                    unsafe {
 | 
				
			||||||
 | 
					                        c::panel_manager_hide(mgr.panel);
 | 
				
			||||||
 | 
					                        c::panel_manager_request_widget(mgr.panel, output.0, height, copied);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    State::SizeRequested{output, height}
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            (
 | 
				
			||||||
 | 
					                Command::Show{output, height},
 | 
				
			||||||
 | 
					                State::SizeAllocated{output: alloc_output, allocated, wanted_height},
 | 
				
			||||||
 | 
					            ) => {
 | 
				
			||||||
 | 
					                let height = height.as_scaled_ceiling();
 | 
				
			||||||
 | 
					                if output == alloc_output && height == wanted_height {
 | 
				
			||||||
 | 
					                    State::SizeAllocated{output: alloc_output, wanted_height, allocated}
 | 
				
			||||||
 | 
					                } else if output == alloc_output && height == allocated.height {
 | 
				
			||||||
 | 
					                    State::SizeAllocated{output: alloc_output, wanted_height: height, allocated}
 | 
				
			||||||
 | 
					                } else if output == alloc_output {
 | 
				
			||||||
 | 
					                    // Should *all* other heights cause a resize?
 | 
				
			||||||
 | 
					                    // What about those between wanted and allocated?
 | 
				
			||||||
 | 
					                    unsafe { c::panel_manager_resize(mgr.panel, height); }
 | 
				
			||||||
 | 
					                    State::SizeRequested{output, height}
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    unsafe {
 | 
				
			||||||
 | 
					                        c::panel_manager_hide(mgr.panel);
 | 
				
			||||||
 | 
					                        c::panel_manager_request_widget(mgr.panel, output.0, height, copied);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    State::SizeRequested{output, height}
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -11,16 +11,11 @@ use ::manager;
 | 
				
			|||||||
use ::resources;
 | 
					use ::resources;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Traits
 | 
					// Traits
 | 
				
			||||||
use gio::ActionMapExt;
 | 
					use gio::prelude::ActionMapExt;
 | 
				
			||||||
use gio::SettingsExt;
 | 
					use gio::prelude::SettingsExt;
 | 
				
			||||||
#[cfg(feature = "gio_v0_5")]
 | 
					 | 
				
			||||||
use gio::SimpleActionExt;
 | 
					 | 
				
			||||||
use glib::translate::FromGlibPtrNone;
 | 
					use glib::translate::FromGlibPtrNone;
 | 
				
			||||||
use glib::variant::ToVariant;
 | 
					use glib::variant::ToVariant;
 | 
				
			||||||
#[cfg(not(feature = "gtk_v0_5"))]
 | 
					 | 
				
			||||||
use gtk::prelude::*;
 | 
					use gtk::prelude::*;
 | 
				
			||||||
use gtk::PopoverExt;
 | 
					 | 
				
			||||||
use gtk::WidgetExt;
 | 
					 | 
				
			||||||
use ::logging::Warn;
 | 
					use ::logging::Warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod c {
 | 
					mod c {
 | 
				
			||||||
@ -110,8 +105,13 @@ mod variants {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn get_settings(schema_name: &str) -> Option<gio::Settings> {
 | 
					fn get_settings(schema_name: &str) -> Option<gio::Settings> {
 | 
				
			||||||
    let mut error_handler = logging::Print{};
 | 
					    let mut error_handler = logging::Print{};
 | 
				
			||||||
    gio::SettingsSchemaSource::get_default()
 | 
					
 | 
				
			||||||
        .or_warn(
 | 
					    #[cfg(feature = "glib_v0_14")]
 | 
				
			||||||
 | 
					    let ss = gio::SettingsSchemaSource::default();
 | 
				
			||||||
 | 
					    #[cfg(not(feature = "glib_v0_14"))]
 | 
				
			||||||
 | 
					    let ss = gio::SettingsSchemaSource::get_default();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    ss.or_warn(
 | 
				
			||||||
            &mut error_handler,
 | 
					            &mut error_handler,
 | 
				
			||||||
            logging::Problem::Surprise,
 | 
					            logging::Problem::Surprise,
 | 
				
			||||||
            "No gsettings schemas installed.",
 | 
					            "No gsettings schemas installed.",
 | 
				
			||||||
@ -130,7 +130,11 @@ fn get_settings(schema_name: &str) -> Option<gio::Settings> {
 | 
				
			|||||||
fn set_layout(kind: String, name: String) {
 | 
					fn set_layout(kind: String, name: String) {
 | 
				
			||||||
    let settings = get_settings("org.gnome.desktop.input-sources");
 | 
					    let settings = get_settings("org.gnome.desktop.input-sources");
 | 
				
			||||||
    if let Some(settings) = settings {
 | 
					    if let Some(settings) = settings {
 | 
				
			||||||
 | 
					        #[cfg(feature = "glib_v0_14")]
 | 
				
			||||||
 | 
					        let inputs = settings.value("sources");
 | 
				
			||||||
 | 
					        #[cfg(not(feature = "glib_v0_14"))]
 | 
				
			||||||
        let inputs = settings.get_value("sources").unwrap();
 | 
					        let inputs = settings.get_value("sources").unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let current = (kind.clone(), name.clone());
 | 
					        let current = (kind.clone(), name.clone());
 | 
				
			||||||
        let inputs = variants::get_tuples(inputs).into_iter()
 | 
					        let inputs = variants::get_tuples(inputs).into_iter()
 | 
				
			||||||
            .filter(|t| t != ¤t);
 | 
					            .filter(|t| t != ¤t);
 | 
				
			||||||
@ -254,7 +258,11 @@ pub fn show(
 | 
				
			|||||||
    let settings = get_settings("org.gnome.desktop.input-sources");
 | 
					    let settings = get_settings("org.gnome.desktop.input-sources");
 | 
				
			||||||
    let inputs = settings
 | 
					    let inputs = settings
 | 
				
			||||||
        .map(|settings| {
 | 
					        .map(|settings| {
 | 
				
			||||||
 | 
					            #[cfg(feature = "glib_v0_14")]
 | 
				
			||||||
 | 
					            let inputs = settings.value("sources");
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "glib_v0_14"))]
 | 
				
			||||||
            let inputs = settings.get_value("sources").unwrap();
 | 
					            let inputs = settings.get_value("sources").unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            variants::get_tuples(inputs)
 | 
					            variants::get_tuples(inputs)
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .unwrap_or_else(|| Vec::new());
 | 
					        .unwrap_or_else(|| Vec::new());
 | 
				
			||||||
@ -285,8 +293,18 @@ pub fn show(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let builder = gtk::Builder::new_from_resource("/sm/puri/squeekboard/popover.ui");
 | 
					    let model: gio::Menu = {
 | 
				
			||||||
    let model: gio::Menu = builder.get_object("app-menu").unwrap();
 | 
					        #[cfg(feature = "glib_v0_14")]
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let builder = gtk::Builder::from_resource("/sm/puri/squeekboard/popover.ui");
 | 
				
			||||||
 | 
					            builder.object("app-menu").unwrap()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        #[cfg(not(feature = "glib_v0_14"))]
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let builder = gtk::Builder::new_from_resource("/sm/puri/squeekboard/popover.ui");
 | 
				
			||||||
 | 
					            builder.get_object("app-menu").unwrap()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (tr, l) in human_names.iter().rev() {
 | 
					    for (tr, l) in human_names.iter().rev() {
 | 
				
			||||||
        let detailed_action = format!("layout::{}", l.get_name());
 | 
					        let detailed_action = format!("layout::{}", l.get_name());
 | 
				
			||||||
@ -294,7 +312,11 @@ pub fn show(
 | 
				
			|||||||
        model.prepend_item (&item);
 | 
					        model.prepend_item (&item);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(feature = "glib_v0_14")]
 | 
				
			||||||
 | 
					    let menu = gtk::Popover::from_model(Some(&window), &model);
 | 
				
			||||||
 | 
					    #[cfg(not(feature = "glib_v0_14"))]
 | 
				
			||||||
    let menu = gtk::Popover::new_from_model(Some(&window), &model);
 | 
					    let menu = gtk::Popover::new_from_model(Some(&window), &model);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    menu.set_pointing_to(>k::Rectangle {
 | 
					    menu.set_pointing_to(>k::Rectangle {
 | 
				
			||||||
        x: position.x.ceil() as i32,
 | 
					        x: position.x.ceil() as i32,
 | 
				
			||||||
        y: position.y.ceil() as i32,
 | 
					        y: position.y.ceil() as i32,
 | 
				
			||||||
 | 
				
			|||||||
@ -54,6 +54,8 @@ static KEYBOARDS: &[(&'static str, &'static str)] = &[
 | 
				
			|||||||
    ("fr_wide", include_str!("../data/keyboards/fr_wide.yaml")),
 | 
					    ("fr_wide", include_str!("../data/keyboards/fr_wide.yaml")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ("gr", include_str!("../data/keyboards/gr.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")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ("il", include_str!("../data/keyboards/il.yaml")),
 | 
					    ("il", include_str!("../data/keyboards/il.yaml")),
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@ -71,6 +73,9 @@ static KEYBOARDS: &[(&'static str, &'static str)] = &[
 | 
				
			|||||||
    ("pl", include_str!("../data/keyboards/pl.yaml")),
 | 
					    ("pl", include_str!("../data/keyboards/pl.yaml")),
 | 
				
			||||||
    ("pl_wide", include_str!("../data/keyboards/pl_wide.yaml")),
 | 
					    ("pl_wide", include_str!("../data/keyboards/pl_wide.yaml")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ("ro", include_str!("../data/keyboards/ro.yaml")),
 | 
				
			||||||
 | 
					    ("ro_wide", include_str!("../data/keyboards/ro_wide.yaml")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ("ru", include_str!("../data/keyboards/ru.yaml")),
 | 
					    ("ru", include_str!("../data/keyboards/ru.yaml")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ("se", include_str!("../data/keyboards/se.yaml")),
 | 
					    ("se", include_str!("../data/keyboards/se.yaml")),
 | 
				
			||||||
 | 
				
			|||||||
@ -20,12 +20,6 @@
 | 
				
			|||||||
#include <gtk/gtk.h>
 | 
					#include <gtk/gtk.h>
 | 
				
			||||||
#include <glib/gi18n.h>
 | 
					#include <glib/gi18n.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "eek/eek.h"
 | 
					 | 
				
			||||||
#include "eek/eek-gtk-keyboard.h"
 | 
					 | 
				
			||||||
#include "eek/layersurface.h"
 | 
					 | 
				
			||||||
#include "eekboard/eekboard-context-service.h"
 | 
					 | 
				
			||||||
#include "submission.h"
 | 
					 | 
				
			||||||
#include "wayland.h"
 | 
					 | 
				
			||||||
#include "server-context-service.h"
 | 
					#include "server-context-service.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
@ -36,196 +30,13 @@ enum {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct _ServerContextService {
 | 
					struct _ServerContextService {
 | 
				
			||||||
    GObject parent;
 | 
					    GObject parent;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    EekboardContextService *state; // unowned
 | 
					 | 
				
			||||||
    /// Needed for instantiating the widget
 | 
					 | 
				
			||||||
    struct submission *submission; // unowned
 | 
					 | 
				
			||||||
    struct squeek_layout_state *layout;
 | 
					 | 
				
			||||||
    struct ui_manager *manager; // unowned
 | 
					 | 
				
			||||||
    struct squeek_state_manager *state_manager; // shared reference
 | 
					    struct squeek_state_manager *state_manager; // shared reference
 | 
				
			||||||
 | 
					 | 
				
			||||||
    PhoshLayerSurface *window;
 | 
					 | 
				
			||||||
    GtkWidget *widget; // nullable
 | 
					 | 
				
			||||||
    guint last_requested_height;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_DEFINE_TYPE(ServerContextService, server_context_service, G_TYPE_OBJECT);
 | 
					G_DEFINE_TYPE(ServerContextService, server_context_service, G_TYPE_OBJECT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_destroy (ServerContextService *self, GtkWidget *widget)
 | 
					/// Height is in scaled units.
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    g_assert (widget == GTK_WIDGET(self->window));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    self->window = NULL;
 | 
					 | 
				
			||||||
    self->widget = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //eekboard_context_service_destroy (EEKBOARD_CONTEXT_SERVICE (context));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static uint32_t
 | 
					 | 
				
			||||||
calculate_height(int32_t width, GdkRectangle *geometry)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    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(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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // 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
 | 
					 | 
				
			||||||
    // (for the same set of surrounding properties),
 | 
					 | 
				
			||||||
    // then it's probably not reasonable to ask for it again,
 | 
					 | 
				
			||||||
    // as it's likely to create pointless loops
 | 
					 | 
				
			||||||
    // of request->reject->request_again->...
 | 
					 | 
				
			||||||
    if (desired_height != configured_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);
 | 
					 | 
				
			||||||
        phosh_layer_surface_wl_surface_commit (surface);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
make_window (ServerContextService *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (self->window) {
 | 
					 | 
				
			||||||
        g_error("Window already present");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct squeek_output_handle output = squeek_outputs_get_current(squeek_wayland->outputs);
 | 
					 | 
				
			||||||
    squeek_uiman_set_output(self->manager, output);
 | 
					 | 
				
			||||||
    uint32_t height = squeek_uiman_get_perceptual_height(self->manager);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    self->window = g_object_new (
 | 
					 | 
				
			||||||
        PHOSH_TYPE_LAYER_SURFACE,
 | 
					 | 
				
			||||||
        "layer-shell", squeek_wayland->layer_shell,
 | 
					 | 
				
			||||||
        "wl-output", 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), self,
 | 
					 | 
				
			||||||
                      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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
destroy_window (ServerContextService *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    gtk_widget_destroy (GTK_WIDGET (self->window));
 | 
					 | 
				
			||||||
    self->window = NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
make_widget (ServerContextService *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (self->widget) {
 | 
					 | 
				
			||||||
        gtk_widget_destroy(self->widget);
 | 
					 | 
				
			||||||
        self->widget = NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    self->widget = eek_gtk_keyboard_new (self->state, self->submission, self->layout);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    gtk_widget_set_has_tooltip (self->widget, TRUE);
 | 
					 | 
				
			||||||
    gtk_container_add (GTK_CONTAINER(self->window), self->widget);
 | 
					 | 
				
			||||||
    gtk_widget_show_all(self->widget);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Called from rust
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
server_context_service_real_show_keyboard (ServerContextService *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (!self->window) {
 | 
					 | 
				
			||||||
        make_window (self);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!self->widget) {
 | 
					 | 
				
			||||||
        make_widget (self);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    gtk_widget_show (GTK_WIDGET(self->window));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Called from rust
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
server_context_service_real_hide_keyboard (ServerContextService *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (self->window) {
 | 
					 | 
				
			||||||
	    gtk_widget_hide (GTK_WIDGET(self->window));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
server_context_service_set_property (GObject      *object,
 | 
					server_context_service_set_property (GObject      *object,
 | 
				
			||||||
                                     guint         prop_id,
 | 
					                                     guint         prop_id,
 | 
				
			||||||
                                     const GValue *value,
 | 
					                                     const GValue *value,
 | 
				
			||||||
@ -256,17 +67,6 @@ server_context_service_get_property (GObject    *object,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
server_context_service_dispose (GObject *object)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    ServerContextService *self = SERVER_CONTEXT_SERVICE(object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    destroy_window (self);
 | 
					 | 
				
			||||||
    self->widget = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    G_OBJECT_CLASS (server_context_service_parent_class)->dispose (object);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
server_context_service_class_init (ServerContextServiceClass *klass)
 | 
					server_context_service_class_init (ServerContextServiceClass *klass)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -275,7 +75,6 @@ server_context_service_class_init (ServerContextServiceClass *klass)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    gobject_class->set_property = server_context_service_set_property;
 | 
					    gobject_class->set_property = server_context_service_set_property;
 | 
				
			||||||
    gobject_class->get_property = server_context_service_get_property;
 | 
					    gobject_class->get_property = server_context_service_get_property;
 | 
				
			||||||
    gobject_class->dispose = server_context_service_dispose;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * ServerContextServie:keyboard:
 | 
					     * ServerContextServie:keyboard:
 | 
				
			||||||
@ -296,42 +95,29 @@ server_context_service_class_init (ServerContextServiceClass *klass)
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
server_context_service_init (ServerContextService *self) {}
 | 
					server_context_service_init (ServerContextService *self) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					
 | 
				
			||||||
init (ServerContextService *self) {
 | 
					ServerContextService *
 | 
				
			||||||
 | 
					server_context_service_new (struct squeek_state_manager *state_manager)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ServerContextService *holder = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
 | 
				
			||||||
 | 
					    holder->state_manager = state_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *schema_name = "org.gnome.desktop.a11y.applications";
 | 
					    const char *schema_name = "org.gnome.desktop.a11y.applications";
 | 
				
			||||||
    GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default();
 | 
					    GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default();
 | 
				
			||||||
    g_autoptr(GSettingsSchema) schema = NULL;
 | 
					    g_autoptr(GSettingsSchema) schema = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!ssrc) {
 | 
					    if (!ssrc) {
 | 
				
			||||||
        g_warning("No gsettings schemas installed.");
 | 
					        g_warning("No gsettings schemas installed.");
 | 
				
			||||||
        return;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    schema = g_settings_schema_source_lookup(ssrc, schema_name, TRUE);
 | 
					    schema = g_settings_schema_source_lookup(ssrc, schema_name, TRUE);
 | 
				
			||||||
    if (schema) {
 | 
					    if (schema) {
 | 
				
			||||||
        g_autoptr(GSettings) settings = g_settings_new (schema_name);
 | 
					        g_autoptr(GSettings) settings = g_settings_new (schema_name);
 | 
				
			||||||
        g_settings_bind (settings, "screen-keyboard-enabled",
 | 
					        g_settings_bind (settings, "screen-keyboard-enabled",
 | 
				
			||||||
                         self, "enabled", G_SETTINGS_BIND_GET);
 | 
					                         holder, "enabled", G_SETTINGS_BIND_GET);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        g_warning("Gsettings schema %s is not installed on the system. "
 | 
					        g_warning("Gsettings schema %s is not installed on the system. "
 | 
				
			||||||
                  "Enabling by default.", schema_name);
 | 
					                  "Enabling by default.", schema_name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					    return holder;
 | 
				
			||||||
 | 
					 | 
				
			||||||
ServerContextService *
 | 
					 | 
				
			||||||
server_context_service_new (EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman,  struct squeek_state_manager *state_manager)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
 | 
					 | 
				
			||||||
    ui->submission = submission;
 | 
					 | 
				
			||||||
    ui->state = self;
 | 
					 | 
				
			||||||
    ui->layout = layout;
 | 
					 | 
				
			||||||
    ui->manager = uiman;
 | 
					 | 
				
			||||||
    ui->state_manager = state_manager;
 | 
					 | 
				
			||||||
    init(ui);
 | 
					 | 
				
			||||||
    return ui;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Used from Rust
 | 
					 | 
				
			||||||
void server_context_service_set_hint_purpose(ServerContextService *self, uint32_t hint,
 | 
					 | 
				
			||||||
                                              uint32_t purpose) {
 | 
					 | 
				
			||||||
    eekboard_context_service_set_hint_purpose(self->state, hint, purpose);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -17,10 +17,9 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
#ifndef SERVER_CONTEXT_SERVICE_H
 | 
					#ifndef SERVER_CONTEXT_SERVICE_H
 | 
				
			||||||
#define SERVER_CONTEXT_SERVICE_H 1
 | 
					#define SERVER_CONTEXT_SERVICE_H 1
 | 
				
			||||||
 | 
					#include <gtk/gtk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "src/layout.h"
 | 
					#include "main.h"
 | 
				
			||||||
#include "src/submission.h"
 | 
					 | 
				
			||||||
#include "ui_manager.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_BEGIN_DECLS
 | 
					G_BEGIN_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -29,10 +28,8 @@ G_BEGIN_DECLS
 | 
				
			|||||||
/** Manages the lifecycle of the window displaying layouts. */
 | 
					/** Manages the lifecycle of the window displaying layouts. */
 | 
				
			||||||
G_DECLARE_FINAL_TYPE (ServerContextService, server_context_service, SERVER, CONTEXT_SERVICE, GObject)
 | 
					G_DECLARE_FINAL_TYPE (ServerContextService, server_context_service, SERVER, CONTEXT_SERVICE, GObject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ServerContextService *server_context_service_new(EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct squeek_state_manager *state_manager);
 | 
					ServerContextService *server_context_service_new(struct squeek_state_manager *state_manager);
 | 
				
			||||||
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
 | 
					 | 
				
			||||||
void server_context_service_force_show_keyboard (ServerContextService *self);
 | 
					 | 
				
			||||||
void server_context_service_hide_keyboard (ServerContextService *self);
 | 
					 | 
				
			||||||
G_END_DECLS
 | 
					G_END_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif  /* SERVER_CONTEXT_SERVICE_H */
 | 
					#endif  /* SERVER_CONTEXT_SERVICE_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -31,9 +31,9 @@
 | 
				
			|||||||
#include "layout.h"
 | 
					#include "layout.h"
 | 
				
			||||||
#include "main.h"
 | 
					#include "main.h"
 | 
				
			||||||
#include "outputs.h"
 | 
					#include "outputs.h"
 | 
				
			||||||
 | 
					#include "panel.h"
 | 
				
			||||||
#include "submission.h"
 | 
					#include "submission.h"
 | 
				
			||||||
#include "server-context-service.h"
 | 
					#include "server-context-service.h"
 | 
				
			||||||
#include "ui_manager.h"
 | 
					 | 
				
			||||||
#include "wayland.h"
 | 
					#include "wayland.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <gdk/gdkwayland.h>
 | 
					#include <gdk/gdkwayland.h>
 | 
				
			||||||
@ -52,12 +52,12 @@ typedef enum _SqueekboardDebugFlags {
 | 
				
			|||||||
struct squeekboard {
 | 
					struct squeekboard {
 | 
				
			||||||
    struct squeek_wayland wayland; // Just hooks.
 | 
					    struct squeek_wayland wayland; // Just hooks.
 | 
				
			||||||
    DBusHandler *dbus_handler; // Controls visibility of the OSK.
 | 
					    DBusHandler *dbus_handler; // Controls visibility of the OSK.
 | 
				
			||||||
    EekboardContextService *settings_context; // Gsettings hooks.
 | 
					    EekboardContextService *settings_context; // Gsettings hooks for layouts.
 | 
				
			||||||
    ServerContextService *ui_context; // mess, includes the entire UI
 | 
					    /// 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
 | 
					    /// Currently wanted layout. TODO: merge into state::Application
 | 
				
			||||||
    struct squeek_layout_state layout_choice;
 | 
					    struct squeek_layout_state layout_choice;
 | 
				
			||||||
    /// UI shape tracker/chooser. TODO: merge into state::Application
 | 
					 | 
				
			||||||
    struct ui_manager *ui_manager;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -112,34 +112,38 @@ registry_handle_global (void *data,
 | 
				
			|||||||
    // Even when lower version would be served, it would not be supported,
 | 
					    // Even when lower version would be served, it would not be supported,
 | 
				
			||||||
    // causing a hard exit
 | 
					    // causing a hard exit
 | 
				
			||||||
    (void)version;
 | 
					    (void)version;
 | 
				
			||||||
    struct squeekboard *instance = data;
 | 
					    struct squeek_wayland *wayland = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!strcmp (interface, zwlr_layer_shell_v1_interface.name)) {
 | 
					    if (!strcmp (interface, zwlr_layer_shell_v1_interface.name)) {
 | 
				
			||||||
        instance->wayland.layer_shell = wl_registry_bind (registry, name,
 | 
					        wayland->layer_shell = wl_registry_bind (registry, name,
 | 
				
			||||||
            &zwlr_layer_shell_v1_interface, 1);
 | 
					            &zwlr_layer_shell_v1_interface, 1);
 | 
				
			||||||
    } else if (!strcmp (interface, zwp_virtual_keyboard_manager_v1_interface.name)) {
 | 
					    } else if (!strcmp (interface, zwp_virtual_keyboard_manager_v1_interface.name)) {
 | 
				
			||||||
        instance->wayland.virtual_keyboard_manager = wl_registry_bind(registry, name,
 | 
					        wayland->virtual_keyboard_manager = wl_registry_bind(registry, name,
 | 
				
			||||||
            &zwp_virtual_keyboard_manager_v1_interface, 1);
 | 
					            &zwp_virtual_keyboard_manager_v1_interface, 1);
 | 
				
			||||||
    } else if (!strcmp (interface, zwp_input_method_manager_v2_interface.name)) {
 | 
					    } else if (!strcmp (interface, zwp_input_method_manager_v2_interface.name)) {
 | 
				
			||||||
        instance->wayland.input_method_manager = wl_registry_bind(registry, name,
 | 
					        wayland->input_method_manager = wl_registry_bind(registry, name,
 | 
				
			||||||
            &zwp_input_method_manager_v2_interface, 1);
 | 
					            &zwp_input_method_manager_v2_interface, 1);
 | 
				
			||||||
    } else if (!strcmp (interface, "wl_output")) {
 | 
					    } else if (!strcmp (interface, "wl_output")) {
 | 
				
			||||||
        struct wl_output *output = wl_registry_bind (registry, name,
 | 
					        struct wl_output *output = wl_registry_bind (registry, name,
 | 
				
			||||||
            &wl_output_interface, 2);
 | 
					            &wl_output_interface, 2);
 | 
				
			||||||
        squeek_outputs_register(instance->wayland.outputs, output);
 | 
					        squeek_outputs_register(wayland->outputs, output, name);
 | 
				
			||||||
    } else if (!strcmp(interface, "wl_seat")) {
 | 
					    } else if (!strcmp(interface, "wl_seat")) {
 | 
				
			||||||
        instance->wayland.seat = wl_registry_bind(registry, name,
 | 
					        wayland->seat = wl_registry_bind(registry, name,
 | 
				
			||||||
            &wl_seat_interface, 1);
 | 
					            &wl_seat_interface, 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
registry_handle_global_remove (void *data,
 | 
					registry_handle_global_remove (void *data,
 | 
				
			||||||
                               struct wl_registry *registry,
 | 
					                               struct wl_registry *registry,
 | 
				
			||||||
                               uint32_t name)
 | 
					                               uint32_t name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  // TODO
 | 
					    (void)registry;
 | 
				
			||||||
 | 
					    struct squeek_wayland *wayland = data;
 | 
				
			||||||
 | 
					    struct wl_output *output = squeek_outputs_try_unregister(wayland->outputs, name);
 | 
				
			||||||
 | 
					    if (output) {
 | 
				
			||||||
 | 
					        wl_output_destroy(output);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct wl_registry_listener registry_listener = {
 | 
					static const struct wl_registry_listener registry_listener = {
 | 
				
			||||||
@ -147,6 +151,54 @@ static const struct wl_registry_listener registry_listener = {
 | 
				
			|||||||
  registry_handle_global_remove
 | 
					  registry_handle_global_remove
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void init_wayland(struct squeek_wayland *wayland) {
 | 
				
			||||||
 | 
					    // Set up Wayland
 | 
				
			||||||
 | 
					    gdk_set_allowed_backends ("wayland");
 | 
				
			||||||
 | 
					    GdkDisplay *gdk_display = gdk_display_get_default ();
 | 
				
			||||||
 | 
					    struct wl_display *display = gdk_wayland_display_get_wl_display (gdk_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (display == NULL) {
 | 
				
			||||||
 | 
					        g_error ("Failed to get display: %m\n");
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct wl_registry *registry = wl_display_get_registry (display);
 | 
				
			||||||
 | 
					    wl_registry_add_listener (registry, ®istry_listener, wayland);
 | 
				
			||||||
 | 
					    wl_display_roundtrip(display); // wait until the registry is actually populated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!wayland->seat) {
 | 
				
			||||||
 | 
					        g_error("No seat Wayland global available.");
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!wayland->virtual_keyboard_manager) {
 | 
				
			||||||
 | 
					        g_error("No virtual keyboard manager Wayland global available.");
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!wayland->layer_shell) {
 | 
				
			||||||
 | 
					        g_error("No layer shell global available.");
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!wayland->input_method_manager) {
 | 
				
			||||||
 | 
					        g_warning("Wayland input method interface not available");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (wayland->input_method_manager) {
 | 
				
			||||||
 | 
					        wayland->input_method = zwp_input_method_manager_v2_get_input_method(
 | 
				
			||||||
 | 
					            wayland->input_method_manager,
 | 
				
			||||||
 | 
					            wayland->seat);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (wayland->virtual_keyboard_manager) {
 | 
				
			||||||
 | 
					        wayland->virtual_keyboard = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(
 | 
				
			||||||
 | 
					            wayland->virtual_keyboard_manager,
 | 
				
			||||||
 | 
					            wayland->seat);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // initialize global
 | 
				
			||||||
 | 
					    squeek_wayland = wayland;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SESSION_NAME "sm.puri.OSK0"
 | 
					#define SESSION_NAME "sm.puri.OSK0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GDBusProxy *_proxy = NULL;
 | 
					GDBusProxy *_proxy = NULL;
 | 
				
			||||||
@ -284,22 +336,6 @@ phosh_theme_init (void)
 | 
				
			|||||||
    g_object_set (G_OBJECT (gtk_settings), "gtk-application-prefer-dark-theme", TRUE, NULL);
 | 
					    g_object_set (G_OBJECT (gtk_settings), "gtk-application-prefer-dark-theme", TRUE, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Create Rust objects in one go,
 | 
					 | 
				
			||||||
/// to avoid crossing the language barrier and losing type information
 | 
					 | 
				
			||||||
static struct rsobjects create_rsobjects(struct zwp_input_method_manager_v2 *immanager,
 | 
					 | 
				
			||||||
                                         struct zwp_virtual_keyboard_manager_v1 *vkmanager,
 | 
					 | 
				
			||||||
                                         struct wl_seat *seat) {
 | 
					 | 
				
			||||||
    struct zwp_input_method_v2 *im = NULL;
 | 
					 | 
				
			||||||
    if (immanager) {
 | 
					 | 
				
			||||||
        im = zwp_input_method_manager_v2_get_input_method(immanager, seat);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    struct zwp_virtual_keyboard_v1 *vk = NULL;
 | 
					 | 
				
			||||||
    if (vkmanager) {
 | 
					 | 
				
			||||||
        vk = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkmanager, seat);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return squeek_rsobjects_new(im, vk);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GDebugKey debug_keys[] =
 | 
					static GDebugKey debug_keys[] =
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        { .key = "force-show",
 | 
					        { .key = "force-show",
 | 
				
			||||||
@ -359,46 +395,10 @@ main (int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    phosh_theme_init ();
 | 
					    phosh_theme_init ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Set up Wayland
 | 
					 | 
				
			||||||
    gdk_set_allowed_backends ("wayland");
 | 
					 | 
				
			||||||
    GdkDisplay *gdk_display = gdk_display_get_default ();
 | 
					 | 
				
			||||||
    struct wl_display *display = gdk_wayland_display_get_wl_display (gdk_display);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (display == NULL) {
 | 
					 | 
				
			||||||
        g_error ("Failed to get display: %m\n");
 | 
					 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct squeekboard instance = {0};
 | 
					    struct squeekboard instance = {0};
 | 
				
			||||||
    squeek_wayland_init (&instance.wayland);
 | 
					 | 
				
			||||||
    struct wl_registry *registry = wl_display_get_registry (display);
 | 
					 | 
				
			||||||
    wl_registry_add_listener (registry, ®istry_listener, &instance);
 | 
					 | 
				
			||||||
    wl_display_roundtrip(display); // wait until the registry is actually populated
 | 
					 | 
				
			||||||
    squeek_wayland_set_global(&instance.wayland);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!instance.wayland.seat) {
 | 
					    // Also initializes wayland
 | 
				
			||||||
        g_error("No seat Wayland global available.");
 | 
					    struct rsobjects rsobjects = squeek_init();
 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!instance.wayland.virtual_keyboard_manager) {
 | 
					 | 
				
			||||||
        g_error("No virtual keyboard manager Wayland global available.");
 | 
					 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!instance.wayland.layer_shell) {
 | 
					 | 
				
			||||||
        g_error("No layer shell global available.");
 | 
					 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!instance.wayland.input_method_manager) {
 | 
					 | 
				
			||||||
        g_warning("Wayland input method interface not available");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct rsobjects rsobjects = create_rsobjects(instance.wayland.input_method_manager,
 | 
					 | 
				
			||||||
        instance.wayland.virtual_keyboard_manager,
 | 
					 | 
				
			||||||
        instance.wayland.seat);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    instance.ui_manager = squeek_uiman_new();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    instance.settings_context = eekboard_context_service_new(&instance.layout_choice);
 | 
					    instance.settings_context = eekboard_context_service_new(&instance.layout_choice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -438,21 +438,21 @@ main (int argc, char **argv)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    eekboard_context_service_set_submission(instance.settings_context, rsobjects.submission);
 | 
					    ServerContextService *setting_listener = server_context_service_new(
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ServerContextService *ui_context = server_context_service_new(
 | 
					 | 
				
			||||||
                instance.settings_context,
 | 
					 | 
				
			||||||
                rsobjects.submission,
 | 
					 | 
				
			||||||
                &instance.layout_choice,
 | 
					 | 
				
			||||||
                instance.ui_manager,
 | 
					 | 
				
			||||||
                rsobjects.state_manager);
 | 
					                rsobjects.state_manager);
 | 
				
			||||||
    if (!ui_context) {
 | 
					    if (!setting_listener) {
 | 
				
			||||||
        g_error("Could not initialize GUI");
 | 
					        g_warning ("could not connect to gsettings");
 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    instance.ui_context = ui_context;
 | 
					    instance.settings_handler = setting_listener;
 | 
				
			||||||
    register_ui_loop_handler(rsobjects.receiver, instance.ui_context, instance.dbus_handler);
 | 
					
 | 
				
			||||||
 | 
					    eekboard_context_service_set_submission(instance.settings_context, rsobjects.submission);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    instance.panel_manager = panel_manager_new(instance.settings_context,
 | 
				
			||||||
 | 
					        rsobjects.submission,
 | 
				
			||||||
 | 
					        &instance.layout_choice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    register_ui_loop_handler(rsobjects.receiver, &instance.panel_manager, instance.settings_context, instance.dbus_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    session_register();
 | 
					    session_register();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -477,6 +477,5 @@ main (int argc, char **argv)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    g_main_loop_unref (loop);
 | 
					    g_main_loop_unref (loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    squeek_wayland_deinit (&instance.wayland);
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										287
									
								
								src/state.rs
									
									
									
									
									
								
							
							
						
						
									
										287
									
								
								src/state.rs
									
									
									
									
									
								
							@ -6,35 +6,46 @@
 | 
				
			|||||||
 * It's driven by the loop defined in the loop module. */
 | 
					 * It's driven by the loop defined in the loop module. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::animation;
 | 
					use crate::animation;
 | 
				
			||||||
 | 
					use crate::debug;
 | 
				
			||||||
use crate::imservice::{ ContentHint, ContentPurpose };
 | 
					use crate::imservice::{ ContentHint, ContentPurpose };
 | 
				
			||||||
use crate::main::{ Commands, PanelCommand };
 | 
					use crate::main::Commands;
 | 
				
			||||||
 | 
					use crate::outputs;
 | 
				
			||||||
 | 
					use crate::outputs::{Millimeter, OutputId, OutputState};
 | 
				
			||||||
 | 
					use crate::panel;
 | 
				
			||||||
 | 
					use crate::panel::PixelSize;
 | 
				
			||||||
 | 
					use crate::util::Rational;
 | 
				
			||||||
 | 
					use std::cmp;
 | 
				
			||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
use std::time::Instant;
 | 
					use std::time::Instant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Copy)]
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
pub enum Presence {
 | 
					pub enum Presence {
 | 
				
			||||||
    Present,
 | 
					    Present,
 | 
				
			||||||
    Missing,
 | 
					    Missing,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub struct InputMethodDetails {
 | 
					pub struct InputMethodDetails {
 | 
				
			||||||
    pub hint: ContentHint,
 | 
					    pub hint: ContentHint,
 | 
				
			||||||
    pub purpose: ContentPurpose,
 | 
					    pub purpose: ContentPurpose,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub enum InputMethod {
 | 
					pub enum InputMethod {
 | 
				
			||||||
    Active(InputMethodDetails),
 | 
					    Active(InputMethodDetails),
 | 
				
			||||||
    InactiveSince(Instant),
 | 
					    InactiveSince(Instant),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Incoming events
 | 
					/// Incoming events.
 | 
				
			||||||
#[derive(Clone)]
 | 
					/// This contains events that cause a change to the internal state.
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub enum Event {
 | 
					pub enum Event {
 | 
				
			||||||
    InputMethod(InputMethod),
 | 
					    InputMethod(InputMethod),
 | 
				
			||||||
    Visibility(visibility::Event),
 | 
					    Visibility(visibility::Event),
 | 
				
			||||||
    PhysicalKeyboard(Presence),
 | 
					    PhysicalKeyboard(Presence),
 | 
				
			||||||
 | 
					    Output(outputs::Event),
 | 
				
			||||||
 | 
					    Debug(debug::Event),
 | 
				
			||||||
    /// Event triggered because a moment in time passed.
 | 
					    /// Event triggered because a moment in time passed.
 | 
				
			||||||
    /// Use to animate state transitions.
 | 
					    /// Use to animate state transitions.
 | 
				
			||||||
    /// The value is the ideal arrival time.
 | 
					    /// The value is the ideal arrival time.
 | 
				
			||||||
@ -47,8 +58,14 @@ impl From<InputMethod> for Event {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<outputs::Event> for Event {
 | 
				
			||||||
 | 
					    fn from(ev: outputs::Event) -> Self {
 | 
				
			||||||
 | 
					        Self::Output(ev)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod visibility {
 | 
					pub mod visibility {
 | 
				
			||||||
    #[derive(Clone)]
 | 
					    #[derive(Clone, Debug)]
 | 
				
			||||||
    pub enum Event {
 | 
					    pub enum Event {
 | 
				
			||||||
        /// User requested the panel to show
 | 
					        /// User requested the panel to show
 | 
				
			||||||
        ForceVisible,
 | 
					        ForceVisible,
 | 
				
			||||||
@ -68,7 +85,7 @@ pub mod visibility {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The outwardly visible state.
 | 
					/// The outwardly visible state.
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub struct Outcome {
 | 
					pub struct Outcome {
 | 
				
			||||||
    pub visibility: animation::Outcome,
 | 
					    pub visibility: animation::Outcome,
 | 
				
			||||||
    pub im: InputMethod,
 | 
					    pub im: InputMethod,
 | 
				
			||||||
@ -83,12 +100,12 @@ impl Outcome {
 | 
				
			|||||||
    pub fn get_commands_to_reach(&self, new_state: &Self) -> Commands {
 | 
					    pub fn get_commands_to_reach(&self, new_state: &Self) -> Commands {
 | 
				
			||||||
        let layout_hint_set = match new_state {
 | 
					        let layout_hint_set = match new_state {
 | 
				
			||||||
            Outcome {
 | 
					            Outcome {
 | 
				
			||||||
                visibility: animation::Outcome::Visible,
 | 
					                visibility: animation::Outcome::Visible{..},
 | 
				
			||||||
                im: InputMethod::Active(hints),
 | 
					                im: InputMethod::Active(hints),
 | 
				
			||||||
            } => Some(hints.clone()),
 | 
					            } => Some(hints.clone()),
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            Outcome {
 | 
					            Outcome {
 | 
				
			||||||
                visibility: animation::Outcome::Visible,
 | 
					                visibility: animation::Outcome::Visible{..},
 | 
				
			||||||
                im: InputMethod::InactiveSince(_),
 | 
					                im: InputMethod::InactiveSince(_),
 | 
				
			||||||
            } => Some(InputMethodDetails {
 | 
					            } => Some(InputMethodDetails {
 | 
				
			||||||
                hint: ContentHint::NONE,
 | 
					                hint: ContentHint::NONE,
 | 
				
			||||||
@ -100,10 +117,11 @@ impl Outcome {
 | 
				
			|||||||
                ..
 | 
					                ..
 | 
				
			||||||
            } => None,
 | 
					            } => None,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					// FIXME: handle switching outputs
 | 
				
			||||||
        let (dbus_visible_set, panel_visibility) = match new_state.visibility {
 | 
					        let (dbus_visible_set, panel_visibility) = match new_state.visibility {
 | 
				
			||||||
            animation::Outcome::Visible => (Some(true), Some(PanelCommand::Show)),
 | 
					            animation::Outcome::Visible{output, height}
 | 
				
			||||||
            animation::Outcome::Hidden => (Some(false), Some(PanelCommand::Hide)),
 | 
					                => (Some(true), Some(panel::Command::Show{output, height})),
 | 
				
			||||||
 | 
					            animation::Outcome::Hidden => (Some(false), Some(panel::Command::Hide)),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Commands {
 | 
					        Commands {
 | 
				
			||||||
@ -125,11 +143,19 @@ impl Outcome {
 | 
				
			|||||||
/// All state changes return the next state and the optimal time for the next check.
 | 
					/// All state changes return the next state and the optimal time for the next check.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// This state tracker can be driven by any event loop.
 | 
					/// This state tracker can be driven by any event loop.
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub struct Application {
 | 
					pub struct Application {
 | 
				
			||||||
    pub im: InputMethod,
 | 
					    pub im: InputMethod,
 | 
				
			||||||
    pub visibility_override: visibility::State,
 | 
					    pub visibility_override: visibility::State,
 | 
				
			||||||
    pub physical_keyboard: Presence,
 | 
					    pub physical_keyboard: Presence,
 | 
				
			||||||
 | 
					    pub debug_mode_enabled: bool,
 | 
				
			||||||
 | 
					    /// The output on which the panel should appear.
 | 
				
			||||||
 | 
					    /// This is stored as part of the state
 | 
				
			||||||
 | 
					    /// because it's not clear how to derive the output from the rest of the state.
 | 
				
			||||||
 | 
					    /// It should probably follow the focused input,
 | 
				
			||||||
 | 
					    /// but not sure about being allowed on non-touch displays.
 | 
				
			||||||
 | 
					    pub preferred_output: Option<OutputId>,
 | 
				
			||||||
 | 
					    pub outputs: HashMap<OutputId, OutputState>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Application {
 | 
					impl Application {
 | 
				
			||||||
@ -144,11 +170,29 @@ impl Application {
 | 
				
			|||||||
            im: InputMethod::InactiveSince(now),
 | 
					            im: InputMethod::InactiveSince(now),
 | 
				
			||||||
            visibility_override: visibility::State::NotForced,
 | 
					            visibility_override: visibility::State::NotForced,
 | 
				
			||||||
            physical_keyboard: Presence::Missing,
 | 
					            physical_keyboard: Presence::Missing,
 | 
				
			||||||
 | 
					            debug_mode_enabled: false,
 | 
				
			||||||
 | 
					            preferred_output: None,
 | 
				
			||||||
 | 
					            outputs: Default::default(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn apply_event(self, event: Event, _now: Instant) -> Self {
 | 
					    pub fn apply_event(self, event: Event, now: Instant) -> Self {
 | 
				
			||||||
        match event {
 | 
					        if self.debug_mode_enabled {
 | 
				
			||||||
 | 
					            println!(
 | 
				
			||||||
 | 
					                "Received event:
 | 
				
			||||||
 | 
					{:#?}",
 | 
				
			||||||
 | 
					                event,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let state = match event {
 | 
				
			||||||
 | 
					            Event::Debug(dbg) => Self {
 | 
				
			||||||
 | 
					                debug_mode_enabled: match dbg {
 | 
				
			||||||
 | 
					                    debug::Event::Enable => true,
 | 
				
			||||||
 | 
					                    debug::Event::Disable => false,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                ..self
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Event::TimeoutReached(_) => self,
 | 
					            Event::TimeoutReached(_) => self,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Event::Visibility(visibility) => Self {
 | 
					            Event::Visibility(visibility) => Self {
 | 
				
			||||||
@ -164,6 +208,25 @@ impl Application {
 | 
				
			|||||||
                ..self
 | 
					                ..self
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Event::Output(outputs::Event { output, change }) => {
 | 
				
			||||||
 | 
					                let mut app = self;
 | 
				
			||||||
 | 
					                match change {
 | 
				
			||||||
 | 
					                    outputs::ChangeType::Altered(state) => {
 | 
				
			||||||
 | 
					                        app.outputs.insert(output, state);
 | 
				
			||||||
 | 
					                        app.preferred_output = app.preferred_output.or(Some(output));
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    outputs::ChangeType::Removed => {
 | 
				
			||||||
 | 
					                        app.outputs.remove(&output);
 | 
				
			||||||
 | 
					                        if app.preferred_output == Some(output) {
 | 
				
			||||||
 | 
					                            // There's currently no policy to choose one output over another,
 | 
				
			||||||
 | 
					                            // so just take whichever comes first.
 | 
				
			||||||
 | 
					                            app.preferred_output = app.outputs.keys().next().map(|output| *output);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                app
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Event::InputMethod(new_im) => match (self.im.clone(), new_im) {
 | 
					            Event::InputMethod(new_im) => match (self.im.clone(), new_im) {
 | 
				
			||||||
                (InputMethod::Active(_old), InputMethod::Active(new_im))
 | 
					                (InputMethod::Active(_old), InputMethod::Active(new_im))
 | 
				
			||||||
                => Self {
 | 
					                => Self {
 | 
				
			||||||
@ -195,23 +258,117 @@ impl Application {
 | 
				
			|||||||
                    ..self
 | 
					                    ..self
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if state.debug_mode_enabled {
 | 
				
			||||||
 | 
					            println!(
 | 
				
			||||||
 | 
					                "State is now:
 | 
				
			||||||
 | 
					{:#?}
 | 
				
			||||||
 | 
					Outcome:
 | 
				
			||||||
 | 
					{:#?}",
 | 
				
			||||||
 | 
					                state,
 | 
				
			||||||
 | 
					                state.get_outcome(now),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        state
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn get_preferred_height(output: &OutputState) -> Option<PixelSize> {
 | 
				
			||||||
 | 
					        output.get_pixel_size()
 | 
				
			||||||
 | 
					            .map(|px_size| {
 | 
				
			||||||
 | 
					                // Assume isotropy.
 | 
				
			||||||
 | 
					                // Pixels/mm.
 | 
				
			||||||
 | 
					                let density = output.get_physical_size()
 | 
				
			||||||
 | 
					                    .and_then(|size| size.width)
 | 
				
			||||||
 | 
					                    .map(|width| Rational {
 | 
				
			||||||
 | 
					                        numerator: px_size.width as i32,
 | 
				
			||||||
 | 
					                        denominator: width.0 as u32,
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    // Whatever the Librem 5 has,
 | 
				
			||||||
 | 
					                    // as a good default.
 | 
				
			||||||
 | 
					                    .unwrap_or(Rational {
 | 
				
			||||||
 | 
					                        numerator: 720,
 | 
				
			||||||
 | 
					                        denominator: 65,
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Based on what works on the L5.
 | 
				
			||||||
 | 
					                // Exceeding that probably wastes space. Reducing makes typing harder.
 | 
				
			||||||
 | 
					                const IDEAL_TARGET_SIZE: Rational<Millimeter> = Rational {
 | 
				
			||||||
 | 
					                    numerator: Millimeter(948),
 | 
				
			||||||
 | 
					                    denominator: 100,
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // 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,
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    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),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn get_outcome(&self, now: Instant) -> Outcome {
 | 
					    pub fn get_outcome(&self, now: Instant) -> Outcome {
 | 
				
			||||||
        // FIXME: include physical keyboard presence
 | 
					        // FIXME: include physical keyboard presence
 | 
				
			||||||
        Outcome {
 | 
					        Outcome {
 | 
				
			||||||
            visibility: match (self.physical_keyboard, self.visibility_override) {
 | 
					            visibility: match self.preferred_output {
 | 
				
			||||||
                (_, visibility::State::ForcedHidden) => animation::Outcome::Hidden,
 | 
					                None => animation::Outcome::Hidden,
 | 
				
			||||||
                (_, visibility::State::ForcedVisible) => animation::Outcome::Visible,
 | 
					                Some(output) => {
 | 
				
			||||||
                (Presence::Present, visibility::State::NotForced) => animation::Outcome::Hidden,
 | 
					                    // Hoping that this will get optimized out on branches not using `visible`.
 | 
				
			||||||
                (Presence::Missing, visibility::State::NotForced) => match self.im {
 | 
					                    let height = Self::get_preferred_height(self.outputs.get(&output).unwrap())
 | 
				
			||||||
                    InputMethod::Active(_) => animation::Outcome::Visible,
 | 
					                        .unwrap_or(PixelSize{pixels: 0, scale_factor: 1});
 | 
				
			||||||
                    InputMethod::InactiveSince(since) => {
 | 
					                    // TODO: Instead of setting size to 0 when the output is invalid,
 | 
				
			||||||
                        if now < since + animation::HIDING_TIMEOUT { animation::Outcome::Visible }
 | 
					                    // simply go invisible.
 | 
				
			||||||
                        else { animation::Outcome::Hidden }
 | 
					                    let visible = animation::Outcome::Visible{ output, height };
 | 
				
			||||||
                    },
 | 
					                    
 | 
				
			||||||
                },
 | 
					                    match (self.physical_keyboard, self.visibility_override) {
 | 
				
			||||||
 | 
					                        (_, visibility::State::ForcedHidden) => animation::Outcome::Hidden,
 | 
				
			||||||
 | 
					                        (_, visibility::State::ForcedVisible) => visible,
 | 
				
			||||||
 | 
					                        (Presence::Present, visibility::State::NotForced) => animation::Outcome::Hidden,
 | 
				
			||||||
 | 
					                        (Presence::Missing, visibility::State::NotForced) => match self.im {
 | 
				
			||||||
 | 
					                            InputMethod::Active(_) => visible,
 | 
				
			||||||
 | 
					                            InputMethod::InactiveSince(since) => {
 | 
				
			||||||
 | 
					                                if now < since + animation::HIDING_TIMEOUT { visible }
 | 
				
			||||||
 | 
					                                else { animation::Outcome::Hidden }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            im: self.im.clone(),
 | 
					            im: self.im.clone(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -236,9 +393,9 @@ impl Application {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test {
 | 
					pub mod test {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    use crate::outputs::c::WlOutput;
 | 
				
			||||||
    use std::time::Duration;
 | 
					    use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn imdetails_new() -> InputMethodDetails {
 | 
					    fn imdetails_new() -> InputMethodDetails {
 | 
				
			||||||
@ -248,6 +405,30 @@ mod test {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn fake_output_id(id: usize) -> OutputId {
 | 
				
			||||||
 | 
					        OutputId(unsafe {
 | 
				
			||||||
 | 
					            std::mem::transmute::<_, WlOutput>(id)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn application_with_fake_output(start: Instant) -> Application {
 | 
				
			||||||
 | 
					        let id = fake_output_id(1);
 | 
				
			||||||
 | 
					        let mut outputs = HashMap::new();
 | 
				
			||||||
 | 
					        outputs.insert(
 | 
				
			||||||
 | 
					            id,
 | 
				
			||||||
 | 
					            OutputState {
 | 
				
			||||||
 | 
					                current_mode: None,
 | 
				
			||||||
 | 
					                geometry: None,
 | 
				
			||||||
 | 
					                scale: 1,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        Application {
 | 
				
			||||||
 | 
					            preferred_output: Some(id),
 | 
				
			||||||
 | 
					            outputs,
 | 
				
			||||||
 | 
					            ..Application::new(start)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Test the original delay scenario: no flicker on quick switches.
 | 
					    /// Test the original delay scenario: no flicker on quick switches.
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn avoid_hide() {
 | 
					    fn avoid_hide() {
 | 
				
			||||||
@ -257,15 +438,16 @@ mod test {
 | 
				
			|||||||
            im: InputMethod::Active(imdetails_new()),
 | 
					            im: InputMethod::Active(imdetails_new()),
 | 
				
			||||||
            physical_keyboard: Presence::Missing,
 | 
					            physical_keyboard: Presence::Missing,
 | 
				
			||||||
            visibility_override: visibility::State::NotForced,
 | 
					            visibility_override: visibility::State::NotForced,
 | 
				
			||||||
 | 
					            ..application_with_fake_output(start)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), now);
 | 
					        let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), now);
 | 
				
			||||||
        // Check 100ms at 1ms intervals. It should remain visible.
 | 
					        // Check 100ms at 1ms intervals. It should remain visible.
 | 
				
			||||||
        for _i in 0..100 {
 | 
					        for _i in 0..100 {
 | 
				
			||||||
            now += Duration::from_millis(1);
 | 
					            now += Duration::from_millis(1);
 | 
				
			||||||
            assert_eq!(
 | 
					            assert_matches!(
 | 
				
			||||||
                state.get_outcome(now).visibility,
 | 
					                state.get_outcome(now).visibility,
 | 
				
			||||||
                animation::Outcome::Visible,
 | 
					                animation::Outcome::Visible{..},
 | 
				
			||||||
                "Hidden when it should remain visible: {:?}",
 | 
					                "Hidden when it should remain visible: {:?}",
 | 
				
			||||||
                now.saturating_duration_since(start),
 | 
					                now.saturating_duration_since(start),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
@ -273,7 +455,7 @@ mod test {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
 | 
					        let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(state.get_outcome(now).visibility, animation::Outcome::Visible);
 | 
					        assert_matches!(state.get_outcome(now).visibility, animation::Outcome::Visible{..});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Make sure that hiding works when input method goes away
 | 
					    /// Make sure that hiding works when input method goes away
 | 
				
			||||||
@ -285,11 +467,12 @@ mod test {
 | 
				
			|||||||
            im: InputMethod::Active(imdetails_new()),
 | 
					            im: InputMethod::Active(imdetails_new()),
 | 
				
			||||||
            physical_keyboard: Presence::Missing,
 | 
					            physical_keyboard: Presence::Missing,
 | 
				
			||||||
            visibility_override: visibility::State::NotForced,
 | 
					            visibility_override: visibility::State::NotForced,
 | 
				
			||||||
 | 
					            ..application_with_fake_output(start)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), 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).visibility {
 | 
				
			||||||
            now += Duration::from_millis(1);
 | 
					            now += Duration::from_millis(1);
 | 
				
			||||||
            assert!(
 | 
					            assert!(
 | 
				
			||||||
                now < start + Duration::from_millis(250),
 | 
					                now < start + Duration::from_millis(250),
 | 
				
			||||||
@ -309,6 +492,7 @@ mod test {
 | 
				
			|||||||
            im: InputMethod::Active(imdetails_new()),
 | 
					            im: InputMethod::Active(imdetails_new()),
 | 
				
			||||||
            physical_keyboard: Presence::Missing,
 | 
					            physical_keyboard: Presence::Missing,
 | 
				
			||||||
            visibility_override: visibility::State::NotForced,
 | 
					            visibility_override: visibility::State::NotForced,
 | 
				
			||||||
 | 
					            ..application_with_fake_output(start)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        // This reflects the sequence from Wayland:
 | 
					        // This reflects the sequence from Wayland:
 | 
				
			||||||
        // disable, disable, enable, disable
 | 
					        // disable, disable, enable, disable
 | 
				
			||||||
@ -318,7 +502,7 @@ mod test {
 | 
				
			|||||||
        let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
 | 
					        let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
 | 
				
			||||||
        let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), 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).visibility {
 | 
				
			||||||
            now += Duration::from_millis(1);
 | 
					            now += Duration::from_millis(1);
 | 
				
			||||||
            assert!(
 | 
					            assert!(
 | 
				
			||||||
                now < start + Duration::from_millis(250),
 | 
					                now < start + Duration::from_millis(250),
 | 
				
			||||||
@ -347,13 +531,14 @@ mod test {
 | 
				
			|||||||
            im: InputMethod::InactiveSince(now),
 | 
					            im: InputMethod::InactiveSince(now),
 | 
				
			||||||
            physical_keyboard: Presence::Missing,
 | 
					            physical_keyboard: Presence::Missing,
 | 
				
			||||||
            visibility_override: visibility::State::NotForced,
 | 
					            visibility_override: visibility::State::NotForced,
 | 
				
			||||||
 | 
					            ..application_with_fake_output(start)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        now += Duration::from_secs(1);
 | 
					        now += Duration::from_secs(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let state = state.apply_event(Event::Visibility(visibility::Event::ForceVisible), now);
 | 
					        let state = state.apply_event(Event::Visibility(visibility::Event::ForceVisible), now);
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_matches!(
 | 
				
			||||||
            state.get_outcome(now).visibility,
 | 
					            state.get_outcome(now).visibility,
 | 
				
			||||||
            animation::Outcome::Visible,
 | 
					            animation::Outcome::Visible{..},
 | 
				
			||||||
            "Failed to show: {:?}",
 | 
					            "Failed to show: {:?}",
 | 
				
			||||||
            now.saturating_duration_since(start),
 | 
					            now.saturating_duration_since(start),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
@ -380,6 +565,7 @@ mod test {
 | 
				
			|||||||
            im: InputMethod::Active(imdetails_new()),
 | 
					            im: InputMethod::Active(imdetails_new()),
 | 
				
			||||||
            physical_keyboard: Presence::Missing,
 | 
					            physical_keyboard: Presence::Missing,
 | 
				
			||||||
            visibility_override: visibility::State::NotForced,
 | 
					            visibility_override: visibility::State::NotForced,
 | 
				
			||||||
 | 
					            ..application_with_fake_output(start)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        now += Duration::from_secs(1);
 | 
					        now += Duration::from_secs(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -406,12 +592,37 @@ mod test {
 | 
				
			|||||||
        now += Duration::from_secs(1);
 | 
					        now += Duration::from_secs(1);
 | 
				
			||||||
        let state = state.apply_event(Event::PhysicalKeyboard(Presence::Missing), now);
 | 
					        let state = state.apply_event(Event::PhysicalKeyboard(Presence::Missing), now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_matches!(
 | 
				
			||||||
            state.get_outcome(now).visibility,
 | 
					            state.get_outcome(now).visibility,
 | 
				
			||||||
            animation::Outcome::Visible,
 | 
					            animation::Outcome::Visible{..},
 | 
				
			||||||
            "Failed to appear: {:?}",
 | 
					            "Failed to appear: {:?}",
 | 
				
			||||||
            now.saturating_duration_since(start),
 | 
					            now.saturating_duration_since(start),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn size_l5() {
 | 
				
			||||||
 | 
					        use crate::outputs::{Mode, Geometry, c, Size};
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            Application::get_preferred_height(&OutputState {
 | 
				
			||||||
 | 
					                current_mode: Some(Mode {
 | 
				
			||||||
 | 
					                    width: 720,
 | 
				
			||||||
 | 
					                    height: 1440,
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					                geometry: Some(Geometry{
 | 
				
			||||||
 | 
					                    transform: c::Transform::Normal,
 | 
				
			||||||
 | 
					                    phys_size: Size {
 | 
				
			||||||
 | 
					                        width: Some(Millimeter(65)),
 | 
				
			||||||
 | 
					                        height: Some(Millimeter(130)),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					                scale: 2,
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            Some(PixelSize {
 | 
				
			||||||
 | 
					                scale_factor: 2,
 | 
				
			||||||
 | 
					                pixels: 420,
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										33
									
								
								src/style.rs
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								src/style.rs
									
									
									
									
									
								
							@ -21,7 +21,7 @@
 | 
				
			|||||||
use std::env;
 | 
					use std::env;
 | 
				
			||||||
use ::logging;
 | 
					use ::logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use glib::object::ObjectExt;
 | 
					use glib::prelude::ObjectExt;
 | 
				
			||||||
use logging::Warn;
 | 
					use logging::Warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gathers stuff defined in C or called by C
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
@ -31,7 +31,7 @@ pub mod c {
 | 
				
			|||||||
    use gtk;
 | 
					    use gtk;
 | 
				
			||||||
    use gtk_sys;
 | 
					    use gtk_sys;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    use gtk::CssProviderExt;
 | 
					    use gtk::prelude::CssProviderExt;
 | 
				
			||||||
    use glib::translate::ToGlibPtr;
 | 
					    use glib::translate::ToGlibPtr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Loads the layout style based on current theme
 | 
					    /// Loads the layout style based on current theme
 | 
				
			||||||
@ -40,8 +40,13 @@ pub mod c {
 | 
				
			|||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_load_style() -> *const gtk_sys::GtkCssProvider {
 | 
					    fn squeek_load_style() -> *const gtk_sys::GtkCssProvider {
 | 
				
			||||||
        unsafe { gtk::set_initialized() };
 | 
					        unsafe { gtk::set_initialized() };
 | 
				
			||||||
        let theme = gtk::Settings::get_default()
 | 
					        
 | 
				
			||||||
            .map(|settings| get_theme_name(&settings));
 | 
					        #[cfg(feature = "glib_v0_14")]
 | 
				
			||||||
 | 
					        let theme = gtk::Settings::default();
 | 
				
			||||||
 | 
					        #[cfg(not(feature = "glib_v0_14"))]
 | 
				
			||||||
 | 
					        let theme = gtk::Settings::get_default();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        let theme = theme.map(|settings| get_theme_name(&settings));
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        let css_name = path_from_theme(theme);
 | 
					        let css_name = path_from_theme(theme);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -93,19 +98,31 @@ fn get_theme_name(settings: >k::Settings) -> GtkTheme {
 | 
				
			|||||||
            e
 | 
					            e
 | 
				
			||||||
        }).ok();
 | 
					        }).ok();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(feature = "glib_v0_14")]
 | 
				
			||||||
 | 
					    let prop = |s: >k::Settings, name| s.property(name);
 | 
				
			||||||
 | 
					    #[cfg(not(feature = "glib_v0_14"))]
 | 
				
			||||||
 | 
					    let prop = |s: >k::Settings, name| s.get_property(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(feature = "glib_v0_14")]
 | 
				
			||||||
 | 
					    fn check<T, E: std::fmt::Display>(v: Result<T, E>) -> Option<T> {
 | 
				
			||||||
 | 
					        v.or_print(logging::Problem::Surprise, "Key not of expected type")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[cfg(not(feature = "glib_v0_14"))]
 | 
				
			||||||
 | 
					    fn check<T>(v: Option<T>) -> Option<T> { v }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    match env_theme {
 | 
					    match env_theme {
 | 
				
			||||||
        Some(theme) => theme,
 | 
					        Some(theme) => theme,
 | 
				
			||||||
        None => GtkTheme {
 | 
					        None => GtkTheme {
 | 
				
			||||||
            name: {
 | 
					            name: {
 | 
				
			||||||
                settings.get_property("gtk-theme-name")
 | 
					                prop(settings, "gtk-theme-name")
 | 
				
			||||||
                    .or_print(logging::Problem::Surprise, "No theme name")
 | 
					                    .or_print(logging::Problem::Surprise, "No theme name")
 | 
				
			||||||
                    .and_then(|value| value.get::<String>())
 | 
					                    .and_then(|value| check(value.get::<String>()))
 | 
				
			||||||
                    .unwrap_or(DEFAULT_THEME_NAME.into())
 | 
					                    .unwrap_or(DEFAULT_THEME_NAME.into())
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            variant: {
 | 
					            variant: {
 | 
				
			||||||
                settings.get_property("gtk-application-prefer-dark-theme")
 | 
					                prop(settings, "gtk-application-prefer-dark-theme")
 | 
				
			||||||
                    .or_print(logging::Problem::Surprise, "No settings key")
 | 
					                    .or_print(logging::Problem::Surprise, "No settings key")
 | 
				
			||||||
                    .and_then(|value| value.get::<bool>())
 | 
					                    .and_then(|value| check(value.get::<bool>()))
 | 
				
			||||||
                    .and_then(|dark_preferred| match dark_preferred {
 | 
					                    .and_then(|dark_preferred| match dark_preferred {
 | 
				
			||||||
                        true => Some("dark".into()),
 | 
					                        true => Some("dark".into()),
 | 
				
			||||||
                        false => None,
 | 
					                        false => None,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,12 @@
 | 
				
			|||||||
#ifndef __SUBMISSION_H
 | 
					#ifndef __SUBMISSION_H
 | 
				
			||||||
#define __SUBMISSION_H
 | 
					#define __SUBMISSION_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "input-method-unstable-v2-client-protocol.h"
 | 
					#include "inttypes.h"
 | 
				
			||||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
					
 | 
				
			||||||
#include "eek/eek-types.h"
 | 
					#include "eek/eek-types.h"
 | 
				
			||||||
#include "main.h"
 | 
					 | 
				
			||||||
#include "src/ui_manager.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_layout;
 | 
					struct squeek_layout;
 | 
				
			||||||
 | 
					struct submission;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Defined in Rust
 | 
					// Defined in Rust
 | 
				
			||||||
uint8_t submission_hint_available(struct submission *self);
 | 
					uint8_t submission_hint_available(struct submission *self);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,19 +0,0 @@
 | 
				
			|||||||
#ifndef UI_MANAGER__
 | 
					 | 
				
			||||||
#define UI_MANAGER__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <inttypes.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "eek/eek-types.h"
 | 
					 | 
				
			||||||
#include "outputs.h"
 | 
					 | 
				
			||||||
#include "main.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ui_manager;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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(struct squeek_state_manager *state_manager);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@ -1,82 +0,0 @@
 | 
				
			|||||||
/* Copyright (C) 2020, 2021 Purism SPC
 | 
					 | 
				
			||||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Centrally manages the shape of the UI widgets, and the choice of layout.
 | 
					 | 
				
			||||||
 * 
 | 
					 | 
				
			||||||
 * Coordinates this based on information collated from all possible sources.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use std::cmp::min;
 | 
					 | 
				
			||||||
use ::outputs::c::OutputHandle;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub mod c {
 | 
					 | 
				
			||||||
    use super::*;
 | 
					 | 
				
			||||||
    use ::util::c::Wrapped;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_uiman_new() -> Wrapped<Manager> {
 | 
					 | 
				
			||||||
        Wrapped::new(Manager { output: None })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Used to size the layer surface containing all the OSK widgets.
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_uiman_get_perceptual_height(
 | 
					 | 
				
			||||||
        uiman: Wrapped<Manager>,
 | 
					 | 
				
			||||||
    ) -> u32 {
 | 
					 | 
				
			||||||
        let uiman = uiman.clone_ref();
 | 
					 | 
				
			||||||
        let uiman = uiman.borrow();
 | 
					 | 
				
			||||||
        // TODO: what to do when there's no output?
 | 
					 | 
				
			||||||
        uiman.get_perceptual_height().unwrap_or(0)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_uiman_set_output(
 | 
					 | 
				
			||||||
        uiman: Wrapped<Manager>,
 | 
					 | 
				
			||||||
        output: OutputHandle,
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        let uiman = uiman.clone_ref();
 | 
					 | 
				
			||||||
        let mut uiman = uiman.borrow_mut();
 | 
					 | 
				
			||||||
        uiman.output = Some(output);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Stores current state of all things influencing what the UI should look like.
 | 
					 | 
				
			||||||
pub struct Manager {
 | 
					 | 
				
			||||||
    /// Shared output handle, current state updated whenever it's needed.
 | 
					 | 
				
			||||||
    // TODO: Stop assuming that the output never changes.
 | 
					 | 
				
			||||||
    // (There's no way for the output manager to update the ui manager.)
 | 
					 | 
				
			||||||
    // FIXME: Turn into an OutputState and apply relevant connections elsewhere.
 | 
					 | 
				
			||||||
    // Otherwise testability and predictablity is low.
 | 
					 | 
				
			||||||
    output: Option<OutputHandle>,
 | 
					 | 
				
			||||||
    //// Pixel size of the surface. Needs explicit updating.
 | 
					 | 
				
			||||||
    //surface_size: Option<Size>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Manager {
 | 
					 | 
				
			||||||
    fn get_perceptual_height(&self) -> Option<u32> {
 | 
					 | 
				
			||||||
        let output_info = (&self.output).as_ref()
 | 
					 | 
				
			||||||
            .and_then(|o| o.get_state())
 | 
					 | 
				
			||||||
            .map(|os| (os.scale as u32, os.get_pixel_size()));
 | 
					 | 
				
			||||||
        match output_info {
 | 
					 | 
				
			||||||
            Some((scale, Some(px_size))) => Some({
 | 
					 | 
				
			||||||
                let height = if (px_size.width < 720) & (px_size.width > 0) {
 | 
					 | 
				
			||||||
                    px_size.width * 7 / 12 // to match 360×210
 | 
					 | 
				
			||||||
                } else if px_size.width < 1080 {
 | 
					 | 
				
			||||||
                    360 + (1080 - px_size.width) * 60 / 360 // smooth transition
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    360
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Don't exceed half the display size
 | 
					 | 
				
			||||||
                min(height, px_size.height / 2) / scale
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
            Some((scale, None)) => Some(360 / scale),
 | 
					 | 
				
			||||||
            None => None,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										49
									
								
								src/util.rs
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								src/util.rs
									
									
									
									
									
								
							@ -7,6 +7,7 @@ use ::float_ord::FloatOrd;
 | 
				
			|||||||
use std::borrow::Borrow;
 | 
					use std::borrow::Borrow;
 | 
				
			||||||
use std::hash::{ Hash, Hasher };
 | 
					use std::hash::{ Hash, Hasher };
 | 
				
			||||||
use std::iter::FromIterator;
 | 
					use std::iter::FromIterator;
 | 
				
			||||||
 | 
					use std::ops::Mul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod c {
 | 
					pub mod c {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
@ -157,6 +158,54 @@ pub fn find_max_double<T, I, F>(iterator: I, get: F)
 | 
				
			|||||||
        .0
 | 
					        .0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait DivCeil<Rhs = Self> {
 | 
				
			||||||
 | 
					    type Output;
 | 
				
			||||||
 | 
					    fn div_ceil(self, rhs: Rhs) -> Self::Output;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Newer Rust introduces this natively,
 | 
				
			||||||
 | 
					/// but we don't always have newer Rust.
 | 
				
			||||||
 | 
					impl DivCeil for i32 {
 | 
				
			||||||
 | 
					    type Output = Self;
 | 
				
			||||||
 | 
					    fn div_ceil(self, other: i32) -> Self::Output {
 | 
				
			||||||
 | 
					        let d = self / other;
 | 
				
			||||||
 | 
					        let m = self % other;
 | 
				
			||||||
 | 
					        if m == 0 { d } else { d + 1}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					pub struct Rational<T> {
 | 
				
			||||||
 | 
					    pub numerator: T,
 | 
				
			||||||
 | 
					    pub denominator: u32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<U, T: DivCeil<i32, Output=U>> Rational<T> {
 | 
				
			||||||
 | 
					    pub fn ceil(self) -> U {
 | 
				
			||||||
 | 
					        self.numerator.div_ceil(self.denominator as i32)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: Mul<i32, Output=T>> Mul<i32> for Rational<T> {
 | 
				
			||||||
 | 
					    type Output = Self;
 | 
				
			||||||
 | 
					    fn mul(self, m: i32) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            numerator: self.numerator * m,
 | 
				
			||||||
 | 
					            denominator: self.denominator,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<U, T: Mul<U, Output=T>> Mul<Rational<U>> for Rational<T> {
 | 
				
			||||||
 | 
					    type Output = Self;
 | 
				
			||||||
 | 
					    fn mul(self, m: Rational<U>) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            numerator: self.numerator * m.numerator,
 | 
				
			||||||
 | 
					            denominator: self.denominator * m.denominator,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Compares pointers but not internal values of Rc
 | 
					/// Compares pointers but not internal values of Rc
 | 
				
			||||||
pub struct Pointer<T>(pub Rc<T>);
 | 
					pub struct Pointer<T>(pub Rc<T>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -10,11 +10,18 @@ type KeyCode = u32;
 | 
				
			|||||||
pub mod c {
 | 
					pub mod c {
 | 
				
			||||||
    use std::ffi::CStr;
 | 
					    use std::ffi::CStr;
 | 
				
			||||||
    use std::os::raw::{ c_char, c_void };
 | 
					    use std::os::raw::{ c_char, c_void };
 | 
				
			||||||
 | 
					    use std::ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[repr(transparent)]
 | 
					    #[repr(transparent)]
 | 
				
			||||||
    #[derive(Clone, Copy)]
 | 
					    #[derive(Clone, Copy)]
 | 
				
			||||||
    pub struct ZwpVirtualKeyboardV1(*const c_void);
 | 
					    pub struct ZwpVirtualKeyboardV1(*const c_void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    impl ZwpVirtualKeyboardV1 {
 | 
				
			||||||
 | 
					        pub fn null() -> Self {
 | 
				
			||||||
 | 
					            Self(ptr::null())
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[repr(C)]
 | 
					    #[repr(C)]
 | 
				
			||||||
    pub struct KeyMap {
 | 
					    pub struct KeyMap {
 | 
				
			||||||
        fd: u32,
 | 
					        fd: u32,
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct squeek_wayland *squeek_wayland = NULL;
 | 
					struct squeek_wayland *squeek_wayland = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void squeek_wayland_init_global(struct squeek_outputs *outputs) {
 | 
				
			||||||
 | 
					    struct squeek_wayland *wayland = {0};
 | 
				
			||||||
 | 
					    wayland->outputs = outputs;
 | 
				
			||||||
 | 
					    squeek_wayland = wayland;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The following functions only exist
 | 
					// The following functions only exist
 | 
				
			||||||
// to create linkable symbols out of inline functions,
 | 
					// to create linkable symbols out of inline functions,
 | 
				
			||||||
// because those are not directly callable from Rust
 | 
					// because those are not directly callable from Rust
 | 
				
			||||||
 | 
				
			|||||||
@ -10,27 +10,18 @@
 | 
				
			|||||||
#include "outputs.h"
 | 
					#include "outputs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_wayland {
 | 
					struct squeek_wayland {
 | 
				
			||||||
 | 
					    // globals
 | 
				
			||||||
    struct zwlr_layer_shell_v1 *layer_shell;
 | 
					    struct zwlr_layer_shell_v1 *layer_shell;
 | 
				
			||||||
    struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager;
 | 
					    struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager;
 | 
				
			||||||
    struct zwp_input_method_manager_v2 *input_method_manager;
 | 
					    struct zwp_input_method_manager_v2 *input_method_manager;
 | 
				
			||||||
    struct squeek_outputs *outputs;
 | 
					    struct squeek_outputs *outputs;
 | 
				
			||||||
    struct wl_seat *seat;
 | 
					    struct wl_seat *seat;
 | 
				
			||||||
 | 
					    // objects
 | 
				
			||||||
 | 
					    struct zwp_input_method_v2 *input_method;
 | 
				
			||||||
 | 
					    struct zwp_virtual_keyboard_v1 *virtual_keyboard;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct squeek_wayland *squeek_wayland;
 | 
					extern struct squeek_wayland *squeek_wayland;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void squeek_wayland_init(struct squeek_wayland *wayland) {
 | 
					 | 
				
			||||||
    wayland->outputs = squeek_outputs_new();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void squeek_wayland_set_global(struct squeek_wayland *wayland) {
 | 
					 | 
				
			||||||
    squeek_wayland = wayland;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void squeek_wayland_deinit(struct squeek_wayland *wayland) {
 | 
					 | 
				
			||||||
    squeek_outputs_free(wayland->outputs);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // WAYLAND_H
 | 
					#endif // WAYLAND_H
 | 
				
			||||||
 | 
				
			|||||||
@ -76,7 +76,8 @@ foreach layout : [
 | 
				
			|||||||
    'es+cat',
 | 
					    'es+cat',
 | 
				
			||||||
    'fi',
 | 
					    'fi',
 | 
				
			||||||
    'fr', 'fr_wide',
 | 
					    'fr', 'fr_wide',
 | 
				
			||||||
    'gr',
 | 
					    'gr', 'gr_wide',
 | 
				
			||||||
 | 
					    'gr+polytonic',
 | 
				
			||||||
    'il',
 | 
					    'il',
 | 
				
			||||||
    'ir',
 | 
					    'ir',
 | 
				
			||||||
    'it',
 | 
					    'it',
 | 
				
			||||||
@ -84,6 +85,7 @@ foreach layout : [
 | 
				
			|||||||
    'jp+kana','jp+kana_wide',
 | 
					    'jp+kana','jp+kana_wide',
 | 
				
			||||||
    'no',
 | 
					    'no',
 | 
				
			||||||
    'pl', 'pl_wide',
 | 
					    'pl', 'pl_wide',
 | 
				
			||||||
 | 
					    'ro', 'ro_wide',
 | 
				
			||||||
    'ru',
 | 
					    'ru',
 | 
				
			||||||
    'se',
 | 
					    'se',
 | 
				
			||||||
    'th', 'th_wide',
 | 
					    'th', 'th_wide',
 | 
				
			||||||
@ -107,15 +109,8 @@ foreach layout : [
 | 
				
			|||||||
        extra += ['allow_missing_return']
 | 
					        extra += ['allow_missing_return']
 | 
				
			||||||
    endif
 | 
					    endif
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    # Older Cargo seens to be sensitive to something
 | 
					    timeout = 30
 | 
				
			||||||
    # about the RUST_FLAGS env var, and rebuilds all tests when it's set,
 | 
					
 | 
				
			||||||
    # increasing test time by 2 orders of magnitude.
 | 
					 | 
				
			||||||
    # Let it have its way.
 | 
					 | 
				
			||||||
    if get_option('legacy') == true
 | 
					 | 
				
			||||||
        timeout = 300
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        timeout = 30
 | 
					 | 
				
			||||||
    endif
 | 
					 | 
				
			||||||
    test(
 | 
					    test(
 | 
				
			||||||
        'test_layout_' + layout,
 | 
					        'test_layout_' + layout,
 | 
				
			||||||
        cargo_script,
 | 
					        cargo_script,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								tools/entry.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										11
									
								
								tools/entry.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@ -46,9 +46,12 @@ class App(Gtk.Application):
 | 
				
			|||||||
    ] + terminal
 | 
					    ] + terminal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hints = [
 | 
					    hints = [
 | 
				
			||||||
        ("OSK provided", Gtk.InputHints.INHIBIT_OSK)
 | 
					        ("OSK provided", Gtk.InputHints.INHIBIT_OSK),
 | 
				
			||||||
 | 
					        ("Uppercase chars", Gtk.InputHints.UPPERCASE_CHARS),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    purpose_timer = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def on_purpose_toggled(self, btn, entry):
 | 
					    def on_purpose_toggled(self, btn, entry):
 | 
				
			||||||
        purpose = Gtk.InputPurpose.PIN if btn.get_active() else Gtk.InputPurpose.PASSWORD
 | 
					        purpose = Gtk.InputPurpose.PIN if btn.get_active() else Gtk.InputPurpose.PASSWORD
 | 
				
			||||||
        entry.set_input_purpose(purpose)
 | 
					        entry.set_input_purpose(purpose)
 | 
				
			||||||
@ -60,13 +63,17 @@ class App(Gtk.Application):
 | 
				
			|||||||
        e.set_input_purpose(purpose)
 | 
					        e.set_input_purpose(purpose)
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_is_focus_changed(self, e, *args):
 | 
				
			||||||
 | 
					        if not self.purpose_timer and e.props.is_focus:
 | 
				
			||||||
 | 
					            GLib.timeout_add_seconds (3, self.on_timeout, e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add_random (self, grid):
 | 
					    def add_random (self, grid):
 | 
				
			||||||
        l = Gtk.Label(label="Random")
 | 
					        l = Gtk.Label(label="Random")
 | 
				
			||||||
        e = Gtk.Entry(hexpand=True)
 | 
					        e = Gtk.Entry(hexpand=True)
 | 
				
			||||||
 | 
					        e.connect("notify::is-focus", self.on_is_focus_changed)
 | 
				
			||||||
        e.set_input_purpose(Gtk.InputPurpose.FREE_FORM)
 | 
					        e.set_input_purpose(Gtk.InputPurpose.FREE_FORM)
 | 
				
			||||||
        grid.attach(l, 0, len(self.purposes), 1, 1)
 | 
					        grid.attach(l, 0, len(self.purposes), 1, 1)
 | 
				
			||||||
        grid.attach(e, 1, len(self.purposes), 1, 1)
 | 
					        grid.attach(e, 1, len(self.purposes), 1, 1)
 | 
				
			||||||
        GLib.timeout_add_seconds (3, self.on_timeout, e)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def do_activate(self):
 | 
					    def do_activate(self):
 | 
				
			||||||
        w = Gtk.ApplicationWindow(application=self)
 | 
					        w = Gtk.ApplicationWindow(application=self)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										104
									
								
								tools/entry4.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										104
									
								
								tools/entry4.py
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,104 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gi
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					gi.require_version('Gtk', '4.0')
 | 
				
			||||||
 | 
					gi.require_version('GLib', '2.0')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from gi.repository import Gtk
 | 
				
			||||||
 | 
					from gi.repository import GLib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def new_grid(items, set_type):
 | 
				
			||||||
 | 
					    grid = Gtk.Grid(orientation='vertical', column_spacing=8, row_spacing=8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i = 0
 | 
				
			||||||
 | 
					    for text, value in items:
 | 
				
			||||||
 | 
					        label = Gtk.Label(label=text)
 | 
				
			||||||
 | 
					        label.props.margin_top = 6
 | 
				
			||||||
 | 
					        label.props.margin_start = 6
 | 
				
			||||||
 | 
					        entry = Gtk.Entry(hexpand=True)
 | 
				
			||||||
 | 
					        entry.props.margin_top = 6
 | 
				
			||||||
 | 
					        entry.props.margin_end = 6
 | 
				
			||||||
 | 
					        set_type(entry, value)
 | 
				
			||||||
 | 
					        grid.attach(label, 0, i, 1, 1)
 | 
				
			||||||
 | 
					        grid.attach(entry, 1, i, 1, 1)
 | 
				
			||||||
 | 
					        i += 1
 | 
				
			||||||
 | 
					    return grid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class App(Gtk.Application):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    purposes = [
 | 
				
			||||||
 | 
					        ("Free form", Gtk.InputPurpose.FREE_FORM),
 | 
				
			||||||
 | 
					        ("Alphabetical", Gtk.InputPurpose.ALPHA),
 | 
				
			||||||
 | 
					        ("Digits", Gtk.InputPurpose.DIGITS),
 | 
				
			||||||
 | 
					        ("Number", Gtk.InputPurpose.NUMBER),
 | 
				
			||||||
 | 
					        ("Phone", Gtk.InputPurpose.PHONE),
 | 
				
			||||||
 | 
					        ("URL", Gtk.InputPurpose.URL),
 | 
				
			||||||
 | 
					        ("E-mail", Gtk.InputPurpose.EMAIL),
 | 
				
			||||||
 | 
					        ("Name", Gtk.InputPurpose.NAME),
 | 
				
			||||||
 | 
					        ("Password", Gtk.InputPurpose.PASSWORD),
 | 
				
			||||||
 | 
					        ("PIN", Gtk.InputPurpose.PIN),
 | 
				
			||||||
 | 
					        ("Terminal", Gtk.InputPurpose.TERMINAL),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hints = [
 | 
				
			||||||
 | 
					        ("OSK provided", Gtk.InputHints.INHIBIT_OSK)
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    purpose_tick_id = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_purpose_toggled(self, btn, entry):
 | 
				
			||||||
 | 
					        purpose = Gtk.InputPurpose.PIN if btn.get_active() else Gtk.InputPurpose.PASSWORD
 | 
				
			||||||
 | 
					        entry.set_input_purpose(purpose)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_timeout(self, e):
 | 
				
			||||||
 | 
					        r = random.randint(0, len(self.purposes) - 1)
 | 
				
			||||||
 | 
					        (_, purpose) = self.purposes[r]
 | 
				
			||||||
 | 
					        print(f"Setting {purpose}")
 | 
				
			||||||
 | 
					        e.set_input_purpose(purpose)
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_random_enter(self, controller, entry):
 | 
				
			||||||
 | 
					        self.purpose_tick_id = GLib.timeout_add_seconds(3, self.on_timeout, entry)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_random_leave(self, controller, entry):
 | 
				
			||||||
 | 
					        GLib.source_remove(self.purpose_tick_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_random(self, grid):
 | 
				
			||||||
 | 
					        label = Gtk.Label(label="Random")
 | 
				
			||||||
 | 
					        entry = Gtk.Entry(hexpand=True)
 | 
				
			||||||
 | 
					        entry.set_input_purpose(Gtk.InputPurpose.FREE_FORM)
 | 
				
			||||||
 | 
					        grid.attach(label, 0, len(self.purposes), 1, 1)
 | 
				
			||||||
 | 
					        grid.attach(entry, 1, len(self.purposes), 1, 1)
 | 
				
			||||||
 | 
					        focus_controller = Gtk.EventControllerFocus()
 | 
				
			||||||
 | 
					        entry.add_controller(focus_controller)
 | 
				
			||||||
 | 
					        focus_controller.connect("enter", self.on_random_enter, entry)
 | 
				
			||||||
 | 
					        focus_controller.connect("leave", self.on_random_leave, entry)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def do_activate(self):
 | 
				
			||||||
 | 
					        w = Gtk.ApplicationWindow(application=self)
 | 
				
			||||||
 | 
					        w.set_default_size(300, 500)
 | 
				
			||||||
 | 
					        notebook = Gtk.Notebook()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def add_purpose(entry, purpose):
 | 
				
			||||||
 | 
					            entry.set_input_purpose(purpose)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def add_hint(entry, hint):
 | 
				
			||||||
 | 
					            entry.set_input_hints(hint)
 | 
				
			||||||
 | 
					        purpose_grid = new_grid(self.purposes, add_purpose)
 | 
				
			||||||
 | 
					        self.add_random(purpose_grid)
 | 
				
			||||||
 | 
					        hint_grid = new_grid(self.hints, add_hint)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        purpose_scroll = Gtk.ScrolledWindow()
 | 
				
			||||||
 | 
					        purpose_scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
 | 
				
			||||||
 | 
					        purpose_scroll.set_child(purpose_grid)
 | 
				
			||||||
 | 
					        notebook.append_page(purpose_scroll, Gtk.Label(label="Purposes"))
 | 
				
			||||||
 | 
					        notebook.append_page(hint_grid, Gtk.Label(label="Hints"))
 | 
				
			||||||
 | 
					        w.set_child(notebook)
 | 
				
			||||||
 | 
					        w.present()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app = App()
 | 
				
			||||||
 | 
					app.run(sys.argv)
 | 
				
			||||||
		Reference in New Issue
	
	Block a user