diff options
| -rw-r--r-- | Cargo.lock | 628 | ||||
| -rw-r--r-- | Cargo.toml | 12 | ||||
| -rw-r--r-- | src/bin/fragment.frag | 7 | ||||
| -rw-r--r-- | src/bin/phosphor_test.rs | 97 | ||||
| -rw-r--r-- | src/bin/vertex.vert | 9 | ||||
| -rw-r--r-- | src/keyboard_input.rs | 19 | ||||
| -rw-r--r-- | src/lib.rs | 60 | ||||
| -rw-r--r-- | src/press_state.rs | 26 | ||||
| -rw-r--r-- | src/program_controller.rs | 13 | ||||
| -rw-r--r-- | src/render.rs | 67 | ||||
| -rw-r--r-- | src/render_hint.rs | 33 | ||||
| -rw-r--r-- | src/render_request.rs | 40 | ||||
| -rw-r--r-- | src/window.rs | 177 | ||||
| -rw-r--r-- | src/window/x11.rs | 66 | ||||
| -rw-r--r-- | src/window_controller.rs | 52 | ||||
| -rw-r--r-- | src/window_manager.rs | 192 | 
16 files changed, 921 insertions, 577 deletions
| @@ -27,12 +27,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"  [[package]] +name = "as-raw-xcb-connection" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5f312b0a56c5cdf967c0aeb67f6289603354951683bc97ddc595ab974ba9aa" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]]  name = "bitflags"  version = "1.3.2"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"  [[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]]  name = "block-sys"  version = "0.1.0-beta.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -66,6 +84,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"  [[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]]  name = "cc"  version = "1.0.83"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -88,6 +126,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"  [[package]] +name = "cocoa" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics 0.23.1", + "foreign-types 0.5.0", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", +] + +[[package]]  name = "colour"  version = "1.0.0"  dependencies = [ @@ -119,7 +187,20 @@ dependencies = [   "bitflags",   "core-foundation",   "core-graphics-types", - "foreign-types", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0",   "libc",  ] @@ -131,23 +212,113 @@ checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"  dependencies = [   "bitflags",   "core-foundation", - "foreign-types", + "foreign-types 0.3.2",   "libc",  ]  [[package]] +name = "ctor" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" +dependencies = [ + "quote", + "syn 2.0.28", +] + +[[package]]  name = "dispatch"  version = "0.2.0"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"  [[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.1", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "drm" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edf9159ef4bcecd0c5e4cbeb573b8d0037493403d542780dba5d840bbf9df56f" +dependencies = [ + "bitflags", + "bytemuck", + "drm-ffi", + "drm-fourcc", + "nix", +] + +[[package]] +name = "drm-ffi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1352481b7b90e27a8a1bf8ef6b33cf18b98dba7c410e75c24bb3eef2f0d8d525" +dependencies = [ + "drm-sys", + "nix", +] + +[[package]] +name = "drm-fourcc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" + +[[package]] +name = "drm-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1369f1679d6b706d234c4c1e0613c415c2c74b598a09ad28080ba2474b72e42d" +dependencies = [ + "libc", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]]  name = "foreign-types"  version = "0.3.2"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"  dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28",  ]  [[package]] @@ -157,10 +328,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"  [[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]]  name = "geometry"  version = "0.1.0"  [[package]] +name = "gethostname" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]]  name = "instant"  version = "0.1.12"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -173,6 +366,17 @@ dependencies = [  ]  [[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]]  name = "jni-sys"  version = "0.3.0"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -189,9 +393,9 @@ dependencies = [  [[package]]  name = "js-sys" -version = "0.3.60" +version = "0.3.64"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"  dependencies = [   "wasm-bindgen",  ] @@ -204,9 +408,29 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"  [[package]]  name = "libc" -version = "0.2.135" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.1"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +]  [[package]]  name = "log" @@ -218,6 +442,39 @@ dependencies = [  ]  [[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memmap2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]]  name = "mio"  version = "0.8.4"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -259,8 +516,17 @@ dependencies = [  ]  [[package]] -name = "nosferatu" -version = "0.1.0" +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset", + "pin-utils", +]  [[package]]  name = "num_enum" @@ -289,7 +555,7 @@ dependencies = [   "proc-macro-crate",   "proc-macro2",   "quote", - "syn 1.0.102", + "syn 1.0.107",  ]  [[package]] @@ -301,7 +567,16 @@ dependencies = [   "proc-macro-crate",   "proc-macro2",   "quote", - "syn 2.0.32", + "syn 2.0.28", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf",  ]  [[package]] @@ -332,9 +607,9 @@ dependencies = [  [[package]]  name = "once_cell" -version = "1.15.0" +version = "1.18.0"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"  [[package]]  name = "orbclient" @@ -357,13 +632,23 @@ version = "0.1.0"  dependencies = [   "buffer",   "geometry", - "nosferatu", - "raw-window-handle", + "softbuffer",   "winit", - "x11-dl",  ]  [[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]]  name = "pkg-config"  version = "0.3.25"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -394,6 +679,15 @@ name = "proportion"  version = "1.0.0"  [[package]] +name = "quick-xml" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +dependencies = [ + "memchr", +] + +[[package]]  name = "quote"  version = "1.0.31"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -418,16 +712,60 @@ dependencies = [  ]  [[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]]  name = "serde"  version = "1.0.145"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"  [[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "softbuffer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd56fe5e6c6f1881aad2bd37acaef4ac4a3689c970dfcbd87a36a6e60210ec8" +dependencies = [ + "as-raw-xcb-connection", + "bytemuck", + "cfg_aliases", + "cocoa", + "core-graphics 0.23.1", + "drm", + "drm-sys", + "fastrand", + "foreign-types 0.5.0", + "js-sys", + "log", + "memmap2", + "nix", + "objc", + "raw-window-handle", + "redox_syscall", + "tiny-xlib", + "wasm-bindgen", + "wayland-backend", + "wayland-client", + "wayland-sys", + "web-sys", + "windows-sys 0.48.0", + "x11rb", +] + +[[package]]  name = "syn" -version = "1.0.102" +version = "1.0.107"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"  dependencies = [   "proc-macro2",   "quote", @@ -436,9 +774,9 @@ dependencies = [  [[package]]  name = "syn" -version = "2.0.32" +version = "2.0.28"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"  dependencies = [   "proc-macro2",   "quote", @@ -447,22 +785,34 @@ dependencies = [  [[package]]  name = "thiserror" -version = "1.0.37" +version = "1.0.44"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"  dependencies = [   "thiserror-impl",  ]  [[package]]  name = "thiserror-impl" -version = "1.0.37" +version = "1.0.44"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"  dependencies = [   "proc-macro2",   "quote", - "syn 1.0.102", + "syn 2.0.28", +] + +[[package]] +name = "tiny-xlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4098d49269baa034a8d1eae9bd63e9fa532148d772121dace3bcd6a6c98eb6d" +dependencies = [ + "as-raw-xcb-connection", + "ctor", + "libloading 0.8.1", + "tracing",  ]  [[package]] @@ -475,6 +825,23 @@ dependencies = [  ]  [[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" + +[[package]]  name = "unicode-ident"  version = "1.0.5"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -488,9 +855,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"  [[package]]  name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.87"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"  dependencies = [   "cfg-if",   "wasm-bindgen-macro", @@ -498,24 +865,24 @@ dependencies = [  [[package]]  name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.87"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"  dependencies = [   "bumpalo",   "log",   "once_cell",   "proc-macro2",   "quote", - "syn 1.0.102", + "syn 2.0.28",   "wasm-bindgen-shared",  ]  [[package]]  name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.87"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"  dependencies = [   "quote",   "wasm-bindgen-macro-support", @@ -523,22 +890,49 @@ dependencies = [  [[package]]  name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.87"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"  dependencies = [   "proc-macro2",   "quote", - "syn 1.0.102", + "syn 2.0.28",   "wasm-bindgen-backend",   "wasm-bindgen-shared",  ]  [[package]]  name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.87"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "wayland-backend" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b48e27457e8da3b2260ac60d0a94512f5cba36448679f3747c0865b7893ed8" +dependencies = [ + "cc", + "downcast-rs", + "io-lifetimes", + "nix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.30.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489c9654770f674fc7e266b3c579f4053d7551df0ceb392f153adb1f9ed06ac8" +dependencies = [ + "bitflags", + "nix", + "wayland-backend", + "wayland-scanner 0.30.1", +]  [[package]]  name = "wayland-scanner" @@ -552,16 +946,70 @@ dependencies = [  ]  [[package]] +name = "wayland-scanner" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06" +dependencies = [ + "dlib", + "lazy_static", + "log", + "pkg-config", +] + +[[package]]  name = "web-sys" -version = "0.3.60" +version = "0.3.64"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"  dependencies = [   "js-sys",   "wasm-bindgen",  ]  [[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]]  name = "windows-sys"  version = "0.36.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -580,7 +1028,16 @@ version = "0.45.0"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"  dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5",  ]  [[package]] @@ -589,22 +1046,43 @@ version = "0.42.2"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"  dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.2",   "windows_aarch64_msvc 0.42.2",   "windows_i686_gnu 0.42.2",   "windows_i686_msvc 0.42.2",   "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.2",   "windows_x86_64_msvc 0.42.2",  ]  [[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]]  name = "windows_aarch64_gnullvm"  version = "0.42.2"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"  [[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]]  name = "windows_aarch64_msvc"  version = "0.36.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -617,6 +1095,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"  [[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]]  name = "windows_i686_gnu"  version = "0.36.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -629,6 +1113,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"  [[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]]  name = "windows_i686_msvc"  version = "0.36.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -641,6 +1131,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"  [[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]]  name = "windows_x86_64_gnu"  version = "0.36.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -653,12 +1149,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"  [[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]]  name = "windows_x86_64_gnullvm"  version = "0.42.2"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"  [[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]]  name = "windows_x86_64_msvc"  version = "0.36.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -671,6 +1179,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"  [[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]]  name = "winit"  version = "0.28.7"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -680,7 +1194,7 @@ dependencies = [   "bitflags",   "cfg_aliases",   "core-foundation", - "core-graphics", + "core-graphics 0.22.3",   "dispatch",   "instant",   "libc", @@ -694,7 +1208,7 @@ dependencies = [   "raw-window-handle",   "redox_syscall",   "wasm-bindgen", - "wayland-scanner", + "wayland-scanner 0.29.5",   "web-sys",   "windows-sys 0.45.0",   "x11-dl", @@ -712,6 +1226,32 @@ dependencies = [  ]  [[package]] +name = "x11rb" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading 0.7.4", + "nix", + "once_cell", + "winapi", + "winapi-wsapoll", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc" +dependencies = [ + "nix", +] + +[[package]]  name = "xml-rs"  version = "0.8.19"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6,12 +6,8 @@ edition = "2021"  # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  [dependencies] -winit = { version = "0.27.4", default-features = false, features = ["x11"] } -x11-dl = "2.19.1" -raw-window-handle = "0.4.2" -# raw-gl-context = "0.1.2" -# gl = "0.14" - -geometry = { path = "/home/ben/Libraries/geometry" } -nosferatu = { path = "/home/ben/Libraries/nosferatu" }  buffer = { path = "/home/ben/Libraries/buffer" } +geometry = { path = "/home/ben/Libraries/geometry" } + +softbuffer = "0.3.1" +winit = { version = "0.28.1", default-features = false, features = ["x11"] } diff --git a/src/bin/fragment.frag b/src/bin/fragment.frag deleted file mode 100644 index 99826f6..0000000 --- a/src/bin/fragment.frag +++ /dev/null @@ -1,7 +0,0 @@ -#version 330 -out vec4 FragColor; -in vec3 vertexColor; - -void main() { -    FragColor = vec4(vertexColor, 1.0); -} diff --git a/src/bin/phosphor_test.rs b/src/bin/phosphor_test.rs index 40a8558..c3b307d 100644 --- a/src/bin/phosphor_test.rs +++ b/src/bin/phosphor_test.rs @@ -1,89 +1,36 @@ -#![allow(dead_code)] - -// use asbestos::{Shader, ShaderProgram};  use buffer::*;  use phosphor::*; -// use raw_gl_context::GlContext;  fn main() { -    let my_program = MyProgram {}; -    let mut wm = WindowManager::with_program(my_program); -    wm.create_window(MainWindow::new()); +    let mut wm = WindowManager::new(std::time::Duration::from_micros(16666)); +    wm.add_window(Box::new(Window {}));      wm.run()  } -struct MyProgram {} -impl ProgramController for MyProgram {} - -struct MainWindow { -    // program: ShaderProgram, -} -impl MainWindow { -    pub fn new() -> Box<Self> { -        // let vertex_shader = Shader::vertex(include_str!("vertex.vert")); -        // let fragment_shader = Shader::fragment(include_str!("fragment.frag")); -        // let program = ShaderProgram::from_shaders(&[vertex_shader, fragment_shader]); -        // Box::new(Self { program }) -        Box::new(Self {}) +struct Window {} +impl WindowController for Window { +    fn minimum_size(&self) -> Option<phosphor::Dimensions> { +        Some(phosphor::Dimensions::new(200, 200))      } -} -impl WindowController for MainWindow { -    fn render(&mut self, buffer: &mut Buffer, _: RenderHint) { -        println!("Rendering..."); -        buffer.fill(Colour::TEAL); +    fn maximum_size(&self) -> Option<phosphor::Dimensions> { +        Some(phosphor::Dimensions::new(400, 400))      } -    // fn render_gl(&mut self, _context: &mut GlContext) { -    //     println!("Rendering GL..."); -    //     unsafe { -    //         gl::ClearColor(1.0, 0.0, 1.0, 1.0); -    //         gl::Clear(gl::COLOR_BUFFER_BIT); -    //     } -    // } -} - -// type Pos = [f32; 2]; -// type Color = [f32; 3]; -// #[repr(C, packed)] -// struct Vertex(Pos, Color); - -// const VERTICES: [Vertex; 3] = [ -//     Vertex([-0.5, -0.5], [1.0, 0.0, 0.0]), -//     Vertex([0.5,  -0.5], [0.0, 1.0, 0.0]), -//     Vertex([0.0,   0.5], [0.0, 0.0, 1.0]) -// ]; +    fn render_request(&self) -> RenderRequest { +        RenderRequest::None +    } -// pub struct Buffer { -//     pub id: GLuint, -//     target: GLuint, -// } -// impl Buffer { -//     pub unsafe fn new(target: GLuint) -> Self { -//         let mut id: GLuint = 0; -//         gl::GenBuffers(1, &mut id); -//         Self { id, target } -//     } +    fn is_resizable(&self) -> bool { +        false +    } -//     pub unsafe fn bind(&self) { -//         gl::BindBuffer(self.target, self.id); -//     } +    fn on_resize(&mut self, size: phosphor::Dimensions) { +        println!("RESIZE: {size:?}"); +    } -//     pub unsafe fn set_data<D>(&self, data: &[D], usage: GLuint) { -//         self.bind(); -//         let (_, data_bytes, _) = data.align_to::<u8>(); -//         gl::BufferData( -//             self.target, -//             data_bytes.len() as GLsizeiptr, -//             data_bytes.as_ptr() as *const _, -//             usage, -//         ); -//     } -// } +    fn on_render(&mut self, buffer: &mut Buffer, _: RenderHint) { +        println!("RENDER"); +        buffer.fill(Colour::TEAL); +    } +} -// impl Drop for Buffer { -//     fn drop(&mut self) { -//         unsafe { -//             gl::DeleteBuffers(1, [self.id].as_ptr()); -//         } -//     } -// } diff --git a/src/bin/vertex.vert b/src/bin/vertex.vert deleted file mode 100644 index 0fd4f8a..0000000 --- a/src/bin/vertex.vert +++ /dev/null @@ -1,9 +0,0 @@ -#version 330 -in vec2 point; -in vec3 color; -out vec3 vertexColor; - -void main() { -    gl_Point = vec4(point, 0.0, 1.0); -    vertexColor = color; -} diff --git a/src/keyboard_input.rs b/src/keyboard_input.rs deleted file mode 100644 index 139db7e..0000000 --- a/src/keyboard_input.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::*; -use winit::event::KeyboardInput as WinitKeyboardInput; - -#[derive(Copy, Clone)] -pub struct KeyboardInput { -    pub state: PressState, -    pub keycode: Option<KeyCode>, -    pub scancode: u32, -} - -impl From<WinitKeyboardInput> for KeyboardInput { -    fn from(input: WinitKeyboardInput) -> Self { -        Self { -            state: input.state.into(), -            keycode: input.virtual_keycode, -            scancode: input.scancode, -        } -    } -} @@ -1,25 +1,16 @@ -mod keyboard_input; -mod press_state; -mod program_controller; -mod render_hint; -mod render_request; +mod render;  mod window;  mod window_controller;  mod window_manager; -use window::Window; - -pub use keyboard_input::KeyboardInput; -pub use press_state::PressState; -pub use program_controller::{DefaultProgramController, ProgramController}; -pub use render_hint::RenderHint; -pub use render_request::RenderRequest; -pub use window_controller::WindowController; -pub use window_manager::WindowManager; +pub use render::*; +pub use window::*; +pub use window_controller::*; +pub use window_manager::*;  pub use buffer::{Buffer, Colour};  pub use winit::{ -    event::ModifiersState, +    event::{ModifiersState, ElementState},      event::VirtualKeyCode as KeyCode,      window::CursorIcon,  }; @@ -27,3 +18,42 @@ pub use winit::{  pub type Point = geometry::Point<i32>;  pub type Dimensions = geometry::Dimensions<u32>;  pub type Rect = geometry::Rect<i32, u32>; + +// ----------------------------------------------------------------------------- + +#[derive(Copy, Clone)] +pub struct KeyboardInput { +    pub action: Action, +    pub key: KeyCode, +} + +impl TryFrom<winit::event::KeyboardInput> for KeyboardInput { +    type Error = (); + +    fn try_from(input: winit::event::KeyboardInput) -> Result<Self, ()> { +        if let Some(key) = input.virtual_keycode { +            Ok( Self { action: input.state.into(), key } ) +        } else { +            Err(()) +        } +    } +} + +// ----------------------------------------------------------------------------- + +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum Action { Pressed, Released } + +impl Action { +    pub fn is_pressed(&self)  -> bool { *self == Self::Pressed  } +    pub fn is_released(&self) -> bool { *self == Self::Released } +} + +impl From<ElementState> for Action { +    fn from(value: ElementState) -> Self { +        match value { +            ElementState::Pressed => Action::Pressed, +            ElementState::Released => Action::Released, +        } +    } +} diff --git a/src/press_state.rs b/src/press_state.rs deleted file mode 100644 index 5136d66..0000000 --- a/src/press_state.rs +++ /dev/null @@ -1,26 +0,0 @@ -use winit::event::ElementState; - -/// Denotes whether an event was a press event or a release event. -#[derive(Clone, Copy, PartialEq, Debug)] -pub enum PressState { -    Pressed, -    Released, -} - -impl PressState { -    pub fn is_pressed(&self) -> bool { -        *self == Self::Pressed -    } -    pub fn is_released(&self) -> bool { -        *self == Self::Released -    } -} - -impl From<ElementState> for PressState { -    fn from(value: ElementState) -> Self { -        match value { -            ElementState::Pressed => PressState::Pressed, -            ElementState::Released => PressState::Released, -        } -    } -} diff --git a/src/program_controller.rs b/src/program_controller.rs deleted file mode 100644 index 638e5ce..0000000 --- a/src/program_controller.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::*; - -pub trait ProgramController { -    fn initialise(&mut self) {} -    fn on_render(&mut self) {} -    fn on_mouse_moved(&mut self, _position: Point) {} - -    fn on_process(&mut self, _create_window: &mut dyn FnMut(Box<dyn WindowController>)) {} -} - -/// An empty program controller, for when a program has only one window. -pub struct DefaultProgramController {} -impl ProgramController for DefaultProgramController {} diff --git a/src/render.rs b/src/render.rs new file mode 100644 index 0000000..e7ec02d --- /dev/null +++ b/src/render.rs @@ -0,0 +1,67 @@ +/// Tells a window controller whether the previous render state is intact and +/// can be updated, or was destroyed and needs to be fully redrawn. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum RenderHint { +    /// The buffer content is unchanged, only updates are required. +    Update, +    /// The buffer content has been destroyed, a full redraw is required. +    Redraw, +} + +impl RenderHint { +    pub fn is_update(&self) -> bool { *self == RenderHint::Update } +    pub fn is_redraw(&self) -> bool { *self == RenderHint::Redraw } +} + +impl std::ops::BitAnd for RenderHint { +    type Output = RenderHint; +    fn bitand(self, other: RenderHint) -> Self::Output { +        if self == RenderHint::Redraw || other == RenderHint::Redraw { +            RenderHint::Redraw +        } else { +            RenderHint::Update +        } +    } +} + +impl std::ops::BitAndAssign for RenderHint { +    fn bitand_assign(&mut self, other: RenderHint) { +        *self = *self & other; +    } +} + +/// A request to the window manager for a render pass to be run. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum RenderRequest { +    None, +    Render(RenderHint), +} + +impl RenderRequest { +    pub const NONE:   RenderRequest = RenderRequest::None; +    pub const UPDATE: RenderRequest = RenderRequest::Render(RenderHint::Update); +    pub const REDRAW: RenderRequest = RenderRequest::Render(RenderHint::Redraw); + +    pub fn is_none(&self)   -> bool { *self == RenderRequest::None } +    pub fn is_some(&self)   -> bool { *self != RenderRequest::None } +    pub fn is_update(&self) -> bool { *self == RenderRequest::UPDATE } +    pub fn is_redraw(&self) -> bool { *self == RenderRequest::REDRAW } +} + +impl std::ops::BitAnd for RenderRequest { +    type Output = RenderRequest; +    fn bitand(self, other: RenderRequest) -> Self::Output { +        use RenderRequest::*; +        match (self, other) { +            (None, req)  => req, +            (req, None)  => req, +            (Render(a), Render(b)) => Render(a & b), +        } +    } +} + +impl std::ops::BitAndAssign for RenderRequest { +    fn bitand_assign(&mut self, other: RenderRequest) { +        *self = *self & other; +    } +} diff --git a/src/render_hint.rs b/src/render_hint.rs deleted file mode 100644 index e4d37c3..0000000 --- a/src/render_hint.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::ops::*; - -/// A hint to tell a window controller whether the previous render state is -/// intact and can be updated, or was destroyed and needs to be fully redrawn. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum RenderHint { -    /// The buffer contents are intact, only updates need to be drawn. -    Update, -    /// The buffer contents were destroyed, a full redraw is required. -    Redraw, -} - -impl RenderHint { -    pub fn is_update(&self) -> bool { *self == RenderHint::Update } -    pub fn is_redraw(&self) -> bool { *self == RenderHint::Redraw } -} - -impl BitAnd for RenderHint { -    type Output = RenderHint; -    fn bitand(self, other: RenderHint) -> Self::Output { -        if self == RenderHint::Redraw || other == RenderHint::Redraw { -            RenderHint::Redraw -        } else { -            RenderHint::Update -        } -    } -} - -impl BitAndAssign for RenderHint { -    fn bitand_assign(&mut self, other: RenderHint) { -        *self = *self & other; -    } -} diff --git a/src/render_request.rs b/src/render_request.rs deleted file mode 100644 index f336dfc..0000000 --- a/src/render_request.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::*; -use std::ops::*; - -/// A request to the window manager for a render pass to be run. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum RenderRequest { -    /// A render is not required. -    None, -    /// A render is required. -    Render(RenderHint), -} - -impl RenderRequest { -    pub const NONE:   RenderRequest = RenderRequest::None; -    pub const UPDATE: RenderRequest = RenderRequest::Render(RenderHint::Update); -    pub const REDRAW: RenderRequest = RenderRequest::Render(RenderHint::Redraw); - -    pub fn is_none(&self) -> bool { *self == RenderRequest::NONE } -    pub fn is_some(&self) -> bool { *self != RenderRequest::None } -    pub fn is_update(&self) -> bool { *self == RenderRequest::UPDATE } -    pub fn is_redraw(&self) -> bool { *self == RenderRequest::REDRAW } -} - -impl BitAnd for RenderRequest { -    type Output = RenderRequest; -    fn bitand(self, other: RenderRequest) -> Self::Output { -        use RenderRequest::*; -        match (self, other) { -            (None, req)  => req, -            (req, None)  => req, -            (Render(a), Render(b)) => Render(a & b), -        } -    } -} - -impl BitAndAssign for RenderRequest { -    fn bitand_assign(&mut self, other: RenderRequest) { -        *self = *self & other; -    } -} diff --git a/src/window.rs b/src/window.rs index 45e37c9..ffe35e8 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,136 +1,133 @@ -mod x11;  use crate::*; -use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; + +use std::num::NonZeroU32;  use winit::dpi::{Size, PhysicalSize};  use winit::event_loop::EventLoopWindowTarget; -use winit::window::{WindowId, Window as WinitWindow, WindowBuilder as WinitWindowBuilder}; -// use raw_gl_context::{GlConfig, GlContext}; +use winit::window::WindowId;  pub struct Window {      pub controller: Box<dyn WindowController>, -    cursor_position: Option<Point>, -    winit_window: WinitWindow, +    window: winit::window::Window,      buffer: Buffer,      dimensions: Dimensions, -    /// The most recent render request for this window. -    render_hint: RenderHint, -    graphics_context: Box<dyn GraphicsContext>, -    // gl_context: GlContext, +    #[allow(dead_code)] context: softbuffer::Context, +    surface: softbuffer::Surface, +    current_render_hint: RenderHint, +    previous_cursor_position: Option<Point>,  }  impl Window { -    pub unsafe fn new(event_loop: &EventLoopWindowTarget<()>, controller: Box<dyn WindowController>) -> Self { -        let mut builder = WinitWindowBuilder::new(); -        builder = builder.with_resizable(controller.resizable()); -        builder = builder.with_inner_size({ -            let dim = controller.initial_dimensions(); -            Size::Physical(PhysicalSize::new(dim.width, dim.height)) -        }); -        if let Some(dim) = controller.minimum_dimensions() { -            let size = Size::Physical(PhysicalSize { width: dim.width, height: dim.height }); -            builder = builder.with_min_inner_size(size); -        } -        if let Some(dim) = controller.maximum_dimensions() { -            let size = Size::Physical(PhysicalSize { width: dim.width, height: dim.height }); -            builder = builder.with_max_inner_size(size); -        } -        let winit_window = builder.build(event_loop).unwrap(); +    pub fn new(event_loop: &EventLoopWindowTarget<()>, controller: Box<dyn WindowController>) -> Self { +        let window = winit::window::WindowBuilder::new() +            .with_title(controller.title()) +            .with_resizable(controller.is_resizable()) +            .with_inner_size(dim_to_size(controller.initial_size())) +            .build(event_loop) +            .unwrap(); + +        let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); +        let surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); -        let graphics_context: Box<dyn GraphicsContext> = match winit_window.raw_window_handle() { -            RawWindowHandle::Xlib(xlib_handle) => Box::new(x11::X11GraphicsContext::new(xlib_handle)), -            _ => panic!("Unknown window handle type"), -        }; -        // let gl_context = GlContext::create(&winit_window, GlConfig::default()).unwrap(); -        // gl_context.make_current(); -        // gl::load_with(|symbol| { -        //     println!("Loaded '{}'", symbol); -        //     gl_context.get_proc_address(symbol) as *const _ -        // });          Self { -            winit_window,              controller, -            graphics_context, -            render_hint: RenderHint::Redraw, -            // gl_context, +            window,              buffer: Buffer::new(Dimensions::ZERO),              dimensions: Dimensions::ZERO, -            cursor_position: None, +            context, +            surface, +            previous_cursor_position: None, +            current_render_hint: RenderHint::Redraw,          }      }      pub fn id(&self) -> WindowId { -        self.winit_window.id() +        self.window.id()      } -    pub fn set_minimum_dimensions(&mut self, dimensions: Option<Dimensions>) { -        self.winit_window.set_min_inner_size(dimensions.map(|dim| { -            Size::Physical(PhysicalSize { width:dim.width, height:dim.height }) -        })) +    pub fn update_title(&mut self) { +        self.window.set_title(&self.controller.title());      } -    pub fn set_maximum_dimensions(&mut self, dimensions: Option<Dimensions>) { -        self.winit_window.set_max_inner_size(dimensions.map(|dim| { -            Size::Physical(PhysicalSize { width:dim.width, height:dim.height }) -        })) + +    pub fn update_cursor_icon(&mut self) { +        let icon = self.controller.cursor_icon().unwrap_or(CursorIcon::Default); +        self.window.set_cursor_icon(icon);      } -    pub fn set_title(&mut self, title: &str) { -        self.winit_window.set_title(title); + +    pub fn update_minimum_size(&mut self) { +        let size = self.controller.minimum_size().map(|d| dim_to_size(d)); +        self.window.set_min_inner_size(size);      } -    /// Call to update the frame buffer to the new size of the window. -    pub fn resize_buffer(&mut self, dimensions: Dimensions) { -        if self.dimensions == dimensions { return } -        self.dimensions = dimensions; -        self.buffer.resize(dimensions); -        self.controller.on_resize(dimensions); -        self.render_hint = RenderHint::Redraw; +    pub fn update_maximum_size(&mut self) { +        let size = self.controller.maximum_size().map(|d| dim_to_size(d)); +        self.window.set_max_inner_size(size);      } -    pub fn set_cursor_icon(&mut self, icon: Option<CursorIcon>) { -        match icon { -            Some(icon) => self.winit_window.set_cursor_icon(icon), -            None => self.winit_window.set_cursor_icon(CursorIcon::Default), -        }; +    pub fn update_cursor_visible(&mut self) { +        self.window.set_cursor_visible(self.controller.is_cursor_visible());      } -    /// Call this after a mouse click so that the cursor-hovering callbacks are -    /// rerun. This is useful where a click changes the UI layout and a new -    /// element that has an on-hover effect appears beneath the cursor. -    pub fn bump_mouse(&mut self) { -        if let Some(position) = self.cursor_position { -            self.controller.on_mouse_move(position) +    pub fn update_resizable(&mut self) { +        let is_resizable = self.controller.is_resizable(); +        self.window.set_resizable(is_resizable); +        // Hack to force window to be impossible to resize on DWM, where the +        // 'is_resizable' window attribute isn't respected. +        if !is_resizable { +            self.window.set_min_inner_size(Some(self.window.inner_size())); +            self.window.set_max_inner_size(Some(self.window.inner_size()));          }      } -    pub fn move_mouse(&mut self, position: Point) { -        if self.cursor_position != Some(position) { -            self.cursor_position = Some(position); -            self.controller.on_mouse_move(position); +    /// Resize the frame buffer to be the new size of the window. +    pub fn resize(&mut self, dimensions: Dimensions) { +        if self.dimensions == dimensions { return } +        self.dimensions = dimensions; +        self.buffer.resize(dimensions); +        if let Some((width, height)) = dim_to_nonzero_size(dimensions) { +            self.surface.resize(width, height).unwrap(); +        }; +        self.controller.on_resize(dimensions); +        self.current_render_hint = RenderHint::Redraw; +    } + +    pub fn move_cursor(&mut self, position: Point) { +        // The cursor position is rounded to i32 from f64, so we need to ignore +        // duplicate consecutive cursor positions. +        if self.previous_cursor_position != Some(position) { +            self.previous_cursor_position = Some(position); +            self.controller.on_cursor_move(position);          }      } -    pub fn check_render_request(&mut self) { +    pub fn handle_render_request(&mut self) {          if let RenderRequest::Render(hint) = self.controller.render_request() { -            self.render_hint &= hint; -            self.winit_window.request_redraw(); +            self.current_render_hint &= hint; +            self.window.request_redraw();          }      }      pub fn render(&mut self) { -        self.controller.render(&mut self.buffer, self.render_hint); -        unsafe { self.graphics_context.blit(&self.buffer); } -        // Reset the render_hint back to the lowest variant. -        self.render_hint = RenderHint::Update; +        let size = self.window.inner_size(); +        let dim = Dimensions::new(size.width, size.height); +        self.resize(dim); +        self.controller.on_render(&mut self.buffer, self.current_render_hint); +        let buffer = self.buffer.as_u32_slice(); +        let mut surface = self.surface.buffer_mut().unwrap(); +        let buffer_len = buffer.len(); +        let surface_len = surface.len(); +        surface[..buffer_len].copy_from_slice(&buffer[..surface_len]); +        surface.present().unwrap(); +        // Reset current_render_hint back to the lowest variant for the next frame. +        self.current_render_hint = RenderHint::Update;      } +} -    // pub fn render_gl(&mut self) { -    //     self.gl_context.make_current(); -    //     self.controller.render_gl(&mut self.gl_context); -    //     self.gl_context.swap_buffers(); -    //     self.gl_context.make_not_current(); -    // } +fn dim_to_size(dimensions: Dimensions) -> Size { +    Size::Physical( PhysicalSize { width:dimensions.width, height:dimensions.height })  } -trait GraphicsContext { -    /// Fill the graphics context with the contents of the provided buffer. -    unsafe fn blit(&mut self, buffer: &Buffer); +fn dim_to_nonzero_size(dimensions: Dimensions) -> Option<(NonZeroU32, NonZeroU32)> { +    let width = NonZeroU32::new(dimensions.width)?; +    let height = NonZeroU32::new(dimensions.height)?; +    return Some((width, height));  } diff --git a/src/window/x11.rs b/src/window/x11.rs deleted file mode 100644 index d4bcbe4..0000000 --- a/src/window/x11.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::window::GraphicsContext; -use buffer::Buffer; -use geometry::HasDimensions; -use raw_window_handle::XlibHandle; -use std::os::raw::{c_char, c_uint}; -use x11_dl::xlib::{Display, Visual, Xlib, ZPixmap, GC}; - -pub struct X11GraphicsContext { -    handle: XlibHandle, -    lib: Xlib, -    gc: GC, -    visual: *mut Visual, -    depth: i32, -} - -impl X11GraphicsContext { -    pub unsafe fn new(handle: XlibHandle) -> Self { -        let lib = match Xlib::open() { -            Ok(lib) => lib, -            Err(e) => panic!("{:?}", e), -        }; -        let screen = (lib.XDefaultScreen)(handle.display as *mut Display); -        let gc = (lib.XDefaultGC)(handle.display as *mut Display, screen); -        let visual = (lib.XDefaultVisual)(handle.display as *mut Display, screen); -        let depth = (lib.XDefaultDepth)(handle.display as *mut Display, screen); - -        Self { handle, lib, gc, visual, depth } -    } -} - -impl GraphicsContext for X11GraphicsContext { -    unsafe fn blit(&mut self, buffer: &Buffer) { -        let array = buffer.as_u32_slice(); -        let dimensions = buffer.dimensions(); -        //create image -        let image = (self.lib.XCreateImage)( -            self.handle.display as *mut Display, -            self.visual, -            self.depth as u32, -            ZPixmap, -            0, -            (array.as_ptr()) as *mut c_char, -            dimensions.width as u32, -            dimensions.height as u32, -            32, -            (dimensions.width * 4) as i32, -        ); - -        //push image to window -        (self.lib.XPutImage)( -            self.handle.display as *mut Display, -            self.handle.window, -            self.gc, -            image, -            0, -            0, -            0, -            0, -            dimensions.width as c_uint, -            dimensions.height as c_uint, -        ); - -        (*image).data = std::ptr::null_mut(); -        (self.lib.XDestroyImage)(image); -    } -} diff --git a/src/window_controller.rs b/src/window_controller.rs index d088b99..34f9fd4 100644 --- a/src/window_controller.rs +++ b/src/window_controller.rs @@ -1,42 +1,44 @@  use crate::*; -// use raw_gl_context::GlContext; -/// Controls a single window.  pub trait WindowController {      fn title(&self) -> String { String::from("Phosphor") } -    fn initial_dimensions(&self) -> Dimensions { Dimensions::new(800,600) } -    fn minimum_dimensions(&self) -> Option<Dimensions> { None } -    fn maximum_dimensions(&self) -> Option<Dimensions> { None } -    fn resizable(&self) -> bool { true } +    fn cursor_icon(&self) -> Option<CursorIcon> { None } +    fn initial_size(&self) -> Dimensions { Dimensions::new(800,600) } +    fn minimum_size(&self) -> Option<Dimensions> { None } +    fn maximum_size(&self) -> Option<Dimensions> { None } +    fn pixel_scale(&self) -> u32 { 1 } +    fn render_request(&self) -> RenderRequest { RenderRequest::None } -    fn cursor_icon(&mut self) -> Option<CursorIcon> { None } -    fn cursor_visible(&mut self) -> bool { true } +    fn is_visible(&self) -> bool { true } +    fn is_cursor_visible(&self) -> bool { true } +    fn is_resizable(&self) -> bool { true } -    fn on_resize(&mut self, _dimensions: Dimensions) {} +    fn on_init(&mut self) {} +    fn on_resize(&mut self, _size: Dimensions) {}      fn on_move(&mut self, _position: Point) {} -    fn on_focus_change(&mut self, _focused: bool) {} +    fn on_focus_change(&mut self, _is_focused: bool) {}      fn on_process(&mut self) {} +    fn on_render(&mut self, _buffer: &mut Buffer, _hint: RenderHint) {} +    fn on_close_request(&mut self) {} +    fn on_close(&mut self) {} -    fn on_mouse_enter(&mut self) {} -    fn on_mouse_exit(&mut self) {} -    fn on_mouse_move(&mut self, _position: Point) {} +    fn on_cursor_enter(&mut self) {} +    fn on_cursor_exit(&mut self) {} +    fn on_cursor_move(&mut self, _position: Point) {} -    fn on_left_mouse_button(&mut self, _pressed: PressState) {} -    fn on_middle_mouse_button(&mut self, _pressed: PressState) {} -    fn on_right_mouse_button(&mut self, _pressed: PressState) {} - -    fn on_keyboard_input(&mut self, _input: KeyboardInput) {} -    fn on_keyboard_modifier_change(&mut self, _modifiers: ModifiersState) {} -    fn on_character_received(&mut self, _character: char) {} -    fn on_file_hovered(&mut self, _path: std::path::PathBuf) {} -    fn on_file_dropped(&mut self, _path: std::path::PathBuf) {} +    fn on_left_mouse_button(&mut self, _action: Action) {} +    fn on_middle_mouse_button(&mut self, _action: Action) {} +    fn on_right_mouse_button(&mut self, _action: Action) {}      fn on_line_scroll_horizontal(&mut self, _delta: f64) {}      fn on_line_scroll_vertical(&mut self, _delta: f64) {}      fn on_pixel_scroll_horizontal(&mut self, _delta: f64) {}      fn on_pixel_scroll_vertical(&mut self, _delta: f64) {} -    fn render_request(&mut self) -> RenderRequest { RenderRequest::None } -    fn render(&mut self, _buffer: &mut Buffer, _hint: RenderHint) {} -    // fn render_gl(&mut self, _context: &mut GlContext) {} +    fn on_keyboard_input(&mut self, _input: KeyboardInput) {} +    fn on_keyboard_modifier_change(&mut self, _modifiers: ModifiersState) {} +    fn on_character_input(&mut self, _character: char) {} +    fn on_file_hover(&mut self, _path: std::path::PathBuf) {} +    fn on_file_hover_cancel(&mut self) {} +    fn on_file_drop(&mut self, _path: std::path::PathBuf) {}  } diff --git a/src/window_manager.rs b/src/window_manager.rs index 144f1c3..065d517 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -1,156 +1,134 @@  use crate::*; -use nosferatu::*; -  use std::collections::HashMap; -use winit::event::{Event, MouseButton, StartCause, WindowEvent, MouseScrollDelta}; -use winit::event_loop::EventLoop; -use winit::window::WindowId; +use std::time::Duration; +use winit::{event::*, event_loop::{EventLoop, ControlFlow}, window::WindowId}; -/// Controls the entire program. -pub struct WindowManager<P: ProgramController> { -    limiter: Option<FrameRateLimiter>, -    frame_timer: FrameTimer, +pub struct WindowManager {      event_loop: EventLoop<()>,      windows: HashMap<WindowId, Window>, -    program: P, -} - -impl WindowManager<DefaultProgramController> { -    pub fn without_program() -> Self { -        Self::with_program(DefaultProgramController {}) -    } +    min_frame_duration: Duration,  } -impl<P: 'static + ProgramController> WindowManager<P> { -    pub fn with_program(program: P) -> Self { +impl WindowManager { +    pub fn new(min_frame_duration: Duration) -> Self {          Self { -            limiter: None, -            frame_timer: FrameTimer::one_second(),              event_loop: EventLoop::new(),              windows: HashMap::new(), -            program, +            min_frame_duration,          }      } -    pub fn with_frame_limit(mut self, limit: usize) -> Self { -        self.limiter = Some(FrameRateLimiter::from_frame_rate(limit)); self -    } - -    /// Used to create one or more windows before the event loop starts. -    pub fn create_window(&mut self, controller: Box<dyn WindowController>) { -        let window = unsafe { Window::new(&self.event_loop, controller) }; +    /// Add a window to the window manager before the event loop begins. +    pub fn add_window(&mut self, controller: Box<dyn WindowController>) { +        let window = Window::new(&self.event_loop, controller);          self.windows.insert(window.id(), window);      } -    /// Starts the event loop, causing program control to be passed permanently to the window manager. +    /// Start the event loop, passing program control to the window manager.      pub fn run(mut self) -> ! { -        self.event_loop.run(move |event, window_target, control_flow| { -            control_flow.set_poll(); - +        self.event_loop.run(move |event, _window_target, control_flow| {              match event { -                // Event loop has just initialised (is only ever emitted once) -                Event::NewEvents(StartCause::Init) => self.program.initialise(), +                // Called when the event loop is first initialized. +                Event::NewEvents(StartCause::Init) => (), + +                Event::NewEvents(_) => { +                    control_flow.set_wait_timeout(self.min_frame_duration); +                } + +                // Called when an application suspends on a mobile platform. +                Event::Suspended => (), + +                // Called when an application resumes, or after initialization on non-mobile platforms. +                Event::Resumed => (),                  Event::WindowEvent { window_id, event } => {                      if let Some(window) = self.windows.get_mut(&window_id) {                          use WindowEvent::*; +                          match event { -                            Resized(dim) => window.resize_buffer(Dimensions::new(dim.width, dim.height)), -                            Moved(p) => window.controller.on_move(Point::new(p.x, p.y)), -                            Focused(state) => window.controller.on_focus_change(state), +                            Resized(dim) => window.resize(Dimensions::new(dim.width, dim.height)), +                            Moved(position) => window.controller.on_move(Point::new(position.x, position.y)), +                            Focused(is_focused) => window.controller.on_focus_change(is_focused), -                            CursorEntered { .. } => window.controller.on_mouse_enter(), -                            CursorLeft { .. } => window.controller.on_mouse_exit(), -                            CursorMoved { position, .. } => { -                                let point = Point::new(position.x as i32, position.y as i32); -                                window.move_mouse(point); -                            } -                            MouseWheel {delta, ..} => { -                                match delta { -                                    MouseScrollDelta::LineDelta(x, y) => { -                                        let (x, y) = (x as f64, y as f64); -                                        if x != 0.0 {window.controller.on_line_scroll_horizontal(x)} -                                        if y != 0.0 {window.controller.on_line_scroll_vertical(y)} -                                    } -                                    MouseScrollDelta::PixelDelta(point) => { -                                        let (x, y) = (point.x, point.y); -                                        if x != 0.0 {window.controller.on_pixel_scroll_horizontal(x)} -                                        if y != 0.0 {window.controller.on_pixel_scroll_vertical(y)} -                                    } +                            CursorEntered { .. } => window.controller.on_cursor_enter(), +                            CursorLeft { .. } => window.controller.on_cursor_exit(), +                            CursorMoved { position: p, .. } => { window.move_cursor(Point::new(p.x as i32, p.y as i32)) } + +                            MouseWheel {delta, ..} => match delta { +                                MouseScrollDelta::LineDelta(x, y) => { +                                    let (x, y) = (x as f64, y as f64); +                                    if x != 0.0 {window.controller.on_line_scroll_horizontal(x)} +                                    if y != 0.0 {window.controller.on_line_scroll_vertical(y)}                                  } -                            }, -                            MouseInput { state, button, .. } => { -                                match button { -                                    MouseButton::Left => window.controller.on_left_mouse_button(state.into()), -                                    MouseButton::Middle => window.controller.on_middle_mouse_button(state.into()), -                                    MouseButton::Right => window.controller.on_right_mouse_button(state.into()), -                                    _ => (), +                                MouseScrollDelta::PixelDelta(point) => { +                                    let (x, y) = (point.x, point.y); +                                    if x != 0.0 {window.controller.on_pixel_scroll_horizontal(x)} +                                    if y != 0.0 {window.controller.on_pixel_scroll_vertical(y)}                                  } -                                window.bump_mouse(); - +                            } +                            MouseInput { state, button, .. } => match button { +                                MouseButton::Left => window.controller.on_left_mouse_button(state.into()), +                                MouseButton::Middle => window.controller.on_middle_mouse_button(state.into()), +                                MouseButton::Right => window.controller.on_right_mouse_button(state.into()), +                                MouseButton::Other(_) => (),                              } -                            KeyboardInput { input, .. } => window.controller.on_keyboard_input(input.into()), +                            KeyboardInput { input, .. } => if let Ok(input) = input.try_into() { window.controller.on_keyboard_input(input)},                              ModifiersChanged(state) => window.controller.on_keyboard_modifier_change(state), -                            ReceivedCharacter(c) => window.controller.on_character_received(c), -                            HoveredFile(path) => window.controller.on_file_hovered(path), -                            DroppedFile(path) => window.controller.on_file_dropped(path), +                            ReceivedCharacter(character) => window.controller.on_character_input(character), +                            HoveredFile(path) => window.controller.on_file_hover(path), +                            HoveredFileCancelled => window.controller.on_file_hover_cancel(), +                            DroppedFile(path) => window.controller.on_file_drop(path), -                            // Tell the window, and let it raise its own event to close itself -                            // When all windows are closed: control_flow.set_exit_with_code(0); -                            CloseRequested => todo!("window.controller.on_close_requested()"), -                            _ => (), +                            CloseRequested => { +                                window.controller.on_close_request(); +                                *control_flow = ControlFlow::Exit; +                            }, +                            Destroyed => window.controller.on_close(), + +                            Ime(_) => (), +                            AxisMotion { .. } => (), +                            Touch(_) => (), +                            TouchpadRotate { .. } => (), +                            TouchpadPressure { .. } => (), +                            TouchpadMagnify { .. } => (), +                            SmartMagnify { .. } => (), +                            ScaleFactorChanged { .. } => (), +                            ThemeChanged(_) => (), +                            Occluded(_) => (),                          }                      }                  } -                // Called each loop before any rendering would begin. +                // Called before any render events are called.                  Event::MainEventsCleared => { -                    self.frame_timer.tick(); -                    // println!("{}", self.frame_timer.frame_rate()); - -                    self.program.on_process(&mut |controller: Box<dyn WindowController>| { -                        let window = unsafe { Window::new(window_target, controller) }; -                        self.windows.insert(window.id(), window); -                    });                      for window in self.windows.values_mut() {                          window.controller.on_process(); -                        let cursor_icon = window.controller.cursor_icon(); -                        window.set_cursor_icon(cursor_icon); -                        // let resizable = window.controller.resizable(); -                        // window.set_resizable(resizable); -                        // let cursor_visible = window.controller.cursor_visible(); -                        // window.set_cursor_visible(cursor_visible); -                        window.check_render_request(); -                        let title = window.controller.title(); -                        window.set_title(&title); -                        let minimum_dimensions = window.controller.minimum_dimensions(); -                        window.set_minimum_dimensions(minimum_dimensions); -                        let maximum_dimensions = window.controller.maximum_dimensions(); -                        window.set_maximum_dimensions(maximum_dimensions); +                        window.update_title(); +                        window.update_minimum_size(); +                        window.update_maximum_size(); +                        window.update_resizable(); +                        window.update_cursor_icon(); +                        window.update_cursor_visible(); +                        window.handle_render_request();                      }                  } -                // Called if a render was requested for a window + +                // Called if a window has requested to be rendered.                  Event::RedrawRequested(window_id) => {                      if let Some(window) = self.windows.get_mut(&window_id) {                          window.render();                      }                  } -                // Called after rendering has completed -                Event::RedrawEventsCleared => { -                    if let Some(limiter) = &mut self.limiter { -                        limiter.tick(); -                    } -                } -                _other => {} // todo!("{:?}", other), +                // Called after all rendering has completed, or if there were no render requests. +                Event::RedrawEventsCleared => (), + +                // Called before the program closes. +                Event::LoopDestroyed => (), + +                _ => (),              }          })      }  } - -impl Default for WindowManager<DefaultProgramController> { -    fn default() -> Self { -        Self::without_program() -    } -} | 
