summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock718
-rw-r--r--Cargo.toml17
-rw-r--r--src/bin/fragment.frag7
-rw-r--r--src/bin/phosphor_test.rs89
-rw-r--r--src/bin/vertex.vert9
-rw-r--r--src/keyboard_input.rs19
-rw-r--r--src/lib.rs29
-rw-r--r--src/press_state.rs26
-rw-r--r--src/program_controller.rs13
-rw-r--r--src/render_hint.rs33
-rw-r--r--src/render_request.rs40
-rw-r--r--src/window.rs136
-rw-r--r--src/window/x11.rs66
-rw-r--r--src/window_controller.rs42
-rw-r--r--src/window_manager.rs156
16 files changed, 1401 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..b7543fc
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,718 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "android-activity"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64529721f27c2314ced0890ce45e469574a73e5e6fdd6e9da1860eb29285f5e0"
+dependencies = [
+ "android-properties",
+ "bitflags",
+ "cc",
+ "jni-sys",
+ "libc",
+ "log",
+ "ndk",
+ "ndk-context",
+ "ndk-sys",
+ "num_enum 0.6.1",
+]
+
+[[package]]
+name = "android-properties"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "block-sys"
+version = "0.1.0-beta.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146"
+dependencies = [
+ "objc-sys",
+]
+
+[[package]]
+name = "block2"
+version = "0.2.0-alpha.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42"
+dependencies = [
+ "block-sys",
+ "objc2-encode",
+]
+
+[[package]]
+name = "buffer"
+version = "0.1.0"
+dependencies = [
+ "colour",
+ "geometry",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
+
+[[package]]
+name = "cc"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "jobserver",
+ "libc",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
+[[package]]
+name = "colour"
+version = "1.0.0"
+dependencies = [
+ "proportion",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
+
+[[package]]
+name = "core-graphics"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-graphics-types",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "dispatch"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "geometry"
+version = "0.1.0"
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
+
+[[package]]
+name = "jobserver"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.135"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
+
+[[package]]
+name = "log"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.36.1",
+]
+
+[[package]]
+name = "ndk"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
+dependencies = [
+ "bitflags",
+ "jni-sys",
+ "ndk-sys",
+ "num_enum 0.5.7",
+ "raw-window-handle",
+ "thiserror",
+]
+
+[[package]]
+name = "ndk-context"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
+
+[[package]]
+name = "ndk-sys"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21d83ec9c63ec5bf950200a8e508bdad6659972187b625469f58ef8c08e29046"
+dependencies = [
+ "jni-sys",
+]
+
+[[package]]
+name = "nosferatu"
+version = "0.1.0"
+
+[[package]]
+name = "num_enum"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
+dependencies = [
+ "num_enum_derive 0.5.7",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1"
+dependencies = [
+ "num_enum_derive 0.6.1",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.102",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.32",
+]
+
+[[package]]
+name = "objc-sys"
+version = "0.2.0-beta.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7"
+
+[[package]]
+name = "objc2"
+version = "0.3.0-beta.3.patch-leaks.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468"
+dependencies = [
+ "block2",
+ "objc-sys",
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "2.0.0-pre.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512"
+dependencies = [
+ "objc-sys",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
+
+[[package]]
+name = "orbclient"
+version = "0.3.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8378ac0dfbd4e7895f2d2c1f1345cab3836910baf3a300b000d04250f0c8428f"
+dependencies = [
+ "redox_syscall",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
+
+[[package]]
+name = "phosphor"
+version = "0.1.0"
+dependencies = [
+ "buffer",
+ "geometry",
+ "nosferatu",
+ "raw-window-handle",
+ "winit",
+ "x11-dl",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
+
+[[package]]
+name = "proc-macro-crate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
+dependencies = [
+ "once_cell",
+ "thiserror",
+ "toml",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "proportion"
+version = "1.0.0"
+
+[[package]]
+name = "quote"
+version = "1.0.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "raw-window-handle"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
+
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.145"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
+
+[[package]]
+name = "syn"
+version = "1.0.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.102",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.102",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.102",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+
+[[package]]
+name = "wayland-scanner"
+version = "0.29.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "xml-rs",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+dependencies = [
+ "windows_aarch64_msvc 0.36.1",
+ "windows_i686_gnu 0.36.1",
+ "windows_i686_msvc 0.36.1",
+ "windows_x86_64_gnu 0.36.1",
+ "windows_x86_64_msvc 0.36.1",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "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_msvc 0.42.2",
+]
+
+[[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_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[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_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "winit"
+version = "0.28.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9596d90b45384f5281384ab204224876e8e8bf7d58366d9b795ad99aa9894b94"
+dependencies = [
+ "android-activity",
+ "bitflags",
+ "cfg_aliases",
+ "core-foundation",
+ "core-graphics",
+ "dispatch",
+ "instant",
+ "libc",
+ "log",
+ "mio",
+ "ndk",
+ "objc2",
+ "once_cell",
+ "orbclient",
+ "percent-encoding",
+ "raw-window-handle",
+ "redox_syscall",
+ "wasm-bindgen",
+ "wayland-scanner",
+ "web-sys",
+ "windows-sys 0.45.0",
+ "x11-dl",
+]
+
+[[package]]
+name = "x11-dl"
+version = "2.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c83627bc137605acc00bb399c7b908ef460b621fc37c953db2b09f88c449ea6"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "xml-rs"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..1aac11d
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "phosphor"
+version = "0.1.0"
+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" }
diff --git a/src/bin/fragment.frag b/src/bin/fragment.frag
new file mode 100644
index 0000000..99826f6
--- /dev/null
+++ b/src/bin/fragment.frag
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 0000000..40a8558
--- /dev/null
+++ b/src/bin/phosphor_test.rs
@@ -0,0 +1,89 @@
+#![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());
+ 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 {})
+ }
+}
+impl WindowController for MainWindow {
+ fn render(&mut self, buffer: &mut Buffer, _: RenderHint) {
+ println!("Rendering...");
+ buffer.fill(Colour::TEAL);
+ }
+
+ // 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])
+// ];
+
+// 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 }
+// }
+
+// pub unsafe fn bind(&self) {
+// gl::BindBuffer(self.target, self.id);
+// }
+
+// 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,
+// );
+// }
+// }
+
+// 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
new file mode 100644
index 0000000..0fd4f8a
--- /dev/null
+++ b/src/bin/vertex.vert
@@ -0,0 +1,9 @@
+#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
new file mode 100644
index 0000000..139db7e
--- /dev/null
+++ b/src/keyboard_input.rs
@@ -0,0 +1,19 @@
+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,
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..75aaa1b
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,29 @@
+mod keyboard_input;
+mod press_state;
+mod program_controller;
+mod render_hint;
+mod render_request;
+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 buffer::{Buffer, Colour};
+pub use winit::{
+ event::ModifiersState,
+ event::VirtualKeyCode as KeyCode,
+ window::CursorIcon,
+};
+
+pub type Point = geometry::Point<i32>;
+pub type Dimensions = geometry::Dimensions<u32>;
+pub type Rect = geometry::Rect<i32, u32>;
diff --git a/src/press_state.rs b/src/press_state.rs
new file mode 100644
index 0000000..5136d66
--- /dev/null
+++ b/src/press_state.rs
@@ -0,0 +1,26 @@
+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
new file mode 100644
index 0000000..638e5ce
--- /dev/null
+++ b/src/program_controller.rs
@@ -0,0 +1,13 @@
+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_hint.rs b/src/render_hint.rs
new file mode 100644
index 0000000..e4d37c3
--- /dev/null
+++ b/src/render_hint.rs
@@ -0,0 +1,33 @@
+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
new file mode 100644
index 0000000..f336dfc
--- /dev/null
+++ b/src/render_request.rs
@@ -0,0 +1,40 @@
+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
new file mode 100644
index 0000000..45e37c9
--- /dev/null
+++ b/src/window.rs
@@ -0,0 +1,136 @@
+mod x11;
+use crate::*;
+use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
+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};
+
+pub struct Window {
+ pub controller: Box<dyn WindowController>,
+ cursor_position: Option<Point>,
+ winit_window: WinitWindow,
+ buffer: Buffer,
+ dimensions: Dimensions,
+ /// The most recent render request for this window.
+ render_hint: RenderHint,
+ graphics_context: Box<dyn GraphicsContext>,
+ // gl_context: GlContext,
+}
+
+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();
+
+ 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,
+ buffer: Buffer::new(Dimensions::ZERO),
+ dimensions: Dimensions::ZERO,
+ cursor_position: None,
+ }
+ }
+
+ pub fn id(&self) -> WindowId {
+ self.winit_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 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 set_title(&mut self, title: &str) {
+ self.winit_window.set_title(title);
+ }
+
+ /// 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 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),
+ };
+ }
+
+ /// 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 move_mouse(&mut self, position: Point) {
+ if self.cursor_position != Some(position) {
+ self.cursor_position = Some(position);
+ self.controller.on_mouse_move(position);
+ }
+ }
+
+ pub fn check_render_request(&mut self) {
+ if let RenderRequest::Render(hint) = self.controller.render_request() {
+ self.render_hint &= hint;
+ self.winit_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;
+ }
+
+ // 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();
+ // }
+}
+
+trait GraphicsContext {
+ /// Fill the graphics context with the contents of the provided buffer.
+ unsafe fn blit(&mut self, buffer: &Buffer);
+}
diff --git a/src/window/x11.rs b/src/window/x11.rs
new file mode 100644
index 0000000..d4bcbe4
--- /dev/null
+++ b/src/window/x11.rs
@@ -0,0 +1,66 @@
+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
new file mode 100644
index 0000000..d088b99
--- /dev/null
+++ b/src/window_controller.rs
@@ -0,0 +1,42 @@
+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(&mut self) -> Option<CursorIcon> { None }
+ fn cursor_visible(&mut self) -> bool { true }
+
+ fn on_resize(&mut self, _dimensions: Dimensions) {}
+ fn on_move(&mut self, _position: Point) {}
+ fn on_focus_change(&mut self, _focused: bool) {}
+ fn on_process(&mut self) {}
+
+ fn on_mouse_enter(&mut self) {}
+ fn on_mouse_exit(&mut self) {}
+ fn on_mouse_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_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) {}
+}
diff --git a/src/window_manager.rs b/src/window_manager.rs
new file mode 100644
index 0000000..144f1c3
--- /dev/null
+++ b/src/window_manager.rs
@@ -0,0 +1,156 @@
+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;
+
+/// Controls the entire program.
+pub struct WindowManager<P: ProgramController> {
+ limiter: Option<FrameRateLimiter>,
+ frame_timer: FrameTimer,
+ event_loop: EventLoop<()>,
+ windows: HashMap<WindowId, Window>,
+ program: P,
+}
+
+impl WindowManager<DefaultProgramController> {
+ pub fn without_program() -> Self {
+ Self::with_program(DefaultProgramController {})
+ }
+}
+
+impl<P: 'static + ProgramController> WindowManager<P> {
+ pub fn with_program(program: P) -> Self {
+ Self {
+ limiter: None,
+ frame_timer: FrameTimer::one_second(),
+ event_loop: EventLoop::new(),
+ windows: HashMap::new(),
+ program,
+ }
+ }
+
+ 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) };
+ self.windows.insert(window.id(), window);
+ }
+
+ /// Starts the event loop, causing program control to be passed permanently to the window manager.
+ pub fn run(mut self) -> ! {
+ self.event_loop.run(move |event, window_target, control_flow| {
+ control_flow.set_poll();
+
+ match event {
+ // Event loop has just initialised (is only ever emitted once)
+ Event::NewEvents(StartCause::Init) => self.program.initialise(),
+
+ 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),
+
+ 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)}
+ }
+ }
+ },
+ 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()),
+ _ => (),
+ }
+ window.bump_mouse();
+
+ }
+
+ KeyboardInput { input, .. } => window.controller.on_keyboard_input(input.into()),
+ 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),
+
+ // 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()"),
+ _ => (),
+ }
+ }
+ }
+
+ // Called each loop before any rendering would begin.
+ 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);
+ }
+ }
+ // Called if a render was requested for a window
+ 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),
+ }
+ })
+ }
+}
+
+impl Default for WindowManager<DefaultProgramController> {
+ fn default() -> Self {
+ Self::without_program()
+ }
+}