mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 13:51:30 +11:00
Redox OS support (#2588)
* Add Redox OS support * Simplify control flow usage * Apply more recommendations * Update naming to indicate that Orbital is a platform * Adjust import order
This commit is contained in:
parent
2f52c23fa9
commit
66ca445caa
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
|
@ -35,3 +35,7 @@
|
|||
# Windows
|
||||
/src/platform/windows.rs @msiglreith
|
||||
/src/platform_impl/windows @msiglreith
|
||||
|
||||
# Orbital (Redox OS)
|
||||
/src/platform/orbital.rs @jackpot51
|
||||
/src/platform_impl/orbital @jackpot51
|
||||
|
|
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
|
@ -34,6 +34,7 @@ jobs:
|
|||
- { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, options: --no-default-features, features: x11 }
|
||||
- { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, options: --no-default-features, features: "wayland,wayland-dlopen" }
|
||||
- { target: aarch64-linux-android, os: ubuntu-latest, options: -p winit, cmd: 'apk --', features: "android-native-activity" }
|
||||
- { target: x86_64-unknown-redox, os: ubuntu-latest, }
|
||||
- { target: x86_64-apple-darwin, os: macos-latest, }
|
||||
- { target: x86_64-apple-ios, os: macos-latest, }
|
||||
- { target: aarch64-apple-ios, os: macos-latest, }
|
||||
|
@ -83,7 +84,9 @@ jobs:
|
|||
|
||||
- name: Build tests
|
||||
shell: bash
|
||||
if: matrix.rust_version != '1.60.0'
|
||||
if: >
|
||||
!contains(matrix.platform.target, 'redox') &&
|
||||
matrix.rust_version != '1.60.0'
|
||||
run: cargo $CMD test --no-run --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES
|
||||
|
||||
- name: Run tests
|
||||
|
@ -92,6 +95,7 @@ jobs:
|
|||
!contains(matrix.platform.target, 'android') &&
|
||||
!contains(matrix.platform.target, 'ios') &&
|
||||
!contains(matrix.platform.target, 'wasm32') &&
|
||||
!contains(matrix.platform.target, 'redox') &&
|
||||
matrix.rust_version != '1.60.0'
|
||||
run: cargo $CMD test --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES
|
||||
|
||||
|
@ -102,7 +106,9 @@ jobs:
|
|||
|
||||
- name: Build tests with serde enabled
|
||||
shell: bash
|
||||
if: matrix.rust_version != '1.60.0'
|
||||
if: >
|
||||
!contains(matrix.platform.target, 'redox') &&
|
||||
matrix.rust_version != '1.60.0'
|
||||
run: cargo $CMD test --no-run --verbose --target ${{ matrix.platform.target }} $OPTIONS --features serde,$FEATURES
|
||||
- name: Run tests with serde enabled
|
||||
shell: bash
|
||||
|
@ -110,5 +116,6 @@ jobs:
|
|||
!contains(matrix.platform.target, 'android') &&
|
||||
!contains(matrix.platform.target, 'ios') &&
|
||||
!contains(matrix.platform.target, 'wasm32') &&
|
||||
!contains(matrix.platform.target, 'redox') &&
|
||||
matrix.rust_version != '1.60.0'
|
||||
run: cargo $CMD test --verbose --target ${{ matrix.platform.target }} $OPTIONS --features serde,$FEATURES
|
||||
|
|
|
@ -50,6 +50,7 @@ And please only add new entries to the top of this list, right below the `# Unre
|
|||
- **Breaking:** On Android, switched to using [`android-activity`](https://github.com/rib/android-activity) crate as a glue layer instead of [`ndk-glue`](https://github.com/rust-windowing/android-ndk-rs/tree/master/ndk-glue). See [README.md#Android](https://github.com/rust-windowing/winit#Android) for more details. ([#2444](https://github.com/rust-windowing/winit/pull/2444))
|
||||
- **Breaking:** Removed support for `raw-window-handle` version `0.4`
|
||||
- On Wayland, `RedrawRequested` not emitted during resize.
|
||||
- Added Orbital support for Redox OS
|
||||
|
||||
# 0.27.5
|
||||
|
||||
|
|
|
@ -113,6 +113,10 @@ x11-dl = { version = "2.18.5", optional = true }
|
|||
percent-encoding = { version = "2.0", optional = true }
|
||||
libc = "0.2.64"
|
||||
|
||||
[target.'cfg(target_os = "redox")'.dependencies]
|
||||
orbclient = { version = "0.3.42", default-features = false }
|
||||
redox_syscall = "0.3"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.web_sys]
|
||||
package = "web-sys"
|
||||
version = "0.3.22"
|
||||
|
|
93
FEATURES.md
93
FEATURES.md
|
@ -8,6 +8,7 @@ be used to create both games and applications. It supports the main graphical pl
|
|||
- Unix
|
||||
- via X11
|
||||
- via Wayland
|
||||
- Redox OS, via Orbital
|
||||
- Mobile
|
||||
- iOS
|
||||
- Android
|
||||
|
@ -171,62 +172,62 @@ Legend:
|
|||
- ❓: Unknown status
|
||||
|
||||
### Windowing
|
||||
|Feature |Windows|MacOS |Linux x11 |Linux Wayland |Android|iOS |WASM |
|
||||
|-------------------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||
|Window initialization |✔️ |✔️ |▢[#5] |✔️ |▢[#33]|▢[#33] |✔️ |
|
||||
|Providing pointer to init OpenGL |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|
|
||||
|Providing pointer to init Vulkan |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |**N/A**|
|
||||
|Window decorations |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
||||
|Window decorations toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
||||
|Window resizing |✔️ |▢[#219]|✔️ |▢[#306] |**N/A**|**N/A**|✔️ |
|
||||
|Window resize increments |❌ |✔️ |✔️ |❌ |**N/A**|**N/A**|**N/A**|
|
||||
|Window transparency |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|N/A |
|
||||
|Window maximization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
||||
|Window maximization toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
||||
|Window minimization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|
||||
|Fullscreen |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |
|
||||
|Fullscreen toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |
|
||||
|Exclusive fullscreen |✔️ |✔️ |✔️ |**N/A** |❌ |✔️ |**N/A**|
|
||||
|HiDPI support |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |
|
||||
|Popup windows |❌ |❌ |❌ |❌ |❌ |❌ |**N/A**|
|
||||
|Feature |Windows|MacOS |Linux x11 |Linux Wayland |Android|iOS |WASM |Redox OS|
|
||||
|-------------------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | ------ |
|
||||
|Window initialization |✔️ |✔️ |▢[#5] |✔️ |▢[#33]|▢[#33] |✔️ |✔️ |
|
||||
|Providing pointer to init OpenGL |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |
|
||||
|Providing pointer to init Vulkan |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |**N/A**|**N/A** |
|
||||
|Window decorations |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|✔️ |
|
||||
|Window decorations toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|Window resizing |✔️ |▢[#219]|✔️ |▢[#306] |**N/A**|**N/A**|✔️ |✔️ |
|
||||
|Window resize increments |❌ |✔️ |✔️ |❌ |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|Window transparency |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|N/A |✔️ |
|
||||
|Window maximization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|Window maximization toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|Window minimization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|Fullscreen |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |**N/A** |
|
||||
|Fullscreen toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |**N/A** |
|
||||
|Exclusive fullscreen |✔️ |✔️ |✔️ |**N/A** |❌ |✔️ |**N/A**|**N/A** |
|
||||
|HiDPI support |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |❌ |
|
||||
|Popup windows |❌ |❌ |❌ |❌ |❌ |❌ |**N/A**|**N/A** |
|
||||
|
||||
### System information
|
||||
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |
|
||||
|---------------- | ----- | ---- | ------- | ----------- | ----- | ------- | -------- |
|
||||
|Monitor list |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|
|
||||
|Video mode query |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|
|
||||
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
|
||||
|---------------- | ----- | ---- | ------- | ----------- | ----- | ------- | -------- | ------ |
|
||||
|Monitor list |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|❌ |
|
||||
|Video mode query |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|❌ |
|
||||
|
||||
### Input handling
|
||||
|Feature |Windows |MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |
|
||||
|----------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||
|Mouse events |✔️ |▢[#63] |✔️ |✔️ |**N/A**|**N/A**|✔️ |
|
||||
|Mouse set location |✔️ |✔️ |✔️ |✔️(when locked) |**N/A**|**N/A**|**N/A**|
|
||||
|Cursor locking |❌ |✔️ |❌ |✔️ |**N/A**|**N/A**|✔️ |
|
||||
|Cursor confining |✔️ |❌ |✔️ |✔️ |**N/A**|**N/A**|❌ |
|
||||
|Cursor icon |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|✔️ |
|
||||
|Cursor hittest |✔️ |✔️ |❌ |✔️ |**N/A**|**N/A**|❌ |
|
||||
|Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |️✔️ |
|
||||
|Touch pressure |✔️ |❌ |❌ |❌ |❌ |✔️ |️✔️ |
|
||||
|Multitouch |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |❌ |
|
||||
|Keyboard events |✔️ |✔️ |✔️ |✔️ |✔️ |❌ |✔️ |
|
||||
|Drag & Drop |▢[#720] |▢[#720] |▢[#720] |❌[#306] |**N/A**|**N/A**|❓ |
|
||||
|Raw Device Events |▢[#750] |▢[#750] |▢[#750] |❌ |❌ |❌ |❓ |
|
||||
|Gamepad/Joystick events |❌[#804] |❌ |❌ |❌ |❌ |❌ |❓ |
|
||||
|Device movement events |❓ |❓ |❓ |❓ |❌ |❌ |❓ |
|
||||
|Drag window with cursor |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A** |
|
||||
|Feature |Windows |MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
|
||||
|----------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | ------ |
|
||||
|Mouse events |✔️ |▢[#63] |✔️ |✔️ |**N/A**|**N/A**|✔️ |✔️ |
|
||||
|Mouse set location |✔️ |✔️ |✔️ |✔️(when locked) |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|Cursor locking |❌ |✔️ |❌ |✔️ |**N/A**|**N/A**|✔️ |❌ |
|
||||
|Cursor confining |✔️ |❌ |✔️ |✔️ |**N/A**|**N/A**|❌ |❌ |
|
||||
|Cursor icon |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|✔️ |**N/A** |
|
||||
|Cursor hittest |✔️ |✔️ |❌ |✔️ |**N/A**|**N/A**|❌ |❌ |
|
||||
|Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A** |
|
||||
|Touch pressure |✔️ |❌ |❌ |❌ |❌ |✔️ |✔️ |**N/A** |
|
||||
|Multitouch |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |❌ |**N/A** |
|
||||
|Keyboard events |✔️ |✔️ |✔️ |✔️ |✔️ |❌ |✔️ |✔️ |
|
||||
|Drag & Drop |▢[#720] |▢[#720] |▢[#720] |❌[#306] |**N/A**|**N/A**|❓ |**N/A** |
|
||||
|Raw Device Events |▢[#750] |▢[#750] |▢[#750] |❌ |❌ |❌ |❓ |**N/A** |
|
||||
|Gamepad/Joystick events |❌[#804] |❌ |❌ |❌ |❌ |❌ |❓ |**N/A** |
|
||||
|Device movement events |❓ |❓ |❓ |❓ |❌ |❌ |❓ |**N/A** |
|
||||
|Drag window with cursor |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A** |**N/A** |
|
||||
|
||||
### Pending API Reworks
|
||||
Changes in the API that have been agreed upon but aren't implemented across all platforms.
|
||||
|
||||
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |
|
||||
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||
|New API for HiDPI ([#315] [#319]) |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |
|
||||
|Event Loop 2.0 ([#459]) |✔️ |✔️ |❌ |✔️ |✔️ |✔️ |❓ |
|
||||
|Keyboard Input ([#812]) |❌ |❌ |❌ |❌ |❌ |❌ |❓ |
|
||||
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
|
||||
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | ------ |
|
||||
|New API for HiDPI ([#315] [#319]) |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |❓ |
|
||||
|Event Loop 2.0 ([#459]) |✔️ |✔️ |❌ |✔️ |✔️ |✔️ |❓ |❓ |
|
||||
|Keyboard Input ([#812]) |❌ |❌ |❌ |❌ |❌ |❌ |❓ |❓ |
|
||||
|
||||
### Completed API Reworks
|
||||
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |
|
||||
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
|
||||
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | ------ |
|
||||
|
||||
[#165]: https://github.com/rust-windowing/winit/issues/165
|
||||
[#219]: https://github.com/rust-windowing/winit/issues/219
|
||||
|
|
|
@ -209,3 +209,8 @@ inside `Event::NewEvents(StartCause::Init)`.
|
|||
[#2051]: https://github.com/rust-windowing/winit/issues/2051
|
||||
[#2087]: https://github.com/rust-windowing/winit/issues/2087
|
||||
[#1705]: https://github.com/rust-windowing/winit/issues/1705
|
||||
|
||||
#### Redox OS
|
||||
|
||||
Redox OS has some functionality not present yet, that will be implemented when
|
||||
its orbital display server provides it.
|
||||
|
|
6
build.rs
6
build.rs
|
@ -13,9 +13,11 @@ fn main() {
|
|||
windows_platform: { target_os = "windows" },
|
||||
apple: { any(target_os = "ios", target_os = "macos") },
|
||||
free_unix: { all(unix, not(apple), not(android_platform)) },
|
||||
redox: { target_os = "redox" },
|
||||
|
||||
// Native displays.
|
||||
x11_platform: { all(feature = "x11", free_unix, not(wasm)) },
|
||||
wayland_platform: { all(feature = "wayland", free_unix, not(wasm)) },
|
||||
x11_platform: { all(feature = "x11", free_unix, not(wasm), not(redox)) },
|
||||
wayland_platform: { all(feature = "wayland", free_unix, not(wasm), not(redox)) },
|
||||
orbital_platform: { redox },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
macos_platform,
|
||||
x11_platform,
|
||||
wayland_platform,
|
||||
android_platform
|
||||
android_platform,
|
||||
orbital_platform,
|
||||
))]
|
||||
fn main() {
|
||||
use std::{thread::sleep, time::Duration};
|
||||
|
|
|
@ -391,7 +391,7 @@ pub enum WindowEvent<'a> {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
Ime(Ime),
|
||||
|
||||
/// The cursor has moved on the window.
|
||||
|
@ -508,7 +508,7 @@ pub enum WindowEvent<'a> {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / X11 / Wayland:** Unsupported.
|
||||
/// - **iOS / Android / X11 / Wayland / Orbital:** Unsupported.
|
||||
ThemeChanged(Theme),
|
||||
|
||||
/// The window has been occluded (completely hidden from view).
|
||||
|
@ -517,7 +517,7 @@ pub enum WindowEvent<'a> {
|
|||
/// minimised, set invisible, or fully occluded by another window.
|
||||
///
|
||||
/// Platform-specific behavior:
|
||||
/// - **iOS / Android / Web / Wayland / Windows:** Unsupported.
|
||||
/// - **iOS / Android / Web / Wayland / Windows / Orbital:** Unsupported.
|
||||
Occluded(bool),
|
||||
}
|
||||
|
||||
|
|
|
@ -335,7 +335,7 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Wayland / macOS / iOS / Android / Web:** Unsupported.
|
||||
/// - **Wayland / macOS / iOS / Android / Web / Orbital:** Unsupported.
|
||||
///
|
||||
/// [`DeviceEvent`]: crate::event::DeviceEvent
|
||||
pub fn set_device_event_filter(&self, _filter: DeviceEventFilter) {
|
||||
|
|
|
@ -61,7 +61,7 @@ impl VideoMode {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Wayland:** Always returns 32.
|
||||
/// - **Wayland / Orbital:** Always returns 32.
|
||||
/// - **iOS:** Always returns 32.
|
||||
#[inline]
|
||||
pub fn bit_depth(&self) -> u16 {
|
||||
|
|
|
@ -21,6 +21,8 @@ pub mod android;
|
|||
pub mod ios;
|
||||
#[cfg(macos_platform)]
|
||||
pub mod macos;
|
||||
#[cfg(orbital_platform)]
|
||||
pub mod orbital;
|
||||
#[cfg(wayland_platform)]
|
||||
pub mod wayland;
|
||||
#[cfg(wasm_platform)]
|
||||
|
@ -35,6 +37,7 @@ pub mod x11;
|
|||
macos_platform,
|
||||
android_platform,
|
||||
x11_platform,
|
||||
wayland_platform
|
||||
wayland_platform,
|
||||
orbital_platform
|
||||
))]
|
||||
pub mod run_return;
|
||||
|
|
1
src/platform/orbital.rs
Normal file
1
src/platform/orbital.rs
Normal file
|
@ -0,0 +1 @@
|
|||
// There are no Orbital specific traits yet.
|
|
@ -19,6 +19,9 @@ mod platform;
|
|||
#[cfg(wasm_platform)]
|
||||
#[path = "web/mod.rs"]
|
||||
mod platform;
|
||||
#[cfg(orbital_platform)]
|
||||
#[path = "orbital/mod.rs"]
|
||||
mod platform;
|
||||
|
||||
pub use self::platform::*;
|
||||
|
||||
|
@ -59,5 +62,6 @@ impl From<Fullscreen> for RootFullscreen {
|
|||
not(x11_platform),
|
||||
not(wayland_platform),
|
||||
not(wasm_platform),
|
||||
not(orbital_platform),
|
||||
))]
|
||||
compile_error!("The platform you're compiling for is not supported by winit");
|
||||
|
|
709
src/platform_impl/orbital/event_loop.rs
Normal file
709
src/platform_impl/orbital/event_loop.rs
Normal file
|
@ -0,0 +1,709 @@
|
|||
use std::{
|
||||
collections::VecDeque,
|
||||
mem, slice,
|
||||
sync::{mpsc, Arc, Mutex},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use orbclient::{
|
||||
ButtonEvent, EventOption, FocusEvent, HoverEvent, KeyEvent, MouseEvent, MoveEvent, QuitEvent,
|
||||
ResizeEvent, ScrollEvent, TextInputEvent,
|
||||
};
|
||||
use raw_window_handle::{OrbitalDisplayHandle, RawDisplayHandle};
|
||||
|
||||
use crate::{
|
||||
event::{self, StartCause, VirtualKeyCode},
|
||||
event_loop::{self, ControlFlow},
|
||||
window::WindowId as RootWindowId,
|
||||
};
|
||||
|
||||
use super::{
|
||||
DeviceId, MonitorHandle, PlatformSpecificEventLoopAttributes, RedoxSocket, TimeSocket,
|
||||
WindowId, WindowProperties,
|
||||
};
|
||||
|
||||
fn convert_scancode(scancode: u8) -> Option<VirtualKeyCode> {
|
||||
match scancode {
|
||||
orbclient::K_A => Some(VirtualKeyCode::A),
|
||||
orbclient::K_B => Some(VirtualKeyCode::B),
|
||||
orbclient::K_C => Some(VirtualKeyCode::C),
|
||||
orbclient::K_D => Some(VirtualKeyCode::D),
|
||||
orbclient::K_E => Some(VirtualKeyCode::E),
|
||||
orbclient::K_F => Some(VirtualKeyCode::F),
|
||||
orbclient::K_G => Some(VirtualKeyCode::G),
|
||||
orbclient::K_H => Some(VirtualKeyCode::H),
|
||||
orbclient::K_I => Some(VirtualKeyCode::I),
|
||||
orbclient::K_J => Some(VirtualKeyCode::J),
|
||||
orbclient::K_K => Some(VirtualKeyCode::K),
|
||||
orbclient::K_L => Some(VirtualKeyCode::L),
|
||||
orbclient::K_M => Some(VirtualKeyCode::M),
|
||||
orbclient::K_N => Some(VirtualKeyCode::N),
|
||||
orbclient::K_O => Some(VirtualKeyCode::O),
|
||||
orbclient::K_P => Some(VirtualKeyCode::P),
|
||||
orbclient::K_Q => Some(VirtualKeyCode::Q),
|
||||
orbclient::K_R => Some(VirtualKeyCode::R),
|
||||
orbclient::K_S => Some(VirtualKeyCode::S),
|
||||
orbclient::K_T => Some(VirtualKeyCode::T),
|
||||
orbclient::K_U => Some(VirtualKeyCode::U),
|
||||
orbclient::K_V => Some(VirtualKeyCode::V),
|
||||
orbclient::K_W => Some(VirtualKeyCode::W),
|
||||
orbclient::K_X => Some(VirtualKeyCode::X),
|
||||
orbclient::K_Y => Some(VirtualKeyCode::Y),
|
||||
orbclient::K_Z => Some(VirtualKeyCode::Z),
|
||||
orbclient::K_0 => Some(VirtualKeyCode::Key0),
|
||||
orbclient::K_1 => Some(VirtualKeyCode::Key1),
|
||||
orbclient::K_2 => Some(VirtualKeyCode::Key2),
|
||||
orbclient::K_3 => Some(VirtualKeyCode::Key3),
|
||||
orbclient::K_4 => Some(VirtualKeyCode::Key4),
|
||||
orbclient::K_5 => Some(VirtualKeyCode::Key5),
|
||||
orbclient::K_6 => Some(VirtualKeyCode::Key6),
|
||||
orbclient::K_7 => Some(VirtualKeyCode::Key7),
|
||||
orbclient::K_8 => Some(VirtualKeyCode::Key8),
|
||||
orbclient::K_9 => Some(VirtualKeyCode::Key9),
|
||||
|
||||
orbclient::K_TICK => Some(VirtualKeyCode::Grave),
|
||||
orbclient::K_MINUS => Some(VirtualKeyCode::Minus),
|
||||
orbclient::K_EQUALS => Some(VirtualKeyCode::Equals),
|
||||
orbclient::K_BACKSLASH => Some(VirtualKeyCode::Backslash),
|
||||
orbclient::K_BRACE_OPEN => Some(VirtualKeyCode::LBracket),
|
||||
orbclient::K_BRACE_CLOSE => Some(VirtualKeyCode::RBracket),
|
||||
orbclient::K_SEMICOLON => Some(VirtualKeyCode::Semicolon),
|
||||
orbclient::K_QUOTE => Some(VirtualKeyCode::Apostrophe),
|
||||
orbclient::K_COMMA => Some(VirtualKeyCode::Comma),
|
||||
orbclient::K_PERIOD => Some(VirtualKeyCode::Period),
|
||||
orbclient::K_SLASH => Some(VirtualKeyCode::Slash),
|
||||
orbclient::K_BKSP => Some(VirtualKeyCode::Back),
|
||||
orbclient::K_SPACE => Some(VirtualKeyCode::Space),
|
||||
orbclient::K_TAB => Some(VirtualKeyCode::Tab),
|
||||
//orbclient::K_CAPS => Some(VirtualKeyCode::CAPS),
|
||||
orbclient::K_LEFT_SHIFT => Some(VirtualKeyCode::LShift),
|
||||
orbclient::K_RIGHT_SHIFT => Some(VirtualKeyCode::RShift),
|
||||
orbclient::K_CTRL => Some(VirtualKeyCode::LControl),
|
||||
orbclient::K_ALT => Some(VirtualKeyCode::LAlt),
|
||||
orbclient::K_ENTER => Some(VirtualKeyCode::Return),
|
||||
orbclient::K_ESC => Some(VirtualKeyCode::Escape),
|
||||
orbclient::K_F1 => Some(VirtualKeyCode::F1),
|
||||
orbclient::K_F2 => Some(VirtualKeyCode::F2),
|
||||
orbclient::K_F3 => Some(VirtualKeyCode::F3),
|
||||
orbclient::K_F4 => Some(VirtualKeyCode::F4),
|
||||
orbclient::K_F5 => Some(VirtualKeyCode::F5),
|
||||
orbclient::K_F6 => Some(VirtualKeyCode::F6),
|
||||
orbclient::K_F7 => Some(VirtualKeyCode::F7),
|
||||
orbclient::K_F8 => Some(VirtualKeyCode::F8),
|
||||
orbclient::K_F9 => Some(VirtualKeyCode::F9),
|
||||
orbclient::K_F10 => Some(VirtualKeyCode::F10),
|
||||
orbclient::K_HOME => Some(VirtualKeyCode::Home),
|
||||
orbclient::K_UP => Some(VirtualKeyCode::Up),
|
||||
orbclient::K_PGUP => Some(VirtualKeyCode::PageUp),
|
||||
orbclient::K_LEFT => Some(VirtualKeyCode::Left),
|
||||
orbclient::K_RIGHT => Some(VirtualKeyCode::Right),
|
||||
orbclient::K_END => Some(VirtualKeyCode::End),
|
||||
orbclient::K_DOWN => Some(VirtualKeyCode::Down),
|
||||
orbclient::K_PGDN => Some(VirtualKeyCode::PageDown),
|
||||
orbclient::K_DEL => Some(VirtualKeyCode::Delete),
|
||||
orbclient::K_F11 => Some(VirtualKeyCode::F11),
|
||||
orbclient::K_F12 => Some(VirtualKeyCode::F12),
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn element_state(pressed: bool) -> event::ElementState {
|
||||
if pressed {
|
||||
event::ElementState::Pressed
|
||||
} else {
|
||||
event::ElementState::Released
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
struct KeyboardModifierState: u8 {
|
||||
const LSHIFT = 1 << 0;
|
||||
const RSHIFT = 1 << 1;
|
||||
const LCTRL = 1 << 2;
|
||||
const RCTRL = 1 << 3;
|
||||
const LALT = 1 << 4;
|
||||
const RALT = 1 << 5;
|
||||
const LSUPER = 1 << 6;
|
||||
const RSUPER = 1 << 7;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
struct MouseButtonState: u8 {
|
||||
const LEFT = 1 << 0;
|
||||
const MIDDLE = 1 << 1;
|
||||
const RIGHT = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct EventState {
|
||||
keyboard: KeyboardModifierState,
|
||||
mouse: MouseButtonState,
|
||||
resize_opt: Option<(u32, u32)>,
|
||||
}
|
||||
|
||||
impl EventState {
|
||||
fn key(&mut self, vk: VirtualKeyCode, pressed: bool) {
|
||||
match vk {
|
||||
VirtualKeyCode::LShift => self.keyboard.set(KeyboardModifierState::LSHIFT, pressed),
|
||||
VirtualKeyCode::RShift => self.keyboard.set(KeyboardModifierState::RSHIFT, pressed),
|
||||
VirtualKeyCode::LControl => self.keyboard.set(KeyboardModifierState::LCTRL, pressed),
|
||||
VirtualKeyCode::RControl => self.keyboard.set(KeyboardModifierState::RCTRL, pressed),
|
||||
VirtualKeyCode::LAlt => self.keyboard.set(KeyboardModifierState::LALT, pressed),
|
||||
VirtualKeyCode::RAlt => self.keyboard.set(KeyboardModifierState::RALT, pressed),
|
||||
VirtualKeyCode::LWin => self.keyboard.set(KeyboardModifierState::LSUPER, pressed),
|
||||
VirtualKeyCode::RWin => self.keyboard.set(KeyboardModifierState::RSUPER, pressed),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse(
|
||||
&mut self,
|
||||
left: bool,
|
||||
middle: bool,
|
||||
right: bool,
|
||||
) -> Option<(event::MouseButton, event::ElementState)> {
|
||||
if self.mouse.contains(MouseButtonState::LEFT) != left {
|
||||
self.mouse.set(MouseButtonState::LEFT, left);
|
||||
return Some((event::MouseButton::Left, element_state(left)));
|
||||
}
|
||||
|
||||
if self.mouse.contains(MouseButtonState::MIDDLE) != middle {
|
||||
self.mouse.set(MouseButtonState::MIDDLE, middle);
|
||||
return Some((event::MouseButton::Middle, element_state(middle)));
|
||||
}
|
||||
|
||||
if self.mouse.contains(MouseButtonState::RIGHT) != right {
|
||||
self.mouse.set(MouseButtonState::RIGHT, right);
|
||||
return Some((event::MouseButton::Right, element_state(right)));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn modifiers(&self) -> event::ModifiersState {
|
||||
let mut modifiers = event::ModifiersState::empty();
|
||||
if self
|
||||
.keyboard
|
||||
.intersects(KeyboardModifierState::LSHIFT | KeyboardModifierState::RSHIFT)
|
||||
{
|
||||
modifiers |= event::ModifiersState::SHIFT;
|
||||
}
|
||||
if self
|
||||
.keyboard
|
||||
.intersects(KeyboardModifierState::LCTRL | KeyboardModifierState::RCTRL)
|
||||
{
|
||||
modifiers |= event::ModifiersState::CTRL;
|
||||
}
|
||||
if self
|
||||
.keyboard
|
||||
.intersects(KeyboardModifierState::LALT | KeyboardModifierState::RALT)
|
||||
{
|
||||
modifiers |= event::ModifiersState::ALT;
|
||||
}
|
||||
if self
|
||||
.keyboard
|
||||
.intersects(KeyboardModifierState::LSUPER | KeyboardModifierState::RSUPER)
|
||||
{
|
||||
modifiers |= event::ModifiersState::LOGO
|
||||
}
|
||||
modifiers
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventLoop<T: 'static> {
|
||||
windows: Vec<(Arc<RedoxSocket>, EventState)>,
|
||||
window_target: event_loop::EventLoopWindowTarget<T>,
|
||||
}
|
||||
|
||||
impl<T: 'static> EventLoop<T> {
|
||||
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||
let (user_events_sender, user_events_receiver) = mpsc::channel();
|
||||
|
||||
let event_socket = Arc::new(RedoxSocket::event().unwrap());
|
||||
|
||||
let wake_socket = Arc::new(TimeSocket::open().unwrap());
|
||||
|
||||
event_socket
|
||||
.write(&syscall::Event {
|
||||
id: wake_socket.0.fd,
|
||||
flags: syscall::EventFlags::EVENT_READ,
|
||||
data: wake_socket.0.fd,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
Self {
|
||||
windows: Vec::new(),
|
||||
window_target: event_loop::EventLoopWindowTarget {
|
||||
p: EventLoopWindowTarget {
|
||||
user_events_sender,
|
||||
user_events_receiver,
|
||||
creates: Mutex::new(VecDeque::new()),
|
||||
redraws: Arc::new(Mutex::new(VecDeque::new())),
|
||||
destroys: Arc::new(Mutex::new(VecDeque::new())),
|
||||
event_socket,
|
||||
wake_socket,
|
||||
},
|
||||
_marker: std::marker::PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run<F>(mut self, event_handler: F) -> !
|
||||
where
|
||||
F: 'static
|
||||
+ FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
|
||||
{
|
||||
let exit_code = self.run_return(event_handler);
|
||||
::std::process::exit(exit_code);
|
||||
}
|
||||
|
||||
fn process_event<F>(
|
||||
window_id: WindowId,
|
||||
event_option: EventOption,
|
||||
event_state: &mut EventState,
|
||||
mut event_handler: F,
|
||||
) where
|
||||
F: FnMut(event::Event<'_, T>),
|
||||
{
|
||||
match event_option {
|
||||
EventOption::Key(KeyEvent {
|
||||
character: _,
|
||||
scancode,
|
||||
pressed,
|
||||
}) => {
|
||||
if scancode != 0 {
|
||||
let vk_opt = convert_scancode(scancode);
|
||||
if let Some(vk) = vk_opt {
|
||||
event_state.key(vk, pressed);
|
||||
}
|
||||
event_handler(
|
||||
#[allow(deprecated)]
|
||||
event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::KeyboardInput {
|
||||
device_id: event::DeviceId(DeviceId),
|
||||
input: event::KeyboardInput {
|
||||
scancode: scancode as u32,
|
||||
state: element_state(pressed),
|
||||
virtual_keycode: vk_opt,
|
||||
modifiers: event_state.modifiers(),
|
||||
},
|
||||
is_synthetic: false,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
EventOption::TextInput(TextInputEvent { character }) => {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::ReceivedCharacter(character),
|
||||
});
|
||||
}
|
||||
EventOption::Mouse(MouseEvent { x, y }) => {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::CursorMoved {
|
||||
device_id: event::DeviceId(DeviceId),
|
||||
position: (x, y).into(),
|
||||
modifiers: event_state.modifiers(),
|
||||
},
|
||||
});
|
||||
}
|
||||
EventOption::Button(ButtonEvent {
|
||||
left,
|
||||
middle,
|
||||
right,
|
||||
}) => {
|
||||
while let Some((button, state)) = event_state.mouse(left, middle, right) {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::MouseInput {
|
||||
device_id: event::DeviceId(DeviceId),
|
||||
state,
|
||||
button,
|
||||
modifiers: event_state.modifiers(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
EventOption::Scroll(ScrollEvent { x, y }) => {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::MouseWheel {
|
||||
device_id: event::DeviceId(DeviceId),
|
||||
delta: event::MouseScrollDelta::LineDelta(x as f32, y as f32),
|
||||
phase: event::TouchPhase::Moved,
|
||||
modifiers: event_state.modifiers(),
|
||||
},
|
||||
});
|
||||
}
|
||||
EventOption::Quit(QuitEvent {}) => {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::CloseRequested,
|
||||
});
|
||||
}
|
||||
EventOption::Focus(FocusEvent { focused }) => {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::Focused(focused),
|
||||
});
|
||||
}
|
||||
EventOption::Move(MoveEvent { x, y }) => {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::Moved((x, y).into()),
|
||||
});
|
||||
}
|
||||
EventOption::Resize(ResizeEvent { width, height }) => {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::Resized((width, height).into()),
|
||||
});
|
||||
|
||||
// Acknowledge resize after event loop.
|
||||
event_state.resize_opt = Some((width, height));
|
||||
}
|
||||
//TODO: Clipboard
|
||||
EventOption::Hover(HoverEvent { entered }) => {
|
||||
if entered {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::CursorEntered {
|
||||
device_id: event::DeviceId(DeviceId),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::CursorLeft {
|
||||
device_id: event::DeviceId(DeviceId),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
other => {
|
||||
warn!("unhandled event: {:?}", other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_return<F>(&mut self, mut event_handler_inner: F) -> i32
|
||||
where
|
||||
F: FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
|
||||
{
|
||||
// Wrapper for event handler function that prevents ExitWithCode from being unset.
|
||||
let mut event_handler =
|
||||
move |event: event::Event<'_, T>,
|
||||
window_target: &event_loop::EventLoopWindowTarget<T>,
|
||||
control_flow: &mut ControlFlow| {
|
||||
if let ControlFlow::ExitWithCode(code) = control_flow {
|
||||
event_handler_inner(
|
||||
event,
|
||||
window_target,
|
||||
&mut ControlFlow::ExitWithCode(*code),
|
||||
);
|
||||
} else {
|
||||
event_handler_inner(event, window_target, control_flow);
|
||||
}
|
||||
};
|
||||
|
||||
let mut control_flow = ControlFlow::default();
|
||||
let mut start_cause = StartCause::Init;
|
||||
|
||||
let code = loop {
|
||||
event_handler(
|
||||
event::Event::NewEvents(start_cause),
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
|
||||
if start_cause == StartCause::Init {
|
||||
event_handler(
|
||||
event::Event::Resumed,
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
|
||||
// Handle window creates.
|
||||
while let Some(window) = {
|
||||
let mut creates = self.window_target.p.creates.lock().unwrap();
|
||||
creates.pop_front()
|
||||
} {
|
||||
let window_id = WindowId {
|
||||
fd: window.fd as u64,
|
||||
};
|
||||
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let path = window.fpath(&mut buf).expect("failed to read properties");
|
||||
let properties = WindowProperties::new(path);
|
||||
|
||||
self.windows.push((window, EventState::default()));
|
||||
|
||||
// Send resize event on create to indicate first size.
|
||||
event_handler(
|
||||
event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::Resized((properties.w, properties.h).into()),
|
||||
},
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
|
||||
// Send resize event on create to indicate first position.
|
||||
event_handler(
|
||||
event::Event::WindowEvent {
|
||||
window_id: RootWindowId(window_id),
|
||||
event: event::WindowEvent::Moved((properties.x, properties.y).into()),
|
||||
},
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
|
||||
// Handle window destroys.
|
||||
while let Some(destroy_id) = {
|
||||
let mut destroys = self.window_target.p.destroys.lock().unwrap();
|
||||
destroys.pop_front()
|
||||
} {
|
||||
event_handler(
|
||||
event::Event::WindowEvent {
|
||||
window_id: RootWindowId(destroy_id),
|
||||
event: event::WindowEvent::Destroyed,
|
||||
},
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
|
||||
self.windows
|
||||
.retain(|(window, _event_state)| window.fd as u64 != destroy_id.fd);
|
||||
}
|
||||
|
||||
// Handle window events.
|
||||
let mut i = 0;
|
||||
// While loop is used here because the same window may be processed more than once.
|
||||
while let Some((window, event_state)) = self.windows.get_mut(i) {
|
||||
let window_id = WindowId {
|
||||
fd: window.fd as u64,
|
||||
};
|
||||
|
||||
let mut event_buf = [0u8; 16 * mem::size_of::<orbclient::Event>()];
|
||||
let count =
|
||||
syscall::read(window.fd, &mut event_buf).expect("failed to read window events");
|
||||
// Safety: orbclient::Event is a packed struct designed to be transferred over a socket.
|
||||
let events = unsafe {
|
||||
slice::from_raw_parts(
|
||||
event_buf.as_ptr() as *const orbclient::Event,
|
||||
count / mem::size_of::<orbclient::Event>(),
|
||||
)
|
||||
};
|
||||
|
||||
for orbital_event in events {
|
||||
Self::process_event(
|
||||
window_id,
|
||||
orbital_event.to_option(),
|
||||
event_state,
|
||||
|event| event_handler(event, &self.window_target, &mut control_flow),
|
||||
);
|
||||
}
|
||||
|
||||
if count == event_buf.len() {
|
||||
// If event buf was full, process same window again to ensure all events are drained.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Acknowledge the latest resize event.
|
||||
if let Some((w, h)) = event_state.resize_opt.take() {
|
||||
window
|
||||
.write(format!("S,{},{}", w, h).as_bytes())
|
||||
.expect("failed to acknowledge resize");
|
||||
|
||||
// Require redraw after resize.
|
||||
let mut redraws = self.window_target.p.redraws.lock().unwrap();
|
||||
if !redraws.contains(&window_id) {
|
||||
redraws.push_back(window_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Move to next window.
|
||||
i += 1;
|
||||
}
|
||||
|
||||
while let Ok(event) = self.window_target.p.user_events_receiver.try_recv() {
|
||||
event_handler(
|
||||
event::Event::UserEvent(event),
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
|
||||
event_handler(
|
||||
event::Event::MainEventsCleared,
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
|
||||
// To avoid deadlocks the redraws lock is not held during event processing.
|
||||
while let Some(window_id) = {
|
||||
let mut redraws = self.window_target.p.redraws.lock().unwrap();
|
||||
redraws.pop_front()
|
||||
} {
|
||||
event_handler(
|
||||
event::Event::RedrawRequested(RootWindowId(window_id)),
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
|
||||
event_handler(
|
||||
event::Event::RedrawEventsCleared,
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
|
||||
let requested_resume = match control_flow {
|
||||
ControlFlow::Poll => {
|
||||
start_cause = StartCause::Poll;
|
||||
continue;
|
||||
}
|
||||
ControlFlow::Wait => None,
|
||||
ControlFlow::WaitUntil(instant) => Some(instant),
|
||||
ControlFlow::ExitWithCode(code) => break code,
|
||||
};
|
||||
|
||||
// Re-using wake socket caused extra wake events before because there were leftover
|
||||
// timeouts, and then new timeouts were added each time a spurious timeout expired.
|
||||
let timeout_socket = TimeSocket::open().unwrap();
|
||||
|
||||
self.window_target
|
||||
.p
|
||||
.event_socket
|
||||
.write(&syscall::Event {
|
||||
id: timeout_socket.0.fd,
|
||||
flags: syscall::EventFlags::EVENT_READ,
|
||||
data: 0,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let start = Instant::now();
|
||||
if let Some(instant) = requested_resume {
|
||||
let mut time = timeout_socket.current_time().unwrap();
|
||||
|
||||
if let Some(duration) = instant.checked_duration_since(start) {
|
||||
time.tv_sec += duration.as_secs() as i64;
|
||||
time.tv_nsec += duration.subsec_nanos() as i32;
|
||||
// Normalize timespec so tv_nsec is not greater than one second.
|
||||
while time.tv_nsec >= 1_000_000_000 {
|
||||
time.tv_sec += 1;
|
||||
time.tv_nsec -= 1_000_000_000;
|
||||
}
|
||||
}
|
||||
|
||||
timeout_socket.timeout(&time).unwrap();
|
||||
}
|
||||
|
||||
// Wait for event if needed.
|
||||
let mut event = syscall::Event::default();
|
||||
self.window_target.p.event_socket.read(&mut event).unwrap();
|
||||
|
||||
// TODO: handle spurious wakeups (redraw caused wakeup but redraw already handled)
|
||||
match requested_resume {
|
||||
Some(requested_resume) if event.id == timeout_socket.0.fd => {
|
||||
// If the event is from the special timeout socket, report that resume
|
||||
// time was reached.
|
||||
start_cause = StartCause::ResumeTimeReached {
|
||||
start,
|
||||
requested_resume,
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
// Normal window event or spurious timeout.
|
||||
start_cause = StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
event_handler(
|
||||
event::Event::LoopDestroyed,
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
|
||||
code
|
||||
}
|
||||
|
||||
pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget<T> {
|
||||
&self.window_target
|
||||
}
|
||||
|
||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||
EventLoopProxy {
|
||||
user_events_sender: self.window_target.p.user_events_sender.clone(),
|
||||
wake_socket: self.window_target.p.wake_socket.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventLoopProxy<T: 'static> {
|
||||
user_events_sender: mpsc::Sender<T>,
|
||||
wake_socket: Arc<TimeSocket>,
|
||||
}
|
||||
|
||||
impl<T> EventLoopProxy<T> {
|
||||
pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed<T>> {
|
||||
self.user_events_sender
|
||||
.send(event)
|
||||
.map_err(|mpsc::SendError(x)| event_loop::EventLoopClosed(x))?;
|
||||
|
||||
self.wake_socket.wake().unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for EventLoopProxy<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
user_events_sender: self.user_events_sender.clone(),
|
||||
wake_socket: self.wake_socket.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Unpin for EventLoopProxy<T> {}
|
||||
|
||||
pub struct EventLoopWindowTarget<T: 'static> {
|
||||
pub(super) user_events_sender: mpsc::Sender<T>,
|
||||
pub(super) user_events_receiver: mpsc::Receiver<T>,
|
||||
pub(super) creates: Mutex<VecDeque<Arc<RedoxSocket>>>,
|
||||
pub(super) redraws: Arc<Mutex<VecDeque<WindowId>>>,
|
||||
pub(super) destroys: Arc<Mutex<VecDeque<WindowId>>>,
|
||||
pub(super) event_socket: Arc<RedoxSocket>,
|
||||
pub(super) wake_socket: Arc<TimeSocket>,
|
||||
}
|
||||
|
||||
impl<T: 'static> EventLoopWindowTarget<T> {
|
||||
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
||||
Some(MonitorHandle)
|
||||
}
|
||||
|
||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
let mut v = VecDeque::with_capacity(1);
|
||||
v.push_back(MonitorHandle);
|
||||
v
|
||||
}
|
||||
|
||||
pub fn raw_display_handle(&self) -> RawDisplayHandle {
|
||||
RawDisplayHandle::Orbital(OrbitalDisplayHandle::empty())
|
||||
}
|
||||
}
|
253
src/platform_impl/orbital/mod.rs
Normal file
253
src/platform_impl/orbital/mod.rs
Normal file
|
@ -0,0 +1,253 @@
|
|||
#![cfg(target_os = "redox")]
|
||||
|
||||
use std::str;
|
||||
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
|
||||
pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
|
||||
mod event_loop;
|
||||
|
||||
pub use self::window::Window;
|
||||
mod window;
|
||||
|
||||
struct RedoxSocket {
|
||||
fd: usize,
|
||||
}
|
||||
|
||||
impl RedoxSocket {
|
||||
fn event() -> syscall::Result<Self> {
|
||||
Self::open_raw("event:")
|
||||
}
|
||||
|
||||
fn orbital(properties: &WindowProperties<'_>) -> syscall::Result<Self> {
|
||||
Self::open_raw(&format!("{}", properties))
|
||||
}
|
||||
|
||||
// Paths should be checked to ensure they are actually sockets and not normal files. If a
|
||||
// non-socket path is used, it could cause read and write to not function as expected. For
|
||||
// example, the seek would change in a potentially unpredictable way if either read or write
|
||||
// were called at the same time by multiple threads.
|
||||
fn open_raw(path: &str) -> syscall::Result<Self> {
|
||||
let fd = syscall::open(path, syscall::O_RDWR | syscall::O_CLOEXEC)?;
|
||||
Ok(Self { fd })
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> syscall::Result<()> {
|
||||
let count = syscall::read(self.fd, buf)?;
|
||||
if count == buf.len() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(syscall::Error::new(syscall::EINVAL))
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> syscall::Result<()> {
|
||||
let count = syscall::write(self.fd, buf)?;
|
||||
if count == buf.len() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(syscall::Error::new(syscall::EINVAL))
|
||||
}
|
||||
}
|
||||
|
||||
fn fpath<'a>(&self, buf: &'a mut [u8]) -> syscall::Result<&'a str> {
|
||||
let count = syscall::fpath(self.fd, buf)?;
|
||||
str::from_utf8(&buf[..count]).map_err(|_err| syscall::Error::new(syscall::EINVAL))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RedoxSocket {
|
||||
fn drop(&mut self) {
|
||||
let _ = syscall::close(self.fd);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TimeSocket(RedoxSocket);
|
||||
|
||||
impl TimeSocket {
|
||||
fn open() -> syscall::Result<Self> {
|
||||
RedoxSocket::open_raw("time:4").map(Self)
|
||||
}
|
||||
|
||||
// Read current time.
|
||||
fn current_time(&self) -> syscall::Result<syscall::TimeSpec> {
|
||||
let mut timespec = syscall::TimeSpec::default();
|
||||
self.0.read(&mut timespec)?;
|
||||
Ok(timespec)
|
||||
}
|
||||
|
||||
// Write a timeout.
|
||||
fn timeout(&self, timespec: &syscall::TimeSpec) -> syscall::Result<()> {
|
||||
self.0.write(timespec)
|
||||
}
|
||||
|
||||
// Wake immediately.
|
||||
fn wake(&self) -> syscall::Result<()> {
|
||||
// Writing a default TimeSpec will always trigger a time event.
|
||||
self.timeout(&syscall::TimeSpec::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct WindowId {
|
||||
fd: u64,
|
||||
}
|
||||
|
||||
impl WindowId {
|
||||
pub const fn dummy() -> Self {
|
||||
WindowId {
|
||||
fd: u64::max_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WindowId> for u64 {
|
||||
fn from(id: WindowId) -> Self {
|
||||
id.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for WindowId {
|
||||
fn from(fd: u64) -> Self {
|
||||
Self { fd }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct DeviceId;
|
||||
|
||||
impl DeviceId {
|
||||
pub const fn dummy() -> Self {
|
||||
DeviceId
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub struct PlatformSpecificWindowBuilderAttributes;
|
||||
|
||||
struct WindowProperties<'a> {
|
||||
flags: &'a str,
|
||||
x: i32,
|
||||
y: i32,
|
||||
w: u32,
|
||||
h: u32,
|
||||
title: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> WindowProperties<'a> {
|
||||
fn new(path: &'a str) -> Self {
|
||||
// orbital:flags/x/y/w/h/t
|
||||
let mut parts = path.splitn(6, '/');
|
||||
let flags = parts.next().unwrap_or("");
|
||||
let x = parts
|
||||
.next()
|
||||
.map_or(0, |part| part.parse::<i32>().unwrap_or(0));
|
||||
let y = parts
|
||||
.next()
|
||||
.map_or(0, |part| part.parse::<i32>().unwrap_or(0));
|
||||
let w = parts
|
||||
.next()
|
||||
.map_or(0, |part| part.parse::<u32>().unwrap_or(0));
|
||||
let h = parts
|
||||
.next()
|
||||
.map_or(0, |part| part.parse::<u32>().unwrap_or(0));
|
||||
let title = parts.next().unwrap_or("");
|
||||
Self {
|
||||
flags,
|
||||
x,
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
title,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for WindowProperties<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"orbital:{}/{}/{}/{}/{}/{}",
|
||||
self.flags, self.x, self.y, self.w, self.h, self.title
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct OsError;
|
||||
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
impl Display for OsError {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "Redox OS Error")
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct MonitorHandle;
|
||||
|
||||
impl MonitorHandle {
|
||||
pub fn name(&self) -> Option<String> {
|
||||
Some("Redox Device".to_owned())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
PhysicalSize::new(0, 0) // TODO
|
||||
}
|
||||
|
||||
pub fn position(&self) -> PhysicalPosition<i32> {
|
||||
(0, 0).into()
|
||||
}
|
||||
|
||||
pub fn scale_factor(&self) -> f64 {
|
||||
1.0 // TODO
|
||||
}
|
||||
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||
// FIXME no way to get real refresh rate for now.
|
||||
None
|
||||
}
|
||||
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
let size = self.size().into();
|
||||
// FIXME this is not the real refresh rate
|
||||
// (it is guaranteed to support 32 bit color though)
|
||||
std::iter::once(VideoMode {
|
||||
size,
|
||||
bit_depth: 32,
|
||||
refresh_rate_millihertz: 60000,
|
||||
monitor: self.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct VideoMode {
|
||||
size: (u32, u32),
|
||||
bit_depth: u16,
|
||||
refresh_rate_millihertz: u32,
|
||||
monitor: MonitorHandle,
|
||||
}
|
||||
|
||||
impl VideoMode {
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
self.size.into()
|
||||
}
|
||||
|
||||
pub fn bit_depth(&self) -> u16 {
|
||||
self.bit_depth
|
||||
}
|
||||
|
||||
pub fn refresh_rate_millihertz(&self) -> u32 {
|
||||
self.refresh_rate_millihertz
|
||||
}
|
||||
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
self.monitor.clone()
|
||||
}
|
||||
}
|
396
src/platform_impl/orbital/window.rs
Normal file
396
src/platform_impl/orbital/window.rs
Normal file
|
@ -0,0 +1,396 @@
|
|||
use std::{
|
||||
collections::VecDeque,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use raw_window_handle::{
|
||||
OrbitalDisplayHandle, OrbitalWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||
error,
|
||||
platform_impl::Fullscreen,
|
||||
window,
|
||||
};
|
||||
|
||||
use super::{
|
||||
EventLoopWindowTarget, MonitorHandle, PlatformSpecificWindowBuilderAttributes, RedoxSocket,
|
||||
TimeSocket, WindowId, WindowProperties,
|
||||
};
|
||||
|
||||
// These values match the values uses in the `window_new` function in orbital:
|
||||
// https://gitlab.redox-os.org/redox-os/orbital/-/blob/master/src/scheme.rs
|
||||
const ORBITAL_FLAG_ASYNC: char = 'a';
|
||||
const ORBITAL_FLAG_BACK: char = 'b';
|
||||
const ORBITAL_FLAG_FRONT: char = 'f';
|
||||
const ORBITAL_FLAG_BORDERLESS: char = 'l';
|
||||
const ORBITAL_FLAG_RESIZABLE: char = 'r';
|
||||
const ORBITAL_FLAG_TRANSPARENT: char = 't';
|
||||
|
||||
pub struct Window {
|
||||
window_socket: Arc<RedoxSocket>,
|
||||
redraws: Arc<Mutex<VecDeque<WindowId>>>,
|
||||
destroys: Arc<Mutex<VecDeque<WindowId>>>,
|
||||
wake_socket: Arc<TimeSocket>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub(crate) fn new<T: 'static>(
|
||||
el: &EventLoopWindowTarget<T>,
|
||||
attrs: window::WindowAttributes,
|
||||
_: PlatformSpecificWindowBuilderAttributes,
|
||||
) -> Result<Self, error::OsError> {
|
||||
let scale = MonitorHandle.scale_factor();
|
||||
|
||||
let (x, y) = if let Some(pos) = attrs.position {
|
||||
pos.to_physical::<i32>(scale).into()
|
||||
} else {
|
||||
// These coordinates are a special value to center the window.
|
||||
(-1, -1)
|
||||
};
|
||||
|
||||
let (w, h): (u32, u32) = if let Some(size) = attrs.inner_size {
|
||||
size.to_physical::<u32>(scale).into()
|
||||
} else {
|
||||
(1024, 768)
|
||||
};
|
||||
|
||||
//TODO: min/max inner_size
|
||||
|
||||
// Async by default.
|
||||
let mut flag_str = ORBITAL_FLAG_ASYNC.to_string();
|
||||
|
||||
if attrs.resizable {
|
||||
flag_str.push(ORBITAL_FLAG_RESIZABLE);
|
||||
}
|
||||
|
||||
//TODO: maximized, fullscreen, visible
|
||||
|
||||
if attrs.transparent {
|
||||
flag_str.push(ORBITAL_FLAG_TRANSPARENT);
|
||||
}
|
||||
|
||||
if !attrs.decorations {
|
||||
flag_str.push(ORBITAL_FLAG_BORDERLESS);
|
||||
}
|
||||
|
||||
match attrs.window_level {
|
||||
window::WindowLevel::AlwaysOnBottom => {
|
||||
flag_str.push(ORBITAL_FLAG_BACK);
|
||||
}
|
||||
window::WindowLevel::Normal => {}
|
||||
window::WindowLevel::AlwaysOnTop => {
|
||||
flag_str.push(ORBITAL_FLAG_FRONT);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: window_icon
|
||||
|
||||
// Open window.
|
||||
let window = RedoxSocket::orbital(&WindowProperties {
|
||||
flags: &flag_str,
|
||||
x,
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
title: &attrs.title,
|
||||
})
|
||||
.expect("failed to open window");
|
||||
|
||||
// Add to event socket.
|
||||
el.event_socket
|
||||
.write(&syscall::Event {
|
||||
id: window.fd,
|
||||
flags: syscall::EventFlags::EVENT_READ,
|
||||
data: window.fd,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let window_socket = Arc::new(window);
|
||||
|
||||
// Notify event thread that this window was created, it will send some default events.
|
||||
{
|
||||
let mut creates = el.creates.lock().unwrap();
|
||||
creates.push_back(window_socket.clone());
|
||||
}
|
||||
|
||||
el.wake_socket.wake().unwrap();
|
||||
|
||||
Ok(Self {
|
||||
window_socket,
|
||||
redraws: el.redraws.clone(),
|
||||
destroys: el.destroys.clone(),
|
||||
wake_socket: el.wake_socket.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn id(&self) -> WindowId {
|
||||
WindowId {
|
||||
fd: self.window_socket.fd as u64,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
||||
Some(MonitorHandle)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
let mut v = VecDeque::with_capacity(1);
|
||||
v.push_back(MonitorHandle);
|
||||
v
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn current_monitor(&self) -> Option<MonitorHandle> {
|
||||
Some(MonitorHandle)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn scale_factor(&self) -> f64 {
|
||||
MonitorHandle.scale_factor()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_redraw(&self) {
|
||||
let window_id = self.id();
|
||||
let mut redraws = self.redraws.lock().unwrap();
|
||||
if !redraws.contains(&window_id) {
|
||||
redraws.push_back(window_id);
|
||||
|
||||
self.wake_socket.wake().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, error::NotSupportedError> {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let path = self
|
||||
.window_socket
|
||||
.fpath(&mut buf)
|
||||
.expect("failed to read properties");
|
||||
let properties = WindowProperties::new(path);
|
||||
Ok((properties.x, properties.y).into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, error::NotSupportedError> {
|
||||
//TODO: adjust for window decorations
|
||||
self.inner_position()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_outer_position(&self, position: Position) {
|
||||
//TODO: adjust for window decorations
|
||||
let (x, y): (i32, i32) = position.to_physical::<i32>(self.scale_factor()).into();
|
||||
self.window_socket
|
||||
.write(format!("P,{},{}", x, y).as_bytes())
|
||||
.expect("failed to set position");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let path = self
|
||||
.window_socket
|
||||
.fpath(&mut buf)
|
||||
.expect("failed to read properties");
|
||||
let properties = WindowProperties::new(path);
|
||||
(properties.w, properties.h).into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_inner_size(&self, size: Size) {
|
||||
let (w, h): (u32, u32) = size.to_physical::<u32>(self.scale_factor()).into();
|
||||
self.window_socket
|
||||
.write(format!("S,{},{}", w, h).as_bytes())
|
||||
.expect("failed to set size");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
||||
//TODO: adjust for window decorations
|
||||
self.inner_size()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_min_inner_size(&self, _: Option<Size>) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_max_inner_size(&self, _: Option<Size>) {}
|
||||
|
||||
#[inline]
|
||||
pub fn title(&self) -> String {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let path = self
|
||||
.window_socket
|
||||
.fpath(&mut buf)
|
||||
.expect("failed to read properties");
|
||||
let properties = WindowProperties::new(path);
|
||||
properties.title.to_string()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_title(&self, title: &str) {
|
||||
self.window_socket
|
||||
.write(format!("T,{}", title).as_bytes())
|
||||
.expect("failed to set title");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_visible(&self, _visibility: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn is_visible(&self) -> Option<bool> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_resize_increments(&self, _increments: Option<Size>) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_resizable(&self, _resizeable: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn is_resizable(&self) -> bool {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let path = self
|
||||
.window_socket
|
||||
.fpath(&mut buf)
|
||||
.expect("failed to read properties");
|
||||
let properties = WindowProperties::new(path);
|
||||
properties.flags.contains(ORBITAL_FLAG_RESIZABLE)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_minimized(&self, _minimized: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_maximized(&self, _maximized: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn is_maximized(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_fullscreen(&self, _monitor: Option<Fullscreen>) {}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn fullscreen(&self) -> Option<Fullscreen> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_decorations(&self, _decorations: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn is_decorated(&self) -> bool {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let path = self
|
||||
.window_socket
|
||||
.fpath(&mut buf)
|
||||
.expect("failed to read properties");
|
||||
let properties = WindowProperties::new(path);
|
||||
!properties.flags.contains(ORBITAL_FLAG_BORDERLESS)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_window_level(&self, _level: window::WindowLevel) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_window_icon(&self, _window_icon: Option<crate::icon::Icon>) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_ime_position(&self, _position: Position) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_ime_allowed(&self, _allowed: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn focus_window(&self) {}
|
||||
|
||||
#[inline]
|
||||
pub fn request_user_attention(&self, _request_type: Option<window::UserAttentionType>) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_icon(&self, _: window::CursorIcon) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> {
|
||||
Err(error::ExternalError::NotSupported(
|
||||
error::NotSupportedError::new(),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_grab(&self, _: window::CursorGrabMode) -> Result<(), error::ExternalError> {
|
||||
Err(error::ExternalError::NotSupported(
|
||||
error::NotSupportedError::new(),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_visible(&self, _: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn drag_window(&self) -> Result<(), error::ExternalError> {
|
||||
Err(error::ExternalError::NotSupported(
|
||||
error::NotSupportedError::new(),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> {
|
||||
Err(error::ExternalError::NotSupported(
|
||||
error::NotSupportedError::new(),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn raw_window_handle(&self) -> RawWindowHandle {
|
||||
let mut handle = OrbitalWindowHandle::empty();
|
||||
handle.window = self.window_socket.fd as *mut _;
|
||||
RawWindowHandle::Orbital(handle)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn raw_display_handle(&self) -> RawDisplayHandle {
|
||||
RawDisplayHandle::Orbital(OrbitalDisplayHandle::empty())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_enabled_buttons(&self, _buttons: window::WindowButtons) {}
|
||||
|
||||
#[inline]
|
||||
pub fn enabled_buttons(&self) -> window::WindowButtons {
|
||||
window::WindowButtons::all()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn theme(&self) -> Option<window::Theme> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_theme(&self, _theme: Option<window::Theme>) {}
|
||||
}
|
||||
|
||||
impl Drop for Window {
|
||||
fn drop(&mut self) {
|
||||
{
|
||||
let mut destroys = self.destroys.lock().unwrap();
|
||||
destroys.push_back(self.id());
|
||||
}
|
||||
|
||||
self.wake_socket.wake().unwrap();
|
||||
}
|
||||
}
|
|
@ -368,7 +368,7 @@ impl WindowBuilder {
|
|||
/// - **Wayland:** This control only CSD. You can also use `WINIT_WAYLAND_CSD_THEME` env variable to set the theme.
|
||||
/// Possible values for env variable are: "dark" and light".
|
||||
/// - **x11:** Build window with `_GTK_THEME_VARIANT` hint set to `dark` or `light`.
|
||||
/// - **iOS / Android / Web / x11:** Ignored.
|
||||
/// - **iOS / Android / Web / x11 / Orbital:** Ignored.
|
||||
#[inline]
|
||||
pub fn with_theme(mut self, theme: Option<Theme>) -> Self {
|
||||
self.window.preferred_theme = theme;
|
||||
|
@ -394,7 +394,7 @@ impl WindowBuilder {
|
|||
///
|
||||
/// - **macOS**: if `false`, [`NSWindowSharingNone`] is used but doesn't completely
|
||||
/// prevent all apps from reading the window content, for instance, QuickTime.
|
||||
/// - **iOS / Android / Web / x11:** Ignored.
|
||||
/// - **iOS / Android / Web / x11 / Orbital:** Ignored.
|
||||
///
|
||||
/// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone
|
||||
#[inline]
|
||||
|
@ -667,7 +667,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_min_inner_size<S: Into<Size>>(&self, min_size: Option<S>) {
|
||||
self.window.set_min_inner_size(min_size.map(|s| s.into()))
|
||||
|
@ -690,7 +690,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_max_inner_size<S: Into<Size>>(&self, max_size: Option<S>) {
|
||||
self.window.set_max_inner_size(max_size.map(|s| s.into()))
|
||||
|
@ -700,7 +700,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web / Wayland / Windows:** Always returns [`None`].
|
||||
/// - **iOS / Android / Web / Wayland / Windows / Orbital:** Always returns [`None`].
|
||||
#[inline]
|
||||
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
|
||||
self.window.resize_increments()
|
||||
|
@ -715,7 +715,7 @@ impl Window {
|
|||
///
|
||||
/// - **macOS:** Increments are converted to logical size and then macOS rounds them to whole numbers.
|
||||
/// - **Wayland / Windows:** Not implemented.
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_resize_increments<S: Into<Size>>(&self, increments: Option<S>) {
|
||||
self.window
|
||||
|
@ -795,7 +795,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Wayland / X11:** Not implemented.
|
||||
/// - **Wayland / X11 / Orbital:** Not implemented.
|
||||
/// - **Web / iOS / Android:** Unsupported.
|
||||
pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
|
||||
self.window.set_enabled_buttons(buttons)
|
||||
|
@ -805,7 +805,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Wayland / X11:** Not implemented. Always returns [`WindowButtons::all`].
|
||||
/// - **Wayland / X11 / Orbital:** Not implemented. Always returns [`WindowButtons::all`].
|
||||
/// - **Web / iOS / Android:** Unsupported. Always returns [`WindowButtons::all`].
|
||||
pub fn enabled_buttons(&self) -> WindowButtons {
|
||||
self.window.enabled_buttons()
|
||||
|
@ -815,7 +815,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
/// - **Wayland:** Un-minimize is unsupported.
|
||||
#[inline]
|
||||
pub fn set_minimized(&self, minimized: bool) {
|
||||
|
@ -826,7 +826,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_maximized(&self, maximized: bool) {
|
||||
self.window.set_maximized(maximized)
|
||||
|
@ -836,7 +836,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn is_maximized(&self) -> bool {
|
||||
self.window.is_maximized()
|
||||
|
@ -861,7 +861,7 @@ impl Window {
|
|||
/// - **iOS:** Can only be called on the main thread.
|
||||
/// - **Wayland:** Does not support exclusive fullscreen mode and will no-op a request.
|
||||
/// - **Windows:** Screen saver is disabled in fullscreen mode.
|
||||
/// - **Android:** Unsupported.
|
||||
/// - **Android / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
|
||||
self.window.set_fullscreen(fullscreen.map(|f| f.into()))
|
||||
|
@ -872,7 +872,7 @@ impl Window {
|
|||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS:** Can only be called on the main thread.
|
||||
/// - **Android:** Will always return `None`.
|
||||
/// - **Android / Orbital:** Will always return `None`.
|
||||
/// - **Wayland:** Can return `Borderless(None)` when there are no monitors.
|
||||
#[inline]
|
||||
pub fn fullscreen(&self) -> Option<Fullscreen> {
|
||||
|
@ -916,7 +916,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web / Wayland / macOS:** Unsupported.
|
||||
/// - **iOS / Android / Web / Wayland / macOS / Orbital:** Unsupported.
|
||||
///
|
||||
/// - **Windows:** Sets `ICON_SMALL`. The base size for a window icon is 16x16, but it's
|
||||
/// recommended to account for screen scaling and pick a multiple of that, i.e. 32x32.
|
||||
|
@ -952,7 +952,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
///
|
||||
/// [chinese]: https://support.apple.com/guide/chinese-input-method/use-the-candidate-window-cim12992/104/mac/12.0
|
||||
/// [japanese]: https://support.apple.com/guide/japanese-input-method/use-the-candidate-window-jpim10262/6.3/mac/12.0
|
||||
|
@ -978,7 +978,7 @@ impl Window {
|
|||
/// ## Platform-specific
|
||||
///
|
||||
/// - **macOS:** IME must be enabled to receive text-input where dead-key sequences are combined.
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
///
|
||||
/// [`Ime`]: crate::event::WindowEvent::Ime
|
||||
/// [`KeyboardInput`]: crate::event::WindowEvent::KeyboardInput
|
||||
|
@ -997,7 +997,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web / Wayland:** Unsupported.
|
||||
/// - **iOS / Android / Web / Wayland / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn focus_window(&self) {
|
||||
self.window.focus_window()
|
||||
|
@ -1012,7 +1012,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
/// - **macOS:** `None` has no effect.
|
||||
/// - **X11:** Requests for user attention must be manually cleared.
|
||||
/// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect.
|
||||
|
@ -1029,7 +1029,7 @@ impl Window {
|
|||
/// - **Wayland:** You can also use `WINIT_WAYLAND_CSD_THEME` env variable to set the theme.
|
||||
/// Possible values for env variable are: "dark" and light". When unspecified, a theme is automatically selected.
|
||||
/// -**x11:** Sets `_GTK_THEME_VARIANT` hint to `dark` or `light` and if `None` is used, it will default to [`Theme::Dark`].
|
||||
/// - **iOS / Android / Web / x11:** Unsupported.
|
||||
/// - **iOS / Android / Web / x11 / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_theme(&self, theme: Option<Theme>) {
|
||||
self.window.set_theme(theme)
|
||||
|
@ -1040,7 +1040,7 @@ impl Window {
|
|||
/// ## Platform-specific
|
||||
///
|
||||
/// - **macOS:** This is an app-wide setting.
|
||||
/// - **iOS / Android / Web / Wayland / x11:** Unsupported.
|
||||
/// - **iOS / Android / Web / Wayland / x11 / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn theme(&self) -> Option<Theme> {
|
||||
self.window.theme()
|
||||
|
@ -1052,7 +1052,7 @@ impl Window {
|
|||
///
|
||||
/// - **macOS**: if `false`, [`NSWindowSharingNone`] is used but doesn't completely
|
||||
/// prevent all apps from reading the window content, for instance, QuickTime.
|
||||
/// - **iOS / Android / x11 / Wayland / Web:** Unsupported.
|
||||
/// - **iOS / Android / x11 / Wayland / Web / Orbital:** Unsupported.
|
||||
///
|
||||
/// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone
|
||||
pub fn set_content_protected(&self, _protected: bool) {
|
||||
|
@ -1077,7 +1077,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android:** Unsupported.
|
||||
/// - **iOS / Android / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
||||
self.window.set_cursor_icon(cursor);
|
||||
|
@ -1100,7 +1100,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web / Wayland:** Always returns an [`ExternalError::NotSupported`].
|
||||
/// - **iOS / Android / Web / Wayland / Orbital:** Always returns an [`ExternalError::NotSupported`].
|
||||
#[inline]
|
||||
pub fn set_cursor_position<P: Into<Position>>(&self, position: P) -> Result<(), ExternalError> {
|
||||
self.window.set_cursor_position(position.into())
|
||||
|
@ -1137,7 +1137,7 @@ impl Window {
|
|||
/// - **Wayland:** The cursor is only hidden within the confines of the window.
|
||||
/// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
|
||||
/// outside of the window.
|
||||
/// - **iOS / Android:** Unsupported.
|
||||
/// - **iOS / Android / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_cursor_visible(&self, visible: bool) {
|
||||
self.window.set_cursor_visible(visible)
|
||||
|
@ -1153,7 +1153,7 @@ impl Window {
|
|||
/// - **X11:** Un-grabs the cursor.
|
||||
/// - **Wayland:** Requires the cursor to be inside the window to be dragged.
|
||||
/// - **macOS:** May prevent the button release event to be triggered.
|
||||
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
|
||||
/// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
|
||||
#[inline]
|
||||
pub fn drag_window(&self) -> Result<(), ExternalError> {
|
||||
self.window.drag_window()
|
||||
|
@ -1166,7 +1166,7 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web / X11:** Always returns an [`ExternalError::NotSupported`].
|
||||
/// - **iOS / Android / Web / X11 / Orbital:** Always returns an [`ExternalError::NotSupported`].
|
||||
#[inline]
|
||||
pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
|
||||
self.window.set_cursor_hittest(hittest)
|
||||
|
@ -1273,7 +1273,7 @@ pub enum CursorGrabMode {
|
|||
/// ## Platform-specific
|
||||
///
|
||||
/// - **macOS:** Not implemented. Always returns [`ExternalError::NotSupported`] for now.
|
||||
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
|
||||
/// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
|
||||
Confined,
|
||||
|
||||
/// The cursor is locked inside the window area to the certain position.
|
||||
|
@ -1284,7 +1284,7 @@ pub enum CursorGrabMode {
|
|||
/// ## Platform-specific
|
||||
///
|
||||
/// - **X11 / Windows:** Not implemented. Always returns [`ExternalError::NotSupported`] for now.
|
||||
/// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`].
|
||||
/// - **iOS / Android / Orbital:** Always returns an [`ExternalError::NotSupported`].
|
||||
Locked,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue