Compare commits
	
		
			31 Commits
		
	
	
		
			pureos/1.1
			...
			gerror_exi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1d50c2a748 | |||
| 4efe57cbb4 | |||
| 19e22418bd | |||
| 83942c27b8 | |||
| 29ef4f5bed | |||
| 9eb397151f | |||
| 3a1ea69006 | |||
| 5c5475d508 | |||
| 389aedac8d | |||
| 9b52edbf99 | |||
| 080186c18b | |||
| 7f0749483e | |||
| 19630334b0 | |||
| 7e4487c757 | |||
| ebc8eafa07 | |||
| 8293c5f10d | |||
| 601c835416 | |||
| 07d7486e06 | |||
| 5cb70a096c | |||
| cb211bb764 | |||
| 8c8728aa0f | |||
| f71e769315 | |||
| 273179e1ec | |||
| eb4b630b39 | |||
| b60ebdbd99 | |||
| 99f062fe31 | |||
| 0bc654b832 | |||
| 00e9641a5f | |||
| ea3da22f9b | |||
| 99c04fd8f5 | |||
| 2b7e8f829e | 
							
								
								
									
										24
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -265,9 +265,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "libc"
 | 
					name = "libc"
 | 
				
			||||||
version = "0.2.93"
 | 
					version = "0.2.94"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
 | 
					checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "linked-hash-map"
 | 
					name = "linked-hash-map"
 | 
				
			||||||
@ -353,9 +353,9 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "regex-syntax"
 | 
					name = "regex-syntax"
 | 
				
			||||||
version = "0.6.23"
 | 
					version = "0.6.25"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
 | 
					checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "rs"
 | 
					name = "rs"
 | 
				
			||||||
@ -380,18 +380,18 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "serde"
 | 
					name = "serde"
 | 
				
			||||||
version = "1.0.125"
 | 
					version = "1.0.126"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
 | 
					checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "serde_derive",
 | 
					 "serde_derive",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "serde_derive"
 | 
					name = "serde_derive"
 | 
				
			||||||
version = "1.0.125"
 | 
					version = "1.0.126"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
 | 
					checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "proc-macro2",
 | 
					 "proc-macro2",
 | 
				
			||||||
 "quote",
 | 
					 "quote",
 | 
				
			||||||
@ -412,9 +412,9 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "syn"
 | 
					name = "syn"
 | 
				
			||||||
version = "1.0.69"
 | 
					version = "1.0.72"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
 | 
					checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "proc-macro2",
 | 
					 "proc-macro2",
 | 
				
			||||||
 "quote",
 | 
					 "quote",
 | 
				
			||||||
@ -438,9 +438,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "unicode-xid"
 | 
					name = "unicode-xid"
 | 
				
			||||||
version = "0.2.1"
 | 
					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 = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
 | 
					checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "winapi"
 | 
					name = "winapi"
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,7 @@ if out_path:
 | 
				
			|||||||
    i = args.index(out_path)
 | 
					    i = args.index(out_path)
 | 
				
			||||||
    args.pop(i)    
 | 
					    args.pop(i)    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
subprocess.run(['sh', "{}/cargo.sh".format(shlex.quote(source_dir.as_posix())), 'build']
 | 
					subprocess.run(['sh', "{}/cargo.sh".format(source_dir.as_posix()), 'build']
 | 
				
			||||||
    + args,
 | 
					    + args,
 | 
				
			||||||
    check=True)
 | 
					    check=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -43,7 +43,7 @@ if out_path:
 | 
				
			|||||||
    out_basename = out_path.name
 | 
					    out_basename = out_path.name
 | 
				
			||||||
    filename = filename or out_basename
 | 
					    filename = filename or out_basename
 | 
				
			||||||
    subprocess.run(['cp', '-a',
 | 
					    subprocess.run(['cp', '-a',
 | 
				
			||||||
        './{}/{}'.format(shlex.quote(binary_dir), shlex.quote(filename)),
 | 
					        './{}/{}'.format(binary_dir, filename),
 | 
				
			||||||
        out_path],
 | 
					        out_path],
 | 
				
			||||||
        check=True)
 | 
					        check=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										70
									
								
								data/keyboards/ara.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								data/keyboards/ara.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					# Maintained by: Khaled Eldoheiri <khalid@kdehairy.com>
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					outlines:
 | 
				
			||||||
 | 
					    default: { width: 32.66, height: 52 }
 | 
				
			||||||
 | 
					    altline: { width: 48.99, height: 52 }
 | 
				
			||||||
 | 
					    wide: { width: 62, height: 52 }
 | 
				
			||||||
 | 
					    spaceline: { width: 195.96, height: 52 }
 | 
				
			||||||
 | 
					    special: { width: 35.66, height: 52 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					views:
 | 
				
			||||||
 | 
					    base:
 | 
				
			||||||
 | 
					        - "ذ ض ص ث ق ف غ ع خ ح ج"
 | 
				
			||||||
 | 
					        - "ش س ي ب ل ا ت ن م ك ط"
 | 
				
			||||||
 | 
					        - "Shift_L ء ؤ ر ة و ز ظ د BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences         space        . Return"
 | 
				
			||||||
 | 
					    extra:
 | 
				
			||||||
 | 
					        - "ذ ض ص ث ق لإ إ ع خ ح ج"
 | 
				
			||||||
 | 
					        - "ش س ى ب لأ أ ت ن م ك ط"
 | 
				
			||||||
 | 
					        - "Shift_L ئ لآ لا ه آ ز ظ د BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences         space        . Return"
 | 
				
			||||||
 | 
					    numbers:
 | 
				
			||||||
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
 | 
					        - "@ # € % & - _ + ( )"
 | 
				
			||||||
 | 
					        - "show_symbols   ، \" ' : ؛ ! ؟  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences         space        . Return"
 | 
				
			||||||
 | 
					    symbols:
 | 
				
			||||||
 | 
					        - "~ ` | · √ π τ ÷ × ¶"
 | 
				
			||||||
 | 
					        - "© ® £ € ¥ ^ ° * { }"
 | 
				
			||||||
 | 
					        - "show_numbers   \\ / < > = [ ]  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences         space        . Return"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					buttons:
 | 
				
			||||||
 | 
					    Shift_L:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "extra"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "key-shift"
 | 
				
			||||||
 | 
					    BackSpace:
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        action: "erase"
 | 
				
			||||||
 | 
					    preferences:
 | 
				
			||||||
 | 
					        action: "show_prefs"
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        icon: "keyboard-mode-symbolic"
 | 
				
			||||||
 | 
					    show_numbers:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "numbers"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "123"
 | 
				
			||||||
 | 
					    show_letters:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "ض"
 | 
				
			||||||
 | 
					    show_symbols:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "symbols"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "*/="
 | 
				
			||||||
 | 
					    space:
 | 
				
			||||||
 | 
					        outline: "spaceline"
 | 
				
			||||||
 | 
					        label: " "
 | 
				
			||||||
 | 
					        text: " "
 | 
				
			||||||
 | 
					    Return:
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
							
								
								
									
										70
									
								
								data/keyboards/ara_wide.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								data/keyboards/ara_wide.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					# Maintained by: Khaled Eldoheiri <khalid@kdehairy.com>
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					outlines:
 | 
				
			||||||
 | 
					    default: { width: 49, height: 42 }
 | 
				
			||||||
 | 
					    altline: { width: 73.5, height: 42 }
 | 
				
			||||||
 | 
					    wide: { width: 108, height: 42 }
 | 
				
			||||||
 | 
					    spaceline: { width: 324, height: 42 }
 | 
				
			||||||
 | 
					    special: { width: 49, height: 42 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					views:
 | 
				
			||||||
 | 
					    base:
 | 
				
			||||||
 | 
					        - "ذ ض ص ث ق ف غ ع خ ح ج"
 | 
				
			||||||
 | 
					        - "ش س ي ب ل ا ت ن م ك ط"
 | 
				
			||||||
 | 
					        - "Shift_L ء ؤ ر ة و ز ظ د BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences         space        . Return"
 | 
				
			||||||
 | 
					    extra:
 | 
				
			||||||
 | 
					        - "ذ ض ص ث ق لإ إ ع خ ح ج"
 | 
				
			||||||
 | 
					        - "ش س ى ب لأ أ ت ن م ك ط"
 | 
				
			||||||
 | 
					        - "Shift_L ئ لآ لا ه آ ز ظ د BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences         space        . Return"
 | 
				
			||||||
 | 
					    numbers:
 | 
				
			||||||
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
 | 
					        - "@ # € % & - _ + ( )"
 | 
				
			||||||
 | 
					        - "show_symbols   ، \" ' : ؛ ! ؟  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences         space        . Return"
 | 
				
			||||||
 | 
					    symbols:
 | 
				
			||||||
 | 
					        - "~ ` | · √ π τ ÷ × ¶"
 | 
				
			||||||
 | 
					        - "© ® £ € ¥ ^ ° * { }"
 | 
				
			||||||
 | 
					        - "show_numbers   \\ / < > = [ ]  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences         space        . Return"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					buttons:
 | 
				
			||||||
 | 
					    Shift_L:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "extra"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "key-shift"
 | 
				
			||||||
 | 
					    BackSpace:
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        action: "erase"
 | 
				
			||||||
 | 
					    preferences:
 | 
				
			||||||
 | 
					        action: "show_prefs"
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        icon: "keyboard-mode-symbolic"
 | 
				
			||||||
 | 
					    show_numbers:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "numbers"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "123"
 | 
				
			||||||
 | 
					    show_letters:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "ض"
 | 
				
			||||||
 | 
					    show_symbols:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "symbols"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "*/="
 | 
				
			||||||
 | 
					    space:
 | 
				
			||||||
 | 
					        outline: "spaceline"
 | 
				
			||||||
 | 
					        label: " "
 | 
				
			||||||
 | 
					        text: " "
 | 
				
			||||||
 | 
					    Return:
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
							
								
								
									
										78
									
								
								data/keyboards/bg+phonetic.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								data/keyboards/bg+phonetic.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					outlines:
 | 
				
			||||||
 | 
					    default: { width: 32.72, height: 52 }
 | 
				
			||||||
 | 
					    altline: { width: 47, height: 52 }
 | 
				
			||||||
 | 
					    wide: { width: 49.09, height: 52 }
 | 
				
			||||||
 | 
					    spaceline: { width: 185, height: 52 }
 | 
				
			||||||
 | 
					    special: { width: 44, height: 52 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					views:
 | 
				
			||||||
 | 
					    base:
 | 
				
			||||||
 | 
					        - "я в е р т ъ у и о п ю"
 | 
				
			||||||
 | 
					        - "а с д ф г х й к л ш щ"
 | 
				
			||||||
 | 
					        - "Shift_L з ь ц ж б н м ч BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences         space   .    Return"
 | 
				
			||||||
 | 
					    upper:
 | 
				
			||||||
 | 
					        - "Я В Е Р Т Ъ У И О П Ю"
 | 
				
			||||||
 | 
					        - "А С Д Ф Г Х Й К Л Ш Щ"
 | 
				
			||||||
 | 
					        - "Shift_L З Ь Ц Ж Б Н М Ч BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers preferences         space   ,    Return"
 | 
				
			||||||
 | 
					    numbers:
 | 
				
			||||||
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
 | 
					        - "@ # € % & - _ + ( )"
 | 
				
			||||||
 | 
					        - "show_symbols   , \" ' colon ; ! ?  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences         space        Return"
 | 
				
			||||||
 | 
					    symbols:
 | 
				
			||||||
 | 
					        - "~ ` | · √ π τ ÷ × ¶"
 | 
				
			||||||
 | 
					        - "© ® £ $ ¥ ^ ° * { }"
 | 
				
			||||||
 | 
					        - "show_numbers_from_symbols   \\ / < > = [ ]  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences         space        Return"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					buttons:
 | 
				
			||||||
 | 
					    Shift_L:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "upper"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "key-shift"
 | 
				
			||||||
 | 
					    BackSpace:
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        action: erase
 | 
				
			||||||
 | 
					    preferences:
 | 
				
			||||||
 | 
					        action: "show_prefs"
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        icon: "keyboard-mode-symbolic"
 | 
				
			||||||
 | 
					    show_numbers:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "numbers"
 | 
				
			||||||
 | 
					        outline: "wide"
 | 
				
			||||||
 | 
					        label: "123"
 | 
				
			||||||
 | 
					    show_numbers_from_symbols:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "numbers"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "123"
 | 
				
			||||||
 | 
					    show_letters:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "base"
 | 
				
			||||||
 | 
					        outline: "wide"
 | 
				
			||||||
 | 
					        label: "abc"
 | 
				
			||||||
 | 
					    show_symbols:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "symbols"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "*/="
 | 
				
			||||||
 | 
					    space:
 | 
				
			||||||
 | 
					        outline: "spaceline"
 | 
				
			||||||
 | 
					        text: " "
 | 
				
			||||||
 | 
					    Return:
 | 
				
			||||||
 | 
					        outline: "wide"
 | 
				
			||||||
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
 | 
					    colon:
 | 
				
			||||||
 | 
					        text: ":"
 | 
				
			||||||
 | 
					    "\"":
 | 
				
			||||||
 | 
					        keysym: "quotedbl"
 | 
				
			||||||
@ -8,19 +8,19 @@ outlines:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
views:
 | 
					views:
 | 
				
			||||||
    base:
 | 
					    base:
 | 
				
			||||||
        - "я в е р т ъ у и о п ю"
 | 
					        - "у е и ш щ к с д з ц б"
 | 
				
			||||||
        - "а с д ф г х й к л ш щ"
 | 
					        - "ь я а о ж г т н в м ч"
 | 
				
			||||||
        - "Shift_L з ь ц ж б н м ч BackSpace"
 | 
					        - "Shift_L ю й ъ ф х п р л BackSpace"
 | 
				
			||||||
        - "show_numbers preferences         space   .    Return"
 | 
					        - "show_numbers preferences         space   .    Return"
 | 
				
			||||||
    upper:
 | 
					    upper:
 | 
				
			||||||
        - "Я В Е Р Т Ъ У И О П Ю"
 | 
					        - "У Е И Ш Щ К С Д З Ц Б"
 | 
				
			||||||
        - "А С Д Ф Г Х Й К Л Ш Щ"
 | 
					        - "Ь Я А О Ж Г Т Н В М Ч"
 | 
				
			||||||
        - "Shift_L З Ь Ц Ж Б Н М Ч BackSpace"
 | 
					        - "Shift_L Ю Й Ъ Ф Х П Р Л BackSpace"
 | 
				
			||||||
        - "show_numbers preferences         space   ,    Return"
 | 
					        - "show_numbers preferences         space   ,    Return"
 | 
				
			||||||
    numbers:
 | 
					    numbers:
 | 
				
			||||||
        - "1 2 3 4 5 6 7 8 9 0"
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
        - "@ # € % & - _ + ( )"
 | 
					        - "@ # € % & - _ + ( )"
 | 
				
			||||||
        - "show_symbols   , \" ' colon ; ! ?  BackSpace"
 | 
					        - "show_symbols , \" ' colon ; ! ? ѝ BackSpace"
 | 
				
			||||||
        - "show_letters preferences         space        Return"
 | 
					        - "show_letters preferences         space        Return"
 | 
				
			||||||
    symbols:
 | 
					    symbols:
 | 
				
			||||||
        - "~ ` | · √ π τ ÷ × ¶"
 | 
					        - "~ ` | · √ π τ ÷ × ¶"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										91
									
								
								data/keyboards/ch+fr.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								data/keyboards/ch+fr.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,91 @@
 | 
				
			|||||||
 | 
					# Maintained by: Jordi Bossy <jordi@bossy.space>. No Copyright, enjoy!
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					outlines:
 | 
				
			||||||
 | 
					    default:   { width: 35.33, height: 52 }
 | 
				
			||||||
 | 
					    altline:   { width: 48,    height: 52 }
 | 
				
			||||||
 | 
					    wide:      { width: 59,    height: 52 }
 | 
				
			||||||
 | 
					    spaceline: { width: 70,    height: 52 }
 | 
				
			||||||
 | 
					    special:   { width: 28,    height: 52 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					views:
 | 
				
			||||||
 | 
					    base:
 | 
				
			||||||
 | 
					        - "q w e r t z u i o p"
 | 
				
			||||||
 | 
					        - "a s d f g h j k l ?"
 | 
				
			||||||
 | 
					        - "Shift_L   y x c v b n m  BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers show_eschars preferences    '   space        , . Return"
 | 
				
			||||||
 | 
					    upper:
 | 
				
			||||||
 | 
					        - "Q W E R T Z U I O P"
 | 
				
			||||||
 | 
					        - "A S D F G H J K L !"
 | 
				
			||||||
 | 
					        - "Shift_L   Y X C V B N M  BackSpace"
 | 
				
			||||||
 | 
					        - "show_numbers show_eschars preferences    \"  space        , . Return"
 | 
				
			||||||
 | 
					    numbers:      
 | 
				
			||||||
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
 | 
					        - "@ * + - = ( ) ~ < >"
 | 
				
			||||||
 | 
					        - "show_symbols  # & / \\ √ ; : BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters show_eschars preferences    _   space        , . Return"
 | 
				
			||||||
 | 
					    symbols:
 | 
				
			||||||
 | 
					        - "€ $ £ ¥ % | § µ [ ]"
 | 
				
			||||||
 | 
					        - "© ® § ` ^ { } · ¡ ¿"
 | 
				
			||||||
 | 
					        - "show_numbers  « » ÷ × “ ” „ BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters show_eschars preferences    -   space        , . Return"
 | 
				
			||||||
 | 
					    eschars:
 | 
				
			||||||
 | 
					        - "à â ç é è ê î ô ù û"
 | 
				
			||||||
 | 
					        - "À Â Ç É È Ê Î Ô Ù Û"
 | 
				
			||||||
 | 
					        - "show_numbers  æ œ ä ë ï ö ü  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters_from_accents preferences  ñ Ñ   space        ° ß Return"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					buttons:
 | 
				
			||||||
 | 
					    Shift_L:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "upper"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "key-shift"
 | 
				
			||||||
 | 
					    BackSpace:
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        action: erase
 | 
				
			||||||
 | 
					    preferences:
 | 
				
			||||||
 | 
					        action: "show_prefs"
 | 
				
			||||||
 | 
					        outline: "special"
 | 
				
			||||||
 | 
					        icon: "keyboard-mode-symbolic"
 | 
				
			||||||
 | 
					    show_numbers:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "numbers"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "123"
 | 
				
			||||||
 | 
					    show_letters:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "abc"
 | 
				
			||||||
 | 
					    show_symbols:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            set_view: "symbols"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "*/="
 | 
				
			||||||
 | 
					    show_eschars:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "eschars"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "âÂ"
 | 
				
			||||||
 | 
					    show_letters_from_accents:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "eschars"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "âÂ"
 | 
				
			||||||
 | 
					    space:
 | 
				
			||||||
 | 
					        outline: "spaceline"
 | 
				
			||||||
 | 
					        label: " "
 | 
				
			||||||
 | 
					        text: " "
 | 
				
			||||||
 | 
					    Return:
 | 
				
			||||||
 | 
					        outline: "wide"
 | 
				
			||||||
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
 | 
					    "\"":
 | 
				
			||||||
 | 
					        keysym: "quotedbl"
 | 
				
			||||||
@ -438,7 +438,7 @@ buttons:
 | 
				
			|||||||
                unlock_view: "カタカナ"
 | 
					                unlock_view: "カタカナ"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        label: "。"
 | 
					        label: "。"
 | 
				
			||||||
    # Buttons for Latin charachters
 | 
					    # Buttons for Latin characters
 | 
				
			||||||
    RSYM1:
 | 
					    RSYM1:
 | 
				
			||||||
        action:
 | 
					        action:
 | 
				
			||||||
            locking:
 | 
					            locking:
 | 
				
			||||||
 | 
				
			|||||||
@ -438,7 +438,7 @@ buttons:
 | 
				
			|||||||
                unlock_view: "カタカナ"
 | 
					                unlock_view: "カタカナ"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        label: "。"
 | 
					        label: "。"
 | 
				
			||||||
    # Buttons for Latin charachters
 | 
					    # Buttons for Latin characters
 | 
				
			||||||
    RSYM1:
 | 
					    RSYM1:
 | 
				
			||||||
        action:
 | 
					        action:
 | 
				
			||||||
            locking:
 | 
					            locking:
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,22 @@
 | 
				
			|||||||
 | 
					ara Арабски
 | 
				
			||||||
 | 
					be Белгийски
 | 
				
			||||||
bg Български
 | 
					bg Български
 | 
				
			||||||
 | 
					br Бразилски
 | 
				
			||||||
 | 
					cz Чешки
 | 
				
			||||||
de Немски
 | 
					de Немски
 | 
				
			||||||
 | 
					dk Датски
 | 
				
			||||||
es Испански
 | 
					es Испански
 | 
				
			||||||
emoji Емоджи
 | 
					emoji Емоджи
 | 
				
			||||||
fi Френски
 | 
					fi Фински
 | 
				
			||||||
 | 
					fr Френски
 | 
				
			||||||
gr Гръцки
 | 
					gr Гръцки
 | 
				
			||||||
it Италянски
 | 
					it Италиански
 | 
				
			||||||
no Норевежки
 | 
					jp Японски
 | 
				
			||||||
 | 
					no Норвежки
 | 
				
			||||||
pl Полски
 | 
					pl Полски
 | 
				
			||||||
ru Руски
 | 
					ru Руски
 | 
				
			||||||
se Шведски
 | 
					se Шведски
 | 
				
			||||||
 | 
					th Тайски
 | 
				
			||||||
 | 
					ua Украински
 | 
				
			||||||
terminal Терминал
 | 
					terminal Терминал
 | 
				
			||||||
us Английски (САЩ)
 | 
					us Английски (САЩ)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,21 @@
 | 
				
			|||||||
 | 
					squeekboard (1.14.0pureos0~amber0) amber-phone; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Dorota Czaplejewicz ]
 | 
				
			||||||
 | 
					  * data: Split into loading and parsing
 | 
				
			||||||
 | 
					  * layout: Remove unused code
 | 
				
			||||||
 | 
					  * build: Fix unnecessary shell quotes
 | 
				
			||||||
 | 
					  * popover: Allow spanning outside panel area
 | 
				
			||||||
 | 
					  * cargo: Update dependencies before release
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ undef ]
 | 
				
			||||||
 | 
					  * Fix typos jp keyboard comments
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ anteater ]
 | 
				
			||||||
 | 
					  * use the correct GtkStyleProviderPriority to indicate that the styles are provided by the application
 | 
				
			||||||
 | 
					  * remove some unnecessary unsafe code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Sat, 15 May 2021 12:45:20 +0000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
squeekboard (1.13.0pureos0~amber0) amber-phone; urgency=medium
 | 
					squeekboard (1.13.0pureos0~amber0) amber-phone; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [ Dorota Czaplejewicz ]
 | 
					  [ Dorota Czaplejewicz ]
 | 
				
			||||||
 | 
				
			|||||||
@ -287,7 +287,7 @@ eek_renderer_new (LevelKeyboard  *keyboard,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    gtk_style_context_add_provider (renderer->view_context,
 | 
					    gtk_style_context_add_provider (renderer->view_context,
 | 
				
			||||||
        GTK_STYLE_PROVIDER(renderer->css_provider),
 | 
					        GTK_STYLE_PROVIDER(renderer->css_provider),
 | 
				
			||||||
        GTK_STYLE_PROVIDER_PRIORITY_USER);
 | 
					        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Create a style context for the buttons */
 | 
					    /* Create a style context for the buttons */
 | 
				
			||||||
    path = gtk_widget_path_new();
 | 
					    path = gtk_widget_path_new();
 | 
				
			||||||
@ -303,7 +303,7 @@ eek_renderer_new (LevelKeyboard  *keyboard,
 | 
				
			|||||||
    gtk_style_context_set_state (renderer->button_context, GTK_STATE_FLAG_NORMAL);
 | 
					    gtk_style_context_set_state (renderer->button_context, GTK_STATE_FLAG_NORMAL);
 | 
				
			||||||
    gtk_style_context_add_provider (renderer->button_context,
 | 
					    gtk_style_context_add_provider (renderer->button_context,
 | 
				
			||||||
        GTK_STYLE_PROVIDER(renderer->css_provider),
 | 
					        GTK_STYLE_PROVIDER(renderer->css_provider),
 | 
				
			||||||
        GTK_STYLE_PROVIDER_PRIORITY_USER);
 | 
					        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 | 
				
			||||||
    return renderer;
 | 
					    return renderer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -312,7 +312,6 @@ on_phosh_layer_surface_unmapped (PhoshLayerSurface *self, gpointer unused)
 | 
				
			|||||||
  PhoshLayerSurfacePrivate *priv;
 | 
					  PhoshLayerSurfacePrivate *priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
 | 
					  g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
 | 
				
			||||||
  priv = phosh_layer_surface_get_instance_private (self);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  priv = phosh_layer_surface_get_instance_private (self);
 | 
					  priv = phosh_layer_surface_get_instance_private (self);
 | 
				
			||||||
  if (priv->layer_surface) {
 | 
					  if (priv->layer_surface) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
project(
 | 
					project(
 | 
				
			||||||
    'squeekboard',
 | 
					    'squeekboard',
 | 
				
			||||||
    'c', 'rust',
 | 
					    'c', 'rust',
 | 
				
			||||||
    version: '1.13.0',
 | 
					    version: '1.14.0',
 | 
				
			||||||
    license: 'GPLv3',
 | 
					    license: 'GPLv3',
 | 
				
			||||||
    meson_version: '>=0.51.0',
 | 
					    meson_version: '>=0.51.0',
 | 
				
			||||||
    default_options: [
 | 
					    default_options: [
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										424
									
								
								src/data/loading.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								src/data/loading.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,424 @@
 | 
				
			|||||||
 | 
					/* Copyright (C) 2020-2021 Purism SPC
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: GPL-3.0+
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Loading layout files */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::env;
 | 
				
			||||||
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					use std::path::PathBuf;
 | 
				
			||||||
 | 
					use std::convert::TryFrom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::{ Error, LoadError };
 | 
				
			||||||
 | 
					use super::parsing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ::layout::ArrangementKind;
 | 
				
			||||||
 | 
					use ::logging;
 | 
				
			||||||
 | 
					use ::util::c::as_str;
 | 
				
			||||||
 | 
					use ::xdg;
 | 
				
			||||||
 | 
					use ::imservice::ContentPurpose;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// traits, derives
 | 
				
			||||||
 | 
					use ::logging::Warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
 | 
					pub mod c {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    use std::os::raw::c_char;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_load_layout(
 | 
				
			||||||
 | 
					        name: *const c_char,    // name of the keyboard
 | 
				
			||||||
 | 
					        type_: u32,             // type like Wide
 | 
				
			||||||
 | 
					        variant: u32,          // purpose variant like numeric, terminal...
 | 
				
			||||||
 | 
					        overlay: *const c_char, // the overlay (looking for "terminal")
 | 
				
			||||||
 | 
					    ) -> *mut ::layout::Layout {
 | 
				
			||||||
 | 
					        let type_ = match type_ {
 | 
				
			||||||
 | 
					            0 => ArrangementKind::Base,
 | 
				
			||||||
 | 
					            1 => ArrangementKind::Wide,
 | 
				
			||||||
 | 
					            _ => panic!("Bad enum value"),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        let name = as_str(&name)
 | 
				
			||||||
 | 
					            .expect("Bad layout name")
 | 
				
			||||||
 | 
					            .expect("Empty layout name");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let variant = ContentPurpose::try_from(variant)
 | 
				
			||||||
 | 
					                    .or_print(
 | 
				
			||||||
 | 
					                        logging::Problem::Warning,
 | 
				
			||||||
 | 
					                        "Received invalid purpose value",
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    .unwrap_or(ContentPurpose::Normal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let overlay_str = as_str(&overlay)
 | 
				
			||||||
 | 
					                .expect("Bad overlay name")
 | 
				
			||||||
 | 
					                .expect("Empty overlay name");
 | 
				
			||||||
 | 
					        let overlay_str = match overlay_str {
 | 
				
			||||||
 | 
					            "" => None,
 | 
				
			||||||
 | 
					            other => Some(other),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let (kind, layout) = load_layout_data_with_fallback(&name, type_, variant, overlay_str);
 | 
				
			||||||
 | 
					        let layout = ::layout::Layout::new(layout, kind);
 | 
				
			||||||
 | 
					        Box::into_raw(Box::new(layout))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const FALLBACK_LAYOUT_NAME: &str = "us";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
 | 
					enum DataSource {
 | 
				
			||||||
 | 
					    File(PathBuf),
 | 
				
			||||||
 | 
					    Resource(String),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for DataSource {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            DataSource::File(path) => write!(f, "Path: {:?}", path.display()),
 | 
				
			||||||
 | 
					            DataSource::Resource(name) => write!(f, "Resource: {}", name),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* All functions in this family carry around ArrangementKind,
 | 
				
			||||||
 | 
					 * because it's not guaranteed to be preserved,
 | 
				
			||||||
 | 
					 * and the resulting layout needs to know which version was loaded.
 | 
				
			||||||
 | 
					 * See `squeek_layout_get_kind`.
 | 
				
			||||||
 | 
					 * Possible TODO: since this is used only in styling,
 | 
				
			||||||
 | 
					 * and makes the below code nastier than needed, maybe it should go.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns ordered names treating `name` as the base name,
 | 
				
			||||||
 | 
					/// ignoring any `+` inside.
 | 
				
			||||||
 | 
					fn _get_arrangement_names(name: &str, arrangement: ArrangementKind)
 | 
				
			||||||
 | 
					    -> Vec<(ArrangementKind, String)>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let name_with_arrangement = match arrangement {    
 | 
				
			||||||
 | 
					        ArrangementKind::Base => name.into(),
 | 
				
			||||||
 | 
					        ArrangementKind::Wide => format!("{}_wide", name),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    let mut ret = Vec::new();
 | 
				
			||||||
 | 
					    if name_with_arrangement != name {
 | 
				
			||||||
 | 
					        ret.push((arrangement, name_with_arrangement));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret.push((ArrangementKind::Base, name.into()));
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns names accounting for any `+` in the `name`,
 | 
				
			||||||
 | 
					/// including the fallback to the default layout.
 | 
				
			||||||
 | 
					fn get_preferred_names(name: &str, kind: ArrangementKind)
 | 
				
			||||||
 | 
					    -> Vec<(ArrangementKind, String)>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let mut ret = _get_arrangement_names(name, kind);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    let base_name_preferences = {
 | 
				
			||||||
 | 
					        let mut parts = name.splitn(2, '+');
 | 
				
			||||||
 | 
					        match parts.next() {
 | 
				
			||||||
 | 
					            Some(base) => {
 | 
				
			||||||
 | 
					                // The name is already equal to base, so nothing to add
 | 
				
			||||||
 | 
					                if base == name {
 | 
				
			||||||
 | 
					                    vec![]
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    _get_arrangement_names(base, kind)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            // The layout's base name starts with a "+". Weird but OK.
 | 
				
			||||||
 | 
					            None => {
 | 
				
			||||||
 | 
					                log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name);
 | 
				
			||||||
 | 
					                vec![]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    ret.extend(base_name_preferences.into_iter());
 | 
				
			||||||
 | 
					    let fallback_names = _get_arrangement_names(FALLBACK_LAYOUT_NAME, kind);
 | 
				
			||||||
 | 
					    ret.extend(fallback_names.into_iter());
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Includes the subdirectory before the forward slash.
 | 
				
			||||||
 | 
					type LayoutPath = String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This is only used inside iter_fallbacks_with_meta.
 | 
				
			||||||
 | 
					// Placed at the top scope
 | 
				
			||||||
 | 
					// because `use LayoutPurpose::*;`
 | 
				
			||||||
 | 
					// complains about "not in scope" otherwise.
 | 
				
			||||||
 | 
					// This seems to be a Rust 2015 edition problem.
 | 
				
			||||||
 | 
					/// Helper for determining where to look up the layout.
 | 
				
			||||||
 | 
					enum LayoutPurpose<'a> {
 | 
				
			||||||
 | 
					    Default,
 | 
				
			||||||
 | 
					    Special(&'a str),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns the directory string
 | 
				
			||||||
 | 
					/// where the layout should be looked up, including the slash.
 | 
				
			||||||
 | 
					fn get_directory_string(
 | 
				
			||||||
 | 
					    content_purpose: ContentPurpose,
 | 
				
			||||||
 | 
					    overlay: Option<&str>) -> String
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use self::LayoutPurpose::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let layout_purpose = match overlay {
 | 
				
			||||||
 | 
					        None => match content_purpose {
 | 
				
			||||||
 | 
					            ContentPurpose::Number => Special("number"),
 | 
				
			||||||
 | 
					            ContentPurpose::Digits => Special("number"),
 | 
				
			||||||
 | 
					            ContentPurpose::Phone => Special("number"),
 | 
				
			||||||
 | 
					            ContentPurpose::Terminal => Special("terminal"),
 | 
				
			||||||
 | 
					            _ => Default,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        Some(overlay) => Special(overlay),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // For intuitiveness,
 | 
				
			||||||
 | 
					    // default purpose layouts are stored in the root directory,
 | 
				
			||||||
 | 
					    // as they correspond to typical text
 | 
				
			||||||
 | 
					    // and are seen the most often.
 | 
				
			||||||
 | 
					    match layout_purpose {
 | 
				
			||||||
 | 
					        Default => "".into(),
 | 
				
			||||||
 | 
					        Special(purpose) => format!("{}/", purpose),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns an iterator over all fallback paths.
 | 
				
			||||||
 | 
					fn to_layout_paths(
 | 
				
			||||||
 | 
					    name_fallbacks: Vec<(ArrangementKind, String)>,
 | 
				
			||||||
 | 
					    content_purpose: ContentPurpose,
 | 
				
			||||||
 | 
					    overlay: Option<&str>,
 | 
				
			||||||
 | 
					) -> impl Iterator<Item=(ArrangementKind, LayoutPath)> {
 | 
				
			||||||
 | 
					    let prepend_directory = get_directory_string(content_purpose, overlay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name_fallbacks.into_iter()
 | 
				
			||||||
 | 
					        .map(move |(arrangement, name)|
 | 
				
			||||||
 | 
					            (arrangement, format!("{}{}", prepend_directory, name))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LayoutSource = (ArrangementKind, DataSource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn to_layout_sources(
 | 
				
			||||||
 | 
					    layout_paths: impl Iterator<Item=(ArrangementKind, LayoutPath)>,
 | 
				
			||||||
 | 
					    filesystem_path: Option<PathBuf>,
 | 
				
			||||||
 | 
					) -> impl Iterator<Item=LayoutSource> {
 | 
				
			||||||
 | 
					    layout_paths.flat_map(move |(arrangement, layout_path)| {
 | 
				
			||||||
 | 
					        let mut sources = Vec::new();
 | 
				
			||||||
 | 
					        if let Some(path) = &filesystem_path {
 | 
				
			||||||
 | 
					            sources.push((
 | 
				
			||||||
 | 
					                arrangement,
 | 
				
			||||||
 | 
					                DataSource::File(
 | 
				
			||||||
 | 
					                    path.join(&layout_path)
 | 
				
			||||||
 | 
					                        .with_extension("yaml")
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        sources.push((arrangement, DataSource::Resource(layout_path.clone())));
 | 
				
			||||||
 | 
					        sources.into_iter()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns possible sources, with first as the most preferred one.
 | 
				
			||||||
 | 
					/// Trying order: native lang of the right kind, native base,
 | 
				
			||||||
 | 
					/// fallback lang of the right kind, fallback base
 | 
				
			||||||
 | 
					fn iter_layout_sources(
 | 
				
			||||||
 | 
					    name: &str,
 | 
				
			||||||
 | 
					    arrangement: ArrangementKind,
 | 
				
			||||||
 | 
					    purpose: ContentPurpose,
 | 
				
			||||||
 | 
					    ui_overlay: Option<&str>,
 | 
				
			||||||
 | 
					    layout_storage: Option<PathBuf>,
 | 
				
			||||||
 | 
					) -> impl Iterator<Item=LayoutSource> {
 | 
				
			||||||
 | 
					    let names = get_preferred_names(name, arrangement);
 | 
				
			||||||
 | 
					    let paths = to_layout_paths(names, purpose, ui_overlay);
 | 
				
			||||||
 | 
					    to_layout_sources(paths, layout_storage)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn load_layout_data(source: DataSource)
 | 
				
			||||||
 | 
					    -> Result<::layout::LayoutData, LoadError>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let handler = logging::Print {};
 | 
				
			||||||
 | 
					    match source {
 | 
				
			||||||
 | 
					        DataSource::File(path) => {
 | 
				
			||||||
 | 
					            parsing::Layout::from_file(path.clone())
 | 
				
			||||||
 | 
					                .map_err(LoadError::BadData)
 | 
				
			||||||
 | 
					                .and_then(|layout|
 | 
				
			||||||
 | 
					                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        DataSource::Resource(name) => {
 | 
				
			||||||
 | 
					            parsing::Layout::from_resource(&name)
 | 
				
			||||||
 | 
					                .and_then(|layout|
 | 
				
			||||||
 | 
					                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn load_layout_data_with_fallback(
 | 
				
			||||||
 | 
					    name: &str,
 | 
				
			||||||
 | 
					    kind: ArrangementKind,
 | 
				
			||||||
 | 
					    purpose: ContentPurpose,
 | 
				
			||||||
 | 
					    overlay: Option<&str>,
 | 
				
			||||||
 | 
					) -> (ArrangementKind, ::layout::LayoutData) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Build the path to the right keyboard layout subdirectory
 | 
				
			||||||
 | 
					    let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
 | 
				
			||||||
 | 
					        .map(PathBuf::from)
 | 
				
			||||||
 | 
					        .or_else(|| xdg::data_path("squeekboard/keyboards"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (kind, source) in iter_layout_sources(&name, kind, purpose, overlay, path) {
 | 
				
			||||||
 | 
					        let layout = load_layout_data(source.clone());
 | 
				
			||||||
 | 
					        match layout {
 | 
				
			||||||
 | 
					            Err(e) => match (e, source) {
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    LoadError::BadData(Error::Missing(e)),
 | 
				
			||||||
 | 
					                    DataSource::File(file)
 | 
				
			||||||
 | 
					                ) => log_print!(
 | 
				
			||||||
 | 
					                    logging::Level::Debug,
 | 
				
			||||||
 | 
					                    "Tried file {:?}, but it's missing: {}",
 | 
				
			||||||
 | 
					                    file, e
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                (e, source) => log_print!(
 | 
				
			||||||
 | 
					                    logging::Level::Warning,
 | 
				
			||||||
 | 
					                    "Failed to load layout from {}: {}, skipping",
 | 
				
			||||||
 | 
					                    source, e
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            Ok(layout) => {
 | 
				
			||||||
 | 
					                log_print!(logging::Level::Info, "Loaded layout {}", source);
 | 
				
			||||||
 | 
					                return (kind, layout);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    panic!("No useful layout found!");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use ::logging::ProblemPanic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn parsing_fallback() {
 | 
				
			||||||
 | 
					        assert!(parsing::Layout::from_resource(FALLBACK_LAYOUT_NAME)
 | 
				
			||||||
 | 
					            .map(|layout| layout.build(ProblemPanic).0.unwrap())
 | 
				
			||||||
 | 
					            .is_ok()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_fallback_basic_builtin() {
 | 
				
			||||||
 | 
					        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, None);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            sources.collect::<Vec<_>>(),
 | 
				
			||||||
 | 
					            vec!(
 | 
				
			||||||
 | 
					                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    ArrangementKind::Base,
 | 
				
			||||||
 | 
					                    DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Prefer loading from file system before builtin.
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_preferences_order_path() {
 | 
				
			||||||
 | 
					        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, Some(".".into()));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            sources.collect::<Vec<_>>(),
 | 
				
			||||||
 | 
					            vec!(
 | 
				
			||||||
 | 
					                (ArrangementKind::Base, DataSource::File("./nb.yaml".into())),
 | 
				
			||||||
 | 
					                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    ArrangementKind::Base,
 | 
				
			||||||
 | 
					                    DataSource::File("./us.yaml".into())
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    ArrangementKind::Base,
 | 
				
			||||||
 | 
					                    DataSource::Resource("us".into())
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// If layout contains a "+", it should reach for what's in front of it too.
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_preferences_order_base() {
 | 
				
			||||||
 | 
					        let sources = iter_layout_sources("nb+aliens", ArrangementKind::Base, ContentPurpose::Normal, None, None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            sources.collect::<Vec<_>>(),
 | 
				
			||||||
 | 
					            vec!(
 | 
				
			||||||
 | 
					                (ArrangementKind::Base, DataSource::Resource("nb+aliens".into())),
 | 
				
			||||||
 | 
					                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    ArrangementKind::Base,
 | 
				
			||||||
 | 
					                    DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_preferences_order_arrangement() {
 | 
				
			||||||
 | 
					        let sources = iter_layout_sources("nb", ArrangementKind::Wide, ContentPurpose::Normal, None, None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            sources.collect::<Vec<_>>(),
 | 
				
			||||||
 | 
					            vec!(
 | 
				
			||||||
 | 
					                (ArrangementKind::Wide, DataSource::Resource("nb_wide".into())),
 | 
				
			||||||
 | 
					                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    ArrangementKind::Wide,
 | 
				
			||||||
 | 
					                    DataSource::Resource("us_wide".into())
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    ArrangementKind::Base,
 | 
				
			||||||
 | 
					                    DataSource::Resource("us".into())
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_preferences_order_overlay() {
 | 
				
			||||||
 | 
					        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, Some("terminal"), None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            sources.collect::<Vec<_>>(),
 | 
				
			||||||
 | 
					            vec!(
 | 
				
			||||||
 | 
					                (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    ArrangementKind::Base,
 | 
				
			||||||
 | 
					                    DataSource::Resource("terminal/us".into())
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_preferences_order_hint() {
 | 
				
			||||||
 | 
					        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Terminal, None, None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            sources.collect::<Vec<_>>(),
 | 
				
			||||||
 | 
					            vec!(
 | 
				
			||||||
 | 
					                (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    ArrangementKind::Base,
 | 
				
			||||||
 | 
					                    DataSource::Resource("terminal/us".into())
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										65
									
								
								src/data/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/data/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					/* Copyright (C) 2020-2021 Purism SPC
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: GPL-3.0+
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Combined module for dealing with layout files */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod loading;
 | 
				
			||||||
 | 
					pub mod parsing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::io;
 | 
				
			||||||
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ::keyboard::FormattingError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Errors encountered loading the layout into yaml
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub enum Error {
 | 
				
			||||||
 | 
					    Yaml(serde_yaml::Error),
 | 
				
			||||||
 | 
					    Io(io::Error),
 | 
				
			||||||
 | 
					    /// The file was missing.
 | 
				
			||||||
 | 
					    /// It's distinct from Io in order to make it matchable
 | 
				
			||||||
 | 
					    /// without calling io::Error::kind()
 | 
				
			||||||
 | 
					    Missing(io::Error),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for Error {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Error::Yaml(e) => write!(f, "YAML: {}", e),
 | 
				
			||||||
 | 
					            Error::Io(e) => write!(f, "IO: {}", e),
 | 
				
			||||||
 | 
					            Error::Missing(e) => write!(f, "Missing: {}", e),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<io::Error> for Error {
 | 
				
			||||||
 | 
					    fn from(e: io::Error) -> Self {
 | 
				
			||||||
 | 
					        let kind = e.kind();
 | 
				
			||||||
 | 
					        match kind {
 | 
				
			||||||
 | 
					            io::ErrorKind::NotFound => Error::Missing(e),
 | 
				
			||||||
 | 
					            _ => Error::Io(e),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub enum LoadError {
 | 
				
			||||||
 | 
					    BadData(Error),
 | 
				
			||||||
 | 
					    MissingResource,
 | 
				
			||||||
 | 
					    BadResource(serde_yaml::Error),
 | 
				
			||||||
 | 
					    BadKeyMap(FormattingError),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for LoadError {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        use self::LoadError::*;
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            BadData(e) => write!(f, "Bad data: {}", e),
 | 
				
			||||||
 | 
					            MissingResource => write!(f, "Missing resource"),
 | 
				
			||||||
 | 
					            BadResource(e) => write!(f, "Bad resource: {}", e),
 | 
				
			||||||
 | 
					            BadKeyMap(e) => write!(f, "Bad key map: {}", e),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,34 +1,30 @@
 | 
				
			|||||||
/**! The parsing of the data files for layouts */
 | 
					/* Copyright (C) 2020-2021 Purism SPC
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: GPL-3.0+
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: find a nice way to make sure non-positive sizes don't break layouts
 | 
					/*! Parsing of the data files containing layouts */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::cell::RefCell;
 | 
					use std::cell::RefCell;
 | 
				
			||||||
use std::collections::{ HashMap, HashSet };
 | 
					use std::collections::{ HashMap, HashSet };
 | 
				
			||||||
use std::env;
 | 
					 | 
				
			||||||
use std::ffi::CString;
 | 
					use std::ffi::CString;
 | 
				
			||||||
use std::fmt;
 | 
					 | 
				
			||||||
use std::fs;
 | 
					use std::fs;
 | 
				
			||||||
use std::io;
 | 
					 | 
				
			||||||
use std::path::PathBuf;
 | 
					use std::path::PathBuf;
 | 
				
			||||||
use std::rc::Rc;
 | 
					use std::rc::Rc;
 | 
				
			||||||
use std::vec::Vec;
 | 
					use std::vec::Vec;
 | 
				
			||||||
use std::convert::TryFrom;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use xkbcommon::xkb;
 | 
					use xkbcommon::xkb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::{ Error, LoadError };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use ::action;
 | 
					use ::action;
 | 
				
			||||||
use ::keyboard::{
 | 
					use ::keyboard::{
 | 
				
			||||||
    KeyState, PressType,
 | 
					    KeyState, PressType,
 | 
				
			||||||
    generate_keymaps, generate_keycodes, KeyCode, FormattingError
 | 
					    generate_keymaps, generate_keycodes, KeyCode, FormattingError
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use ::layout;
 | 
					use ::layout;
 | 
				
			||||||
use ::layout::ArrangementKind;
 | 
					 | 
				
			||||||
use ::logging;
 | 
					use ::logging;
 | 
				
			||||||
use ::resources;
 | 
					 | 
				
			||||||
use ::util::c::as_str;
 | 
					 | 
				
			||||||
use ::util::hash_map_map;
 | 
					use ::util::hash_map_map;
 | 
				
			||||||
use ::xdg;
 | 
					use ::resources;
 | 
				
			||||||
use ::imservice::ContentPurpose;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// traits, derives
 | 
					// traits, derives
 | 
				
			||||||
use serde::Deserialize;
 | 
					use serde::Deserialize;
 | 
				
			||||||
@ -36,299 +32,7 @@ use std::io::BufReader;
 | 
				
			|||||||
use std::iter::FromIterator;
 | 
					use std::iter::FromIterator;
 | 
				
			||||||
use ::logging::Warn;
 | 
					use ::logging::Warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gathers stuff defined in C or called by C
 | 
					// TODO: find a nice way to make sure non-positive sizes don't break layouts
 | 
				
			||||||
pub mod c {
 | 
					 | 
				
			||||||
    use super::*;
 | 
					 | 
				
			||||||
    use std::os::raw::c_char;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_load_layout(
 | 
					 | 
				
			||||||
        name: *const c_char,    // name of the keyboard
 | 
					 | 
				
			||||||
        type_: u32,             // type like Wide
 | 
					 | 
				
			||||||
        variant: u32,          // purpose variant like numeric, terminal...
 | 
					 | 
				
			||||||
        overlay: *const c_char, // the overlay (looking for "terminal")
 | 
					 | 
				
			||||||
    ) -> *mut ::layout::Layout {
 | 
					 | 
				
			||||||
        let type_ = match type_ {
 | 
					 | 
				
			||||||
            0 => ArrangementKind::Base,
 | 
					 | 
				
			||||||
            1 => ArrangementKind::Wide,
 | 
					 | 
				
			||||||
            _ => panic!("Bad enum value"),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        let name = as_str(&name)
 | 
					 | 
				
			||||||
            .expect("Bad layout name")
 | 
					 | 
				
			||||||
            .expect("Empty layout name");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let variant = ContentPurpose::try_from(variant)
 | 
					 | 
				
			||||||
                    .or_print(
 | 
					 | 
				
			||||||
                        logging::Problem::Warning,
 | 
					 | 
				
			||||||
                        "Received invalid purpose value",
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                    .unwrap_or(ContentPurpose::Normal);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let overlay_str = as_str(&overlay)
 | 
					 | 
				
			||||||
                .expect("Bad overlay name")
 | 
					 | 
				
			||||||
                .expect("Empty overlay name");
 | 
					 | 
				
			||||||
        let overlay_str = match overlay_str {
 | 
					 | 
				
			||||||
            "" => None,
 | 
					 | 
				
			||||||
            other => Some(other),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let (kind, layout) = load_layout_data_with_fallback(&name, type_, variant, overlay_str);
 | 
					 | 
				
			||||||
        let layout = ::layout::Layout::new(layout, kind);
 | 
					 | 
				
			||||||
        Box::into_raw(Box::new(layout))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const FALLBACK_LAYOUT_NAME: &str = "us";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug)]
 | 
					 | 
				
			||||||
pub enum LoadError {
 | 
					 | 
				
			||||||
    BadData(Error),
 | 
					 | 
				
			||||||
    MissingResource,
 | 
					 | 
				
			||||||
    BadResource(serde_yaml::Error),
 | 
					 | 
				
			||||||
    BadKeyMap(FormattingError),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for LoadError {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        use self::LoadError::*;
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            BadData(e) => write!(f, "Bad data: {}", e),
 | 
					 | 
				
			||||||
            MissingResource => write!(f, "Missing resource"),
 | 
					 | 
				
			||||||
            BadResource(e) => write!(f, "Bad resource: {}", e),
 | 
					 | 
				
			||||||
            BadKeyMap(e) => write!(f, "Bad key map: {}", e),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, PartialEq)]
 | 
					 | 
				
			||||||
enum DataSource {
 | 
					 | 
				
			||||||
    File(PathBuf),
 | 
					 | 
				
			||||||
    Resource(String),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for DataSource {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            DataSource::File(path) => write!(f, "Path: {:?}", path.display()),
 | 
					 | 
				
			||||||
            DataSource::Resource(name) => write!(f, "Resource: {}", name),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* All functions in this family carry around ArrangementKind,
 | 
					 | 
				
			||||||
 * because it's not guaranteed to be preserved,
 | 
					 | 
				
			||||||
 * and the resulting layout needs to know which version was loaded.
 | 
					 | 
				
			||||||
 * See `squeek_layout_get_kind`.
 | 
					 | 
				
			||||||
 * Possible TODO: since this is used only in styling,
 | 
					 | 
				
			||||||
 * and makes the below code nastier than needed, maybe it should go.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Returns ordered names treating `name` as the base name,
 | 
					 | 
				
			||||||
/// ignoring any `+` inside.
 | 
					 | 
				
			||||||
fn _get_arrangement_names(name: &str, arrangement: ArrangementKind)
 | 
					 | 
				
			||||||
    -> Vec<(ArrangementKind, String)>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    let name_with_arrangement = match arrangement {    
 | 
					 | 
				
			||||||
        ArrangementKind::Base => name.into(),
 | 
					 | 
				
			||||||
        ArrangementKind::Wide => format!("{}_wide", name),
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    let mut ret = Vec::new();
 | 
					 | 
				
			||||||
    if name_with_arrangement != name {
 | 
					 | 
				
			||||||
        ret.push((arrangement, name_with_arrangement));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    ret.push((ArrangementKind::Base, name.into()));
 | 
					 | 
				
			||||||
    ret
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Returns names accounting for any `+` in the `name`,
 | 
					 | 
				
			||||||
/// including the fallback to the default layout.
 | 
					 | 
				
			||||||
fn get_preferred_names(name: &str, kind: ArrangementKind)
 | 
					 | 
				
			||||||
    -> Vec<(ArrangementKind, String)>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    let mut ret = _get_arrangement_names(name, kind);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    let base_name_preferences = {
 | 
					 | 
				
			||||||
        let mut parts = name.splitn(2, '+');
 | 
					 | 
				
			||||||
        match parts.next() {
 | 
					 | 
				
			||||||
            Some(base) => {
 | 
					 | 
				
			||||||
                // The name is already equal to base, so nothing to add
 | 
					 | 
				
			||||||
                if base == name {
 | 
					 | 
				
			||||||
                    vec![]
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    _get_arrangement_names(base, kind)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            // The layout's base name starts with a "+". Weird but OK.
 | 
					 | 
				
			||||||
            None => {
 | 
					 | 
				
			||||||
                log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name);
 | 
					 | 
				
			||||||
                vec![]
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    ret.extend(base_name_preferences.into_iter());
 | 
					 | 
				
			||||||
    let fallback_names = _get_arrangement_names(FALLBACK_LAYOUT_NAME, kind);
 | 
					 | 
				
			||||||
    ret.extend(fallback_names.into_iter());
 | 
					 | 
				
			||||||
    ret
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Includes the subdirectory before the forward slash.
 | 
					 | 
				
			||||||
type LayoutPath = String;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// This is only used inside iter_fallbacks_with_meta.
 | 
					 | 
				
			||||||
// Placed at the top scope
 | 
					 | 
				
			||||||
// because `use LayoutPurpose::*;`
 | 
					 | 
				
			||||||
// complains about "not in scope" otherwise.
 | 
					 | 
				
			||||||
// This seems to be a Rust 2015 edition problem.
 | 
					 | 
				
			||||||
/// Helper for determining where to look up the layout.
 | 
					 | 
				
			||||||
enum LayoutPurpose<'a> {
 | 
					 | 
				
			||||||
    Default,
 | 
					 | 
				
			||||||
    Special(&'a str),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Returns the directory string
 | 
					 | 
				
			||||||
/// where the layout should be looked up, including the slash.
 | 
					 | 
				
			||||||
fn get_directory_string(
 | 
					 | 
				
			||||||
    content_purpose: ContentPurpose,
 | 
					 | 
				
			||||||
    overlay: Option<&str>) -> String
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    use self::LayoutPurpose::*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let layout_purpose = match overlay {
 | 
					 | 
				
			||||||
        None => match content_purpose {
 | 
					 | 
				
			||||||
            ContentPurpose::Number => Special("number"),
 | 
					 | 
				
			||||||
            ContentPurpose::Digits => Special("number"),
 | 
					 | 
				
			||||||
            ContentPurpose::Phone => Special("number"),
 | 
					 | 
				
			||||||
            ContentPurpose::Terminal => Special("terminal"),
 | 
					 | 
				
			||||||
            _ => Default,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        Some(overlay) => Special(overlay),
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // For intuitiveness,
 | 
					 | 
				
			||||||
    // default purpose layouts are stored in the root directory,
 | 
					 | 
				
			||||||
    // as they correspond to typical text
 | 
					 | 
				
			||||||
    // and are seen the most often.
 | 
					 | 
				
			||||||
    match layout_purpose {
 | 
					 | 
				
			||||||
        Default => "".into(),
 | 
					 | 
				
			||||||
        Special(purpose) => format!("{}/", purpose),
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Returns an iterator over all fallback paths.
 | 
					 | 
				
			||||||
fn to_layout_paths(
 | 
					 | 
				
			||||||
    name_fallbacks: Vec<(ArrangementKind, String)>,
 | 
					 | 
				
			||||||
    content_purpose: ContentPurpose,
 | 
					 | 
				
			||||||
    overlay: Option<&str>,
 | 
					 | 
				
			||||||
) -> impl Iterator<Item=(ArrangementKind, LayoutPath)> {
 | 
					 | 
				
			||||||
    let prepend_directory = get_directory_string(content_purpose, overlay);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    name_fallbacks.into_iter()
 | 
					 | 
				
			||||||
        .map(move |(arrangement, name)|
 | 
					 | 
				
			||||||
            (arrangement, format!("{}{}", prepend_directory, name))
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type LayoutSource = (ArrangementKind, DataSource);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn to_layout_sources(
 | 
					 | 
				
			||||||
    layout_paths: impl Iterator<Item=(ArrangementKind, LayoutPath)>,
 | 
					 | 
				
			||||||
    filesystem_path: Option<PathBuf>,
 | 
					 | 
				
			||||||
) -> impl Iterator<Item=LayoutSource> {
 | 
					 | 
				
			||||||
    layout_paths.flat_map(move |(arrangement, layout_path)| {
 | 
					 | 
				
			||||||
        let mut sources = Vec::new();
 | 
					 | 
				
			||||||
        if let Some(path) = &filesystem_path {
 | 
					 | 
				
			||||||
            sources.push((
 | 
					 | 
				
			||||||
                arrangement,
 | 
					 | 
				
			||||||
                DataSource::File(
 | 
					 | 
				
			||||||
                    path.join(&layout_path)
 | 
					 | 
				
			||||||
                        .with_extension("yaml")
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            ));
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        sources.push((arrangement, DataSource::Resource(layout_path.clone())));
 | 
					 | 
				
			||||||
        sources.into_iter()
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Returns possible sources, with first as the most preferred one.
 | 
					 | 
				
			||||||
/// Trying order: native lang of the right kind, native base,
 | 
					 | 
				
			||||||
/// fallback lang of the right kind, fallback base
 | 
					 | 
				
			||||||
fn iter_layout_sources(
 | 
					 | 
				
			||||||
    name: &str,
 | 
					 | 
				
			||||||
    arrangement: ArrangementKind,
 | 
					 | 
				
			||||||
    purpose: ContentPurpose,
 | 
					 | 
				
			||||||
    ui_overlay: Option<&str>,
 | 
					 | 
				
			||||||
    layout_storage: Option<PathBuf>,
 | 
					 | 
				
			||||||
) -> impl Iterator<Item=LayoutSource> {
 | 
					 | 
				
			||||||
    let names = get_preferred_names(name, arrangement);
 | 
					 | 
				
			||||||
    let paths = to_layout_paths(names, purpose, ui_overlay);
 | 
					 | 
				
			||||||
    to_layout_sources(paths, layout_storage)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn load_layout_data(source: DataSource)
 | 
					 | 
				
			||||||
    -> Result<::layout::LayoutData, LoadError>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    let handler = logging::Print {};
 | 
					 | 
				
			||||||
    match source {
 | 
					 | 
				
			||||||
        DataSource::File(path) => {
 | 
					 | 
				
			||||||
            Layout::from_file(path.clone())
 | 
					 | 
				
			||||||
                .map_err(LoadError::BadData)
 | 
					 | 
				
			||||||
                .and_then(|layout|
 | 
					 | 
				
			||||||
                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        DataSource::Resource(name) => {
 | 
					 | 
				
			||||||
            Layout::from_resource(&name)
 | 
					 | 
				
			||||||
                .and_then(|layout|
 | 
					 | 
				
			||||||
                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn load_layout_data_with_fallback(
 | 
					 | 
				
			||||||
    name: &str,
 | 
					 | 
				
			||||||
    kind: ArrangementKind,
 | 
					 | 
				
			||||||
    purpose: ContentPurpose,
 | 
					 | 
				
			||||||
    overlay: Option<&str>,
 | 
					 | 
				
			||||||
) -> (ArrangementKind, ::layout::LayoutData) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Build the path to the right keyboard layout subdirectory
 | 
					 | 
				
			||||||
    let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
 | 
					 | 
				
			||||||
        .map(PathBuf::from)
 | 
					 | 
				
			||||||
        .or_else(|| xdg::data_path("squeekboard/keyboards"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (kind, source) in iter_layout_sources(&name, kind, purpose, overlay, path) {
 | 
					 | 
				
			||||||
        let layout = load_layout_data(source.clone());
 | 
					 | 
				
			||||||
        match layout {
 | 
					 | 
				
			||||||
            Err(e) => match (e, source) {
 | 
					 | 
				
			||||||
                (
 | 
					 | 
				
			||||||
                    LoadError::BadData(Error::Missing(e)),
 | 
					 | 
				
			||||||
                    DataSource::File(file)
 | 
					 | 
				
			||||||
                ) => log_print!(
 | 
					 | 
				
			||||||
                    logging::Level::Debug,
 | 
					 | 
				
			||||||
                    "Tried file {:?}, but it's missing: {}",
 | 
					 | 
				
			||||||
                    file, e
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                (e, source) => log_print!(
 | 
					 | 
				
			||||||
                    logging::Level::Warning,
 | 
					 | 
				
			||||||
                    "Failed to load layout from {}: {}, skipping",
 | 
					 | 
				
			||||||
                    source, e
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            Ok(layout) => {
 | 
					 | 
				
			||||||
                log_print!(logging::Level::Info, "Loaded layout {}", source);
 | 
					 | 
				
			||||||
                return (kind, layout);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    panic!("No useful layout found!");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The root element describing an entire keyboard
 | 
					/// The root element describing an entire keyboard
 | 
				
			||||||
#[derive(Debug, Deserialize, PartialEq)]
 | 
					#[derive(Debug, Deserialize, PartialEq)]
 | 
				
			||||||
@ -421,37 +125,6 @@ struct Outline {
 | 
				
			|||||||
    height: f64,
 | 
					    height: f64,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Errors encountered loading the layout into yaml
 | 
					 | 
				
			||||||
#[derive(Debug)]
 | 
					 | 
				
			||||||
pub enum Error {
 | 
					 | 
				
			||||||
    Yaml(serde_yaml::Error),
 | 
					 | 
				
			||||||
    Io(io::Error),
 | 
					 | 
				
			||||||
    /// The file was missing.
 | 
					 | 
				
			||||||
    /// It's distinct from Io in order to make it matchable
 | 
					 | 
				
			||||||
    /// without calling io::Error::kind()
 | 
					 | 
				
			||||||
    Missing(io::Error),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for Error {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            Error::Yaml(e) => write!(f, "YAML: {}", e),
 | 
					 | 
				
			||||||
            Error::Io(e) => write!(f, "IO: {}", e),
 | 
					 | 
				
			||||||
            Error::Missing(e) => write!(f, "Missing: {}", e),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl From<io::Error> for Error {
 | 
					 | 
				
			||||||
    fn from(e: io::Error) -> Self {
 | 
					 | 
				
			||||||
        let kind = e.kind();
 | 
					 | 
				
			||||||
        match kind {
 | 
					 | 
				
			||||||
            io::ErrorKind::NotFound => Error::Missing(e),
 | 
					 | 
				
			||||||
            _ => Error::Io(e),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn add_offsets<'a, I: 'a, T, F: 'a>(iterator: I, get_size: F)
 | 
					pub fn add_offsets<'a, I: 'a, T, F: 'a>(iterator: I, get_size: F)
 | 
				
			||||||
    -> impl Iterator<Item=(f64, T)> + 'a
 | 
					    -> impl Iterator<Item=(f64, T)> + 'a
 | 
				
			||||||
    where I: Iterator<Item=T>,
 | 
					    where I: Iterator<Item=T>,
 | 
				
			||||||
@ -871,10 +544,13 @@ fn extract_symbol_names<'a>(actions: &'a [(&str, action::Action)])
 | 
				
			|||||||
        .map(|named_keysym| named_keysym.0)
 | 
					        .map(|named_keysym| named_keysym.0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    use std::env;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    use ::logging::ProblemPanic;
 | 
					    use ::logging::ProblemPanic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn path_from_root(file: &'static str) -> PathBuf {
 | 
					    fn path_from_root(file: &'static str) -> PathBuf {
 | 
				
			||||||
@ -1024,124 +700,6 @@ mod tests {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					 | 
				
			||||||
    fn parsing_fallback() {
 | 
					 | 
				
			||||||
        assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
 | 
					 | 
				
			||||||
            .map(|layout| layout.build(ProblemPanic).0.unwrap())
 | 
					 | 
				
			||||||
            .is_ok()
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME
 | 
					 | 
				
			||||||
    #[test]
 | 
					 | 
				
			||||||
    fn test_fallback_basic_builtin() {
 | 
					 | 
				
			||||||
        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, None);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            sources.collect::<Vec<_>>(),
 | 
					 | 
				
			||||||
            vec!(
 | 
					 | 
				
			||||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
					 | 
				
			||||||
                (
 | 
					 | 
				
			||||||
                    ArrangementKind::Base,
 | 
					 | 
				
			||||||
                    DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /// Prefer loading from file system before builtin.
 | 
					 | 
				
			||||||
    #[test]
 | 
					 | 
				
			||||||
    fn test_preferences_order_path() {
 | 
					 | 
				
			||||||
        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, Some(".".into()));
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            sources.collect::<Vec<_>>(),
 | 
					 | 
				
			||||||
            vec!(
 | 
					 | 
				
			||||||
                (ArrangementKind::Base, DataSource::File("./nb.yaml".into())),
 | 
					 | 
				
			||||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
					 | 
				
			||||||
                (
 | 
					 | 
				
			||||||
                    ArrangementKind::Base,
 | 
					 | 
				
			||||||
                    DataSource::File("./us.yaml".into())
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                (
 | 
					 | 
				
			||||||
                    ArrangementKind::Base,
 | 
					 | 
				
			||||||
                    DataSource::Resource("us".into())
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// If layout contains a "+", it should reach for what's in front of it too.
 | 
					 | 
				
			||||||
    #[test]
 | 
					 | 
				
			||||||
    fn test_preferences_order_base() {
 | 
					 | 
				
			||||||
        let sources = iter_layout_sources("nb+aliens", ArrangementKind::Base, ContentPurpose::Normal, None, None);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            sources.collect::<Vec<_>>(),
 | 
					 | 
				
			||||||
            vec!(
 | 
					 | 
				
			||||||
                (ArrangementKind::Base, DataSource::Resource("nb+aliens".into())),
 | 
					 | 
				
			||||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
					 | 
				
			||||||
                (
 | 
					 | 
				
			||||||
                    ArrangementKind::Base,
 | 
					 | 
				
			||||||
                    DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[test]
 | 
					 | 
				
			||||||
    fn test_preferences_order_arrangement() {
 | 
					 | 
				
			||||||
        let sources = iter_layout_sources("nb", ArrangementKind::Wide, ContentPurpose::Normal, None, None);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            sources.collect::<Vec<_>>(),
 | 
					 | 
				
			||||||
            vec!(
 | 
					 | 
				
			||||||
                (ArrangementKind::Wide, DataSource::Resource("nb_wide".into())),
 | 
					 | 
				
			||||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
					 | 
				
			||||||
                (
 | 
					 | 
				
			||||||
                    ArrangementKind::Wide,
 | 
					 | 
				
			||||||
                    DataSource::Resource("us_wide".into())
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                (
 | 
					 | 
				
			||||||
                    ArrangementKind::Base,
 | 
					 | 
				
			||||||
                    DataSource::Resource("us".into())
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[test]
 | 
					 | 
				
			||||||
    fn test_preferences_order_overlay() {
 | 
					 | 
				
			||||||
        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, Some("terminal"), None);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            sources.collect::<Vec<_>>(),
 | 
					 | 
				
			||||||
            vec!(
 | 
					 | 
				
			||||||
                (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
 | 
					 | 
				
			||||||
                (
 | 
					 | 
				
			||||||
                    ArrangementKind::Base,
 | 
					 | 
				
			||||||
                    DataSource::Resource("terminal/us".into())
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[test]
 | 
					 | 
				
			||||||
    fn test_preferences_order_hint() {
 | 
					 | 
				
			||||||
        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Terminal, None, None);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            sources.collect::<Vec<_>>(),
 | 
					 | 
				
			||||||
            vec!(
 | 
					 | 
				
			||||||
                (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
 | 
					 | 
				
			||||||
                (
 | 
					 | 
				
			||||||
                    ArrangementKind::Base,
 | 
					 | 
				
			||||||
                    DataSource::Resource("terminal/us".into())
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn unicode_keysym() {
 | 
					    fn unicode_keysym() {
 | 
				
			||||||
        let keysym = xkb::keysym_from_name(
 | 
					        let keysym = xkb::keysym_from_name(
 | 
				
			||||||
@ -621,12 +621,6 @@ pub enum LatchedState {
 | 
				
			|||||||
    Not,
 | 
					    Not,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl LatchedState {
 | 
					 | 
				
			||||||
    pub fn is_latched(&self) -> bool {
 | 
					 | 
				
			||||||
        self != &LatchedState::Not
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: split into sth like
 | 
					// TODO: split into sth like
 | 
				
			||||||
// Arrangement (views) + details (keymap) + State (keys)
 | 
					// Arrangement (views) + details (keymap) + State (keys)
 | 
				
			||||||
/// State of the UI, contains the backend as well
 | 
					/// State of the UI, contains the backend as well
 | 
				
			||||||
@ -776,23 +770,6 @@ impl Layout {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get_locked_keys(&self) -> Vec<Rc<RefCell<KeyState>>> {
 | 
					 | 
				
			||||||
        let mut out = Vec::new();
 | 
					 | 
				
			||||||
        let view = self.get_current_view();
 | 
					 | 
				
			||||||
        for (_, row) in view.get_rows() {
 | 
					 | 
				
			||||||
            for (_, button) in &row.buttons {
 | 
					 | 
				
			||||||
                let locked = {
 | 
					 | 
				
			||||||
                    let state = RefCell::borrow(&button.state).clone();
 | 
					 | 
				
			||||||
                    state.action.is_locked(&self.current_view)
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
                if locked {
 | 
					 | 
				
			||||||
                    out.push(button.state.clone());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        out
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    fn apply_view_transition(
 | 
					    fn apply_view_transition(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
 | 
				
			|||||||
@ -401,6 +401,7 @@ pub fn show(
 | 
				
			|||||||
        width: position.width.floor() as i32,
 | 
					        width: position.width.floor() as i32,
 | 
				
			||||||
        height: position.width.floor() as i32,
 | 
					        height: position.width.floor() as i32,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    menu.set_constrain_to(gtk::PopoverConstraint::None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if let Some(current_layout) = get_current_layout(manager, &system_layouts) {
 | 
					    if let Some(current_layout) = get_current_layout(manager, &system_layouts) {
 | 
				
			||||||
        let current_name_variant = choices.iter()
 | 
					        let current_name_variant = choices.iter()
 | 
				
			||||||
 | 
				
			|||||||
@ -11,19 +11,25 @@ use std::iter::FromIterator;
 | 
				
			|||||||
// and what a convenience layout. "_wide" is not a layout,
 | 
					// and what a convenience layout. "_wide" is not a layout,
 | 
				
			||||||
// neither is "number"
 | 
					// neither is "number"
 | 
				
			||||||
/// List of builtin layouts
 | 
					/// List of builtin layouts
 | 
				
			||||||
const KEYBOARDS: &[(*const str, *const str)] = &[
 | 
					static KEYBOARDS: &[(&'static str, &'static str)] = &[
 | 
				
			||||||
    // layouts: us must be left as first, as it is the,
 | 
					    // layouts: us must be left as first, as it is the,
 | 
				
			||||||
    // fallback layout.
 | 
					    // fallback layout.
 | 
				
			||||||
    ("us", include_str!("../data/keyboards/us.yaml")),
 | 
					    ("us", include_str!("../data/keyboards/us.yaml")),
 | 
				
			||||||
    ("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
 | 
					    ("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Language layouts: keep alphabetical.
 | 
					    // Language layouts: keep alphabetical.
 | 
				
			||||||
 | 
					    ("ara", include_str!("../data/keyboards/ara.yaml")),
 | 
				
			||||||
 | 
					    ("ara_wide", include_str!("../data/keyboards/ara_wide.yaml")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ("be", include_str!("../data/keyboards/be.yaml")),
 | 
					    ("be", include_str!("../data/keyboards/be.yaml")),
 | 
				
			||||||
    ("be_wide", include_str!("../data/keyboards/be_wide.yaml")),
 | 
					    ("be_wide", include_str!("../data/keyboards/be_wide.yaml")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ("bg", include_str!("../data/keyboards/bg.yaml")),
 | 
					    ("bg", include_str!("../data/keyboards/bg.yaml")),
 | 
				
			||||||
 | 
					    ("bg+phonetic", include_str!("../data/keyboards/bg+phonetic.yaml")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ("br", include_str!("../data/keyboards/br.yaml")),
 | 
					    ("br", include_str!("../data/keyboards/br.yaml")),
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    ("ch+fr", include_str!("../data/keyboards/ch+fr.yaml")),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ("de", include_str!("../data/keyboards/de.yaml")),
 | 
					    ("de", include_str!("../data/keyboards/de.yaml")),
 | 
				
			||||||
    ("de_wide", include_str!("../data/keyboards/de_wide.yaml")),
 | 
					    ("de_wide", include_str!("../data/keyboards/de_wide.yaml")),
 | 
				
			||||||
@ -93,34 +99,20 @@ const KEYBOARDS: &[(*const str, *const str)] = &[
 | 
				
			|||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn get_keyboard(needle: &str) -> Option<&'static str> {
 | 
					pub fn get_keyboard(needle: &str) -> Option<&'static str> {
 | 
				
			||||||
    // Need to dereference in unsafe code
 | 
					    KEYBOARDS.iter().find(|(name, _)| *name == needle).map(|(_, layout)| *layout)
 | 
				
			||||||
    // comparing *const str to &str will compare pointers
 | 
					 | 
				
			||||||
    KEYBOARDS.iter()
 | 
					 | 
				
			||||||
        .find(|(name, _)| {
 | 
					 | 
				
			||||||
            let name: *const str = *name;
 | 
					 | 
				
			||||||
            (unsafe { &*name }) == needle
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        .map(|(_, value)| {
 | 
					 | 
				
			||||||
            let value: *const str = *value;
 | 
					 | 
				
			||||||
            unsafe { &*value }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const OVERLAY_NAMES: &[*const str] = &[
 | 
					static OVERLAY_NAMES: &[&'static str] = &[
 | 
				
			||||||
    "emoji",
 | 
					    "emoji",
 | 
				
			||||||
    "terminal",
 | 
					    "terminal",
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn get_overlays() -> Vec<&'static str> {
 | 
					pub fn get_overlays() -> Vec<&'static str> {
 | 
				
			||||||
    OVERLAY_NAMES.iter()
 | 
					    OVERLAY_NAMES.to_vec()
 | 
				
			||||||
        .map(|name| {
 | 
					 | 
				
			||||||
            let name: *const str = *name;
 | 
					 | 
				
			||||||
            unsafe { &*name }
 | 
					 | 
				
			||||||
        }).collect()
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Translations of the layout identifier strings
 | 
					/// Translations of the layout identifier strings
 | 
				
			||||||
const LAYOUT_NAMES: &[(*const str, *const str)] = &[
 | 
					static LAYOUT_NAMES: &[(&'static str, &'static str)] = &[
 | 
				
			||||||
    ("de-DE", include_str!("../data/langs/de-DE.txt")),
 | 
					    ("de-DE", include_str!("../data/langs/de-DE.txt")),
 | 
				
			||||||
    ("en-US", include_str!("../data/langs/en-US.txt")),
 | 
					    ("en-US", include_str!("../data/langs/en-US.txt")),
 | 
				
			||||||
    ("es-ES", include_str!("../data/langs/es-ES.txt")),
 | 
					    ("es-ES", include_str!("../data/langs/es-ES.txt")),
 | 
				
			||||||
@ -135,14 +127,8 @@ pub fn get_layout_names(lang: &str)
 | 
				
			|||||||
    -> Option<HashMap<&'static str, Translation<'static>>>
 | 
					    -> Option<HashMap<&'static str, Translation<'static>>>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    let translations = LAYOUT_NAMES.iter()
 | 
					    let translations = LAYOUT_NAMES.iter()
 | 
				
			||||||
        .find(|(name, _data)| {
 | 
					        .find(|(name, _data)| *name == lang)
 | 
				
			||||||
            let name: *const str = *name;
 | 
					        .map(|(_name, data)| *data);
 | 
				
			||||||
            (unsafe { &*name }) == lang
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        .map(|(_name, data)| {
 | 
					 | 
				
			||||||
            let data: *const str = *data;
 | 
					 | 
				
			||||||
            unsafe { &*data }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    translations.map(make_mapping)
 | 
					    translations.map(make_mapping)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -83,7 +83,6 @@ on_name_lost (GDBusConnection *connection,
 | 
				
			|||||||
    (void)name;
 | 
					    (void)name;
 | 
				
			||||||
    (void)user_data;
 | 
					    (void)user_data;
 | 
				
			||||||
    g_error("DBus unavailable, unclear how to continue.");
 | 
					    g_error("DBus unavailable, unclear how to continue.");
 | 
				
			||||||
    exit (1);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Wayland
 | 
					// Wayland
 | 
				
			||||||
@ -264,7 +263,6 @@ main (int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (display == NULL) {
 | 
					    if (display == NULL) {
 | 
				
			||||||
        g_error ("Failed to get display: %m\n");
 | 
					        g_error ("Failed to get display: %m\n");
 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -277,11 +275,12 @@ main (int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (!instance.wayland.seat) {
 | 
					    if (!instance.wayland.seat) {
 | 
				
			||||||
        g_error("No seat Wayland global available.");
 | 
					        g_error("No seat Wayland global available.");
 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!instance.wayland.virtual_keyboard_manager) {
 | 
					    if (!instance.wayland.virtual_keyboard_manager) {
 | 
				
			||||||
        g_error("No virtual keyboard manager Wayland global available.");
 | 
					        g_error("No virtual keyboard manager Wayland global available.");
 | 
				
			||||||
        exit(1);
 | 
					    }
 | 
				
			||||||
 | 
					    if (!instance.wayland.layer_shell) {
 | 
				
			||||||
 | 
					        g_error("No layer shell global available.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!instance.wayland.input_method_manager) {
 | 
					    if (!instance.wayland.input_method_manager) {
 | 
				
			||||||
@ -380,7 +379,6 @@ main (int argc, char **argv)
 | 
				
			|||||||
                vis_manager);
 | 
					                vis_manager);
 | 
				
			||||||
    if (!ui_context) {
 | 
					    if (!ui_context) {
 | 
				
			||||||
        g_error("Could not initialize GUI");
 | 
					        g_error("Could not initialize GUI");
 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    instance.ui_context = ui_context;
 | 
					    instance.ui_context = ui_context;
 | 
				
			||||||
    squeek_visman_set_ui(vis_manager, instance.ui_context);
 | 
					    squeek_visman_set_ui(vis_manager, instance.ui_context);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
/*! Testing functionality */
 | 
					/*! Testing functionality */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use ::data::Layout;
 | 
					use ::data::parsing::Layout;
 | 
				
			||||||
use ::logging;
 | 
					use ::logging;
 | 
				
			||||||
use xkbcommon::xkb;
 | 
					use xkbcommon::xkb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -58,9 +58,12 @@ foreach layout : [
 | 
				
			|||||||
    'us', 'us_wide',
 | 
					    'us', 'us_wide',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Block: Languages
 | 
					    # Block: Languages
 | 
				
			||||||
 | 
					    'ara', 'ara_wide',
 | 
				
			||||||
    'be', 'be_wide',
 | 
					    'be', 'be_wide',
 | 
				
			||||||
    'bg',
 | 
					    'bg',
 | 
				
			||||||
 | 
					    'bg+phonetic',
 | 
				
			||||||
    'br',
 | 
					    'br',
 | 
				
			||||||
 | 
					    'ch+fr',
 | 
				
			||||||
    'cz', 'cz_wide',
 | 
					    'cz', 'cz_wide',
 | 
				
			||||||
    'cz+qwerty', 'cz+qwerty_wide',
 | 
					    'cz+qwerty', 'cz+qwerty_wide',
 | 
				
			||||||
    'de', 'de_wide',
 | 
					    'de', 'de_wide',
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user