diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index b247266c..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,56 +0,0 @@ -version: 2 - -jobs: - - android-test: - working_directory: ~/winit - docker: - - image: tomaka/cargo-apk - steps: - - run: apt-get -qq update && apt-get install -y git - - checkout - - restore_cache: - key: android-test-cache-{{ checksum "Cargo.toml" }} - - run: cargo apk build --example window - - save_cache: - key: android-test-cache-{{ checksum "Cargo.toml" }} - paths: - - target - - asmjs-test: - working_directory: ~/winit - docker: - - image: tomaka/rustc-emscripten - steps: - - run: apt-get -qq update && apt-get install -y git - - checkout - - restore_cache: - key: asmjs-test-cache-{{ checksum "Cargo.toml" }} - - run: cargo build --example window --target asmjs-unknown-emscripten - - save_cache: - key: asmjs-test-cache-{{ checksum "Cargo.toml" }} - paths: - - target - - wasm-test: - working_directory: ~/winit - docker: - - image: tomaka/rustc-emscripten - steps: - - run: apt-get -qq update && apt-get install -y git - - checkout - - restore_cache: - key: wasm-test-cache-{{ checksum "Cargo.toml" }} - - run: cargo build --example window --target wasm32-unknown-emscripten - - save_cache: - key: wasm-test-cache-{{ checksum "Cargo.toml" }} - paths: - - target - -workflows: - version: 2 - build-test-and-deploy: - jobs: - - android-test - - asmjs-test - - wasm-test diff --git a/.gitattributes b/.gitattributes index 412eeda7..81f4fe3a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -20,3 +20,5 @@ *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain + +/CHANGELOG.md merge=union diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e1b4afe8..d6f55915 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,6 @@ - [ ] Tested on all platforms changed +- [ ] `cargo fmt` has been run on this branch - [ ] Added an entry to `CHANGELOG.md` if knowledge of this change could be valuable to users - [ ] Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior -- [ ] Created an example program if it would help users understand this functionality -- [ ] Updated [feature matrix](https://github.com/tomaka/winit/blob/master/FEATURES.md), if new features were added or implemented +- [ ] Created or updated an example program if it would help users understand this functionality +- [ ] Updated [feature matrix](https://github.com/rust-windowing/winit/blob/master/FEATURES.md), if new features were added or implemented diff --git a/.gitmodules b/.gitmodules index c885e6c1..9656dc78 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "deps/apk-builder"] path = deps/apk-builder - url = https://github.com/tomaka/android-rs-glue + url = https://github.com/rust-windowing/android-rs-glue diff --git a/.travis.yml b/.travis.yml index e8b7e47c..7e6bc833 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: rust -cache: cargo - matrix: include: # Linux 32bit @@ -47,8 +45,10 @@ matrix: install: - rustup self update - rustup target add $TARGET; true + - rustup component add rustfmt script: + - cargo fmt --all -- --check - cargo build --target $TARGET --verbose - cargo build --target $TARGET --features serde --verbose # Running iOS apps on OSX requires the simulator so we skip that for now diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d48e850..65555cf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Unreleased +# 0.20.0 Alpha 2 (2019-07-09) + +- On X11, non-resizable windows now have maximize explicitly disabled. +- On Windows, support paths longer than MAX_PATH (260 characters) in `WindowEvent::DroppedFile` +and `WindowEvent::HoveredFile`. +- On Mac, implement `DeviceEvent::Button`. +- Change `Event::Suspended(true / false)` to `Event::Suspended` and `Event::Resumed`. +- On X11, fix sanity check which checks that a monitor's reported width and height (in millimeters) are non-zero when calculating the DPI factor. +- Revert the use of invisible surfaces in Wayland, which introduced graphical glitches with OpenGL (#835) +- On X11, implement `_NET_WM_PING` to allow desktop environment to kill unresponsive programs. +- On Windows, when a window is initially invisible, it won't take focus from the existing visible windows. +- On Windows, fix multiple calls to `request_redraw` during `EventsCleared` sending multiple `RedrawRequested events.` +- On Windows, fix edge case where `RedrawRequested` could be dispatched before input events in event loop iteration. +- On Windows, fix timing issue that could cause events to be improperly dispatched after `RedrawRequested` but before `EventsCleared`. +- On macOS, drop unused Metal dependency. +- On Windows, fix the trail effect happening on transparent decorated windows. Borderless (or un-decorated) windows were not affected. +- On Windows, fix `with_maximized` not properly setting window size to entire window. +- On macOS, change `WindowExtMacOS::request_user_attention()` to take an `enum` instead of a `bool`. + +# 0.20.0 Alpha 1 (2019-06-21) + - Changes below are considered **breaking**. - Change all occurrences of `EventsLoop` to `EventLoop`. - Previously flat API is now exposed through `event`, `event_loop`, `monitor`, and `window` modules. @@ -39,6 +60,11 @@ - Removed `serde` implementations from `ControlFlow`. - Rename several functions to improve both internal consistency and compliance with Rust API guidelines. - Remove `WindowBuilder::multitouch` field, since it was only implemented on a few platforms. Multitouch is always enabled now. +- **Breaking:** On macOS, change `ns` identifiers to use snake_case for consistency with iOS's `ui` identifiers. +- Add `MonitorHandle::video_modes` method for retrieving supported video modes for the given monitor. +- On Wayland, the window now exists even if nothing has been drawn. +- On Windows, fix initial dimensions of a fullscreen window. +- On Windows, Fix transparent borderless windows rendering wrong. # Version 0.19.1 (2019-04-08) @@ -46,6 +72,9 @@ - On Windows, fix `CursorMoved(0, 0)` getting dispatched on window focus. - On macOS, fix command key event left and right reverse. - On FreeBSD, NetBSD, and OpenBSD, fix build of X11 backend. +- On Linux, the numpad's add, subtract and divide keys are now mapped to the `Add`, `Subtract` and `Divide` virtual key codes +- On macOS, the numpad's subtract key has been added to the `Subtract` mapping +- On Wayland, the numpad's home, end, page up and page down keys are now mapped to the `Home`, `End`, `PageUp` and `PageDown` virtual key codes - On Windows, fix icon not showing up in corner of window. - On X11, change DPI scaling factor behavior. First, winit tries to read it from "Xft.dpi" XResource, and uses DPI calculation from xrandr dimensions as fallback behavior. @@ -64,9 +93,6 @@ - On Windows, cursor grabs used to get perpetually canceled when the grabbing window lost focus. Now, cursor grabs automatically get re-initialized when the window regains focus and the mouse moves over the client area. - On Windows, only vertical mouse wheel events were handled. Now, horizontal mouse wheel events are also handled. - On Windows, ignore the AltGr key when populating the `ModifersState` type. -- On Linux, the numpad's add, subtract and divide keys are now mapped to the `Add`, `Subtract` and `Divide` virtual key codes -- On macOS, the numpad's subtract key has been added to the `Subtract` mapping -- On Wayland, the numpad's home, end, page up and page down keys are now mapped to the `Home`, `End`, `PageUp` and `PageDown` virtual key codes # Version 0.18.1 (2018-12-30) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7de04ab8..0657334f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,20 +36,7 @@ at least a maintainer of the platform (a maintainer making a PR themselves count ## Maintainers & Testers -Winit is managed by several people, each with their specialities, and each maintaining a subset of the -backends of winit. As such, depending on your platform of interest, your contacts will be different. +The current [list of testers and contributors](https://github.com/rust-windowing/winit/wiki/Testers-and-Contributors) +can be found on the Wiki. -This table summarizes who can be contacted in which case, with the following legend: - -- `M` - Maintainer: is a main maintainer for this platform -- `C` - Collaborator: can review code and address issues on this platform -- `T` - Tester: has the ability of testing the platform -- ` `: knows nothing of this platform - -| Platform | Windows | macOS | X11 | Wayland | Android | iOS | Emscripten | Stdweb | -| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | -| @mitchmindtree | T | | T | T | | | | | -| @Osspial | M | | T | T | T | | T | | -| @vberger | | | T | M | | | | | -| @mtak- | | T | | | T | M | | | -| @ryanisacg | T | T | | | | | | M | +If you are interested in contributing or testing on a platform, please add yourself to that table! diff --git a/Cargo.toml b/Cargo.toml index 15b2c62e..9885cd23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "winit" -version = "0.20.0-alpha1" +version = "0.20.0-alpha2" authors = ["The winit contributors", "Pierre Krieger "] description = "Cross-platform window creation library." +edition = "2018" keywords = ["windowing"] license = "Apache-2.0" readme = "README.md" -repository = "https://github.com/tomaka/winit" +repository = "https://github.com/rust-windowing/winit" documentation = "https://docs.rs/winit" categories = ["gui"] @@ -23,6 +24,7 @@ lazy_static = "1" libc = "0.2" log = "0.4" serde = { version = "1", optional = true, features = ["serde_derive"] } +derivative = "1.0.2" [dev-dependencies] image = "0.21" @@ -41,6 +43,11 @@ core-graphics = "0.17.3" dispatch = "0.1.4" objc = "0.2.3" +[target.'cfg(target_os = "macos")'.dependencies.core-video-sys] +version = "0.1.3" +default_features = false +features = ["display_link"] + [target.'cfg(target_os = "windows")'.dependencies] bitflags = "1" diff --git a/FEATURES.md b/FEATURES.md index 515ff597..d71b00e4 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -92,6 +92,7 @@ If your PR makes notable changes to Winit's features, please update this section ### System Information - **Monitor list**: Retrieve the list of monitors and their metadata, including which one is primary. +- **Video mode query**: Monitors can be queried for their supported fullscreen video modes (consisting of resolution, refresh rate, and bit depth). ### Input Handling - **Mouse events**: Generating mouse events associated with pointer motion, click, and scrolling events. @@ -160,9 +161,10 @@ Legend: |Popup windows |❌ |❌ |❌ |❌ |❌ |❌ |❌ | ### System information -|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |Emscripten| -|------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | -|Monitor list |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A** | +|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |Emscripten| +|---------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | +|Monitor list |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A** | +|Video mode query |✔️ |✔️ |✔️ |✔️ |❌ |✔️ |❌ | ### Input handling |Feature |Windows |MacOS |Linux x11|Linux Wayland|Android|iOS |Emscripten| @@ -192,18 +194,18 @@ Changes in the API that have been agreed upon but aren't implemented across all |Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |Emscripten| |------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | -[#165]: https://github.com/tomaka/winit/issues/165 -[#219]: https://github.com/tomaka/winit/issues/219 -[#242]: https://github.com/tomaka/winit/issues/242 -[#306]: https://github.com/tomaka/winit/issues/306 -[#315]: https://github.com/tomaka/winit/issues/315 -[#319]: https://github.com/tomaka/winit/issues/319 -[#33]: https://github.com/tomaka/winit/issues/33 -[#459]: https://github.com/tomaka/winit/issues/459 -[#5]: https://github.com/tomaka/winit/issues/5 -[#63]: https://github.com/tomaka/winit/issues/63 -[#720]: https://github.com/tomaka/winit/issues/720 -[#721]: https://github.com/tomaka/winit/issues/721 -[#750]: https://github.com/tomaka/winit/issues/750 -[#804]: https://github.com/tomaka/winit/issues/804 -[#812]: https://github.com/tomaka/winit/issues/812 +[#165]: https://github.com/rust-windowing/winit/issues/165 +[#219]: https://github.com/rust-windowing/winit/issues/219 +[#242]: https://github.com/rust-windowing/winit/issues/242 +[#306]: https://github.com/rust-windowing/winit/issues/306 +[#315]: https://github.com/rust-windowing/winit/issues/315 +[#319]: https://github.com/rust-windowing/winit/issues/319 +[#33]: https://github.com/rust-windowing/winit/issues/33 +[#459]: https://github.com/rust-windowing/winit/issues/459 +[#5]: https://github.com/rust-windowing/winit/issues/5 +[#63]: https://github.com/rust-windowing/winit/issues/63 +[#720]: https://github.com/rust-windowing/winit/issues/720 +[#721]: https://github.com/rust-windowing/winit/issues/721 +[#750]: https://github.com/rust-windowing/winit/issues/750 +[#804]: https://github.com/rust-windowing/winit/issues/804 +[#812]: https://github.com/rust-windowing/winit/issues/812 diff --git a/HALL_OF_CHAMPIONS.md b/HALL_OF_CHAMPIONS.md index c3427514..946f5eb4 100644 --- a/HALL_OF_CHAMPIONS.md +++ b/HALL_OF_CHAMPIONS.md @@ -5,7 +5,10 @@ contributors, without whom Winit would not exist in its current form. We thank them deeply for their time and efforts, and wish them best of luck in their future endeavors: -* @tomaka: For creating the Winit project and guiding it through its early +* [@tomaka]: For creating the Winit project and guiding it through its early years of existence. -* @francesca64: For taking over the responsibility of maintaining almost every +* [@francesca64]: For taking over the responsibility of maintaining almost every Winit backend, and standardizing HiDPI support across all of them + +[@tomaka]: https://github.com/tomaka +[@francesca64]: https://github.com/francesca64 diff --git a/README.md b/README.md index bc4b6971..6abcecdf 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,21 @@ # winit - Cross-platform window creation and management in Rust -[![](http://meritbadge.herokuapp.com/winit)](https://crates.io/crates/winit) +[![Crates.io](https://img.shields.io/crates/v/winit.svg)](https://crates.io/crates/winit) [![Docs.rs](https://docs.rs/winit/badge.svg)](https://docs.rs/winit) [![Build Status](https://travis-ci.org/rust-windowing/winit.svg?branch=master)](https://travis-ci.org/rust-windowing/winit) [![Build status](https://ci.appveyor.com/api/projects/status/hr89but4x1n3dphq/branch/master?svg=true)](https://ci.appveyor.com/project/Osspial/winit/branch/master) ```toml [dependencies] -winit = "0.19.1" +winit = "0.20.0-alpha2" ``` ## [Documentation](https://docs.rs/winit) +For features _within_ the scope of winit, see [FEATURES.md](FEATURES.md). + +For features _outside_ the scope of winit, see [Missing features provided by other crates](https://github.com/rust-windowing/winit/wiki/Missing-features-provided-by-other-crates) in the wiki. + ## Contact Us Join us in any of these: @@ -31,19 +35,23 @@ show something on the window you need to use the platform-specific getters provi another library. ```rust -extern crate winit; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; fn main() { - let mut event_loop = winit::EventLoop::new(); - let window = winit::Window::new(&event_loop).unwrap(); + let event_loop = EventLoop::new(); + let window = WindowBuilder::new().build(&event_loop).unwrap(); - event_loop.run(|event| { + event_loop.run(move |event, _, control_flow| { match event { - winit::Event::WindowEvent { - event: winit::WindowEvent::CloseRequested, - .. - } => winit::ControlFlow::Break, - _ => winit::ControlFlow::Continue, + Event::WindowEvent { + event: WindowEvent::CloseRequested, + window_id, + } if window_id == window.id() => *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, } }); } diff --git a/examples/cursor.rs b/examples/cursor.rs index 59441c22..d5bd34a9 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -1,8 +1,8 @@ -extern crate winit; - -use winit::window::{WindowBuilder, CursorIcon}; -use winit::event::{Event, WindowEvent, ElementState, KeyboardInput}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{ElementState, Event, KeyboardInput, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::{CursorIcon, WindowBuilder}, +}; fn main() { let event_loop = EventLoop::new(); @@ -12,37 +12,72 @@ fn main() { let mut cursor_idx = 0; - event_loop.run(move |event, _, control_flow| { - match event { - Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => { - println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]); - window.set_cursor_icon(CURSORS[cursor_idx]); - if cursor_idx < CURSORS.len() - 1 { - cursor_idx += 1; - } else { - cursor_idx = 0; - } - }, - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { - *control_flow = ControlFlow::Exit; - return; - }, - _ => () + event_loop.run(move |event, _, control_flow| match event { + Event::WindowEvent { + event: + WindowEvent::KeyboardInput { + input: + KeyboardInput { + state: ElementState::Pressed, + .. + }, + .. + }, + .. + } => { + println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]); + window.set_cursor_icon(CURSORS[cursor_idx]); + if cursor_idx < CURSORS.len() - 1 { + cursor_idx += 1; + } else { + cursor_idx = 0; + } } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => { + *control_flow = ControlFlow::Exit; + return; + } + _ => (), }); } const CURSORS: &[CursorIcon] = &[ - CursorIcon::Default, CursorIcon::Crosshair, CursorIcon::Hand, - CursorIcon::Arrow, CursorIcon::Move, CursorIcon::Text, - CursorIcon::Wait, CursorIcon::Help, CursorIcon::Progress, - CursorIcon::NotAllowed, CursorIcon::ContextMenu, CursorIcon::Cell, - CursorIcon::VerticalText, CursorIcon::Alias, CursorIcon::Copy, - CursorIcon::NoDrop, CursorIcon::Grab, CursorIcon::Grabbing, - CursorIcon::AllScroll, CursorIcon::ZoomIn, CursorIcon::ZoomOut, - CursorIcon::EResize, CursorIcon::NResize, CursorIcon::NeResize, - CursorIcon::NwResize, CursorIcon::SResize, CursorIcon::SeResize, - CursorIcon::SwResize, CursorIcon::WResize, CursorIcon::EwResize, - CursorIcon::NsResize, CursorIcon::NeswResize, CursorIcon::NwseResize, - CursorIcon::ColResize, CursorIcon::RowResize + CursorIcon::Default, + CursorIcon::Crosshair, + CursorIcon::Hand, + CursorIcon::Arrow, + CursorIcon::Move, + CursorIcon::Text, + CursorIcon::Wait, + CursorIcon::Help, + CursorIcon::Progress, + CursorIcon::NotAllowed, + CursorIcon::ContextMenu, + CursorIcon::Cell, + CursorIcon::VerticalText, + CursorIcon::Alias, + CursorIcon::Copy, + CursorIcon::NoDrop, + CursorIcon::Grab, + CursorIcon::Grabbing, + CursorIcon::AllScroll, + CursorIcon::ZoomIn, + CursorIcon::ZoomOut, + CursorIcon::EResize, + CursorIcon::NResize, + CursorIcon::NeResize, + CursorIcon::NwResize, + CursorIcon::SResize, + CursorIcon::SeResize, + CursorIcon::SwResize, + CursorIcon::WResize, + CursorIcon::EwResize, + CursorIcon::NsResize, + CursorIcon::NeswResize, + CursorIcon::NwseResize, + CursorIcon::ColResize, + CursorIcon::RowResize, ]; diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index 8e7b1f7e..726aba56 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -1,8 +1,8 @@ -extern crate winit; - -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent, ElementState, KeyboardInput}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{DeviceEvent, ElementState, Event, KeyboardInput, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; fn main() { let event_loop = EventLoop::new(); @@ -14,16 +14,17 @@ fn main() { event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; - if let Event::WindowEvent { event, .. } = event { - match event { + match event { + Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::KeyboardInput { - input: KeyboardInput { - state: ElementState::Released, - virtual_keycode: Some(key), - modifiers, - .. - }, + input: + KeyboardInput { + state: ElementState::Released, + virtual_keycode: Some(key), + modifiers, + .. + }, .. } => { use winit::event::VirtualKeyCode::*; @@ -35,7 +36,16 @@ fn main() { } } _ => (), - } + }, + Event::DeviceEvent { event, .. } => match event { + DeviceEvent::MouseMotion { delta } => println!("mouse moved: {:?}", delta), + DeviceEvent::Button { button, state } => match state { + ElementState::Pressed => println!("mouse button {} pressed", button), + ElementState::Released => println!("mouse button {} released", button), + }, + _ => (), + }, + _ => (), } }); } diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index 8827751f..27df2276 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -1,10 +1,10 @@ -extern crate winit; - use std::io::{self, Write}; -use winit::monitor::MonitorHandle; -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInput}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + monitor::MonitorHandle, + window::WindowBuilder, +}; fn main() { let event_loop = EventLoop::new(); @@ -91,7 +91,10 @@ fn main() { #[cfg(target_os = "macos")] { use winit::platform::macos::WindowExtMacOS; - println!("window.simple_fullscreen {:?}", WindowExtMacOS::simple_fullscreen(&window)); + println!( + "window.simple_fullscreen {:?}", + WindowExtMacOS::simple_fullscreen(&window) + ); } } (VirtualKeyCode::M, ElementState::Pressed) => { @@ -123,7 +126,10 @@ fn prompt_for_monitor(event_loop: &EventLoop<()>) -> MonitorHandle { let mut num = String::new(); io::stdin().read_line(&mut num).unwrap(); let num = num.trim().parse().ok().expect("Please enter a number"); - let monitor = event_loop.available_monitors().nth(num).expect("Please enter a valid ID"); + let monitor = event_loop + .available_monitors() + .nth(num) + .expect("Please enter a valid ID"); println!("Using {:?}", monitor.name()); diff --git a/examples/handling_close.rs b/examples/handling_close.rs index 31f17da3..d67c0046 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -1,8 +1,8 @@ -extern crate winit; - -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent, KeyboardInput}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{Event, KeyboardInput, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; fn main() { let event_loop = EventLoop::new(); @@ -15,61 +15,67 @@ fn main() { let mut close_requested = false; event_loop.run(move |event, _, control_flow| { - use winit::event::ElementState::Released; - use winit::event::VirtualKeyCode::{N, Y}; + use winit::event::{ + ElementState::Released, + VirtualKeyCode::{N, Y}, + }; *control_flow = ControlFlow::Wait; match event { - Event::WindowEvent { event, .. } => match event { - WindowEvent::CloseRequested => { - // `CloseRequested` is sent when the close button on the window is pressed (or - // through whatever other mechanisms the window manager provides for closing a - // window). If you don't handle this event, the close button won't actually do - // anything. + Event::WindowEvent { event, .. } => { + match event { + WindowEvent::CloseRequested => { + // `CloseRequested` is sent when the close button on the window is pressed (or + // through whatever other mechanisms the window manager provides for closing a + // window). If you don't handle this event, the close button won't actually do + // anything. - // A common thing to do here is prompt the user if they have unsaved work. - // Creating a proper dialog box for that is far beyond the scope of this - // example, so here we'll just respond to the Y and N keys. - println!("Are you ready to bid your window farewell? [Y/N]"); - close_requested = true; + // A common thing to do here is prompt the user if they have unsaved work. + // Creating a proper dialog box for that is far beyond the scope of this + // example, so here we'll just respond to the Y and N keys. + println!("Are you ready to bid your window farewell? [Y/N]"); + close_requested = true; - // In applications where you can safely close the window without further - // action from the user, this is generally where you'd handle cleanup before - // closing the window. How to close the window is detailed in the handler for - // the Y key. - } - WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode: Some(virtual_code), - state: Released, - .. - }, - .. - } => match virtual_code { - Y => { - if close_requested { - // This is where you'll want to do any cleanup you need. - println!("Buh-bye!"); - - // For a single-window application like this, you'd normally just - // break out of the event loop here. If you wanted to keep running the - // event loop (i.e. if it's a multi-window application), you need to - // drop the window. That closes it, and results in `Destroyed` being - // sent. - *control_flow = ControlFlow::Exit; - } + // In applications where you can safely close the window without further + // action from the user, this is generally where you'd handle cleanup before + // closing the window. How to close the window is detailed in the handler for + // the Y key. } - N => { - if close_requested { - println!("Your window will continue to stay by your side."); - close_requested = false; + WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(virtual_code), + state: Released, + .. + }, + .. + } => { + match virtual_code { + Y => { + if close_requested { + // This is where you'll want to do any cleanup you need. + println!("Buh-bye!"); + + // For a single-window application like this, you'd normally just + // break out of the event loop here. If you wanted to keep running the + // event loop (i.e. if it's a multi-window application), you need to + // drop the window. That closes it, and results in `Destroyed` being + // sent. + *control_flow = ControlFlow::Exit; + } + } + N => { + if close_requested { + println!("Your window will continue to stay by your side."); + close_requested = false; + } + } + _ => (), } } _ => (), - }, - _ => (), - }, + } + } _ => (), } }); diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index 37c0fe7f..4b24d161 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -1,16 +1,14 @@ -extern crate winit; - -use winit::dpi::LogicalSize; -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + dpi::LogicalSize, + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; fn main() { let event_loop = EventLoop::new(); - let window = WindowBuilder::new() - .build(&event_loop) - .unwrap(); + let window = WindowBuilder::new().build(&event_loop).unwrap(); window.set_min_inner_size(Some(LogicalSize::new(400.0, 200.0))); window.set_max_inner_size(Some(LogicalSize::new(800.0, 400.0))); @@ -19,8 +17,10 @@ fn main() { println!("{:?}", event); match event { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => - *control_flow = ControlFlow::Exit, + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, _ => *control_flow = ControlFlow::Wait, } }); diff --git a/examples/monitor_list.rs b/examples/monitor_list.rs index 42e683bf..55a2dde8 100644 --- a/examples/monitor_list.rs +++ b/examples/monitor_list.rs @@ -1,9 +1,9 @@ -extern crate winit; -use winit::event_loop::EventLoop; -use winit::window::WindowBuilder; +use winit::{event_loop::EventLoop, window::WindowBuilder}; fn main() { let event_loop = EventLoop::new(); let window = WindowBuilder::new().build(&event_loop).unwrap(); - println!("{:#?}\nPrimary: {:#?}", window.available_monitors(), window.primary_monitor()); + + dbg!(window.available_monitors()); + dbg!(window.primary_monitor()); } diff --git a/examples/multithreaded.rs b/examples/multithreaded.rs index 05408799..39f7af3d 100644 --- a/examples/multithreaded.rs +++ b/examples/multithreaded.rs @@ -1,11 +1,10 @@ extern crate env_logger; -extern crate winit; - use std::{collections::HashMap, sync::mpsc, thread, time::Duration}; use winit::{ event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, window::{CursorIcon, WindowBuilder}, + event_loop::{ControlFlow, EventLoop}, + window::{CursorIcon, WindowBuilder}, }; const WINDOW_COUNT: usize = 3; @@ -25,12 +24,16 @@ fn main() { thread::spawn(move || { while let Ok(event) = rx.recv() { match event { - WindowEvent::KeyboardInput { input: KeyboardInput { - state: ElementState::Released, - virtual_keycode: Some(key), - modifiers, + WindowEvent::KeyboardInput { + input: + KeyboardInput { + state: ElementState::Released, + virtual_keycode: Some(key), + modifiers, + .. + }, .. - }, .. } => { + } => { window.set_title(&format!("{:?}", key)); let state = !modifiers.shift; use self::VirtualKeyCode::*; @@ -53,7 +56,7 @@ fn main() { println!("-> inner_position : {:?}", window.inner_position()); println!("-> outer_size : {:?}", window.outer_size()); println!("-> inner_size : {:?}", window.inner_size()); - }, + } L => window.set_min_inner_size(match state { true => Some(WINDOW_SIZE.into()), false => None, @@ -68,22 +71,26 @@ fn main() { }), Q => window.request_redraw(), R => window.set_resizable(state), - S => window.set_inner_size(match state { - true => (WINDOW_SIZE.0 + 100, WINDOW_SIZE.1 + 100), - false => WINDOW_SIZE, - }.into()), - W => window.set_cursor_position(( - WINDOW_SIZE.0 as i32 / 2, - WINDOW_SIZE.1 as i32 / 2, - ).into()).unwrap(), + S => window.set_inner_size( + match state { + true => (WINDOW_SIZE.0 + 100, WINDOW_SIZE.1 + 100), + false => WINDOW_SIZE, + } + .into(), + ), + W => window + .set_cursor_position( + (WINDOW_SIZE.0 as i32 / 2, WINDOW_SIZE.1 as i32 / 2).into(), + ) + .unwrap(), Z => { window.set_visible(false); thread::sleep(Duration::from_secs(1)); window.set_visible(true); - }, + } _ => (), } - }, + } _ => (), } } @@ -95,20 +102,25 @@ fn main() { false => ControlFlow::Exit, }; match event { - Event::WindowEvent { event, window_id } => { - match event { - WindowEvent::CloseRequested - | WindowEvent::Destroyed - | WindowEvent::KeyboardInput { input: KeyboardInput { - virtual_keycode: Some(VirtualKeyCode::Escape), - .. }, .. } => { - window_senders.remove(&window_id); - }, - _ => if let Some(tx) = window_senders.get(&window_id) { - tx.send(event).unwrap(); - }, + Event::WindowEvent { event, window_id } => match event { + WindowEvent::CloseRequested + | WindowEvent::Destroyed + | WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(VirtualKeyCode::Escape), + .. + }, + .. + } => { + window_senders.remove(&window_id); } - } + _ => { + if let Some(tx) = window_senders.get(&window_id) { + tx.send(event).unwrap(); + } + } + }, _ => (), } }) diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index cf2703c2..61dc1fd7 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -1,9 +1,9 @@ -extern crate winit; - use std::collections::HashMap; -use winit::window::Window; -use winit::event::{Event, WindowEvent, ElementState, KeyboardInput}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{ElementState, Event, KeyboardInput, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::Window, +}; fn main() { let event_loop = EventLoop::new(); @@ -28,12 +28,19 @@ fn main() { if windows.is_empty() { *control_flow = ControlFlow::Exit; } - }, - WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. } => { + } + WindowEvent::KeyboardInput { + input: + KeyboardInput { + state: ElementState::Pressed, + .. + }, + .. + } => { let window = Window::new(&event_loop).unwrap(); windows.insert(window.id(), window); - }, - _ => () + } + _ => (), } } _ => (), diff --git a/examples/proxy.rs b/examples/proxy.rs index 3e9b2e9d..06198ecd 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -1,7 +1,8 @@ -extern crate winit; -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; fn main() { let event_loop: EventLoop = EventLoop::new_user_event(); @@ -26,8 +27,10 @@ fn main() { event_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => - *control_flow = ControlFlow::Exit, + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, _ => *control_flow = ControlFlow::Wait, } }); diff --git a/examples/request_redraw.rs b/examples/request_redraw.rs index 4ed4e8fb..ac9377e7 100644 --- a/examples/request_redraw.rs +++ b/examples/request_redraw.rs @@ -1,9 +1,10 @@ -extern crate winit; -use std::time::{Instant, Duration}; +use std::time::{Duration, Instant}; -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; fn main() { let event_loop = EventLoop::new(); @@ -13,19 +14,21 @@ fn main() { .build(&event_loop) .unwrap(); - event_loop.run(move |event, _, control_flow| { - println!("{:?}", event); - - match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => *control_flow = ControlFlow::Exit, - Event::EventsCleared => { - window.request_redraw(); - *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0)) - }, - _ => () + event_loop.run(move |event, _, control_flow| match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + Event::EventsCleared => { + window.request_redraw(); + *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0)) } + Event::WindowEvent { + event: WindowEvent::RedrawRequested, + .. + } => { + println!("{:?}", event); + } + _ => (), }); } diff --git a/examples/resizable.rs b/examples/resizable.rs index 969ce04b..8aa6f706 100644 --- a/examples/resizable.rs +++ b/examples/resizable.rs @@ -1,7 +1,8 @@ -extern crate winit; -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInput}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; fn main() { let event_loop = EventLoop::new(); diff --git a/examples/timer.rs b/examples/timer.rs index 97b61b84..8d3b9bde 100644 --- a/examples/timer.rs +++ b/examples/timer.rs @@ -1,8 +1,9 @@ -extern crate winit; use std::time::{Duration, Instant}; -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent, StartCause}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{Event, StartCause, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; fn main() { let event_loop = EventLoop::new(); @@ -12,22 +13,24 @@ fn main() { .build(&event_loop) .unwrap(); + let timer_length = Duration::new(1, 0); + event_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { - Event::NewEvents(StartCause::Init) => - *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0)), - Event::NewEvents(StartCause::ResumeTimeReached{..}) => { - *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0)); + Event::NewEvents(StartCause::Init) => { + *control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length) + } + Event::NewEvents(StartCause::ResumeTimeReached { .. }) => { + *control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length); println!("\nTimer\n"); - _window.set_inner_size(winit::dpi::LogicalSize::new(300.0, 300.0)); - }, + } Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => *control_flow = ControlFlow::Exit, - _ => () + _ => (), } }); } diff --git a/examples/transparent.rs b/examples/transparent.rs index 4da6f9f2..8eddb902 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -1,14 +1,17 @@ -extern crate winit; -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent}; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; fn main() { let event_loop = EventLoop::new(); - let window = WindowBuilder::new().with_decorations(false) - .with_transparency(true) - .build(&event_loop).unwrap(); + let window = WindowBuilder::new() + .with_decorations(false) + .with_transparent(true) + .build(&event_loop) + .unwrap(); window.set_title("A fantastic window!"); @@ -16,8 +19,10 @@ fn main() { println!("{:?}", event); match event { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => - *control_flow = ControlFlow::Exit, + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, _ => *control_flow = ControlFlow::Wait, } }); diff --git a/examples/video_modes.rs b/examples/video_modes.rs new file mode 100644 index 00000000..f8c6aa08 --- /dev/null +++ b/examples/video_modes.rs @@ -0,0 +1,12 @@ +use winit::event_loop::EventLoop; + +fn main() { + let event_loop = EventLoop::new(); + let monitor = event_loop.primary_monitor(); + + println!("Listing available video modes:"); + + for mode in monitor.video_modes() { + println!("{:?}", mode); + } +} diff --git a/examples/window.rs b/examples/window.rs index 5ae76e29..12e0593e 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -1,38 +1,26 @@ -extern crate winit; -#[cfg(feature = "stdweb")] -#[macro_use] -extern crate stdweb; -#[cfg(feature = "wasm-bindgen")] -extern crate wasm_bindgen; -#[cfg(feature = "wasm-bindgen")] -extern crate web_sys; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent}; -use winit::event_loop::{EventLoop, ControlFlow}; -use wasm_bindgen::{prelude::*, JsValue}; -use web_sys::console; - -#[wasm_bindgen(start)] -pub fn main() { - console::log_1(&JsValue::from_str("main")); +fn main() { let event_loop = EventLoop::new(); - let _window = WindowBuilder::new() + let window = WindowBuilder::new() .with_title("A fantastic window!") .build(&event_loop) .unwrap(); - console::log_1(&JsValue::from_str("Created window")); - event_loop.run(|event, _, control_flow| { - console::log_1(&JsValue::from_str(&format!("{:?}", event))); + event_loop.run(move |event, _, control_flow| { + println!("{:?}", event); match event { Event::WindowEvent { event: WindowEvent::CloseRequested, - .. - } => *control_flow = ControlFlow::Exit, - _ => () + window_id, + } if window_id == window.id() => *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, } }); -} \ No newline at end of file +} diff --git a/examples/window_icon.rs b/examples/window_icon.rs index 2af5a6d7..8fdcdd40 100644 --- a/examples/window_icon.rs +++ b/examples/window_icon.rs @@ -1,30 +1,19 @@ -extern crate winit; extern crate image; - use std::path::Path; -use winit::window::{WindowBuilder, Icon}; -use winit::event::Event; -use winit::event_loop::{EventLoop, ControlFlow}; +use winit::{ + event::Event, + event_loop::{ControlFlow, EventLoop}, + window::{Icon, WindowBuilder}, +}; fn main() { - // You'll have to choose an icon size at your own discretion. On X11, the desired size varies // by WM, and on Windows, you still have to account for screen scaling. Here we use 32px, // since it seems to work well enough in most cases. Be careful about going too high, or // you'll be bitten by the low-quality downscaling built into the WM. let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); - let (icon_rgba, icon_width, icon_height) = { - let image = image::open(path).expect("Failed to open icon path"); - use image::{GenericImageView, Pixel}; - let (width, height) = image.dimensions(); - let mut rgba = Vec::with_capacity((width * height) as usize * 4); - for (_, _, pixel) in image.pixels() { - rgba.extend_from_slice(&pixel.to_rgba().data); - } - (rgba, width, height) - }; - let icon = Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon"); + let icon = load_icon(Path::new(path)); let event_loop = EventLoop::new(); @@ -43,10 +32,8 @@ fn main() { match event { CloseRequested => *control_flow = ControlFlow::Exit, DroppedFile(path) => { - use image::GenericImageView; - window.set_window_icon(Some(load_icon(&path))); - }, + } _ => (), } } diff --git a/examples/window_run_return.rs b/examples/window_run_return.rs index ff619902..d2516c7a 100644 --- a/examples/window_run_return.rs +++ b/examples/window_run_return.rs @@ -1,9 +1,9 @@ -extern crate winit; - -use winit::window::WindowBuilder; -use winit::event::{Event, WindowEvent}; -use winit::event_loop::{EventLoop, ControlFlow}; -use winit::platform::desktop::EventLoopExtDesktop; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + platform::desktop::EventLoopExtDesktop, + window::WindowBuilder, +}; fn main() { let mut event_loop = EventLoop::new(); @@ -14,14 +14,12 @@ fn main() { .unwrap(); println!("Close the window to continue."); - event_loop.run_return(|event, _, control_flow| { - match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => *control_flow = ControlFlow::Exit, - _ => *control_flow = ControlFlow::Wait, - } + event_loop.run_return(|event, _, control_flow| match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, }); drop(window); @@ -31,14 +29,12 @@ fn main() { .unwrap(); println!("Wa ha ha! You thought that closing the window would finish this?!"); - event_loop.run_return(|event, _, control_flow| { - match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => *control_flow = ControlFlow::Exit, - _ => *control_flow = ControlFlow::Wait, - } + event_loop.run_return(|event, _, control_flow| match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, }); println!("Okay we're done now for real."); diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..a069b434 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,3 @@ +force_explicit_abi=true +use_field_init_shorthand=true +# merge_imports=true diff --git a/src/dpi.rs b/src/dpi.rs index afd1cbfd..9c89c12c 100644 --- a/src/dpi.rs +++ b/src/dpi.rs @@ -1,4 +1,3 @@ - //! DPI is important, so read the docs for this module if you don't want to be confused. //! //! Originally, `winit` dealt entirely in physical pixels (excluding unintentional inconsistencies), but now all diff --git a/src/error.rs b/src/error.rs index 83c37210..c039f3b8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,6 @@ -use std::fmt; -use std::error; +use std::{error, fmt}; -use platform_impl; +use crate::platform_impl; /// An error whose cause it outside Winit's control. #[derive(Debug)] @@ -30,20 +29,14 @@ impl NotSupportedError { #[inline] #[allow(dead_code)] pub(crate) fn new() -> NotSupportedError { - NotSupportedError { - _marker: () - } + NotSupportedError { _marker: () } } } impl OsError { #[allow(dead_code)] pub(crate) fn new(line: u32, file: &'static str, error: platform_impl::OsError) -> OsError { - OsError { - line, - file, - error, - } + OsError { line, file, error } } } @@ -51,33 +44,36 @@ impl OsError { macro_rules! os_error { ($error:expr) => {{ crate::error::OsError::new(line!(), file!(), $error) - }} + }}; } impl fmt::Display for OsError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - formatter.pad(&format!("os error at {}:{}: {}", self.file, self.line, self.error)) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.pad(&format!( + "os error at {}:{}: {}", + self.file, self.line, self.error + )) } } impl fmt::Display for ExternalError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match self { - ExternalError::NotSupported(e) => e.fmt(formatter), - ExternalError::Os(e) => e.fmt(formatter), + ExternalError::NotSupported(e) => e.fmt(f), + ExternalError::Os(e) => e.fmt(f), } } } impl fmt::Debug for NotSupportedError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - formatter.debug_struct("NotSupportedError").finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.debug_struct("NotSupportedError").finish() } } impl fmt::Display for NotSupportedError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - formatter.pad("the requested operation is not supported by Winit") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.pad("the requested operation is not supported by Winit") } } diff --git a/src/event.rs b/src/event.rs index 7eaee201..7e40fcf9 100644 --- a/src/event.rs +++ b/src/event.rs @@ -7,9 +7,11 @@ use instant::Instant; use std::path::PathBuf; -use dpi::{LogicalPosition, LogicalSize}; -use window::WindowId; -use platform_impl; +use crate::{ + dpi::{LogicalPosition, LogicalSize}, + platform_impl, + window::WindowId, +}; /// Describes a generic event. #[derive(Clone, Debug, PartialEq)] @@ -36,10 +38,11 @@ pub enum Event { /// emitted, it is guaranteed to be the last event emitted. LoopDestroyed, - /// Emitted when the application has been suspended or resumed. - /// - /// The parameter is true if app was suspended, and false if it has been resumed. - Suspended(bool), + /// Emitted when the application has been suspended. + Suspended, + + /// Emitted when the application has been resumed. + Resumed, } impl Event { @@ -47,12 +50,13 @@ impl Event { use self::Event::*; match self { UserEvent(_) => Err(self), - WindowEvent{window_id, event} => Ok(WindowEvent{window_id, event}), - DeviceEvent{device_id, event} => Ok(DeviceEvent{device_id, event}), + WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }), + DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }), NewEvents(cause) => Ok(NewEvents(cause)), EventsCleared => Ok(EventsCleared), LoopDestroyed => Ok(LoopDestroyed), - Suspended(suspended) => Ok(Suspended(suspended)), + Suspended => Ok(Suspended), + Resumed => Ok(Resumed), } } } @@ -65,14 +69,14 @@ pub enum StartCause { /// guaranteed to be equal to or after the requested resume time. ResumeTimeReached { start: Instant, - requested_resume: Instant + requested_resume: Instant, }, /// Sent if the OS has new events to send to the window, after a wait was requested. Contains /// the moment the wait was requested and the resume time, if requested. WaitCancelled { start: Instant, - requested_resume: Option + requested_resume: Option, }, /// Sent if the event loop is being resumed after the loop's control flow was set to @@ -80,7 +84,7 @@ pub enum StartCause { Poll, /// Sent once, immediately after `run` is called. Indicates that the loop was just initialized. - Init + Init, } /// Describes an event from a `Window`. @@ -125,7 +129,10 @@ pub enum WindowEvent { Focused(bool), /// An event from the keyboard has been received. - KeyboardInput { device_id: DeviceId, input: KeyboardInput }, + KeyboardInput { + device_id: DeviceId, + input: KeyboardInput, + }, /// The cursor has moved on the window. CursorMoved { @@ -135,7 +142,7 @@ pub enum WindowEvent { /// limited by the display area and it may have been transformed by the OS to implement effects such as cursor /// acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control. position: LogicalPosition, - modifiers: ModifiersState + modifiers: ModifiersState, }, /// The cursor has entered the window. @@ -145,21 +152,38 @@ pub enum WindowEvent { CursorLeft { device_id: DeviceId }, /// A mouse wheel movement or touchpad scroll occurred. - MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase, modifiers: ModifiersState }, + MouseWheel { + device_id: DeviceId, + delta: MouseScrollDelta, + phase: TouchPhase, + modifiers: ModifiersState, + }, /// An mouse button press has been received. - MouseInput { device_id: DeviceId, state: ElementState, button: MouseButton, modifiers: ModifiersState }, - + MouseInput { + device_id: DeviceId, + state: ElementState, + button: MouseButton, + modifiers: ModifiersState, + }, /// Touchpad pressure event. /// /// At the moment, only supported on Apple forcetouch-capable macbooks. /// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad /// is being pressed) and stage (integer representing the click level). - TouchpadPressure { device_id: DeviceId, pressure: f32, stage: i64 }, + TouchpadPressure { + device_id: DeviceId, + pressure: f32, + stage: i64, + }, /// Motion on some analog axis. May report data redundant to other, more specific events. - AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 }, + AxisMotion { + device_id: DeviceId, + axis: AxisId, + value: f64, + }, /// The OS or application has requested that the window be redrawn. RedrawRequested, @@ -175,7 +199,7 @@ pub enum WindowEvent { /// * Changing the display's DPI factor (e.g. in Control Panel on Windows). /// * Moving the window to a display with a different DPI factor. /// - /// For more information about DPI in general, see the [`dpi`](dpi/index.html) module. + /// For more information about DPI in general, see the [`dpi`](../dpi/index.html) module. HiDpiFactorChanged(f64), } @@ -229,11 +253,19 @@ pub enum DeviceEvent { /// Motion on some analog axis. This event will be reported for all arbitrary input devices /// that winit supports on this platform, including mouse devices. If the device is a mouse /// device then this will be reported alongside the MouseMotion event. - Motion { axis: AxisId, value: f64 }, + Motion { + axis: AxisId, + value: f64, + }, - Button { button: ButtonId, state: ElementState }, + Button { + button: ButtonId, + state: ElementState, + }, Key(KeyboardInput), - Text { codepoint: char }, + Text { + codepoint: char, + }, } /// Describes a keyboard input event. @@ -259,7 +291,7 @@ pub struct KeyboardInput { /// /// This is tracked internally to avoid tracking errors arising from modifier key state changes when events from /// this device are not being delivered to the application, e.g. due to keyboard focus being elsewhere. - pub modifiers: ModifiersState + pub modifiers: ModifiersState, } /// Describes touch-screen input state. @@ -269,7 +301,7 @@ pub enum TouchPhase { Started, Moved, Ended, - Cancelled + Cancelled, } /// Represents touch event @@ -293,7 +325,7 @@ pub struct Touch { pub phase: TouchPhase, pub location: LogicalPosition, /// unique identifier of a finger. - pub id: u64 + pub id: u64, } /// Hardware-dependent keyboard scan code. @@ -327,19 +359,19 @@ pub enum MouseButton { #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum MouseScrollDelta { - /// Amount in lines or rows to scroll in the horizontal - /// and vertical directions. - /// - /// Positive values indicate movement forward - /// (away from the user) or rightwards. - LineDelta(f32, f32), - /// Amount in pixels to scroll in the horizontal and - /// vertical direction. - /// - /// Scroll events are expressed as a PixelDelta if - /// supported by the device (eg. a touchpad) and - /// platform. - PixelDelta(LogicalPosition), + /// Amount in lines or rows to scroll in the horizontal + /// and vertical directions. + /// + /// Positive values indicate movement forward + /// (away from the user) or rightwards. + LineDelta(f32, f32), + /// Amount in pixels to scroll in the horizontal and + /// vertical direction. + /// + /// Scroll events are expressed as a PixelDelta if + /// supported by the device (eg. a touchpad) and + /// platform. + PixelDelta(LogicalPosition), } /// Symbolic name for a keyboard key. @@ -499,7 +531,7 @@ pub enum VirtualKeyCode { Multiply, Mute, MyComputer, - NavigateForward, // also called "Prior" + NavigateForward, // also called "Prior" NavigateBackward, // also called "Next" NextTrack, NoConvert, @@ -557,5 +589,5 @@ pub struct ModifiersState { /// The "logo" key /// /// This is the "windows" key on PC and "command" key on Mac. - pub logo: bool + pub logo: bool, } diff --git a/src/event_loop.rs b/src/event_loop.rs index 1e5fb21c..68c6f93d 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -22,14 +22,14 @@ use platform_impl; /// /// An `EventLoop` can be seen more or less as a "context". Calling `EventLoop::new()` /// initializes everything that will be required to create windows. For example on Linux creating -/// an events loop opens a connection to the X or Wayland server. +/// an event loop opens a connection to the X or Wayland server. /// /// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs. /// /// Note that the `EventLoop` cannot be shared across threads (due to platform-dependant logic /// forbidding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the /// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the -/// `EventLoopProxy` allows you to wake up an `EventLoop` from an other thread. +/// `EventLoopProxy` allows you to wake up an `EventLoop` from another thread. pub struct EventLoop { pub(crate) event_loop: platform_impl::EventLoop, pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync @@ -46,14 +46,14 @@ pub struct EventLoopWindowTarget { } impl fmt::Debug for EventLoop { - fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { - fmtr.pad("EventLoop { .. }") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("EventLoop { .. }") } } impl fmt::Debug for EventLoopWindowTarget { - fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { - fmtr.pad("EventLoopWindowTarget { .. }") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("EventLoopWindowTarget { .. }") } } @@ -121,7 +121,7 @@ impl EventLoop { } } - /// Hijacks the calling thread and initializes the `winit` event loop with the provided + /// Hijacks the calling thread and initializes the winit event loop with the provided /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to /// access any data from the calling context. /// @@ -147,10 +147,8 @@ impl EventLoop { } /// Returns the list of all the monitors available on the system. - /// - // Note: should be replaced with `-> impl Iterator` once stable. #[inline] - pub fn available_monitors(&self) -> AvailableMonitorsIter { + pub fn available_monitors(&self) -> impl Iterator { let data = self.event_loop.available_monitors(); AvailableMonitorsIter { data: data.into_iter(), @@ -191,8 +189,8 @@ impl EventLoopProxy { } impl fmt::Debug for EventLoopProxy { - fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { - fmtr.pad("EventLoopProxy { .. }") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("EventLoopProxy { .. }") } } @@ -202,7 +200,7 @@ impl fmt::Debug for EventLoopProxy { pub struct EventLoopClosed; impl fmt::Display for EventLoopClosed { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", error::Error::description(self)) } } diff --git a/src/icon.rs b/src/icon.rs index c136b63e..bbbb53f9 100644 --- a/src/icon.rs +++ b/src/icon.rs @@ -1,5 +1,4 @@ -use std::{fmt, mem}; -use std::error::Error; +use std::{error::Error, fmt, mem}; #[repr(C)] #[derive(Debug)] @@ -17,9 +16,7 @@ pub(crate) const PIXEL_SIZE: usize = mem::size_of::(); pub enum BadIcon { /// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be /// safely interpreted as 32bpp RGBA pixels. - ByteCountNotDivisibleBy4 { - byte_count: usize, - }, + ByteCountNotDivisibleBy4 { byte_count: usize }, /// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`. /// At least one of your arguments is incorrect. DimensionsVsPixelCount { @@ -31,7 +28,7 @@ pub enum BadIcon { } impl fmt::Display for BadIcon { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let msg = match self { &BadIcon::ByteCountNotDivisibleBy4 { byte_count } => format!( "The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.", @@ -47,7 +44,7 @@ impl fmt::Display for BadIcon { width, height, pixel_count, width_x_height, ), }; - write!(formatter, "{}", msg) + write!(f, "{}", msg) } } @@ -56,7 +53,7 @@ impl Error for BadIcon { "A valid icon cannot be created from these arguments" } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { Some(self) } } @@ -76,7 +73,9 @@ impl Icon { /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error. pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { if rgba.len() % PIXEL_SIZE != 0 { - return Err(BadIcon::ByteCountNotDivisibleBy4 { byte_count: rgba.len() }); + return Err(BadIcon::ByteCountNotDivisibleBy4 { + byte_count: rgba.len(), + }); } let pixel_count = rgba.len() / PIXEL_SIZE; if pixel_count != (width * height) as usize { @@ -87,7 +86,11 @@ impl Icon { pixel_count, }) } else { - Ok(Icon { rgba, width, height }) + Ok(Icon { + rgba, + width, + height, + }) } } } diff --git a/src/lib.rs b/src/lib.rs index ada920a2..87d7d2a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,29 +22,62 @@ //! //! # Event handling //! -//! Once a [`Window`] has been created, it will *generate events*. For example whenever the user moves -//! the [`Window`], resizes the [`Window`], moves the mouse, etc. an event is generated. +//! Once a [`Window`] has been created, it will generate different *events*. A [`Window`] object can +//! generate a [`WindowEvent`] when certain things happen, like whenever the user moves their mouse +//! or presses a key inside the [`Window`]. Devices can generate a [`DeviceEvent`] directly as well, +//! which contains unfiltered event data that isn't specific to a certain window. Some user +//! activity, like mouse movement, can generate both a [`WindowEvent`] *and* a [`DeviceEvent`]. You +//! can also create and handle your own custom [`UserEvent`]s, if desired. //! -//! The events generated by a [`Window`] can be retreived from the [`EventLoop`] the [`Window`] was created -//! with. +//! Events can be retreived by using an [`EventLoop`]. A [`Window`] will send its events to the +//! [`EventLoop`] object it was created with. //! //! You do this by calling [`event_loop.run(...)`][event_loop_run]. This function will run forever //! unless `control_flow` is set to [`ControlFlow`]`::`[`Exit`], at which point [`Event`]`::`[`LoopDestroyed`] //! is emitted and the entire program terminates. //! //! ```no_run -//! use winit::event_loop::ControlFlow; -//! use winit::event::{Event, WindowEvent}; -//! # use winit::event_loop::EventLoop; -//! # let event_loop = EventLoop::new(); +//! use winit::{ +//! event::{Event, WindowEvent}, +//! event_loop::{ControlFlow, EventLoop}, +//! window::WindowBuilder, +//! }; +//! +//! let event_loop = EventLoop::new(); +//! let window = WindowBuilder::new().build(&event_loop).unwrap(); //! //! event_loop.run(move |event, _, control_flow| { //! match event { -//! Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { +//! Event::EventsCleared => { +//! // Application update code. +//! +//! // Queue a RedrawRequested event. +//! window.request_redraw(); +//! }, +//! Event::WindowEvent { +//! event: WindowEvent::RedrawRequested, +//! .. +//! } => { +//! // Redraw the application. +//! // +//! // It's preferrable to render in this event rather than in EventsCleared, since +//! // rendering in here allows the program to gracefully handle redraws requested +//! // by the OS. +//! }, +//! Event::WindowEvent { +//! event: WindowEvent::CloseRequested, +//! .. +//! } => { //! println!("The close button was pressed; stopping"); //! *control_flow = ControlFlow::Exit //! }, -//! _ => *control_flow = ControlFlow::Wait, +//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't +//! // dispatched any events. This is ideal for games and similar applications. +//! _ => *control_flow = ControlFlow::Poll, +//! // ControlFlow::Wait pauses the event loop if no events are available to process. +//! // This is ideal for non-game applications that only update in response to user +//! // input, and uses significantly less power/CPU time than ControlFlow::Poll. +//! // _ => *control_flow = ControlFlow::Wait, //! } //! }); //! ``` @@ -71,85 +104,34 @@ //! [window_builder_build]: ./window/struct.WindowBuilder.html#method.build //! [window_id_fn]: ./window/struct.Window.html#method.id //! [`Event`]: ./event/enum.Event.html -//! [`WindowEvent`]: ./event/enum.Event.html#variant.WindowEvent +//! [`WindowEvent`]: ./event/enum.WindowEvent.html +//! [`DeviceEvent`]: ./event/enum.DeviceEvent.html +//! [`UserEvent`]: ./event/enum.Event.html#variant.UserEvent //! [`LoopDestroyed`]: ./event/enum.Event.html#variant.LoopDestroyed //! [`platform`]: ./platform/index.html -extern crate instant; +#![deny(rust_2018_idioms)] + #[allow(unused_imports)] #[macro_use] extern crate lazy_static; -extern crate libc; #[macro_use] extern crate log; #[cfg(feature = "serde")] #[macro_use] extern crate serde; - +#[macro_use] #[cfg(target_os = "windows")] -extern crate winapi; +extern crate derivative; #[macro_use] #[cfg(target_os = "windows")] extern crate bitflags; #[cfg(any(target_os = "macos", target_os = "ios"))] #[macro_use] extern crate objc; -#[cfg(target_os = "macos")] -extern crate cocoa; -#[cfg(target_os = "macos")] -extern crate core_foundation; -#[cfg(target_os = "macos")] -extern crate core_graphics; -#[cfg(target_os = "macos")] -extern crate dispatch; -#[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "windows" -))] -extern crate parking_lot; -#[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" -))] -extern crate percent_encoding; -#[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" -))] -extern crate smithay_client_toolkit as sctk; -#[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" -))] -extern crate x11_dl; #[cfg(feature = "std_web")] #[macro_use] extern crate std_web as stdweb; -#[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" -))] -extern crate calloop; -#[cfg(feature = "wasm-bindgen")] -extern crate wasm_bindgen; -#[cfg(feature = "web-sys")] -extern crate web_sys; pub mod dpi; #[macro_use] diff --git a/src/monitor.rs b/src/monitor.rs index 8fab7ca4..f27ef9d7 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -12,8 +12,10 @@ //! [window_get]: ../window/struct.Window.html#method.available_monitors use std::collections::vec_deque::IntoIter as VecDequeIter; -use platform_impl; -use dpi::{PhysicalPosition, PhysicalSize}; +use crate::{ + dpi::{PhysicalPosition, PhysicalSize}, + platform_impl, +}; /// An iterator over all available monitors. /// @@ -44,6 +46,45 @@ impl Iterator for AvailableMonitorsIter { } } +/// Describes a fullscreen video mode of a monitor. +/// +/// Can be acquired with: +/// - [`MonitorHandle::video_modes`][monitor_get]. +/// +/// [monitor_get]: ../monitor/struct.MonitorHandle.html#method.video_modes +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct VideoMode { + pub(crate) size: (u32, u32), + pub(crate) bit_depth: u16, + pub(crate) refresh_rate: u16, +} + +impl VideoMode { + /// Returns the resolution of this video mode. + pub fn size(&self) -> PhysicalSize { + self.size.into() + } + + /// Returns the bit depth of this video mode, as in how many bits you have + /// available per color. This is generally 24 bits or 32 bits on modern + /// systems, depending on whether the alpha channel is counted or not. + /// + /// ## Platform-specific + /// + /// - **Wayland:** Always returns 32. + /// - **iOS:** Always returns 32. + pub fn bit_depth(&self) -> u16 { + self.bit_depth + } + + /// Returns the refresh rate of this video mode. **Note**: the returned + /// refresh rate is an integer approximation, and you shouldn't rely on this + /// value to be exact. + pub fn refresh_rate(&self) -> u16 { + self.refresh_rate + } +} + /// Handle to a monitor. /// /// Allows you to retrieve information about a given monitor and can be used in [`Window`] creation. @@ -51,7 +92,7 @@ impl Iterator for AvailableMonitorsIter { /// [`Window`]: ../window/struct.Window.html #[derive(Debug, Clone)] pub struct MonitorHandle { - pub(crate) inner: platform_impl::MonitorHandle + pub(crate) inner: platform_impl::MonitorHandle, } impl MonitorHandle { @@ -65,8 +106,8 @@ impl MonitorHandle { /// Returns the monitor's resolution. #[inline] - pub fn dimensions(&self) -> PhysicalSize { - self.inner.dimensions() + pub fn size(&self) -> PhysicalSize { + self.inner.size() } /// Returns the top-left corner position of the monitor relative to the larger full @@ -78,7 +119,7 @@ impl MonitorHandle { /// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa. /// - /// See the [`dpi`](dpi/index.html) module for more information. + /// See the [`dpi`](../dpi/index.html) module for more information. /// /// ## Platform-specific /// @@ -88,4 +129,10 @@ impl MonitorHandle { pub fn hidpi_factor(&self) -> f64 { self.inner.hidpi_factor() } + + /// Returns all fullscreen video modes supported by this monitor. + #[inline] + pub fn video_modes(&self) -> impl Iterator { + self.inner.video_modes() + } } diff --git a/src/platform/android.rs b/src/platform/android.rs index 82a73453..dafb7a39 100644 --- a/src/platform/android.rs +++ b/src/platform/android.rs @@ -1,18 +1,16 @@ #![cfg(any(target_os = "android"))] +use crate::{EventLoop, Window, WindowBuilder}; use std::os::raw::c_void; -use EventLoop; -use Window; -use WindowBuilder; /// Additional methods on `EventLoop` that are specific to Android. pub trait EventLoopExtAndroid { /// Makes it possible for glutin to register a callback when a suspend event happens on Android - fn set_suspend_callback(&self, cb: Option ()>>); + fn set_suspend_callback(&self, cb: Option ()>>); } impl EventLoopExtAndroid for EventLoop { - fn set_suspend_callback(&self, cb: Option ()>>) { + fn set_suspend_callback(&self, cb: Option ()>>) { self.event_loop.set_suspend_callback(cb); } } @@ -30,9 +28,6 @@ impl WindowExtAndroid for Window { } /// Additional methods on `WindowBuilder` that are specific to Android. -pub trait WindowBuilderExtAndroid { +pub trait WindowBuilderExtAndroid {} -} - -impl WindowBuilderExtAndroid for WindowBuilder { -} +impl WindowBuilderExtAndroid for WindowBuilder {} diff --git a/src/platform/desktop.rs b/src/platform/desktop.rs index 05783890..1ec20562 100644 --- a/src/platform/desktop.rs +++ b/src/platform/desktop.rs @@ -4,8 +4,10 @@ target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd" ))] -use event::Event; -use event_loop::{EventLoop, EventLoopWindowTarget, ControlFlow}; +use crate::{ + event::Event, + event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget}, +}; /// Additional methods on `EventLoop` that are specific to desktop platforms. pub trait EventLoopExtDesktop { @@ -16,15 +18,27 @@ pub trait EventLoopExtDesktop { /// /// Unlike `run`, this function accepts non-`'static` (i.e. non-`move`) closures and returns /// control flow to the caller when `control_flow` is set to `ControlFlow::Exit`. + /// + /// # Caveats + /// Despite its apperance at first glance, this is *not* a perfect replacement for + /// `poll_events`. For example, this function will not return on Windows or macOS while a + /// window is getting resized, resulting in all application logic outside of the + /// `event_handler` closure not running until the resize operation ends. Other OS operations + /// may also result in such freezes. This behavior is caused by fundamental limitations in the + /// underyling OS APIs, which cannot be hidden by Winit without severe stability reprecussions. + /// + /// You are strongly encouraged to use `run`, unless the use of this is absolutely necessary. fn run_return(&mut self, event_handler: F) - where F: FnMut(Event, &EventLoopWindowTarget, &mut ControlFlow); + where + F: FnMut(Event, &EventLoopWindowTarget, &mut ControlFlow); } impl EventLoopExtDesktop for EventLoop { type UserEvent = T; fn run_return(&mut self, event_handler: F) - where F: FnMut(Event, &EventLoopWindowTarget, &mut ControlFlow) + where + F: FnMut(Event, &EventLoopWindowTarget, &mut ControlFlow), { self.event_loop.run_return(event_handler) } diff --git a/src/platform/ios.rs b/src/platform/ios.rs index 85fcdff6..8c1034a4 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -2,9 +2,11 @@ use std::os::raw::c_void; -use event_loop::EventLoop; -use monitor::MonitorHandle; -use window::{Window, WindowBuilder}; +use crate::{ + event_loop::EventLoop, + monitor::MonitorHandle, + window::{Window, WindowBuilder}, +}; /// Additional methods on `EventLoop` that are specific to iOS. pub trait EventLoopExtIOS { diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 3162b6ef..f08c774b 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -2,29 +2,47 @@ use std::os::raw::c_void; -use crate::dpi::LogicalSize; -use crate::monitor::MonitorHandle; -use crate::window::{Window, WindowBuilder}; +use crate::{ + dpi::LogicalSize, + monitor::MonitorHandle, + window::{Window, WindowBuilder}, +}; + +/// Corresponds to `NSRequestUserAttentionType`. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum RequestUserAttentionType { + /// Corresponds to `NSCriticalRequest`. + /// + /// Dock icon will bounce until the application is focused. + Critical, + + /// Corresponds to `NSInformationalRequest`. + /// + /// Dock icon will bounce once. + Informational, +} + +impl Default for RequestUserAttentionType { + fn default() -> Self { + RequestUserAttentionType::Critical + } +} /// Additional methods on `Window` that are specific to MacOS. pub trait WindowExtMacOS { /// Returns a pointer to the cocoa `NSWindow` that is used by this window. /// /// The pointer will become invalid when the `Window` is destroyed. - fn nswindow(&self) -> *mut c_void; + fn ns_window(&self) -> *mut c_void; /// Returns a pointer to the cocoa `NSView` that is used by this window. /// /// The pointer will become invalid when the `Window` is destroyed. - fn nsview(&self) -> *mut c_void; + fn ns_view(&self) -> *mut c_void; /// Request user attention, causing the application's dock icon to bounce. /// Note that this has no effect if the application is already focused. - /// - /// The `is_critical` flag has the following effects: - /// - `false`: the dock icon will only bounce once. - /// - `true`: the dock icon will bounce until the application is focused. - fn request_user_attention(&self, is_critical: bool); + fn request_user_attention(&self, request_type: RequestUserAttentionType); /// Returns whether or not the window is in simple fullscreen mode. fn simple_fullscreen(&self) -> bool; @@ -41,18 +59,18 @@ pub trait WindowExtMacOS { impl WindowExtMacOS for Window { #[inline] - fn nswindow(&self) -> *mut c_void { - self.window.nswindow() + fn ns_window(&self) -> *mut c_void { + self.window.ns_window() } #[inline] - fn nsview(&self) -> *mut c_void { - self.window.nsview() + fn ns_view(&self) -> *mut c_void { + self.window.ns_view() } #[inline] - fn request_user_attention(&self, is_critical: bool) { - self.window.request_user_attention(is_critical) + fn request_user_attention(&self, request_type: RequestUserAttentionType) { + self.window.request_user_attention(request_type) } #[inline] @@ -97,7 +115,8 @@ pub trait WindowBuilderExtMacOS { /// Sets the activation policy for the window being built. fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder; /// Enables click-and-drag behavior for the entire window, not just the titlebar. - fn with_movable_by_window_background(self, movable_by_window_background: bool) -> WindowBuilder; + fn with_movable_by_window_background(self, movable_by_window_background: bool) + -> WindowBuilder; /// Makes the titlebar transparent and allows the content to appear behind it. fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder; /// Hides the window title. @@ -120,7 +139,10 @@ impl WindowBuilderExtMacOS for WindowBuilder { } #[inline] - fn with_movable_by_window_background(mut self, movable_by_window_background: bool) -> WindowBuilder { + fn with_movable_by_window_background( + mut self, + movable_by_window_background: bool, + ) -> WindowBuilder { self.platform_specific.movable_by_window_background = movable_by_window_background; self } @@ -167,7 +189,7 @@ pub trait MonitorHandleExtMacOS { /// Returns the identifier of the monitor for Cocoa. fn native_id(&self) -> u32; /// Returns a pointer to the NSScreen representing this monitor. - fn nsscreen(&self) -> Option<*mut c_void>; + fn ns_screen(&self) -> Option<*mut c_void>; } impl MonitorHandleExtMacOS for MonitorHandle { @@ -176,7 +198,7 @@ impl MonitorHandleExtMacOS for MonitorHandle { self.inner.native_identifier() } - fn nsscreen(&self) -> Option<*mut c_void> { - self.inner.nsscreen().map(|s| s as *mut c_void) + fn ns_screen(&self) -> Option<*mut c_void> { + self.inner.ns_screen().map(|s| s as *mut c_void) } } diff --git a/src/platform/unix.rs b/src/platform/unix.rs index 5f212fdf..494ed398 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -1,29 +1,26 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] -use std::os::raw; -use std::ptr; -use std::sync::Arc; +use std::{os::raw, ptr, sync::Arc}; -use sctk::window::{ButtonState, Theme}; +use smithay_client_toolkit::window::{ButtonState, Theme}; -use dpi::LogicalSize; -use event_loop::EventLoop; -use monitor::MonitorHandle; -use window::{Window, WindowBuilder}; - -use platform_impl::{ - EventLoop as LinuxEventLoop, - Window as LinuxWindow, +use crate::{ + dpi::LogicalSize, + event_loop::EventLoop, + monitor::MonitorHandle, + window::{Window, WindowBuilder}, +}; + +use crate::platform_impl::{ + x11::{ffi::XVisualInfo, XConnection}, + EventLoop as LinuxEventLoop, Window as LinuxWindow, }; -use platform_impl::x11::XConnection; -use platform_impl::x11::ffi::XVisualInfo; // TODO: stupid hack so that glutin can do its work #[doc(hidden)] -pub use platform_impl::x11; +pub use crate::platform_impl::x11; -pub use platform_impl::XNotSupported; -pub use platform_impl::x11::util::WindowType as XWindowType; +pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported}; /// Theme for wayland client side decorations /// @@ -97,11 +94,13 @@ impl Theme for WaylandThemeObject { pub trait EventLoopExtUnix { /// Builds a new `EventLoops` that is forced to use X11. fn new_x11() -> Result - where Self: Sized; + where + Self: Sized; /// Builds a new `EventLoop` that is forced to use Wayland. fn new_wayland() -> Self - where Self: Sized; + where + Self: Sized; /// True if the `EventLoop` uses Wayland. fn is_wayland(&self) -> bool; @@ -123,12 +122,10 @@ pub trait EventLoopExtUnix { impl EventLoopExtUnix for EventLoop { #[inline] fn new_x11() -> Result { - LinuxEventLoop::new_x11().map(|ev| - EventLoop { - event_loop: ev, - _marker: ::std::marker::PhantomData, - } - ) + LinuxEventLoop::new_x11().map(|ev| EventLoop { + event_loop: ev, + _marker: ::std::marker::PhantomData, + }) } #[inline] @@ -136,7 +133,7 @@ impl EventLoopExtUnix for EventLoop { EventLoop { event_loop: match LinuxEventLoop::new_wayland() { Ok(e) => e, - Err(_) => panic!() // TODO: propagate + Err(_) => panic!(), // TODO: propagate }, _marker: ::std::marker::PhantomData, } @@ -157,7 +154,7 @@ impl EventLoopExtUnix for EventLoop { fn xlib_xconnection(&self) -> Option> { match self.event_loop { LinuxEventLoop::X(ref e) => Some(e.x_connection().clone()), - _ => None + _ => None, } } @@ -165,7 +162,7 @@ impl EventLoopExtUnix for EventLoop { fn wayland_display(&self) -> Option<*mut raw::c_void> { match self.event_loop { LinuxEventLoop::Wayland(ref e) => Some(e.display().get_display_ptr() as *mut _), - _ => None + _ => None, } } } @@ -231,7 +228,7 @@ impl WindowExtUnix for Window { fn xlib_window(&self) -> Option { match self.window { LinuxWindow::X(ref w) => Some(w.xlib_window()), - _ => None + _ => None, } } @@ -239,7 +236,7 @@ impl WindowExtUnix for Window { fn xlib_display(&self) -> Option<*mut raw::c_void> { match self.window { LinuxWindow::X(ref w) => Some(w.xlib_display()), - _ => None + _ => None, } } @@ -247,7 +244,7 @@ impl WindowExtUnix for Window { fn xlib_screen_id(&self) -> Option { match self.window { LinuxWindow::X(ref w) => Some(w.xlib_screen_id()), - _ => None + _ => None, } } @@ -256,7 +253,7 @@ impl WindowExtUnix for Window { fn xlib_xconnection(&self) -> Option> { match self.window { LinuxWindow::X(ref w) => Some(w.xlib_xconnection()), - _ => None + _ => None, } } @@ -264,7 +261,7 @@ impl WindowExtUnix for Window { fn xcb_connection(&self) -> Option<*mut raw::c_void> { match self.window { LinuxWindow::X(ref w) => Some(w.xcb_connection()), - _ => None + _ => None, } } @@ -279,7 +276,7 @@ impl WindowExtUnix for Window { fn wayland_surface(&self) -> Option<*mut raw::c_void> { match self.window { LinuxWindow::Wayland(ref w) => Some(w.surface().as_ref().c_ptr() as *mut _), - _ => None + _ => None, } } @@ -287,7 +284,7 @@ impl WindowExtUnix for Window { fn wayland_display(&self) -> Option<*mut raw::c_void> { match self.window { LinuxWindow::Wayland(ref w) => Some(w.display().as_ref().c_ptr() as *mut _), - _ => None + _ => None, } } @@ -334,9 +331,8 @@ pub trait WindowBuilderExtUnix { impl WindowBuilderExtUnix for WindowBuilder { #[inline] fn with_x11_visual(mut self, visual_infos: *const T) -> WindowBuilder { - self.platform_specific.visual_infos = Some( - unsafe { ptr::read(visual_infos as *const XVisualInfo) } - ); + self.platform_specific.visual_infos = + Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) }); self } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 9f47365c..43133e04 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -5,17 +5,21 @@ use std::os::raw::c_void; use libc; use winapi::shared::windef::HWND; -use event::DeviceId; -use monitor::MonitorHandle; -use event_loop::EventLoop; -use window::{Icon, Window, WindowBuilder}; -use platform_impl::EventLoop as WindowsEventLoop; +use crate::{ + event::DeviceId, + event_loop::EventLoop, + monitor::MonitorHandle, + platform_impl::EventLoop as WindowsEventLoop, + window::{Icon, Window, WindowBuilder}, +}; /// Additional methods on `EventLoop` that are specific to Windows. pub trait EventLoopExtWindows { /// By default, winit on Windows will attempt to enable process-wide DPI awareness. If that's /// undesirable, you can create an `EventLoop` using this function instead. - fn new_dpi_unaware() -> Self where Self: Sized; + fn new_dpi_unaware() -> Self + where + Self: Sized; } impl EventLoopExtWindows for EventLoop { diff --git a/src/platform_impl/android/ffi.rs b/src/platform_impl/android/ffi.rs index af8c50b3..93a59b82 100644 --- a/src/platform_impl/android/ffi.rs +++ b/src/platform_impl/android/ffi.rs @@ -9,32 +9,32 @@ use std::os::raw; #[link(name = "android")] #[link(name = "EGL")] #[link(name = "GLESv2")] -extern {} +extern "C" {} /** - * asset_manager.h - */ + ** asset_manager.h + **/ pub type AAssetManager = raw::c_void; /** - * native_window.h - */ + ** native_window.h + **/ pub type ANativeWindow = raw::c_void; -extern { +extern "C" { pub fn ANativeWindow_getHeight(window: *const ANativeWindow) -> libc::int32_t; pub fn ANativeWindow_getWidth(window: *const ANativeWindow) -> libc::int32_t; } /** - * native_activity.h - */ + ** native_activity.h + **/ pub type JavaVM = (); pub type JNIEnv = (); pub type jobject = *const libc::c_void; -pub type AInputQueue = (); // FIXME: wrong -pub type ARect = (); // FIXME: wrong +pub type AInputQueue = (); // FIXME: wrong +pub type ARect = (); // FIXME: wrong #[repr(C)] pub struct ANativeActivity { @@ -52,43 +52,56 @@ pub struct ANativeActivity { #[repr(C)] pub struct ANativeActivityCallbacks { - pub onStart: extern fn(*mut ANativeActivity), - pub onResume: extern fn(*mut ANativeActivity), - pub onSaveInstanceState: extern fn(*mut ANativeActivity, *mut libc::size_t), - pub onPause: extern fn(*mut ANativeActivity), - pub onStop: extern fn(*mut ANativeActivity), - pub onDestroy: extern fn(*mut ANativeActivity), - pub onWindowFocusChanged: extern fn(*mut ANativeActivity, libc::c_int), - pub onNativeWindowCreated: extern fn(*mut ANativeActivity, *const ANativeWindow), - pub onNativeWindowResized: extern fn(*mut ANativeActivity, *const ANativeWindow), - pub onNativeWindowRedrawNeeded: extern fn(*mut ANativeActivity, *const ANativeWindow), - pub onNativeWindowDestroyed: extern fn(*mut ANativeActivity, *const ANativeWindow), - pub onInputQueueCreated: extern fn(*mut ANativeActivity, *mut AInputQueue), - pub onInputQueueDestroyed: extern fn(*mut ANativeActivity, *mut AInputQueue), - pub onContentRectChanged: extern fn(*mut ANativeActivity, *const ARect), - pub onConfigurationChanged: extern fn(*mut ANativeActivity), - pub onLowMemory: extern fn(*mut ANativeActivity), + pub onStart: extern "C" fn(*mut ANativeActivity), + pub onResume: extern "C" fn(*mut ANativeActivity), + pub onSaveInstanceState: extern "C" fn(*mut ANativeActivity, *mut libc::size_t), + pub onPause: extern "C" fn(*mut ANativeActivity), + pub onStop: extern "C" fn(*mut ANativeActivity), + pub onDestroy: extern "C" fn(*mut ANativeActivity), + pub onWindowFocusChanged: extern "C" fn(*mut ANativeActivity, libc::c_int), + pub onNativeWindowCreated: extern "C" fn(*mut ANativeActivity, *const ANativeWindow), + pub onNativeWindowResized: extern "C" fn(*mut ANativeActivity, *const ANativeWindow), + pub onNativeWindowRedrawNeeded: extern "C" fn(*mut ANativeActivity, *const ANativeWindow), + pub onNativeWindowDestroyed: extern "C" fn(*mut ANativeActivity, *const ANativeWindow), + pub onInputQueueCreated: extern "C" fn(*mut ANativeActivity, *mut AInputQueue), + pub onInputQueueDestroyed: extern "C" fn(*mut ANativeActivity, *mut AInputQueue), + pub onContentRectChanged: extern "C" fn(*mut ANativeActivity, *const ARect), + pub onConfigurationChanged: extern "C" fn(*mut ANativeActivity), + pub onLowMemory: extern "C" fn(*mut ANativeActivity), } /** - * looper.h - */ + ** looper.h + **/ pub type ALooper = (); #[link(name = "android")] -extern { +extern "C" { pub fn ALooper_forThread() -> *const ALooper; pub fn ALooper_acquire(looper: *const ALooper); pub fn ALooper_release(looper: *const ALooper); pub fn ALooper_prepare(opts: libc::c_int) -> *const ALooper; - pub fn ALooper_pollOnce(timeoutMillis: libc::c_int, outFd: *mut libc::c_int, - outEvents: *mut libc::c_int, outData: *mut *mut libc::c_void) -> libc::c_int; - pub fn ALooper_pollAll(timeoutMillis: libc::c_int, outFd: *mut libc::c_int, - outEvents: *mut libc::c_int, outData: *mut *mut libc::c_void) -> libc::c_int; + pub fn ALooper_pollOnce( + timeoutMillis: libc::c_int, + outFd: *mut libc::c_int, + outEvents: *mut libc::c_int, + outData: *mut *mut libc::c_void, + ) -> libc::c_int; + pub fn ALooper_pollAll( + timeoutMillis: libc::c_int, + outFd: *mut libc::c_int, + outEvents: *mut libc::c_int, + outData: *mut *mut libc::c_void, + ) -> libc::c_int; pub fn ALooper_wake(looper: *const ALooper); - pub fn ALooper_addFd(looper: *const ALooper, fd: libc::c_int, ident: libc::c_int, - events: libc::c_int, callback: ALooper_callbackFunc, data: *mut libc::c_void) - -> libc::c_int; + pub fn ALooper_addFd( + looper: *const ALooper, + fd: libc::c_int, + ident: libc::c_int, + events: libc::c_int, + callback: ALooper_callbackFunc, + data: *mut libc::c_void, + ) -> libc::c_int; pub fn ALooper_removeFd(looper: *const ALooper, fd: libc::c_int) -> libc::c_int; } @@ -105,4 +118,5 @@ pub const ALOOPER_EVENT_ERROR: libc::c_int = 1 << 2; pub const ALOOPER_EVENT_HANGUP: libc::c_int = 1 << 3; pub const ALOOPER_EVENT_INVALID: libc::c_int = 1 << 4; -pub type ALooper_callbackFunc = extern fn(libc::c_int, libc::c_int, *mut libc::c_void) -> libc::c_int; +pub type ALooper_callbackFunc = + extern "C" fn(libc::c_int, libc::c_int, *mut libc::c_void) -> libc::c_int; diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index ce58c0e7..42430d01 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -4,34 +4,28 @@ extern crate android_glue; mod ffi; -use std::cell::RefCell; -use std::collections::VecDeque; -use std::fmt; -use std::os::raw::c_void; -use std::sync::mpsc::{Receiver, channel}; +use std::{ + cell::RefCell, + collections::VecDeque, + fmt, + os::raw::c_void, + sync::mpsc::{channel, Receiver}, +}; -use { - CreationError, - Event, - LogicalPosition, - LogicalSize, - CursorIcon, - PhysicalPosition, - PhysicalSize, - WindowAttributes, - WindowEvent, - WindowId as RootWindowId, +use crate::{ + error::{ExternalError, NotSupportedError}, + events::{Touch, TouchPhase}, + window::MonitorHandle as RootMonitorHandle, + CreationError, CursorIcon, Event, LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, + WindowAttributes, WindowEvent, WindowId as RootWindowId, }; use CreationError::OsError; -use error::{ExternalError, NotSupportedError}; -use events::{Touch, TouchPhase}; -use window::MonitorHandle as RootMonitorHandle; pub type OsError = std::io::Error; pub struct EventLoop { event_rx: Receiver, - suspend_callback: RefCell ()>>>, + suspend_callback: RefCell ()>>>, } #[derive(Clone)] @@ -60,10 +54,11 @@ impl EventLoop { } pub fn poll_events(&mut self, mut callback: F) - where F: FnMut(::Event) + where + F: FnMut(::Event), { while let Ok(event) = self.event_rx.try_recv() { - let e = match event{ + let e = match event { android_glue::Event::EventMotion(motion) => { let dpi_factor = MonitorHandle.hidpi_factor(); let location = LogicalPosition::from_physical( @@ -84,37 +79,36 @@ impl EventLoop { device_id: DEVICE_ID, }), }) - }, + } android_glue::Event::InitWindow => { // The activity went to foreground. if let Some(cb) = self.suspend_callback.borrow().as_ref() { (*cb)(false); } - Some(Event::Suspended(false)) - }, + Some(Event::Resumed) + } android_glue::Event::TermWindow => { // The activity went to background. if let Some(cb) = self.suspend_callback.borrow().as_ref() { (*cb)(true); } - Some(Event::Suspended(true)) - }, - android_glue::Event::WindowResized | - android_glue::Event::ConfigChanged => { + Some(Event::Suspended) + } + android_glue::Event::WindowResized | android_glue::Event::ConfigChanged => { // Activity Orientation changed or resized. let native_window = unsafe { android_glue::native_window() }; if native_window.is_null() { None } else { let dpi_factor = MonitorHandle.hidpi_factor(); - let physical_size = MonitorHandle.dimensions(); + let physical_size = MonitorHandle.size(); let size = LogicalSize::from_physical(physical_size, dpi_factor); Some(Event::WindowEvent { window_id: RootWindowId(WindowId), event: WindowEvent::Resized(size), }) } - }, + } android_glue::Event::WindowRedrawNeeded => { // The activity needs to be redrawn. Some(Event::WindowEvent { @@ -122,26 +116,23 @@ impl EventLoop { event: WindowEvent::Redraw, }) } - android_glue::Event::Wake => { - Some(Event::Awakened) - } - _ => { - None - } + android_glue::Event::Wake => Some(Event::Awakened), + _ => None, }; if let Some(event) = e { callback(event); } - }; + } } - pub fn set_suspend_callback(&self, cb: Option ()>>) { + pub fn set_suspend_callback(&self, cb: Option ()>>) { *self.suspend_callback.borrow_mut() = cb; } pub fn run_forever(&mut self, mut callback: F) - where F: FnMut(::Event) -> ::ControlFlow, + where + F: FnMut(::Event) -> ::ControlFlow, { // Yeah that's a very bad implementation. loop { @@ -196,7 +187,7 @@ pub struct Window { pub struct MonitorHandle; impl fmt::Debug for MonitorHandle { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[derive(Debug)] struct MonitorHandle { name: Option, @@ -207,7 +198,7 @@ impl fmt::Debug for MonitorHandle { let monitor_id_proxy = MonitorHandle { name: self.name(), - dimensions: self.dimensions(), + dimensions: self.size(), position: self.outer_position(), hidpi_factor: self.hidpi_factor(), }; @@ -223,13 +214,14 @@ impl MonitorHandle { } #[inline] - pub fn dimensions(&self) -> PhysicalSize { + pub fn size(&self) -> PhysicalSize { unsafe { let window = android_glue::native_window(); ( ffi::ANativeWindow_getWidth(window) as f64, ffi::ANativeWindow_getHeight(window) as f64, - ).into() + ) + .into() } } @@ -251,10 +243,11 @@ pub struct PlatformSpecificWindowBuilderAttributes; pub struct PlatformSpecificHeadlessBuilderAttributes; impl Window { - pub fn new(_: &EventLoop, win_attribs: WindowAttributes, - _: PlatformSpecificWindowBuilderAttributes) - -> Result - { + pub fn new( + _: &EventLoop, + win_attribs: WindowAttributes, + _: PlatformSpecificWindowBuilderAttributes, + ) -> Result { let native_window = unsafe { android_glue::native_window() }; if native_window.is_null() { return Err(OsError(format!("Android's native window is null"))); @@ -325,7 +318,7 @@ impl Window { None } else { let dpi_factor = self.hidpi_factor(); - let physical_size = self.current_monitor().dimensions(); + let physical_size = self.current_monitor().size(); Some(LogicalSize::from_physical(physical_size, dpi_factor)) } } @@ -406,7 +399,9 @@ impl Window { #[inline] pub fn current_monitor(&self) -> RootMonitorHandle { - RootMonitorHandle { inner: MonitorHandle } + RootMonitorHandle { + inner: MonitorHandle, + } } #[inline] diff --git a/src/platform_impl/emscripten/ffi.rs b/src/platform_impl/emscripten/ffi.rs index 8da26636..6eb9d743 100644 --- a/src/platform_impl/emscripten/ffi.rs +++ b/src/platform_impl/emscripten/ffi.rs @@ -1,8 +1,8 @@ #![allow(dead_code, non_camel_case_types, non_snake_case)] -use std::os::raw::{c_int, c_char, c_void, c_ulong, c_double, c_long, c_ushort}; #[cfg(test)] use std::mem; +use std::os::raw::{c_char, c_double, c_int, c_long, c_ulong, c_ushort, c_void}; pub type EM_BOOL = c_int; pub type EM_UTF8 = c_char; @@ -71,30 +71,45 @@ pub const DOM_KEY_LOCATION_NUMPAD: c_ulong = 0x03; pub type em_callback_func = Option; -pub type em_key_callback_func = Option EM_BOOL>; +pub type em_key_callback_func = Option< + unsafe extern "C" fn( + eventType: c_int, + keyEvent: *const EmscriptenKeyboardEvent, + userData: *mut c_void, + ) -> EM_BOOL, +>; -pub type em_mouse_callback_func = Option EM_BOOL>; +pub type em_mouse_callback_func = Option< + unsafe extern "C" fn( + eventType: c_int, + mouseEvent: *const EmscriptenMouseEvent, + userData: *mut c_void, + ) -> EM_BOOL, +>; -pub type em_pointerlockchange_callback_func = Option EM_BOOL>; +pub type em_pointerlockchange_callback_func = Option< + unsafe extern "C" fn( + eventType: c_int, + pointerlockChangeEvent: *const EmscriptenPointerlockChangeEvent, + userData: *mut c_void, + ) -> EM_BOOL, +>; -pub type em_fullscreenchange_callback_func = Option EM_BOOL>; +pub type em_fullscreenchange_callback_func = Option< + unsafe extern "C" fn( + eventType: c_int, + fullscreenChangeEvent: *const EmscriptenFullscreenChangeEvent, + userData: *mut c_void, + ) -> EM_BOOL, +>; -pub type em_touch_callback_func = Option EM_BOOL>; +pub type em_touch_callback_func = Option< + unsafe extern "C" fn( + eventType: c_int, + touchEvent: *const EmscriptenTouchEvent, + userData: *mut c_void, + ) -> EM_BOOL, +>; #[repr(C)] pub struct EmscriptenFullscreenChangeEvent { @@ -136,7 +151,9 @@ fn bindgen_test_layout_EmscriptenKeyboardEvent() { assert_eq!(mem::align_of::(), 8usize); } impl Clone for EmscriptenKeyboardEvent { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } #[repr(C)] @@ -219,96 +236,128 @@ fn bindgen_test_layout_EmscriptenPointerlockChangeEvent() { } extern "C" { - pub fn emscripten_set_canvas_size( - width: c_int, height: c_int) - -> EMSCRIPTEN_RESULT; + pub fn emscripten_set_canvas_size(width: c_int, height: c_int) -> EMSCRIPTEN_RESULT; pub fn emscripten_get_canvas_size( - width: *mut c_int, height: *mut c_int, - is_fullscreen: *mut c_int) - -> EMSCRIPTEN_RESULT; + width: *mut c_int, + height: *mut c_int, + is_fullscreen: *mut c_int, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_element_css_size( - target: *const c_char, width: c_double, - height: c_double) -> EMSCRIPTEN_RESULT; + target: *const c_char, + width: c_double, + height: c_double, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_get_element_css_size( - target: *const c_char, width: *mut c_double, - height: *mut c_double) -> EMSCRIPTEN_RESULT; + target: *const c_char, + width: *mut c_double, + height: *mut c_double, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_request_pointerlock( - target: *const c_char, deferUntilInEventHandler: EM_BOOL) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + deferUntilInEventHandler: EM_BOOL, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_exit_pointerlock() -> EMSCRIPTEN_RESULT; pub fn emscripten_request_fullscreen( - target: *const c_char, deferUntilInEventHandler: EM_BOOL) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + deferUntilInEventHandler: EM_BOOL, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_exit_fullscreen() -> EMSCRIPTEN_RESULT; pub fn emscripten_set_keydown_callback( - target: *const c_char, userData: *mut c_void, - useCapture: EM_BOOL, callback: em_key_callback_func) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + userData: *mut c_void, + useCapture: EM_BOOL, + callback: em_key_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_keyup_callback( - target: *const c_char, userData: *mut c_void, - useCapture: EM_BOOL, callback: em_key_callback_func) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + userData: *mut c_void, + useCapture: EM_BOOL, + callback: em_key_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_mousemove_callback( - target: *const c_char, user_data: *mut c_void, - use_capture: EM_BOOL, callback: em_mouse_callback_func) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + user_data: *mut c_void, + use_capture: EM_BOOL, + callback: em_mouse_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_mousedown_callback( - target: *const c_char, user_data: *mut c_void, - use_capture: EM_BOOL, callback: em_mouse_callback_func) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + user_data: *mut c_void, + use_capture: EM_BOOL, + callback: em_mouse_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_mouseup_callback( - target: *const c_char, user_data: *mut c_void, - use_capture: EM_BOOL, callback: em_mouse_callback_func) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + user_data: *mut c_void, + use_capture: EM_BOOL, + callback: em_mouse_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_hide_mouse(); pub fn emscripten_get_device_pixel_ratio() -> f64; pub fn emscripten_set_pointerlockchange_callback( - target: *const c_char, userData: *mut c_void, useCapture: EM_BOOL, - callback: em_pointerlockchange_callback_func) -> EMSCRIPTEN_RESULT; + target: *const c_char, + userData: *mut c_void, + useCapture: EM_BOOL, + callback: em_pointerlockchange_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_fullscreenchange_callback( - target: *const c_char, userData: *mut c_void, useCapture: EM_BOOL, - callback: em_fullscreenchange_callback_func) -> EMSCRIPTEN_RESULT; + target: *const c_char, + userData: *mut c_void, + useCapture: EM_BOOL, + callback: em_fullscreenchange_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_asm_const(code: *const c_char); pub fn emscripten_set_main_loop( - func: em_callback_func, fps: c_int, simulate_infinite_loop: EM_BOOL); + func: em_callback_func, + fps: c_int, + simulate_infinite_loop: EM_BOOL, + ); pub fn emscripten_cancel_main_loop(); pub fn emscripten_set_touchstart_callback( - target: *const c_char, userData: *mut c_void, - useCapture: c_int, callback: em_touch_callback_func) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + userData: *mut c_void, + useCapture: c_int, + callback: em_touch_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_touchend_callback( - target: *const c_char, userData: *mut c_void, - useCapture: c_int, callback: em_touch_callback_func) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + userData: *mut c_void, + useCapture: c_int, + callback: em_touch_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_touchmove_callback( - target: *const c_char, userData: *mut c_void, - useCapture: c_int, callback: em_touch_callback_func) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + userData: *mut c_void, + useCapture: c_int, + callback: em_touch_callback_func, + ) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_touchcancel_callback( - target: *const c_char, userData: *mut c_void, - useCapture: c_int, callback: em_touch_callback_func) - -> EMSCRIPTEN_RESULT; + target: *const c_char, + userData: *mut c_void, + useCapture: c_int, + callback: em_touch_callback_func, + ) -> EMSCRIPTEN_RESULT; } diff --git a/src/platform_impl/emscripten/mod.rs b/src/platform_impl/emscripten/mod.rs index 140ba53d..9148dab0 100644 --- a/src/platform_impl/emscripten/mod.rs +++ b/src/platform_impl/emscripten/mod.rs @@ -2,16 +2,23 @@ mod ffi; -use std::{mem, ptr, str}; -use std::cell::RefCell; -use std::collections::VecDeque; -use std::os::raw::{c_char, c_void, c_double, c_ulong, c_int}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Mutex, Arc}; +use std::{ + cell::RefCell, + collections::VecDeque, + mem, + os::raw::{c_char, c_double, c_int, c_ulong, c_void}, + ptr, str, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, Mutex, + }, +}; -use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; -use error::{ExternalError, NotSupportedError}; -use window::MonitorHandle as RootMonitorHandle; +use crate::{ + dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}, + error::{ExternalError, NotSupportedError}, + window::MonitorHandle as RootMonitorHandle, +}; const DOCUMENT_NAME: &'static str = "#document\0"; @@ -54,7 +61,7 @@ impl MonitorHandle { } #[inline] - pub fn dimensions(&self) -> PhysicalSize { + pub fn size(&self) -> PhysicalSize { (0, 0).into() } @@ -68,14 +75,22 @@ impl MonitorHandle { thread_local!(static MAIN_LOOP_CALLBACK: RefCell<*mut c_void> = RefCell::new(ptr::null_mut())); // Used to assign a callback to emscripten main loop -pub fn set_main_loop_callback(callback : F) where F : FnMut() { +pub fn set_main_loop_callback(callback: F) +where + F: FnMut(), +{ MAIN_LOOP_CALLBACK.with(|log| { *log.borrow_mut() = &callback as *const _ as *mut c_void; }); - unsafe { ffi::emscripten_set_main_loop(Some(wrapper::), 0, 1); } + unsafe { + ffi::emscripten_set_main_loop(Some(wrapper::), 0, 1); + } - unsafe extern "C" fn wrapper() where F : FnMut() { + unsafe extern "C" fn wrapper() + where + F: FnMut(), + { MAIN_LOOP_CALLBACK.with(|z| { let closure = *z.borrow_mut() as *mut F; (*closure)(); @@ -128,7 +143,8 @@ impl EventLoop { } pub fn poll_events(&self, mut callback: F) - where F: FnMut(::Event) + where + F: FnMut(::Event), { let ref mut window = *self.window.lock().unwrap(); if let &mut Some(ref mut window) = window { @@ -139,17 +155,22 @@ impl EventLoop { } pub fn run_forever(&self, mut callback: F) - where F: FnMut(::Event) -> ::ControlFlow + where + F: FnMut(::Event) -> ::ControlFlow, { self.interrupted.store(false, Ordering::Relaxed); // TODO: handle control flow set_main_loop_callback(|| { - self.poll_events(|e| { callback(e); }); + self.poll_events(|e| { + callback(e); + }); ::std::thread::sleep(::std::time::Duration::from_millis(5)); if self.interrupted.load(Ordering::Relaxed) { - unsafe { ffi::emscripten_cancel_main_loop(); } + unsafe { + ffi::emscripten_cancel_main_loop(); + } } }); } @@ -190,15 +211,15 @@ fn show_mouse() { // } // styleSheet.insertRule('canvas.emscripten { border: none; cursor: auto; }', 0); unsafe { - ffi::emscripten_asm_const(b"var styleSheet = document.styleSheets[0]; var rules = styleSheet.cssRules; for (var i = 0; i < rules.length; i++) { if (rules[i].cssText.substr(0, 6) == 'canvas') { styleSheet.deleteRule(i); i--; } } styleSheet.insertRule('canvas.emscripten { border: none; cursor: auto; }', 0);\0".as_ptr() as *const c_char); + ffi::emscripten_asm_const(b"var styleSheet = document.styleSheets[0]; var rules = styleSheet.cssRules; for (var i = 0; i < rules.length; i++) { if (rules[i].cssText.substr(0, 6) == 'canvas') { styleSheet.deleteRule(i); i--; } } styleSheet.insertRule('canvas.emscripten { border: none; cursor: auto; }', 0);\0".as_ptr() as *const c_char); } } extern "C" fn mouse_callback( event_type: c_int, event: *const ffi::EmscriptenMouseEvent, - event_queue: *mut c_void) -> ffi::EM_BOOL -{ + event_queue: *mut c_void, +) -> ffi::EM_BOOL { unsafe { let queue: &Mutex> = mem::transmute(event_queue); @@ -221,18 +242,18 @@ extern "C" fn mouse_callback( event: ::WindowEvent::CursorMoved { device_id: ::DeviceId(DeviceId), position, - modifiers: modifiers, - } + modifiers, + }, }); queue.lock().unwrap().push_back(::Event::DeviceEvent { device_id: ::DeviceId(DeviceId), event: ::DeviceEvent::MouseMotion { delta: ((*event).movementX as f64, (*event).movementY as f64), - } + }, }); - }, - mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEDOWN | - mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEUP => { + } + mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEDOWN + | mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEUP => { let button = match (*event).button { 0 => ::MouseButton::Left, 1 => ::MouseButton::Middle, @@ -248,14 +269,13 @@ extern "C" fn mouse_callback( window_id: ::WindowId(WindowId(0)), event: ::WindowEvent::MouseInput { device_id: ::DeviceId(DeviceId), - state: state, - button: button, - modifiers: modifiers, - } + state, + button, + modifiers, + }, }) - }, - _ => { } + _ => {} } } ffi::EM_FALSE @@ -264,8 +284,8 @@ extern "C" fn mouse_callback( extern "C" fn keyboard_callback( event_type: c_int, event: *const ffi::EmscriptenKeyboardEvent, - event_queue: *mut c_void) -> ffi::EM_BOOL -{ + event_queue: *mut c_void, +) -> ffi::EM_BOOL { unsafe { let queue: &Mutex> = mem::transmute(event_queue); @@ -290,7 +310,7 @@ extern "C" fn keyboard_callback( }, }, }); - }, + } ffi::EMSCRIPTEN_EVENT_KEYUP => { queue.lock().unwrap().push_back(::Event::WindowEvent { window_id: ::WindowId(WindowId(0)), @@ -304,19 +324,18 @@ extern "C" fn keyboard_callback( }, }, }); - }, - _ => { } + _ => {} } } ffi::EM_FALSE } -extern fn touch_callback( +extern "C" fn touch_callback( event_type: c_int, event: *const ffi::EmscriptenTouchEvent, - event_queue: *mut c_void) -> ffi::EM_BOOL -{ + event_queue: *mut c_void, +) -> ffi::EM_BOOL { unsafe { let queue: &Mutex> = mem::transmute(event_queue); @@ -356,8 +375,8 @@ extern fn touch_callback( unsafe extern "C" fn fullscreen_callback( _eventType: c_int, _fullscreenChangeEvent: *const ffi::EmscriptenFullscreenChangeEvent, - _userData: *mut c_void) -> ffi::EM_BOOL -{ + _userData: *mut c_void, +) -> ffi::EM_BOOL { ffi::emscripten_request_fullscreen(ptr::null(), ffi::EM_TRUE); ffi::EM_FALSE } @@ -367,8 +386,8 @@ unsafe extern "C" fn fullscreen_callback( unsafe extern "C" fn pointerlockchange_callback( _eventType: c_int, _pointerlockChangeEvent: *const ffi::EmscriptenPointerlockChangeEvent, - _userData: *mut c_void) -> ffi::EM_BOOL -{ + _userData: *mut c_void, +) -> ffi::EM_BOOL { ffi::emscripten_request_pointerlock(ptr::null(), ffi::EM_TRUE); ffi::EM_FALSE } @@ -381,12 +400,15 @@ fn em_try(res: ffi::EMSCRIPTEN_RESULT) -> Result<(), String> { } impl Window { - pub fn new(event_loop: &EventLoop, attribs: ::WindowAttributes, - _pl_attribs: PlatformSpecificWindowBuilderAttributes) - -> Result - { + pub fn new( + event_loop: &EventLoop, + attribs: ::WindowAttributes, + _pl_attribs: PlatformSpecificWindowBuilderAttributes, + ) -> Result { if event_loop.window.lock().unwrap().is_some() { - return Err(::CreationError::OsError("Cannot create another window".to_owned())); + return Err(::CreationError::OsError( + "Cannot create another window".to_owned(), + )); } let w = Window2 { @@ -400,35 +422,87 @@ impl Window { window: Arc::new(w), }; - // TODO: set up more event callbacks unsafe { - em_try(ffi::emscripten_set_mousemove_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(mouse_callback))) - .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; - em_try(ffi::emscripten_set_mousedown_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(mouse_callback))) - .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; - em_try(ffi::emscripten_set_mouseup_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(mouse_callback))) - .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; - em_try(ffi::emscripten_set_keydown_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(keyboard_callback))) - .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; - em_try(ffi::emscripten_set_keyup_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(keyboard_callback))) - .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; - em_try(ffi::emscripten_set_touchstart_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(touch_callback))) - .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; - em_try(ffi::emscripten_set_touchend_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(touch_callback))) - .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; - em_try(ffi::emscripten_set_touchmove_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(touch_callback))) - .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; - em_try(ffi::emscripten_set_touchcancel_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(touch_callback))) - .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_mousemove_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + mem::transmute(&*window.window.events), + ffi::EM_FALSE, + Some(mouse_callback), + )) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_mousedown_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + mem::transmute(&*window.window.events), + ffi::EM_FALSE, + Some(mouse_callback), + )) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_mouseup_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + mem::transmute(&*window.window.events), + ffi::EM_FALSE, + Some(mouse_callback), + )) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_keydown_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + mem::transmute(&*window.window.events), + ffi::EM_FALSE, + Some(keyboard_callback), + )) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_keyup_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + mem::transmute(&*window.window.events), + ffi::EM_FALSE, + Some(keyboard_callback), + )) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_touchstart_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + mem::transmute(&*window.window.events), + ffi::EM_FALSE, + Some(touch_callback), + )) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_touchend_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + mem::transmute(&*window.window.events), + ffi::EM_FALSE, + Some(touch_callback), + )) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_touchmove_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + mem::transmute(&*window.window.events), + ffi::EM_FALSE, + Some(touch_callback), + )) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_touchcancel_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + mem::transmute(&*window.window.events), + ffi::EM_FALSE, + Some(touch_callback), + )) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; } if attribs.fullscreen.is_some() { unsafe { - em_try(ffi::emscripten_request_fullscreen(ptr::null(), ffi::EM_TRUE)) - .map_err(|e| ::CreationError::OsError(e))?; - em_try(ffi::emscripten_set_fullscreenchange_callback(ptr::null(), 0 as *mut c_void, ffi::EM_FALSE, Some(fullscreen_callback))) - .map_err(|e| ::CreationError::OsError(e))?; + em_try(ffi::emscripten_request_fullscreen( + ptr::null(), + ffi::EM_TRUE, + )) + .map_err(|e| ::CreationError::OsError(e))?; + em_try(ffi::emscripten_set_fullscreenchange_callback( + ptr::null(), + 0 as *mut c_void, + ffi::EM_FALSE, + Some(fullscreen_callback), + )) + .map_err(|e| ::CreationError::OsError(e))?; } } else if let Some(size) = attribs.inner_size { window.set_inner_size(size); @@ -444,8 +518,7 @@ impl Window { } #[inline] - pub fn set_title(&self, _title: &str) { - } + pub fn set_title(&self, _title: &str) {} #[inline] pub fn outer_position(&self) -> Option { @@ -458,8 +531,7 @@ impl Window { } #[inline] - pub fn set_outer_position(&self, _: LogicalPosition) { - } + pub fn set_outer_position(&self, _: LogicalPosition) {} #[inline] pub fn inner_size(&self) -> Option { @@ -532,7 +604,9 @@ impl Window { #[inline] pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> { let mut grabbed_lock = self.window.cursor_grabbed.lock().unwrap(); - if grab == *grabbed_lock { return Ok(()); } + if grab == *grabbed_lock { + return Ok(()); + } unsafe { if grab { em_try(ffi::emscripten_set_pointerlockchange_callback( @@ -541,7 +615,10 @@ impl Window { ffi::EM_FALSE, Some(pointerlockchange_callback), ))?; - em_try(ffi::emscripten_request_pointerlock(ptr::null(), ffi::EM_TRUE))?; + em_try(ffi::emscripten_request_pointerlock( + ptr::null(), + ffi::EM_TRUE, + ))?; } else { em_try(ffi::emscripten_set_pointerlockchange_callback( ptr::null(), @@ -559,7 +636,9 @@ impl Window { #[inline] pub fn set_cursor_visible(&self, visible: bool) { let mut visible_lock = self.window.cursor_visible.lock().unwrap(); - if visible == *visible_lock { return; } + if visible == *visible_lock { + return; + } if visible { show_mouse(); } else { @@ -615,7 +694,9 @@ impl Window { #[inline] pub fn current_monitor(&self) -> RootMonitorHandle { - RootMonitorHandle { inner: MonitorHandle } + RootMonitorHandle { + inner: MonitorHandle, + } } #[inline] @@ -646,21 +727,37 @@ impl Drop for Window { // Exit fullscreen if on if self.window.is_fullscreen { - ffi::emscripten_set_fullscreenchange_callback(ptr::null(), 0 as *mut c_void, ffi::EM_FALSE, None); + ffi::emscripten_set_fullscreenchange_callback( + ptr::null(), + 0 as *mut c_void, + ffi::EM_FALSE, + None, + ); ffi::emscripten_exit_fullscreen(); } // Delete callbacks - ffi::emscripten_set_keydown_callback(DOCUMENT_NAME.as_ptr() as *const c_char, 0 as *mut c_void, ffi::EM_FALSE,None); - ffi::emscripten_set_keyup_callback(DOCUMENT_NAME.as_ptr() as *const c_char, 0 as *mut c_void, ffi::EM_FALSE,None); + ffi::emscripten_set_keydown_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + 0 as *mut c_void, + ffi::EM_FALSE, + None, + ); + ffi::emscripten_set_keyup_callback( + DOCUMENT_NAME.as_ptr() as *const c_char, + 0 as *mut c_void, + ffi::EM_FALSE, + None, + ); } } } fn error_to_str(code: ffi::EMSCRIPTEN_RESULT) -> &'static str { match code { - ffi::EMSCRIPTEN_RESULT_SUCCESS | ffi::EMSCRIPTEN_RESULT_DEFERRED - => "Internal error in the library (success detected as failure)", + ffi::EMSCRIPTEN_RESULT_SUCCESS | ffi::EMSCRIPTEN_RESULT_DEFERRED => { + "Internal error in the library (success detected as failure)" + } ffi::EMSCRIPTEN_RESULT_NOT_SUPPORTED => "Not supported", ffi::EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED => "Failed not deferred", @@ -670,7 +767,7 @@ fn error_to_str(code: ffi::EMSCRIPTEN_RESULT) -> &'static str { ffi::EMSCRIPTEN_RESULT_FAILED => "Failed", ffi::EMSCRIPTEN_RESULT_NO_DATA => "No data", - _ => "Undocumented error" + _ => "Undocumented error", } } @@ -679,7 +776,9 @@ fn key_translate(input: [ffi::EM_UTF8; ffi::EM_HTML5_SHORT_STRING_LEN_BYTES]) -> let maybe_key = unsafe { str::from_utf8(mem::transmute::<_, &[u8]>(slice)) }; let key = match maybe_key { Ok(key) => key, - Err(_) => { return 0; }, + Err(_) => { + return 0; + } }; if key.chars().count() == 1 { key.as_bytes()[0] @@ -688,14 +787,17 @@ fn key_translate(input: [ffi::EM_UTF8; ffi::EM_HTML5_SHORT_STRING_LEN_BYTES]) -> } } -fn key_translate_virt(input: [ffi::EM_UTF8; ffi::EM_HTML5_SHORT_STRING_LEN_BYTES], - location: c_ulong) -> Option<::VirtualKeyCode> -{ +fn key_translate_virt( + input: [ffi::EM_UTF8; ffi::EM_HTML5_SHORT_STRING_LEN_BYTES], + location: c_ulong, +) -> Option<::VirtualKeyCode> { let slice = &input[0..input.iter().take_while(|x| **x != 0).count()]; let maybe_key = unsafe { str::from_utf8(mem::transmute::<_, &[u8]>(slice)) }; let key = match maybe_key { Ok(key) => key, - Err(_) => { return None; }, + Err(_) => { + return None; + } }; use VirtualKeyCode::*; match key { diff --git a/src/platform_impl/ios/app_state.rs b/src/platform_impl/ios/app_state.rs index 295891d5..5b982b14 100644 --- a/src/platform_impl/ios/app_state.rs +++ b/src/platform_impl/ios/app_state.rs @@ -1,26 +1,23 @@ -use std::{mem, ptr}; -use std::cell::{RefCell, RefMut}; -use std::mem::ManuallyDrop; -use std::os::raw::c_void; -use std::time::Instant; +use std::{ + cell::{RefCell, RefMut}, + mem::{self, ManuallyDrop}, + os::raw::c_void, + ptr, + time::Instant, +}; -use event::{Event, StartCause}; -use event_loop::ControlFlow; +use crate::{ + event::{Event, StartCause}, + event_loop::ControlFlow, +}; -use platform_impl::platform::event_loop::{EventHandler, Never}; -use platform_impl::platform::ffi::{ - id, - CFAbsoluteTimeGetCurrent, - CFRelease, - CFRunLoopAddTimer, - CFRunLoopGetMain, - CFRunLoopRef, - CFRunLoopTimerCreate, - CFRunLoopTimerInvalidate, - CFRunLoopTimerRef, - CFRunLoopTimerSetNextFireDate, - kCFRunLoopCommonModes, - NSUInteger, +use crate::platform_impl::platform::{ + event_loop::{EventHandler, Never}, + ffi::{ + id, kCFRunLoopCommonModes, CFAbsoluteTimeGetCurrent, CFRelease, CFRunLoopAddTimer, + CFRunLoopGetMain, CFRunLoopRef, CFRunLoopTimerCreate, CFRunLoopTimerInvalidate, + CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, NSUInteger, + }, }; macro_rules! bug { @@ -39,10 +36,10 @@ enum AppStateImpl { Launching { queued_windows: Vec, queued_events: Vec>, - queued_event_handler: Box, + queued_event_handler: Box, }, ProcessingEvents { - event_handler: Box, + event_handler: Box, active_control_flow: ControlFlow, }, // special state to deal with reentrancy and prevent mutable aliasing. @@ -50,11 +47,11 @@ enum AppStateImpl { queued_events: Vec>, }, Waiting { - waiting_event_handler: Box, + waiting_event_handler: Box, start: Instant, }, PollFinished { - waiting_event_handler: Box, + waiting_event_handler: Box, }, Terminated, } @@ -62,12 +59,18 @@ enum AppStateImpl { impl Drop for AppStateImpl { fn drop(&mut self) { match self { - &mut AppStateImpl::NotLaunched { ref mut queued_windows, .. } | - &mut AppStateImpl::Launching { ref mut queued_windows, .. } => unsafe { + &mut AppStateImpl::NotLaunched { + ref mut queued_windows, + .. + } + | &mut AppStateImpl::Launching { + ref mut queued_windows, + .. + } => unsafe { for &mut window in queued_windows { let () = msg_send![window, release]; } - } + }, _ => {} } } @@ -88,7 +91,9 @@ impl AppState { static mut APP_STATE: RefCell> = RefCell::new(None); if cfg!(debug_assertions) { - assert_main_thread!("bug in winit: `AppState::get_mut()` can only be called on the main thread"); + assert_main_thread!( + "bug in winit: `AppState::get_mut()` can only be called on the main thread" + ); } let mut guard = APP_STATE.borrow_mut(); @@ -108,33 +113,36 @@ impl AppState { } init_guard(&mut guard) } - RefMut::map(guard, |state| { - state.as_mut().unwrap() - }) + RefMut::map(guard, |state| state.as_mut().unwrap()) } - + // requires main thread and window is a UIWindow // retains window pub unsafe fn set_key_window(window: id) { let mut this = AppState::get_mut(); match &mut this.app_state { - &mut AppStateImpl::NotLaunched { ref mut queued_windows, .. } => { + &mut AppStateImpl::NotLaunched { + ref mut queued_windows, + .. + } => { queued_windows.push(window); msg_send![window, retain]; return; } - &mut AppStateImpl::ProcessingEvents { .. } => {}, - &mut AppStateImpl::InUserCallback { .. } => {}, - &mut AppStateImpl::Terminated => panic!("Attempt to create a `Window` \ - after the app has terminated"), - app_state => unreachable!("unexpected state: {:#?}", app_state), // all other cases should be impossible + &mut AppStateImpl::ProcessingEvents { .. } => {} + &mut AppStateImpl::InUserCallback { .. } => {} + &mut AppStateImpl::Terminated => panic!( + "Attempt to create a `Window` \ + after the app has terminated" + ), + app_state => unreachable!("unexpected state: {:#?}", app_state), /* all other cases should be impossible */ } drop(this); msg_send![window, makeKeyAndVisible] } // requires main thread - pub unsafe fn will_launch(queued_event_handler: Box) { + pub unsafe fn will_launch(queued_event_handler: Box) { let mut this = AppState::get_mut(); let (queued_windows, queued_events) = match &mut this.app_state { &mut AppStateImpl::NotLaunched { @@ -145,14 +153,19 @@ impl AppState { let events = ptr::read(queued_events); (windows, events) } - _ => panic!("winit iOS expected the app to be in a `NotLaunched` \ - state, but was not - please file an issue"), + _ => panic!( + "winit iOS expected the app to be in a `NotLaunched` \ + state, but was not - please file an issue" + ), }; - ptr::write(&mut this.app_state, AppStateImpl::Launching { - queued_windows, - queued_events, - queued_event_handler, - }); + ptr::write( + &mut this.app_state, + AppStateImpl::Launching { + queued_windows, + queued_events, + queued_event_handler, + }, + ); } // requires main thread @@ -188,11 +201,11 @@ impl AppState { let screen: id = msg_send![window, screen]; let () = msg_send![screen, retain]; let () = msg_send![window, setScreen:0 as id]; - let () = msg_send![window, setScreen:screen]; + let () = msg_send![window, setScreen: screen]; let () = msg_send![screen, release]; let controller: id = msg_send![window, rootViewController]; let () = msg_send![window, setRootViewController:ptr::null::<()>()]; - let () = msg_send![window, setRootViewController:controller]; + let () = msg_send![window, setRootViewController: controller]; let () = msg_send![window, makeKeyAndVisible]; } let () = msg_send![window, release]; @@ -210,15 +223,20 @@ impl AppState { let event_handler = ptr::read(queued_event_handler); (windows, events, event_handler) } - _ => panic!("winit iOS expected the app to be in a `Launching` \ - state, but was not - please file an issue"), + _ => panic!( + "winit iOS expected the app to be in a `Launching` \ + state, but was not - please file an issue" + ), }; - ptr::write(&mut this.app_state, AppStateImpl::ProcessingEvents { - event_handler, - active_control_flow: ControlFlow::Poll, - }); + ptr::write( + &mut this.app_state, + AppStateImpl::ProcessingEvents { + event_handler, + active_control_flow: ControlFlow::Poll, + }, + ); drop(this); - + let events = std::iter::once(Event::NewEvents(StartCause::Init)).chain(events); AppState::handle_nonuser_events(events); @@ -238,69 +256,79 @@ impl AppState { // AppState::did_finish_launching handles the special transition `Init` pub unsafe fn handle_wakeup_transition() { let mut this = AppState::get_mut(); - let event = match this.control_flow { - ControlFlow::Poll => { - let event_handler = match &mut this.app_state { - &mut AppStateImpl::NotLaunched { .. } | - &mut AppStateImpl::Launching { .. } => return, - &mut AppStateImpl::PollFinished { - ref mut waiting_event_handler, - } => ptr::read(waiting_event_handler), - _ => bug!("`EventHandler` unexpectedly started polling"), - }; - ptr::write(&mut this.app_state, AppStateImpl::ProcessingEvents { - event_handler, - active_control_flow: ControlFlow::Poll, - }); - Event::NewEvents(StartCause::Poll) - } - ControlFlow::Wait => { - let (event_handler, start) = match &mut this.app_state { - &mut AppStateImpl::NotLaunched { .. } | - &mut AppStateImpl::Launching { .. } => return, - &mut AppStateImpl::Waiting { - ref mut waiting_event_handler, - ref mut start, - } => (ptr::read(waiting_event_handler), *start), - _ => bug!("`EventHandler` unexpectedly woke up"), - }; - ptr::write(&mut this.app_state, AppStateImpl::ProcessingEvents { - event_handler, - active_control_flow: ControlFlow::Wait, - }); - Event::NewEvents(StartCause::WaitCancelled { - start, - requested_resume: None, - }) - } - ControlFlow::WaitUntil(requested_resume) => { - let (event_handler, start) = match &mut this.app_state { - &mut AppStateImpl::NotLaunched { .. } | - &mut AppStateImpl::Launching { .. } => return, - &mut AppStateImpl::Waiting { - ref mut waiting_event_handler, - ref mut start, - } => (ptr::read(waiting_event_handler), *start), - _ => bug!("`EventHandler` unexpectedly woke up"), - }; - ptr::write(&mut this.app_state, AppStateImpl::ProcessingEvents { - event_handler, - active_control_flow: ControlFlow::WaitUntil(requested_resume), - }); - if Instant::now() >= requested_resume { - Event::NewEvents(StartCause::ResumeTimeReached { - start, - requested_resume, - }) - } else { + let event = + match this.control_flow { + ControlFlow::Poll => { + let event_handler = match &mut this.app_state { + &mut AppStateImpl::NotLaunched { .. } + | &mut AppStateImpl::Launching { .. } => return, + &mut AppStateImpl::PollFinished { + ref mut waiting_event_handler, + } => ptr::read(waiting_event_handler), + _ => bug!("`EventHandler` unexpectedly started polling"), + }; + ptr::write( + &mut this.app_state, + AppStateImpl::ProcessingEvents { + event_handler, + active_control_flow: ControlFlow::Poll, + }, + ); + Event::NewEvents(StartCause::Poll) + } + ControlFlow::Wait => { + let (event_handler, start) = match &mut this.app_state { + &mut AppStateImpl::NotLaunched { .. } + | &mut AppStateImpl::Launching { .. } => return, + &mut AppStateImpl::Waiting { + ref mut waiting_event_handler, + ref mut start, + } => (ptr::read(waiting_event_handler), *start), + _ => bug!("`EventHandler` unexpectedly woke up"), + }; + ptr::write( + &mut this.app_state, + AppStateImpl::ProcessingEvents { + event_handler, + active_control_flow: ControlFlow::Wait, + }, + ); Event::NewEvents(StartCause::WaitCancelled { start, - requested_resume: Some(requested_resume), + requested_resume: None, }) } - } - ControlFlow::Exit => bug!("unexpected controlflow `Exit`"), - }; + ControlFlow::WaitUntil(requested_resume) => { + let (event_handler, start) = match &mut this.app_state { + &mut AppStateImpl::NotLaunched { .. } + | &mut AppStateImpl::Launching { .. } => return, + &mut AppStateImpl::Waiting { + ref mut waiting_event_handler, + ref mut start, + } => (ptr::read(waiting_event_handler), *start), + _ => bug!("`EventHandler` unexpectedly woke up"), + }; + ptr::write( + &mut this.app_state, + AppStateImpl::ProcessingEvents { + event_handler, + active_control_flow: ControlFlow::WaitUntil(requested_resume), + }, + ); + if Instant::now() >= requested_resume { + Event::NewEvents(StartCause::ResumeTimeReached { + start, + requested_resume, + }) + } else { + Event::NewEvents(StartCause::WaitCancelled { + start, + requested_resume: Some(requested_resume), + }) + } + } + ControlFlow::Exit => bug!("unexpected controlflow `Exit`"), + }; drop(this); AppState::handle_nonuser_event(event) } @@ -328,7 +356,7 @@ impl AppState { .. } => { queued_events.extend(events); - return + return; } &mut AppStateImpl::ProcessingEvents { ref mut event_handler, @@ -338,9 +366,12 @@ impl AppState { | &mut AppStateImpl::Waiting { .. } | &mut AppStateImpl::Terminated => bug!("unexpected attempted to process an event"), }; - ptr::write(&mut this.app_state, AppStateImpl::InUserCallback { - queued_events: Vec::new(), - }); + ptr::write( + &mut this.app_state, + AppStateImpl::InUserCallback { + queued_events: Vec::new(), + }, + ); drop(this); for event in events { @@ -360,7 +391,7 @@ impl AppState { active_control_flow, }; this.control_flow = control_flow; - break + break; } drop(this); for event in queued_events { @@ -384,9 +415,12 @@ impl AppState { | &mut AppStateImpl::Waiting { .. } | &mut AppStateImpl::Terminated => bug!("unexpected attempted to process an event"), }; - ptr::write(&mut this.app_state, AppStateImpl::InUserCallback { - queued_events: Vec::new(), - }); + ptr::write( + &mut this.app_state, + AppStateImpl::InUserCallback { + queued_events: Vec::new(), + }, + ); drop(this); event_handler.handle_user_events(&mut control_flow); @@ -404,7 +438,7 @@ impl AppState { active_control_flow, }; this.control_flow = control_flow; - break + break; } drop(this); for event in queued_events { @@ -432,20 +466,21 @@ impl AppState { &mut AppStateImpl::ProcessingEvents { ref mut event_handler, ref mut active_control_flow, - } => (ManuallyDrop::new(ptr::read(event_handler)), *active_control_flow), + } => ( + ManuallyDrop::new(ptr::read(event_handler)), + *active_control_flow, + ), _ => unreachable!(), }; let new = this.control_flow; match (old, new) { - (ControlFlow::Poll, ControlFlow::Poll) => { - ptr::write( - &mut this.app_state, - AppStateImpl::PollFinished { - waiting_event_handler: ManuallyDrop::into_inner(event_handler), - }, - ) - }, + (ControlFlow::Poll, ControlFlow::Poll) => ptr::write( + &mut this.app_state, + AppStateImpl::PollFinished { + waiting_event_handler: ManuallyDrop::into_inner(event_handler), + }, + ), (ControlFlow::Wait, ControlFlow::Wait) => { let start = Instant::now(); ptr::write( @@ -455,9 +490,10 @@ impl AppState { start, }, ) - }, + } (ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant)) - if old_instant == new_instant => { + if old_instant == new_instant => + { let start = Instant::now(); ptr::write( &mut this.app_state, @@ -477,7 +513,7 @@ impl AppState { }, ); this.waker.stop() - }, + } (_, ControlFlow::WaitUntil(new_instant)) => { let start = Instant::now(); ptr::write( @@ -488,7 +524,7 @@ impl AppState { }, ); this.waker.start_at(new_instant) - }, + } (_, ControlFlow::Poll) => { ptr::write( &mut this.app_state, @@ -497,7 +533,7 @@ impl AppState { }, ); this.waker.start() - }, + } (_, ControlFlow::Exit) => { // https://developer.apple.com/library/archive/qa/qa1561/_index.html // it is not possible to quit an iOS app gracefully and programatically @@ -511,7 +547,11 @@ impl AppState { let mut this = unsafe { AppState::get_mut() }; let mut old = mem::replace(&mut this.app_state, AppStateImpl::Terminated); let mut control_flow = this.control_flow; - if let AppStateImpl::ProcessingEvents { ref mut event_handler, .. } = old { + if let AppStateImpl::ProcessingEvents { + ref mut event_handler, + .. + } = old + { drop(this); event_handler.handle_nonuser_event(Event::LoopDestroyed, &mut control_flow) } else { @@ -535,7 +575,7 @@ impl Drop for EventLoopWaker { impl EventLoopWaker { fn new(rl: CFRunLoopRef) -> EventLoopWaker { - extern fn wakeup_main_loop(_timer: CFRunLoopTimerRef, _info: *mut c_void) {} + extern "C" fn wakeup_main_loop(_timer: CFRunLoopTimerRef, _info: *mut c_void) {} unsafe { // create a timer with a 1microsec interval (1ns does not work) to mimic polling. // it is initially setup with a first fire time really far into the @@ -577,4 +617,4 @@ impl EventLoopWaker { } } } -} \ No newline at end of file +} diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs index 589348c7..469d11b1 100644 --- a/src/platform_impl/ios/event_loop.rs +++ b/src/platform_impl/ios/event_loop.rs @@ -1,50 +1,33 @@ -use std::{mem, ptr}; -use std::collections::VecDeque; -use std::ffi::c_void; -use std::fmt::{self, Debug, Formatter}; -use std::marker::PhantomData; -use std::sync::mpsc::{self, Sender, Receiver}; - -use event::Event; -use event_loop::{ - ControlFlow, - EventLoopWindowTarget as RootEventLoopWindowTarget, - EventLoopClosed, +use std::{ + collections::VecDeque, + ffi::c_void, + fmt::{self, Debug}, + marker::PhantomData, + mem, ptr, + sync::mpsc::{self, Receiver, Sender}, }; -use platform::ios::Idiom; -use platform_impl::platform::app_state::AppState; -use platform_impl::platform::ffi::{ - id, - nil, - CFIndex, - CFRelease, - CFRunLoopActivity, - CFRunLoopAddObserver, - CFRunLoopAddSource, - CFRunLoopGetMain, - CFRunLoopObserverCreate, - CFRunLoopObserverRef, - CFRunLoopSourceContext, - CFRunLoopSourceCreate, - CFRunLoopSourceInvalidate, - CFRunLoopSourceRef, - CFRunLoopSourceSignal, - CFRunLoopWakeUp, - kCFRunLoopCommonModes, - kCFRunLoopDefaultMode, - kCFRunLoopEntry, - kCFRunLoopBeforeWaiting, - kCFRunLoopAfterWaiting, - kCFRunLoopExit, - NSOperatingSystemVersion, - NSString, - UIApplicationMain, - UIUserInterfaceIdiom, +use crate::{ + event::Event, + event_loop::{ + ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget, + }, + platform::ios::Idiom, +}; + +use crate::platform_impl::platform::{ + app_state::AppState, + ffi::{ + id, kCFRunLoopAfterWaiting, kCFRunLoopBeforeWaiting, kCFRunLoopCommonModes, + kCFRunLoopDefaultMode, kCFRunLoopEntry, kCFRunLoopExit, nil, CFIndex, CFRelease, + CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopAddSource, CFRunLoopGetMain, + CFRunLoopObserverCreate, CFRunLoopObserverRef, CFRunLoopSourceContext, + CFRunLoopSourceCreate, CFRunLoopSourceInvalidate, CFRunLoopSourceRef, + CFRunLoopSourceSignal, CFRunLoopWakeUp, NSOperatingSystemVersion, NSString, + UIApplicationMain, UIUserInterfaceIdiom, + }, + monitor, view, MonitorHandle, }; -use platform_impl::platform::monitor; -use platform_impl::platform::MonitorHandle; -use platform_impl::platform::view; pub struct EventLoopWindowTarget { receiver: Receiver, @@ -67,8 +50,11 @@ impl EventLoop { static mut SINGLETON_INIT: bool = false; unsafe { assert_main_thread!("`EventLoop` can only be created on the main thread on iOS"); - assert!(!SINGLETON_INIT, "Only one `EventLoop` is supported on iOS. \ - `EventLoopProxy` might be helpful"); + assert!( + !SINGLETON_INIT, + "Only one `EventLoop` is supported on iOS. \ + `EventLoopProxy` might be helpful" + ); SINGLETON_INIT = true; view::create_delegate_class(); } @@ -92,25 +78,34 @@ impl EventLoop { capabilities, }, _marker: PhantomData, - } + }, } } pub fn run(self, event_handler: F) -> ! where - F: 'static + FnMut(Event, &RootEventLoopWindowTarget, &mut ControlFlow) + F: 'static + FnMut(Event, &RootEventLoopWindowTarget, &mut ControlFlow), { unsafe { let application: *mut c_void = msg_send![class!(UIApplication), sharedApplication]; - assert_eq!(application, ptr::null_mut(), "\ - `EventLoop` cannot be `run` after a call to `UIApplicationMain` on iOS\n\ - Note: `EventLoop::run` calls `UIApplicationMain` on iOS"); + assert_eq!( + application, + ptr::null_mut(), + "\ + `EventLoop` cannot be `run` after a call to `UIApplicationMain` on iOS\n\ + Note: `EventLoop::run` calls `UIApplicationMain` on iOS" + ); AppState::will_launch(Box::new(EventLoopHandler { f: event_handler, event_loop: self.window_target, })); - UIApplicationMain(0, ptr::null(), nil, NSString::alloc(nil).init_str("AppDelegate")); + UIApplicationMain( + 0, + ptr::null(), + nil, + NSString::alloc(nil).init_str("AppDelegate"), + ); unreachable!() } } @@ -121,16 +116,12 @@ impl EventLoop { pub fn available_monitors(&self) -> VecDeque { // guaranteed to be on main thread - unsafe { - monitor::uiscreens() - } + unsafe { monitor::uiscreens() } } pub fn primary_monitor(&self) -> MonitorHandle { // guaranteed to be on main thread - unsafe { - monitor::main_uiscreen() - } + unsafe { monitor::main_uiscreen() } } pub fn window_target(&self) -> &RootEventLoopWindowTarget { @@ -142,9 +133,7 @@ impl EventLoop { impl EventLoop { pub fn idiom(&self) -> Idiom { // guaranteed to be on main thread - unsafe { - self::get_idiom() - } + unsafe { self::get_idiom() } } } @@ -183,18 +172,12 @@ impl EventLoopProxy { // we want all the members of context to be zero/null, except one let mut context: CFRunLoopSourceContext = mem::zeroed(); context.perform = event_loop_proxy_handler; - let source = CFRunLoopSourceCreate( - ptr::null_mut(), - CFIndex::max_value() - 1, - &mut context, - ); + let source = + CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context); CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes); CFRunLoopWakeUp(rl); - EventLoopProxy { - sender, - source, - } + EventLoopProxy { sender, source } } } @@ -213,7 +196,7 @@ impl EventLoopProxy { fn setup_control_flow_observers() { unsafe { // begin is queued with the highest priority to ensure it is processed before other observers - extern fn control_flow_begin_handler( + extern "C" fn control_flow_begin_handler( _: CFRunLoopObserverRef, activity: CFRunLoopActivity, _: *mut c_void, @@ -230,7 +213,7 @@ fn setup_control_flow_observers() { // end is queued with the lowest priority to ensure it is processed after other observers // without that, LoopDestroyed will get sent after EventsCleared - extern fn control_flow_end_handler( + extern "C" fn control_flow_end_handler( _: CFRunLoopObserverRef, activity: CFRunLoopActivity, _: *mut c_void, @@ -281,8 +264,8 @@ struct EventLoopHandler { } impl Debug for EventLoopHandler { - fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.debug_struct("EventLoopHandler") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EventLoopHandler") .field("event_loop", &self.event_loop) .finish() } @@ -303,11 +286,7 @@ where fn handle_user_events(&mut self, control_flow: &mut ControlFlow) { for event in self.event_loop.p.receiver.try_iter() { - (self.f)( - Event::UserEvent(event), - &self.event_loop, - control_flow, - ); + (self.f)(Event::UserEvent(event), &self.event_loop, control_flow); } } } @@ -325,7 +304,10 @@ pub struct Capabilities { impl From for Capabilities { fn from(os_version: NSOperatingSystemVersion) -> Capabilities { - assert!(os_version.major >= 8, "`winit` current requires iOS version 8 or greater"); + assert!( + os_version.major >= 8, + "`winit` current requires iOS version 8 or greater" + ); let supports_safe_area = os_version.major >= 11; diff --git a/src/platform_impl/ios/ffi.rs b/src/platform_impl/ios/ffi.rs index 8583dbd7..9b0c26be 100644 --- a/src/platform_impl/ios/ffi.rs +++ b/src/platform_impl/ios/ffi.rs @@ -1,13 +1,10 @@ #![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] -use std::ffi::CString; -use std::ops::BitOr; -use std::os::raw::*; +use std::{ffi::CString, ops::BitOr, os::raw::*}; -use objc::{Encode, Encoding}; -use objc::runtime::Object; +use objc::{runtime::Object, Encode, Encoding}; -use platform::ios::{Idiom, ValidOrientations}; +use crate::platform::ios::{Idiom, ValidOrientations}; pub type id = *mut Object; pub const nil: id = 0 as id; @@ -87,7 +84,9 @@ pub struct UIEdgeInsets { pub struct UIUserInterfaceIdiom(NSInteger); unsafe impl Encode for UIUserInterfaceIdiom { - fn encode() -> Encoding { NSInteger::encode() } + fn encode() -> Encoding { + NSInteger::encode() + } } impl UIUserInterfaceIdiom { @@ -128,7 +127,9 @@ impl Into for UIUserInterfaceIdiom { pub struct UIInterfaceOrientationMask(NSUInteger); unsafe impl Encode for UIInterfaceOrientationMask { - fn encode() -> Encoding { NSUInteger::encode() } + fn encode() -> Encoding { + NSUInteger::encode() + } } impl UIInterfaceOrientationMask { @@ -136,9 +137,12 @@ impl UIInterfaceOrientationMask { pub const PortraitUpsideDown: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 2); pub const LandscapeLeft: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 4); pub const LandscapeRight: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 3); - pub const Landscape: UIInterfaceOrientationMask = UIInterfaceOrientationMask(Self::LandscapeLeft.0 | Self::LandscapeRight.0); - pub const AllButUpsideDown: UIInterfaceOrientationMask = UIInterfaceOrientationMask(Self::Landscape.0 | Self::Portrait.0); - pub const All: UIInterfaceOrientationMask = UIInterfaceOrientationMask(Self::AllButUpsideDown.0 | Self::PortraitUpsideDown.0); + pub const Landscape: UIInterfaceOrientationMask = + UIInterfaceOrientationMask(Self::LandscapeLeft.0 | Self::LandscapeRight.0); + pub const AllButUpsideDown: UIInterfaceOrientationMask = + UIInterfaceOrientationMask(Self::Landscape.0 | Self::Portrait.0); + pub const All: UIInterfaceOrientationMask = + UIInterfaceOrientationMask(Self::AllButUpsideDown.0 | Self::PortraitUpsideDown.0); } impl BitOr for UIInterfaceOrientationMask { @@ -155,18 +159,23 @@ impl UIInterfaceOrientationMask { idiom: Idiom, ) -> UIInterfaceOrientationMask { match (valid_orientations, idiom) { - (ValidOrientations::LandscapeAndPortrait, Idiom::Phone) => UIInterfaceOrientationMask::AllButUpsideDown, + (ValidOrientations::LandscapeAndPortrait, Idiom::Phone) => { + UIInterfaceOrientationMask::AllButUpsideDown + } (ValidOrientations::LandscapeAndPortrait, _) => UIInterfaceOrientationMask::All, (ValidOrientations::Landscape, _) => UIInterfaceOrientationMask::Landscape, (ValidOrientations::Portrait, Idiom::Phone) => UIInterfaceOrientationMask::Portrait, - (ValidOrientations::Portrait, _) => UIInterfaceOrientationMask::Portrait | UIInterfaceOrientationMask::PortraitUpsideDown, + (ValidOrientations::Portrait, _) => { + UIInterfaceOrientationMask::Portrait + | UIInterfaceOrientationMask::PortraitUpsideDown + } } } } #[link(name = "UIKit", kind = "framework")] #[link(name = "CoreFoundation", kind = "framework")] -extern { +extern "C" { pub static kCFRunLoopDefaultMode: CFRunLoopMode; pub static kCFRunLoopCommonModes: CFRunLoopMode; @@ -203,15 +212,8 @@ extern { callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext, ) -> CFRunLoopTimerRef; - pub fn CFRunLoopAddTimer( - rl: CFRunLoopRef, - timer: CFRunLoopTimerRef, - mode: CFRunLoopMode, - ); - pub fn CFRunLoopTimerSetNextFireDate( - timer: CFRunLoopTimerRef, - fireDate: CFAbsoluteTime, - ); + pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFRunLoopMode); + pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime); pub fn CFRunLoopTimerInvalidate(time: CFRunLoopTimerRef); pub fn CFRunLoopSourceCreate( @@ -219,11 +221,7 @@ extern { order: CFIndex, context: *mut CFRunLoopSourceContext, ) -> CFRunLoopSourceRef; - pub fn CFRunLoopAddSource( - rl: CFRunLoopRef, - source: CFRunLoopSourceRef, - mode: CFRunLoopMode, - ); + pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFRunLoopMode); pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef); pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef); @@ -259,15 +257,9 @@ pub const kCFRunLoopBeforeWaiting: CFRunLoopActivity = 1 << 5; pub const kCFRunLoopAfterWaiting: CFRunLoopActivity = 1 << 6; pub const kCFRunLoopExit: CFRunLoopActivity = 1 << 7; -pub type CFRunLoopObserverCallBack = extern "C" fn( - observer: CFRunLoopObserverRef, - activity: CFRunLoopActivity, - info: *mut c_void, -); -pub type CFRunLoopTimerCallBack = extern "C" fn( - timer: CFRunLoopTimerRef, - info: *mut c_void, -); +pub type CFRunLoopObserverCallBack = + extern "C" fn(observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void); +pub type CFRunLoopTimerCallBack = extern "C" fn(timer: CFRunLoopTimerRef, info: *mut c_void); pub enum CFRunLoopObserverContext {} pub enum CFRunLoopTimerContext {} @@ -299,11 +291,11 @@ pub trait NSString: Sized { impl NSString for id { unsafe fn initWithUTF8String_(self, c_string: *const c_char) -> id { - msg_send![self, initWithUTF8String:c_string as id] + msg_send![self, initWithUTF8String: c_string as id] } unsafe fn stringByAppendingString_(self, other: id) -> id { - msg_send![self, stringByAppendingString:other] + msg_send![self, stringByAppendingString: other] } unsafe fn init_str(self, string: &str) -> id { diff --git a/src/platform_impl/ios/mod.rs b/src/platform_impl/ios/mod.rs index 73dd2b2e..dfb659f9 100644 --- a/src/platform_impl/ios/mod.rs +++ b/src/platform_impl/ios/mod.rs @@ -26,7 +26,6 @@ //! fn start_inner() { //! ... //! } -//! //! ``` //! //! Compile project and then drag resulting .a into Xcode project. Add winit.h to xcode. @@ -47,8 +46,8 @@ //! //! This is how those event are represented in winit: //! -//! - applicationDidBecomeActive is Suspended(false) -//! - applicationWillResignActive is Suspended(true) +//! - applicationDidBecomeActive is Resumed +//! - applicationWillResignActive is Suspended //! - applicationWillTerminate is LoopDestroyed //! //! Keep in mind that after LoopDestroyed event is received every attempt to draw with @@ -78,12 +77,10 @@ mod window; use std::fmt; -pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}; -pub use self::monitor::MonitorHandle; -pub use self::window::{ - PlatformSpecificWindowBuilderAttributes, - Window, - WindowId, +pub use self::{ + event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}, + monitor::MonitorHandle, + window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId}, }; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -106,9 +103,9 @@ unsafe impl Sync for DeviceId {} pub enum OsError {} impl fmt::Display for OsError { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - _ => unreachable!() + _ => unreachable!(), } } } diff --git a/src/platform_impl/ios/monitor.rs b/src/platform_impl/ios/monitor.rs index 14e7d379..c75b7ef6 100644 --- a/src/platform_impl/ios/monitor.rs +++ b/src/platform_impl/ios/monitor.rs @@ -1,17 +1,16 @@ use std::{ - collections::VecDeque, + collections::{HashSet, VecDeque}, fmt, ops::{Deref, DerefMut}, }; -use dpi::{PhysicalPosition, PhysicalSize}; +use crate::{ + dpi::{PhysicalPosition, PhysicalSize}, + monitor::VideoMode, +}; -use platform_impl::platform::ffi::{ - id, - nil, - CGFloat, - CGRect, - NSUInteger, +use crate::platform_impl::platform::ffi::{ + id, nil, CGFloat, CGRect, CGSize, NSInteger, NSUInteger, }; pub struct Inner { @@ -35,7 +34,9 @@ impl Deref for MonitorHandle { fn deref(&self) -> &Inner { unsafe { - assert_main_thread!("`MonitorHandle` methods can only be run on the main thread on iOS"); + assert_main_thread!( + "`MonitorHandle` methods can only be run on the main thread on iOS" + ); } &self.inner } @@ -44,7 +45,9 @@ impl Deref for MonitorHandle { impl DerefMut for MonitorHandle { fn deref_mut(&mut self) -> &mut Inner { unsafe { - assert_main_thread!("`MonitorHandle` methods can only be run on the main thread on iOS"); + assert_main_thread!( + "`MonitorHandle` methods can only be run on the main thread on iOS" + ); } &mut self.inner } @@ -68,18 +71,18 @@ impl Drop for MonitorHandle { } impl fmt::Debug for MonitorHandle { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[derive(Debug)] struct MonitorHandle { name: Option, - dimensions: PhysicalSize, + size: PhysicalSize, position: PhysicalPosition, hidpi_factor: f64, } let monitor_id_proxy = MonitorHandle { name: self.name(), - dimensions: self.dimensions(), + size: self.size(), position: self.position(), hidpi_factor: self.hidpi_factor(), }; @@ -94,7 +97,9 @@ impl MonitorHandle { assert_main_thread!("`MonitorHandle` can only be cloned on the main thread on iOS"); let () = msg_send![uiscreen, retain]; } - MonitorHandle { inner: Inner { uiscreen } } + MonitorHandle { + inner: Inner { uiscreen }, + } } } @@ -114,7 +119,7 @@ impl Inner { } } - pub fn dimensions(&self) -> PhysicalSize { + pub fn size(&self) -> PhysicalSize { unsafe { let bounds: CGRect = msg_send![self.ui_screen(), nativeBounds]; (bounds.size.width as f64, bounds.size.height as f64).into() @@ -134,6 +139,27 @@ impl Inner { scale as f64 } } + + pub fn video_modes(&self) -> impl Iterator { + let refresh_rate: NSInteger = unsafe { msg_send![self.uiscreen, maximumFramesPerSecond] }; + + let available_modes: id = unsafe { msg_send![self.uiscreen, availableModes] }; + let available_mode_count: NSUInteger = unsafe { msg_send![available_modes, count] }; + + let mut modes = HashSet::with_capacity(available_mode_count); + + for i in 0..available_mode_count { + let mode: id = unsafe { msg_send![available_modes, objectAtIndex: i] }; + let size: CGSize = unsafe { msg_send![mode, size] }; + modes.insert(VideoMode { + size: (size.width as u32, size.height as u32), + bit_depth: 32, + refresh_rate: refresh_rate as u16, + }); + } + + modes.into_iter() + } } // MonitorHandleExtIOS @@ -164,7 +190,7 @@ pub unsafe fn uiscreens() -> VecDeque { loop { let screen: id = msg_send![screens_enum, nextObject]; if screen == nil { - break result + break result; } result.push_back(MonitorHandle::retained_new(screen)); } diff --git a/src/platform_impl/ios/view.rs b/src/platform_impl/ios/view.rs index 9205df43..b174b75a 100644 --- a/src/platform_impl/ios/view.rs +++ b/src/platform_impl/ios/view.rs @@ -1,31 +1,23 @@ use std::collections::HashMap; -use objc::declare::ClassDecl; -use objc::runtime::{BOOL, Class, NO, Object, Sel, YES}; - -use event::{ - DeviceId as RootDeviceId, - Event, - Touch, - TouchPhase, - WindowEvent +use objc::{ + declare::ClassDecl, + runtime::{Class, Object, Sel, BOOL, NO, YES}, }; -use platform::ios::MonitorHandleExtIOS; -use window::{WindowAttributes, WindowId as RootWindowId}; -use platform_impl::platform::app_state::AppState; -use platform_impl::platform::DeviceId; -use platform_impl::platform::event_loop; -use platform_impl::platform::ffi::{ - id, - nil, - CGFloat, - CGPoint, - CGRect, - UIInterfaceOrientationMask, - UITouchPhase, +use crate::{ + event::{DeviceId as RootDeviceId, Event, Touch, TouchPhase, WindowEvent}, + platform::ios::MonitorHandleExtIOS, + window::{WindowAttributes, WindowId as RootWindowId}, +}; + +use crate::platform_impl::platform::{ + app_state::AppState, + event_loop, + ffi::{id, nil, CGFloat, CGPoint, CGRect, UIInterfaceOrientationMask, UITouchPhase}, + window::PlatformSpecificWindowBuilderAttributes, + DeviceId, }; -use platform_impl::platform::window::{PlatformSpecificWindowBuilderAttributes}; // requires main thread unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { @@ -40,10 +32,13 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { classes.entry(root_view_class).or_insert_with(move || { let uiview_class = class!(UIView); - let is_uiview: BOOL = msg_send![root_view_class, isSubclassOfClass:uiview_class]; - assert_eq!(is_uiview, YES, "`root_view_class` must inherit from `UIView`"); + let is_uiview: BOOL = msg_send![root_view_class, isSubclassOfClass: uiview_class]; + assert_eq!( + is_uiview, YES, + "`root_view_class` must inherit from `UIView`" + ); - extern fn draw_rect(object: &Object, _: Sel, rect: CGRect) { + extern "C" fn draw_rect(object: &Object, _: Sel, rect: CGRect) { unsafe { let window: id = msg_send![object, window]; AppState::handle_nonuser_event(Event::WindowEvent { @@ -55,13 +50,14 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { } } - extern fn layout_subviews(object: &Object, _: Sel) { + extern "C" fn layout_subviews(object: &Object, _: Sel) { unsafe { let window: id = msg_send![object, window]; let bounds: CGRect = msg_send![window, bounds]; let screen: id = msg_send![window, screen]; let screen_space: id = msg_send![screen, coordinateSpace]; - let screen_frame: CGRect = msg_send![object, convertRect:bounds toCoordinateSpace:screen_space]; + let screen_frame: CGRect = + msg_send![object, convertRect:bounds toCoordinateSpace:screen_space]; let size = crate::dpi::LogicalSize { width: screen_frame.size.width, height: screen_frame.size.height, @@ -78,10 +74,14 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { let mut decl = ClassDecl::new(&format!("WinitUIView{}", ID), root_view_class) .expect("Failed to declare class `WinitUIView`"); ID += 1; - decl.add_method(sel!(drawRect:), - draw_rect as extern fn(&Object, Sel, CGRect)); - decl.add_method(sel!(layoutSubviews), - layout_subviews as extern fn(&Object, Sel)); + decl.add_method( + sel!(drawRect:), + draw_rect as extern "C" fn(&Object, Sel, CGRect), + ); + decl.add_method( + sel!(layoutSubviews), + layout_subviews as extern "C" fn(&Object, Sel), + ); decl.register() }) } @@ -92,33 +92,39 @@ unsafe fn get_view_controller_class() -> &'static Class { if CLASS.is_none() { let uiviewcontroller_class = class!(UIViewController); - extern fn set_prefers_status_bar_hidden(object: &mut Object, _: Sel, hidden: BOOL) { + extern "C" fn set_prefers_status_bar_hidden(object: &mut Object, _: Sel, hidden: BOOL) { unsafe { object.set_ivar::("_prefers_status_bar_hidden", hidden); let () = msg_send![object, setNeedsStatusBarAppearanceUpdate]; } } - extern fn prefers_status_bar_hidden(object: &Object, _: Sel) -> BOOL { - unsafe { - *object.get_ivar::("_prefers_status_bar_hidden") - } + extern "C" fn prefers_status_bar_hidden(object: &Object, _: Sel) -> BOOL { + unsafe { *object.get_ivar::("_prefers_status_bar_hidden") } } - extern fn set_supported_orientations(object: &mut Object, _: Sel, orientations: UIInterfaceOrientationMask) { + extern "C" fn set_supported_orientations( + object: &mut Object, + _: Sel, + orientations: UIInterfaceOrientationMask, + ) { unsafe { - object.set_ivar::("_supported_orientations", orientations); + object.set_ivar::( + "_supported_orientations", + orientations, + ); let () = msg_send![class!(UIViewController), attemptRotationToDeviceOrientation]; } } - extern fn supported_orientations(object: &Object, _: Sel) -> UIInterfaceOrientationMask { - unsafe { - *object.get_ivar::("_supported_orientations") - } + extern "C" fn supported_orientations( + object: &Object, + _: Sel, + ) -> UIInterfaceOrientationMask { + unsafe { *object.get_ivar::("_supported_orientations") } } - extern fn should_autorotate(_: &Object, _: Sel) -> BOOL { + extern "C" fn should_autorotate(_: &Object, _: Sel) -> BOOL { YES } @@ -126,16 +132,27 @@ unsafe fn get_view_controller_class() -> &'static Class { .expect("Failed to declare class `WinitUIViewController`"); decl.add_ivar::("_prefers_status_bar_hidden"); decl.add_ivar::("_supported_orientations"); - decl.add_method(sel!(setPrefersStatusBarHidden:), - set_prefers_status_bar_hidden as extern fn(&mut Object, Sel, BOOL)); - decl.add_method(sel!(prefersStatusBarHidden), - prefers_status_bar_hidden as extern fn(&Object, Sel) -> BOOL); - decl.add_method(sel!(setSupportedInterfaceOrientations:), - set_supported_orientations as extern fn(&mut Object, Sel, UIInterfaceOrientationMask)); - decl.add_method(sel!(supportedInterfaceOrientations), - supported_orientations as extern fn(&Object, Sel) -> UIInterfaceOrientationMask); - decl.add_method(sel!(shouldAutorotate), - should_autorotate as extern fn(&Object, Sel) -> BOOL); + decl.add_method( + sel!(setPrefersStatusBarHidden:), + set_prefers_status_bar_hidden as extern "C" fn(&mut Object, Sel, BOOL), + ); + decl.add_method( + sel!(prefersStatusBarHidden), + prefers_status_bar_hidden as extern "C" fn(&Object, Sel) -> BOOL, + ); + decl.add_method( + sel!(setSupportedInterfaceOrientations:), + set_supported_orientations + as extern "C" fn(&mut Object, Sel, UIInterfaceOrientationMask), + ); + decl.add_method( + sel!(supportedInterfaceOrientations), + supported_orientations as extern "C" fn(&Object, Sel) -> UIInterfaceOrientationMask, + ); + decl.add_method( + sel!(shouldAutorotate), + should_autorotate as extern "C" fn(&Object, Sel) -> BOOL, + ); CLASS = Some(decl.register()); } CLASS.unwrap() @@ -147,7 +164,7 @@ unsafe fn get_window_class() -> &'static Class { if CLASS.is_none() { let uiwindow_class = class!(UIWindow); - extern fn become_key_window(object: &Object, _: Sel) { + extern "C" fn become_key_window(object: &Object, _: Sel) { unsafe { AppState::handle_nonuser_event(Event::WindowEvent { window_id: RootWindowId(object.into()), @@ -157,7 +174,7 @@ unsafe fn get_window_class() -> &'static Class { } } - extern fn resign_key_window(object: &Object, _: Sel) { + extern "C" fn resign_key_window(object: &Object, _: Sel) { unsafe { AppState::handle_nonuser_event(Event::WindowEvent { window_id: RootWindowId(object.into()), @@ -167,7 +184,7 @@ unsafe fn get_window_class() -> &'static Class { } } - extern fn handle_touches(object: &Object, _: Sel, touches: id, _:id) { + extern "C" fn handle_touches(object: &Object, _: Sel, touches: id, _: id) { unsafe { let uiscreen = msg_send![object, screen]; let touches_enum: id = msg_send![touches, objectEnumerator]; @@ -175,9 +192,9 @@ unsafe fn get_window_class() -> &'static Class { loop { let touch: id = msg_send![touches_enum, nextObject]; if touch == nil { - break + break; } - let location: CGPoint = msg_send![touch, locationInView:nil]; + let location: CGPoint = msg_send![touch, locationInView: nil]; let touch_id = touch as u64; let phase: UITouchPhase = msg_send![touch, phase]; let phase = match phase { @@ -203,16 +220,20 @@ unsafe fn get_window_class() -> &'static Class { } } - extern fn set_content_scale_factor(object: &mut Object, _: Sel, hidpi_factor: CGFloat) { + extern "C" fn set_content_scale_factor(object: &mut Object, _: Sel, hidpi_factor: CGFloat) { unsafe { - let () = msg_send![super(object, class!(UIWindow)), setContentScaleFactor:hidpi_factor]; + let () = msg_send![ + super(object, class!(UIWindow)), + setContentScaleFactor: hidpi_factor + ]; let view_controller: id = msg_send![object, rootViewController]; let view: id = msg_send![view_controller, view]; - let () = msg_send![view, setContentScaleFactor:hidpi_factor]; + let () = msg_send![view, setContentScaleFactor: hidpi_factor]; let bounds: CGRect = msg_send![object, bounds]; let screen: id = msg_send![object, screen]; let screen_space: id = msg_send![screen, coordinateSpace]; - let screen_frame: CGRect = msg_send![object, convertRect:bounds toCoordinateSpace:screen_space]; + let screen_frame: CGRect = + msg_send![object, convertRect:bounds toCoordinateSpace:screen_space]; let size = crate::dpi::LogicalSize { width: screen_frame.size.width, height: screen_frame.size.height, @@ -221,32 +242,47 @@ unsafe fn get_window_class() -> &'static Class { std::iter::once(Event::WindowEvent { window_id: RootWindowId(object.into()), event: WindowEvent::HiDpiFactorChanged(hidpi_factor as _), - }).chain(std::iter::once(Event::WindowEvent { + }) + .chain(std::iter::once(Event::WindowEvent { window_id: RootWindowId(object.into()), event: WindowEvent::Resized(size), - })) + })), ); } } let mut decl = ClassDecl::new("WinitUIWindow", uiwindow_class) .expect("Failed to declare class `WinitUIWindow`"); - decl.add_method(sel!(becomeKeyWindow), - become_key_window as extern fn(&Object, Sel)); - decl.add_method(sel!(resignKeyWindow), - resign_key_window as extern fn(&Object, Sel)); + decl.add_method( + sel!(becomeKeyWindow), + become_key_window as extern "C" fn(&Object, Sel), + ); + decl.add_method( + sel!(resignKeyWindow), + resign_key_window as extern "C" fn(&Object, Sel), + ); - decl.add_method(sel!(touchesBegan:withEvent:), - handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id)); - decl.add_method(sel!(touchesMoved:withEvent:), - handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id)); - decl.add_method(sel!(touchesEnded:withEvent:), - handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id)); - decl.add_method(sel!(touchesCancelled:withEvent:), - handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id)); + decl.add_method( + sel!(touchesBegan:withEvent:), + handle_touches as extern "C" fn(this: &Object, _: Sel, _: id, _: id), + ); + decl.add_method( + sel!(touchesMoved:withEvent:), + handle_touches as extern "C" fn(this: &Object, _: Sel, _: id, _: id), + ); + decl.add_method( + sel!(touchesEnded:withEvent:), + handle_touches as extern "C" fn(this: &Object, _: Sel, _: id, _: id), + ); + decl.add_method( + sel!(touchesCancelled:withEvent:), + handle_touches as extern "C" fn(this: &Object, _: Sel, _: id, _: id), + ); - decl.add_method(sel!(setContentScaleFactor:), - set_content_scale_factor as extern fn(&mut Object, Sel, CGFloat)); + decl.add_method( + sel!(setContentScaleFactor:), + set_content_scale_factor as extern "C" fn(&mut Object, Sel, CGFloat), + ); CLASS = Some(decl.register()); } @@ -263,9 +299,9 @@ pub unsafe fn create_view( let view: id = msg_send![class, alloc]; assert!(!view.is_null(), "Failed to create `UIView` instance"); - let view: id = msg_send![view, initWithFrame:frame]; + let view: id = msg_send![view, initWithFrame: frame]; assert!(!view.is_null(), "Failed to initialize `UIView` instance"); - let () = msg_send![view, setMultipleTouchEnabled:YES]; + let () = msg_send![view, setMultipleTouchEnabled: YES]; view } @@ -279,9 +315,15 @@ pub unsafe fn create_view_controller( let class = get_view_controller_class(); let view_controller: id = msg_send![class, alloc]; - assert!(!view_controller.is_null(), "Failed to create `UIViewController` instance"); + assert!( + !view_controller.is_null(), + "Failed to create `UIViewController` instance" + ); let view_controller: id = msg_send![view_controller, init]; - assert!(!view_controller.is_null(), "Failed to initialize `UIViewController` instance"); + assert!( + !view_controller.is_null(), + "Failed to initialize `UIViewController` instance" + ); let status_bar_hidden = if window_attributes.decorations { NO } else { @@ -292,9 +334,15 @@ pub unsafe fn create_view_controller( platform_attributes.valid_orientations, idiom, ); - let () = msg_send![view_controller, setPrefersStatusBarHidden:status_bar_hidden]; - let () = msg_send![view_controller, setSupportedInterfaceOrientations:supported_orientations]; - let () = msg_send![view_controller, setView:view]; + let () = msg_send![ + view_controller, + setPrefersStatusBarHidden: status_bar_hidden + ]; + let () = msg_send![ + view_controller, + setSupportedInterfaceOrientations: supported_orientations + ]; + let () = msg_send![view_controller, setView: view]; view_controller } @@ -309,11 +357,14 @@ pub unsafe fn create_window( let window: id = msg_send![class, alloc]; assert!(!window.is_null(), "Failed to create `UIWindow` instance"); - let window: id = msg_send![window, initWithFrame:frame]; - assert!(!window.is_null(), "Failed to initialize `UIWindow` instance"); - let () = msg_send![window, setRootViewController:view_controller]; + let window: id = msg_send![window, initWithFrame: frame]; + assert!( + !window.is_null(), + "Failed to initialize `UIWindow` instance" + ); + let () = msg_send![window, setRootViewController: view_controller]; if let Some(hidpi_factor) = platform_attributes.hidpi_factor { - let () = msg_send![window, setContentScaleFactor:hidpi_factor as CGFloat]; + let () = msg_send![window, setContentScaleFactor: hidpi_factor as CGFloat]; } if let &Some(ref monitor) = &window_attributes.fullscreen { let () = msg_send![window, setScreen:monitor.ui_screen()]; @@ -323,29 +374,25 @@ pub unsafe fn create_window( } pub fn create_delegate_class() { - extern fn did_finish_launching(_: &mut Object, _: Sel, _: id, _: id) -> BOOL { + extern "C" fn did_finish_launching(_: &mut Object, _: Sel, _: id, _: id) -> BOOL { unsafe { AppState::did_finish_launching(); } YES } - extern fn did_become_active(_: &Object, _: Sel, _: id) { - unsafe { - AppState::handle_nonuser_event(Event::Suspended(false)) - } + extern "C" fn did_become_active(_: &Object, _: Sel, _: id) { + unsafe { AppState::handle_nonuser_event(Event::Resumed) } } - extern fn will_resign_active(_: &Object, _: Sel, _: id) { - unsafe { - AppState::handle_nonuser_event(Event::Suspended(true)) - } + extern "C" fn will_resign_active(_: &Object, _: Sel, _: id) { + unsafe { AppState::handle_nonuser_event(Event::Suspended) } } - extern fn will_enter_foreground(_: &Object, _: Sel, _: id) {} - extern fn did_enter_background(_: &Object, _: Sel, _: id) {} + extern "C" fn will_enter_foreground(_: &Object, _: Sel, _: id) {} + extern "C" fn did_enter_background(_: &Object, _: Sel, _: id) {} - extern fn will_terminate(_: &Object, _: Sel, _: id) { + extern "C" fn will_terminate(_: &Object, _: Sel, _: id) { unsafe { let app: id = msg_send![class!(UIApplication), sharedApplication]; let windows: id = msg_send![app, windows]; @@ -354,9 +401,9 @@ pub fn create_delegate_class() { loop { let window: id = msg_send![windows_enum, nextObject]; if window == nil { - break + break; } - let is_winit_window: BOOL = msg_send![window, isKindOfClass:class!(WinitUIWindow)]; + let is_winit_window: BOOL = msg_send![window, isKindOfClass: class!(WinitUIWindow)]; if is_winit_window == YES { events.push(Event::WindowEvent { window_id: RootWindowId(window.into()), @@ -370,23 +417,36 @@ pub fn create_delegate_class() { } let ui_responder = class!(UIResponder); - let mut decl = ClassDecl::new("AppDelegate", ui_responder).expect("Failed to declare class `AppDelegate`"); + let mut decl = + ClassDecl::new("AppDelegate", ui_responder).expect("Failed to declare class `AppDelegate`"); unsafe { - decl.add_method(sel!(application:didFinishLaunchingWithOptions:), - did_finish_launching as extern fn(&mut Object, Sel, id, id) -> BOOL); + decl.add_method( + sel!(application:didFinishLaunchingWithOptions:), + did_finish_launching as extern "C" fn(&mut Object, Sel, id, id) -> BOOL, + ); - decl.add_method(sel!(applicationDidBecomeActive:), - did_become_active as extern fn(&Object, Sel, id)); - decl.add_method(sel!(applicationWillResignActive:), - will_resign_active as extern fn(&Object, Sel, id)); - decl.add_method(sel!(applicationWillEnterForeground:), - will_enter_foreground as extern fn(&Object, Sel, id)); - decl.add_method(sel!(applicationDidEnterBackground:), - did_enter_background as extern fn(&Object, Sel, id)); + decl.add_method( + sel!(applicationDidBecomeActive:), + did_become_active as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(applicationWillResignActive:), + will_resign_active as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(applicationWillEnterForeground:), + will_enter_foreground as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(applicationDidEnterBackground:), + did_enter_background as extern "C" fn(&Object, Sel, id), + ); - decl.add_method(sel!(applicationWillTerminate:), - will_terminate as extern fn(&Object, Sel, id)); + decl.add_method( + sel!(applicationWillTerminate:), + will_terminate as extern "C" fn(&Object, Sel, id), + ); decl.register(); } diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs index 2ebbb469..ea4f022f 100644 --- a/src/platform_impl/ios/window.rs +++ b/src/platform_impl/ios/window.rs @@ -3,35 +3,21 @@ use std::{ ops::{Deref, DerefMut}, }; -use objc::runtime::{Class, NO, Object, YES}; +use objc::runtime::{Class, Object, NO, YES}; -use dpi::{self, LogicalPosition, LogicalSize}; -use error::{ExternalError, NotSupportedError, OsError as RootOsError}; -use icon::Icon; -use monitor::MonitorHandle as RootMonitorHandle; -use platform::ios::{MonitorHandleExtIOS, ValidOrientations}; -use window::{ - CursorIcon, - WindowAttributes, -}; -use platform_impl::{ - platform::{ +use crate::{ + dpi::{self, LogicalPosition, LogicalSize}, + error::{ExternalError, NotSupportedError, OsError as RootOsError}, + icon::Icon, + monitor::MonitorHandle as RootMonitorHandle, + platform::ios::{MonitorHandleExtIOS, ValidOrientations}, + platform_impl::platform::{ app_state::AppState, event_loop, - ffi::{ - id, - CGFloat, - CGPoint, - CGRect, - CGSize, - UIEdgeInsets, - UIInterfaceOrientationMask, - }, - monitor, - view, - EventLoopWindowTarget, - MonitorHandle + ffi::{id, CGFloat, CGPoint, CGRect, CGSize, UIEdgeInsets, UIInterfaceOrientationMask}, + monitor, view, EventLoopWindowTarget, MonitorHandle, }, + window::{CursorIcon, WindowAttributes}, }; pub struct Inner { @@ -59,10 +45,10 @@ impl Inner { pub fn set_visible(&self, visible: bool) { match visible { true => unsafe { - let () = msg_send![self.window, setHidden:NO]; + let () = msg_send![self.window, setHidden: NO]; }, false => unsafe { - let () = msg_send![self.window, setHidden:YES]; + let () = msg_send![self.window, setHidden: YES]; }, } } @@ -104,7 +90,7 @@ impl Inner { size: screen_frame.size, }; let bounds = self.from_screen_space(new_screen_frame); - let () = msg_send![self.window, setBounds:bounds]; + let () = msg_send![self.window, setBounds: bounds]; } } @@ -181,9 +167,9 @@ impl Inner { // this is pretty slow on iOS, so avoid doing it if we can if uiscreen != current { - let () = msg_send![self.window, setScreen:uiscreen]; + let () = msg_send![self.window, setScreen: uiscreen]; } - let () = msg_send![self.window, setFrame:bounds]; + let () = msg_send![self.window, setFrame: bounds]; } None => warn!("`Window::set_fullscreen(None)` ignored on iOS"), } @@ -213,7 +199,10 @@ impl Inner { pub fn set_decorations(&self, decorations: bool) { unsafe { let status_bar_hidden = if decorations { NO } else { YES }; - let () = msg_send![self.view_controller, setPrefersStatusBarHidden:status_bar_hidden]; + let () = msg_send![ + self.view_controller, + setPrefersStatusBarHidden: status_bar_hidden + ]; } } @@ -232,20 +221,18 @@ impl Inner { pub fn current_monitor(&self) -> RootMonitorHandle { unsafe { let uiscreen: id = msg_send![self.window, screen]; - RootMonitorHandle { inner: MonitorHandle::retained_new(uiscreen) } + RootMonitorHandle { + inner: MonitorHandle::retained_new(uiscreen), + } } } pub fn available_monitors(&self) -> VecDeque { - unsafe { - monitor::uiscreens() - } + unsafe { monitor::uiscreens() } } pub fn primary_monitor(&self) -> MonitorHandle { - unsafe { - monitor::main_uiscreen() - } + unsafe { monitor::main_uiscreen() } } pub fn id(&self) -> WindowId { @@ -306,7 +293,8 @@ impl Window { // TODO: transparency, visible unsafe { - let screen = window_attributes.fullscreen + let screen = window_attributes + .fullscreen .as_ref() .map(|screen| screen.ui_screen() as _) .unwrap_or_else(|| monitor::main_uiscreen().ui_screen()); @@ -315,14 +303,23 @@ impl Window { let frame = match window_attributes.inner_size { Some(dim) => CGRect { origin: screen_bounds.origin, - size: CGSize { width: dim.width, height: dim.height }, + size: CGSize { + width: dim.width, + height: dim.height, + }, }, None => screen_bounds, }; let view = view::create_view(&window_attributes, &platform_attributes, frame.clone()); - let view_controller = view::create_view_controller(&window_attributes, &platform_attributes, view); - let window = view::create_window(&window_attributes, &platform_attributes, frame, view_controller); + let view_controller = + view::create_view_controller(&window_attributes, &platform_attributes, view); + let window = view::create_window( + &window_attributes, + &platform_attributes, + frame, + view_controller, + ); let supports_safe_area = event_loop.capabilities().supports_safe_area; @@ -342,23 +339,38 @@ impl Window { // WindowExtIOS impl Inner { - pub fn ui_window(&self) -> id { self.window } - pub fn ui_view_controller(&self) -> id { self.view_controller } - pub fn ui_view(&self) -> id { self.view } + pub fn ui_window(&self) -> id { + self.window + } + pub fn ui_view_controller(&self) -> id { + self.view_controller + } + pub fn ui_view(&self) -> id { + self.view + } pub fn set_hidpi_factor(&self, hidpi_factor: f64) { unsafe { - assert!(dpi::validate_hidpi_factor(hidpi_factor), "`WindowExtIOS::set_hidpi_factor` received an invalid hidpi factor"); + assert!( + dpi::validate_hidpi_factor(hidpi_factor), + "`WindowExtIOS::set_hidpi_factor` received an invalid hidpi factor" + ); let hidpi_factor = hidpi_factor as CGFloat; - let () = msg_send![self.view, setContentScaleFactor:hidpi_factor]; + let () = msg_send![self.view, setContentScaleFactor: hidpi_factor]; } } pub fn set_valid_orientations(&self, valid_orientations: ValidOrientations) { unsafe { let idiom = event_loop::get_idiom(); - let supported_orientations = UIInterfaceOrientationMask::from_valid_orientations_idiom(valid_orientations, idiom); - msg_send![self.view_controller, setSupportedInterfaceOrientations:supported_orientations]; + let supported_orientations = UIInterfaceOrientationMask::from_valid_orientations_idiom( + valid_orientations, + idiom, + ); + msg_send![ + self.view_controller, + setSupportedInterfaceOrientations: supported_orientations + ]; } } } @@ -411,14 +423,18 @@ impl Inner { let screen_frame = self.to_screen_space(bounds); let status_bar_frame: CGRect = { let app: id = msg_send![class!(UIApplication), sharedApplication]; - assert!(!app.is_null(), "`Window::get_inner_position` cannot be called before `EventLoop::run` on iOS"); + assert!( + !app.is_null(), + "`Window::get_inner_position` cannot be called before `EventLoop::run` on iOS" + ); msg_send![app, statusBarFrame] }; let (y, height) = if screen_frame.origin.y > status_bar_frame.size.height { (screen_frame.origin.y, screen_frame.size.height) } else { let y = status_bar_frame.size.height; - let height = screen_frame.size.height - (status_bar_frame.size.height - screen_frame.origin.y); + let height = screen_frame.size.height + - (status_bar_frame.size.height - screen_frame.origin.y); (y, height) }; CGRect { @@ -429,7 +445,7 @@ impl Inner { size: CGSize { width: screen_frame.size.width, height, - } + }, } } } @@ -453,13 +469,17 @@ unsafe impl Sync for WindowId {} impl From<&Object> for WindowId { fn from(window: &Object) -> WindowId { - WindowId { window: window as *const _ as _ } + WindowId { + window: window as *const _ as _, + } } } impl From<&mut Object> for WindowId { fn from(window: &mut Object) -> WindowId { - WindowId { window: window as _ } + WindowId { + window: window as _, + } } } diff --git a/src/platform_impl/linux/dlopen.rs b/src/platform_impl/linux/dlopen.rs index 96547481..8be592e4 100644 --- a/src/platform_impl/linux/dlopen.rs +++ b/src/platform_impl/linux/dlopen.rs @@ -1,13 +1,13 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] #![allow(dead_code)] -use std::os::raw::{c_void, c_char, c_int}; +use std::os::raw::{c_char, c_int, c_void}; pub const RTLD_LAZY: c_int = 0x001; pub const RTLD_NOW: c_int = 0x002; -#[link(name ="dl")] -extern { +#[link(name = "dl")] +extern "C" { pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void; pub fn dlerror() -> *mut c_char; pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void; diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 3b316a25..73d9f643 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -1,24 +1,21 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] -use std::collections::VecDeque; -use std::{env, mem, fmt}; -use std::ffi::CStr; -use std::os::raw::*; -use std::sync::Arc; +use std::{collections::VecDeque, env, ffi::CStr, fmt, mem, os::raw::*, sync::Arc}; use parking_lot::Mutex; -use sctk::reexports::client::ConnectError; +use smithay_client_toolkit::reexports::client::ConnectError; -use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; -use icon::Icon; -use error::{ExternalError, NotSupportedError, OsError as RootOsError}; -use event::Event; -use event_loop::{EventLoopClosed, ControlFlow, EventLoopWindowTarget as RootELW}; -use monitor::MonitorHandle as RootMonitorHandle; -use window::{WindowAttributes, CursorIcon}; -use self::x11::{XConnection, XError}; -use self::x11::ffi::XVisualInfo; pub use self::x11::XNotSupported; +use self::x11::{ffi::XVisualInfo, XConnection, XError}; +use crate::{ + dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}, + error::{ExternalError, NotSupportedError, OsError as RootOsError}, + event::Event, + event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, + icon::Icon, + monitor::{MonitorHandle as RootMonitorHandle, VideoMode}, + window::{CursorIcon, WindowAttributes}, +}; mod dlopen; pub mod wayland; @@ -43,14 +40,13 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub override_redirect: bool, pub x11_window_type: x11::util::WindowType, pub gtk_theme_variant: Option, - pub app_id: Option + pub app_id: Option, } -lazy_static!( - pub static ref X11_BACKEND: Mutex, XNotSupported>> = { - Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)) - }; -); +lazy_static! { + pub static ref X11_BACKEND: Mutex, XNotSupported>> = + { Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)) }; +} #[derive(Debug, Clone)] pub enum OsError { @@ -59,10 +55,10 @@ pub enum OsError { } impl fmt::Display for OsError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match self { - OsError::XError(e) => formatter.pad(&e.description), - OsError::XMisc(e) => formatter.pad(e), + OsError::XError(e) => f.pad(&e.description), + OsError::XMisc(e) => f.pad(e), } } } @@ -120,10 +116,10 @@ impl MonitorHandle { } #[inline] - pub fn dimensions(&self) -> PhysicalSize { + pub fn size(&self) -> PhysicalSize { match self { - &MonitorHandle::X(ref m) => m.dimensions(), - &MonitorHandle::Wayland(ref m) => m.dimensions(), + &MonitorHandle::X(ref m) => m.size(), + &MonitorHandle::Wayland(ref m) => m.size(), } } @@ -142,6 +138,14 @@ impl MonitorHandle { &MonitorHandle::Wayland(ref m) => m.hidpi_factor() as f64, } } + + #[inline] + pub fn video_modes(&self) -> Box> { + match self { + MonitorHandle::X(m) => Box::new(m.video_modes()), + MonitorHandle::Wayland(m) => Box::new(m.video_modes()), + } + } } impl Window { @@ -154,10 +158,10 @@ impl Window { match *window_target { EventLoopWindowTarget::Wayland(ref window_target) => { wayland::Window::new(window_target, attribs, pl_attribs).map(Window::Wayland) - }, + } EventLoopWindowTarget::X(ref window_target) => { x11::Window::new(window_target, attribs, pl_attribs).map(Window::X) - }, + } } } @@ -261,7 +265,7 @@ impl Window { pub fn set_cursor_icon(&self, cursor: CursorIcon) { match self { &Window::X(ref w) => w.set_cursor_icon(cursor), - &Window::Wayland(ref w) => w.set_cursor_icon(cursor) + &Window::Wayland(ref w) => w.set_cursor_icon(cursor), } } @@ -283,7 +287,7 @@ impl Window { #[inline] pub fn hidpi_factor(&self) -> f64 { - match self { + match self { &Window::X(ref w) => w.hidpi_factor(), &Window::Wayland(ref w) => w.hidpi_factor() as f64, } @@ -309,8 +313,9 @@ impl Window { pub fn fullscreen(&self) -> Option { match self { &Window::X(ref w) => w.fullscreen(), - &Window::Wayland(ref w) => w.fullscreen() - .map(|monitor_id| RootMonitorHandle { inner: MonitorHandle::Wayland(monitor_id) }) + &Window::Wayland(ref w) => w.fullscreen().map(|monitor_id| RootMonitorHandle { + inner: MonitorHandle::Wayland(monitor_id), + }), } } @@ -318,7 +323,7 @@ impl Window { pub fn set_fullscreen(&self, monitor: Option) { match self { &Window::X(ref w) => w.set_fullscreen(monitor), - &Window::Wayland(ref w) => w.set_fullscreen(monitor) + &Window::Wayland(ref w) => w.set_fullscreen(monitor), } } @@ -326,7 +331,7 @@ impl Window { pub fn set_decorations(&self, decorations: bool) { match self { &Window::X(ref w) => w.set_decorations(decorations), - &Window::Wayland(ref w) => w.set_decorations(decorations) + &Window::Wayland(ref w) => w.set_decorations(decorations), } } @@ -365,19 +370,25 @@ impl Window { #[inline] pub fn current_monitor(&self) -> RootMonitorHandle { match self { - &Window::X(ref window) => RootMonitorHandle { inner: MonitorHandle::X(window.current_monitor()) }, - &Window::Wayland(ref window) => RootMonitorHandle { inner: MonitorHandle::Wayland(window.current_monitor()) }, + &Window::X(ref window) => RootMonitorHandle { + inner: MonitorHandle::X(window.current_monitor()), + }, + &Window::Wayland(ref window) => RootMonitorHandle { + inner: MonitorHandle::Wayland(window.current_monitor()), + }, } } #[inline] pub fn available_monitors(&self) -> VecDeque { match self { - &Window::X(ref window) => window.available_monitors() + &Window::X(ref window) => window + .available_monitors() .into_iter() .map(MonitorHandle::X) .collect(), - &Window::Wayland(ref window) => window.available_monitors() + &Window::Wayland(ref window) => window + .available_monitors() .into_iter() .map(MonitorHandle::Wayland) .collect(), @@ -393,7 +404,6 @@ impl Window { } } - unsafe extern "C" fn x_error_callback( display: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent, @@ -424,10 +434,9 @@ unsafe extern "C" fn x_error_callback( 0 } - pub enum EventLoop { Wayland(wayland::EventLoop), - X(x11::EventLoop) + X(x11::EventLoop), } #[derive(Clone)] @@ -436,18 +445,17 @@ pub enum EventLoopProxy { Wayland(wayland::EventLoopProxy), } -impl EventLoop { +impl EventLoop { pub fn new() -> EventLoop { if let Ok(env_var) = env::var(BACKEND_PREFERENCE_ENV_VAR) { match env_var.as_str() { "x11" => { // TODO: propagate return EventLoop::new_x11().expect("Failed to initialize X11 backend"); - }, + } "wayland" => { - return EventLoop::new_wayland() - .expect("Failed to initialize Wayland backend"); - }, + return EventLoop::new_wayland().expect("Failed to initialize Wayland backend"); + } _ => panic!( "Unknown environment variable value for {}, try one of `x11`,`wayland`", BACKEND_PREFERENCE_ENV_VAR, @@ -467,15 +475,13 @@ impl EventLoop { let err_string = format!( "Failed to initialize any backend! Wayland status: {:?} X11 status: {:?}", - wayland_err, - x11_err, + wayland_err, x11_err, ); panic!(err_string); } pub fn new_wayland() -> Result, ConnectError> { - wayland::EventLoop::new() - .map(EventLoop::Wayland) + wayland::EventLoop::new().map(EventLoop::Wayland) } pub fn new_x11() -> Result, XNotSupported> { @@ -521,20 +527,22 @@ impl EventLoop { } pub fn run_return(&mut self, callback: F) - where F: FnMut(::event::Event, &RootELW, &mut ControlFlow) + where + F: FnMut(crate::event::Event, &RootELW, &mut ControlFlow), { match *self { EventLoop::Wayland(ref mut evlp) => evlp.run_return(callback), - EventLoop::X(ref mut evlp) => evlp.run_return(callback) + EventLoop::X(ref mut evlp) => evlp.run_return(callback), } } pub fn run(self, callback: F) -> ! - where F: 'static + FnMut(::event::Event, &RootELW, &mut ControlFlow) + where + F: 'static + FnMut(crate::event::Event, &RootELW, &mut ControlFlow), { match self { EventLoop::Wayland(evlp) => evlp.run(callback), - EventLoop::X(evlp) => evlp.run(callback) + EventLoop::X(evlp) => evlp.run(callback), } } @@ -546,10 +554,10 @@ impl EventLoop { } } - pub fn window_target(&self) -> &::event_loop::EventLoopWindowTarget { + pub fn window_target(&self) -> &crate::event_loop::EventLoopWindowTarget { match *self { EventLoop::Wayland(ref evl) => evl.window_target(), - EventLoop::X(ref evl) => evl.window_target() + EventLoop::X(ref evl) => evl.window_target(), } } } @@ -565,12 +573,16 @@ impl EventLoopProxy { pub enum EventLoopWindowTarget { Wayland(wayland::EventLoopWindowTarget), - X(x11::EventLoopWindowTarget) + X(x11::EventLoopWindowTarget), } fn sticky_exit_callback( - evt: Event, target: &RootELW, control_flow: &mut ControlFlow, callback: &mut F -) where F: FnMut(Event, &RootELW, &mut ControlFlow) + evt: Event, + target: &RootELW, + control_flow: &mut ControlFlow, + callback: &mut F, +) where + F: FnMut(Event, &RootELW, &mut ControlFlow), { // make ControlFlow::Exit sticky by providing a dummy // control flow reference if it is already Exit. diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index c73a225f..7c3b21a0 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -1,46 +1,67 @@ -use std::cell::RefCell; -use std::collections::VecDeque; -use std::fmt; -use std::rc::Rc; -use std::sync::{Arc, Mutex}; -use std::time::Instant; - -use event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}; -use event::ModifiersState; -use dpi::{PhysicalPosition, PhysicalSize}; -use platform_impl::platform::sticky_exit_callback; - -use super::window::WindowStore; -use super::WindowId; - -use sctk::output::OutputMgr; -use sctk::reexports::client::protocol::{ - wl_keyboard, wl_output, wl_pointer, wl_registry, wl_seat, wl_touch, +use std::{ + cell::RefCell, + collections::VecDeque, + fmt, + rc::Rc, + sync::{Arc, Mutex}, + time::Instant, }; -use sctk::reexports::client::{ConnectError, Display, EventQueue, GlobalEvent}; -use sctk::Environment; -pub struct WindowEventsSink { - buffer: VecDeque<(::event::WindowEvent, ::window::WindowId)>, +use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1::client::{ + zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, + zwp_relative_pointer_v1::ZwpRelativePointerV1, +}; + +use crate::{ + dpi::{PhysicalPosition, PhysicalSize}, + event::ModifiersState, + event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, + monitor::VideoMode, + platform_impl::platform::sticky_exit_callback, +}; + +use super::{window::WindowStore, DeviceId, WindowId}; + +use smithay_client_toolkit::{ + output::OutputMgr, + reexports::client::{ + protocol::{wl_keyboard, wl_output, wl_pointer, wl_registry, wl_seat, wl_touch}, + ConnectError, Display, EventQueue, GlobalEvent, + }, + Environment, +}; + +pub struct WindowEventsSink { + buffer: VecDeque>, } -impl WindowEventsSink { - pub fn new() -> WindowEventsSink { +impl WindowEventsSink { + pub fn new() -> WindowEventsSink { WindowEventsSink { buffer: VecDeque::new(), } } - pub fn send_event(&mut self, evt: ::event::WindowEvent, wid: WindowId) { - self.buffer.push_back((evt, ::window::WindowId(::platform_impl::WindowId::Wayland(wid)))); + pub fn send_window_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) { + self.buffer.push_back(crate::event::Event::WindowEvent { + event: evt, + window_id: crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid)), + }); } - fn empty_with(&mut self, mut callback: F) + pub fn send_device_event(&mut self, evt: crate::event::DeviceEvent, dev_id: DeviceId) { + self.buffer.push_back(crate::event::Event::DeviceEvent { + event: evt, + device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(dev_id)), + }); + } + + fn empty_with(&mut self, mut callback: F) where - F: FnMut(::event::Event), + F: FnMut(crate::event::Event), { - for (evt, wid) in self.buffer.drain(..) { - callback(::event::Event::WindowEvent { event: evt, window_id: wid}) + for evt in self.buffer.drain(..) { + callback(evt) } } } @@ -53,12 +74,14 @@ pub struct EventLoop { // the output manager pub outputs: OutputMgr, // our sink, shared with some handlers, buffering the events - sink: Arc>, + sink: Arc>>, pending_user_events: Rc>>, _user_source: ::calloop::Source<::calloop::channel::Channel>, user_sender: ::calloop::channel::Sender, - _kbd_source: ::calloop::Source<::calloop::channel::Channel<(::event::WindowEvent, super::WindowId)>>, - window_target: RootELW + _kbd_source: ::calloop::Source< + ::calloop::channel::Channel<(crate::event::WindowEvent, super::WindowId)>, + >, + window_target: RootELW, } // A handle that can be sent across threads and used to wake up the `EventLoop`. @@ -66,7 +89,7 @@ pub struct EventLoop { // We should only try and wake up the `EventLoop` if it still exists, so we hold Weak ptrs. #[derive(Clone)] pub struct EventLoopProxy { - user_sender: ::calloop::channel::Sender + user_sender: ::calloop::channel::Sender, } pub struct EventLoopWindowTarget { @@ -82,7 +105,7 @@ pub struct EventLoopWindowTarget { pub display: Arc, // The list of seats pub seats: Arc>>, - _marker: ::std::marker::PhantomData + _marker: ::std::marker::PhantomData, } impl EventLoopProxy { @@ -104,14 +127,18 @@ impl EventLoop { let (kbd_sender, kbd_channel) = ::calloop::channel::channel(); let kbd_sink = sink.clone(); - let kbd_source = inner_loop.handle().insert_source(kbd_channel, move |evt, &mut()| { - if let ::calloop::channel::Event::Msg((evt, wid)) = evt { - kbd_sink.lock().unwrap().send_event(evt, wid); - } - }).unwrap(); + let kbd_source = inner_loop + .handle() + .insert_source(kbd_channel, move |evt, &mut ()| { + if let ::calloop::channel::Event::Msg((evt, wid)) = evt { + kbd_sink.lock().unwrap().send_window_event(evt, wid); + } + }) + .unwrap(); let mut seat_manager = SeatManager { sink: sink.clone(), + relative_pointer_manager_proxy: None, store: store.clone(), seats: seats.clone(), kbd_sender, @@ -120,34 +147,52 @@ impl EventLoop { let env = Environment::from_display_with_cb( &display, &mut event_queue, - move |event, registry| { - match event { - GlobalEvent::New { id, ref interface, version } => { - if interface == "wl_seat" { - seat_manager.add_seat(id, version, registry) - } - }, - GlobalEvent::Removed { id, ref interface } => { - if interface == "wl_seat" { - seat_manager.remove_seat(id) - } - }, + move |event, registry| match event { + GlobalEvent::New { + id, + ref interface, + version, + } => { + if interface == "zwp_relative_pointer_manager_v1" { + seat_manager.relative_pointer_manager_proxy = Some( + registry + .bind(version, id, move |pointer_manager| { + pointer_manager.implement_closure(|_, _| (), ()) + }) + .unwrap(), + ) + } + if interface == "wl_seat" { + seat_manager.add_seat(id, version, registry) + } + } + GlobalEvent::Removed { id, ref interface } => { + if interface == "wl_seat" { + seat_manager.remove_seat(id) + } } }, - ).unwrap(); + ) + .unwrap(); - let source = inner_loop.handle().insert_source(event_queue, |(), &mut ()| {}).unwrap(); + let source = inner_loop + .handle() + .insert_source(event_queue, |(), &mut ()| {}) + .unwrap(); let pending_user_events = Rc::new(RefCell::new(VecDeque::new())); let pending_user_events2 = pending_user_events.clone(); let (user_sender, user_channel) = ::calloop::channel::channel(); - let user_source = inner_loop.handle().insert_source(user_channel, move |evt, &mut()| { - if let ::calloop::channel::Event::Msg(msg) = evt { - pending_user_events2.borrow_mut().push_back(msg); - } - }).unwrap(); + let user_source = inner_loop + .handle() + .insert_source(user_channel, move |evt, &mut ()| { + if let ::calloop::channel::Event::Msg(msg) = evt { + pending_user_events2.borrow_mut().push_back(msg); + } + }) + .unwrap(); Ok(EventLoop { inner_loop, @@ -159,35 +204,37 @@ impl EventLoop { user_sender, _kbd_source: kbd_source, window_target: RootELW { - p: ::platform_impl::EventLoopWindowTarget::Wayland(EventLoopWindowTarget { + p: crate::platform_impl::EventLoopWindowTarget::Wayland(EventLoopWindowTarget { evq: RefCell::new(source), store, env, cleanup_needed: Arc::new(Mutex::new(false)), seats, display, - _marker: ::std::marker::PhantomData + _marker: ::std::marker::PhantomData, }), - _marker: ::std::marker::PhantomData - } + _marker: ::std::marker::PhantomData, + }, }) } pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { - user_sender: self.user_sender.clone() + user_sender: self.user_sender.clone(), } } pub fn run(mut self, callback: F) -> ! - where F: 'static + FnMut(::event::Event, &RootELW, &mut ControlFlow) + where + F: 'static + FnMut(crate::event::Event, &RootELW, &mut ControlFlow), { self.run_return(callback); ::std::process::exit(0); } pub fn run_return(&mut self, mut callback: F) - where F: FnMut(::event::Event, &RootELW, &mut ControlFlow) + where + F: FnMut(crate::event::Event, &RootELW, &mut ControlFlow), { // send pending events to the server self.display.flush().expect("Wayland connection lost."); @@ -197,7 +244,11 @@ impl EventLoop { let sink = self.sink.clone(); let user_events = self.pending_user_events.clone(); - callback(::event::Event::NewEvents(::event::StartCause::Init), &self.window_target, &mut control_flow); + callback( + crate::event::Event::NewEvents(crate::event::StartCause::Init), + &self.window_target, + &mut control_flow, + ); loop { self.post_dispatch_triggers(); @@ -206,7 +257,12 @@ impl EventLoop { { let mut guard = sink.lock().unwrap(); guard.empty_with(|evt| { - sticky_exit_callback(evt, &self.window_target, &mut control_flow, &mut callback); + sticky_exit_callback( + evt, + &self.window_target, + &mut control_flow, + &mut callback, + ); }); } // empty user events @@ -214,10 +270,10 @@ impl EventLoop { let mut guard = user_events.borrow_mut(); for evt in guard.drain(..) { sticky_exit_callback( - ::event::Event::UserEvent(evt), + crate::event::Event::UserEvent(evt), &self.window_target, &mut control_flow, - &mut callback + &mut callback, ); } } @@ -227,16 +283,21 @@ impl EventLoop { { let mut guard = sink.lock().unwrap(); guard.empty_with(|evt| { - sticky_exit_callback(evt, &self.window_target, &mut control_flow, &mut callback); + sticky_exit_callback( + evt, + &self.window_target, + &mut control_flow, + &mut callback, + ); }); } // send Events cleared { sticky_exit_callback( - ::event::Event::EventsCleared, + crate::event::Event::EventsCleared, &self.window_target, &mut control_flow, - &mut callback + &mut callback, ); } @@ -247,22 +308,26 @@ impl EventLoop { ControlFlow::Exit => break, ControlFlow::Poll => { // non-blocking dispatch - self.inner_loop.dispatch(Some(::std::time::Duration::from_millis(0)), &mut ()).unwrap(); - control_flow = ControlFlow::default(); - callback(::event::Event::NewEvents(::event::StartCause::Poll), &self.window_target, &mut control_flow); - }, + self.inner_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut ()) + .unwrap(); + callback( + crate::event::Event::NewEvents(crate::event::StartCause::Poll), + &self.window_target, + &mut control_flow, + ); + } ControlFlow::Wait => { self.inner_loop.dispatch(None, &mut ()).unwrap(); - control_flow = ControlFlow::default(); callback( - ::event::Event::NewEvents(::event::StartCause::WaitCancelled { + crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled { start: Instant::now(), - requested_resume: None + requested_resume: None, }), &self.window_target, - &mut control_flow + &mut control_flow, ); - }, + } ControlFlow::WaitUntil(deadline) => { let start = Instant::now(); // compute the blocking duration @@ -272,32 +337,39 @@ impl EventLoop { ::std::time::Duration::from_millis(0) }; self.inner_loop.dispatch(Some(duration), &mut ()).unwrap(); - control_flow = ControlFlow::default(); let now = Instant::now(); if now < deadline { callback( - ::event::Event::NewEvents(::event::StartCause::WaitCancelled { - start, - requested_resume: Some(deadline) - }), + crate::event::Event::NewEvents( + crate::event::StartCause::WaitCancelled { + start, + requested_resume: Some(deadline), + }, + ), &self.window_target, - &mut control_flow + &mut control_flow, ); } else { callback( - ::event::Event::NewEvents(::event::StartCause::ResumeTimeReached { - start, - requested_resume: deadline - }), + crate::event::Event::NewEvents( + crate::event::StartCause::ResumeTimeReached { + start, + requested_resume: deadline, + }, + ), &self.window_target, - &mut control_flow + &mut control_flow, ); } - }, + } } } - callback(::event::Event::LoopDestroyed, &self.window_target, &mut control_flow); + callback( + crate::event::Event::LoopDestroyed, + &self.window_target, + &mut control_flow, + ); } pub fn primary_monitor(&self) -> MonitorHandle { @@ -325,8 +397,8 @@ impl EventLoop { fn post_dispatch_triggers(&mut self) { let mut sink = self.sink.lock().unwrap(); let window_target = match self.window_target.p { - ::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt, - _ => unreachable!() + crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt, + _ => unreachable!(), }; // prune possible dead windows { @@ -335,7 +407,7 @@ impl EventLoop { let pruned = window_target.store.lock().unwrap().cleanup(); *cleanup_needed = false; for wid in pruned { - sink.send_event(::event::WindowEvent::Destroyed, wid); + sink.send_window_event(crate::event::WindowEvent::Destroyed, wid); } } } @@ -346,8 +418,11 @@ impl EventLoop { if let Some((w, h)) = newsize { frame.resize(w, h); frame.refresh(); - let logical_size = ::dpi::LogicalSize::new(w as f64, h as f64); - sink.send_event(::event::WindowEvent::Resized(logical_size), wid); + let logical_size = crate::dpi::LogicalSize::new(w as f64, h as f64); + sink.send_window_event( + crate::event::WindowEvent::Resized(logical_size), + wid, + ); *size = (w, h); } else if frame_refresh { frame.refresh(); @@ -357,13 +432,16 @@ impl EventLoop { } } if let Some(dpi) = new_dpi { - sink.send_event(::event::WindowEvent::HiDpiFactorChanged(dpi as f64), wid); + sink.send_window_event( + crate::event::WindowEvent::HiDpiFactorChanged(dpi as f64), + wid, + ); } if refresh { - sink.send_event(::event::WindowEvent::RedrawRequested, wid); + sink.send_window_event(crate::event::WindowEvent::RedrawRequested, wid); } if closed { - sink.send_event(::event::WindowEvent::CloseRequested, wid); + sink.send_window_event(crate::event::WindowEvent::CloseRequested, wid); } }, ) @@ -374,14 +452,15 @@ impl EventLoop { * Wayland protocol implementations */ -struct SeatManager { - sink: Arc>, +struct SeatManager { + sink: Arc>>, store: Arc>, seats: Arc>>, - kbd_sender: ::calloop::channel::Sender<(::event::WindowEvent, super::WindowId)> + kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, + relative_pointer_manager_proxy: Option, } -impl SeatManager { +impl SeatManager { fn add_seat(&mut self, id: u32, version: u32, registry: wl_registry::WlRegistry) { use std::cmp::min; @@ -389,6 +468,8 @@ impl SeatManager { sink: self.sink.clone(), store: self.store.clone(), pointer: None, + relative_pointer: None, + relative_pointer_manager_proxy: self.relative_pointer_manager_proxy.as_ref().cloned(), keyboard: None, touch: None, kbd_sender: self.kbd_sender.clone(), @@ -396,9 +477,7 @@ impl SeatManager { }; let seat = registry .bind(min(version, 5), id, move |seat| { - seat.implement_closure(move |event, seat| { - seat_data.receive(event, seat) - }, ()) + seat.implement_closure(move |event, seat| seat_data.receive(event, seat), ()) }) .unwrap(); self.store.lock().unwrap().new_seat(&seat); @@ -416,17 +495,19 @@ impl SeatManager { } } -struct SeatData { - sink: Arc>, +struct SeatData { + sink: Arc>>, store: Arc>, - kbd_sender: ::calloop::channel::Sender<(::event::WindowEvent, super::WindowId)>, + kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, pointer: Option, + relative_pointer: Option, + relative_pointer_manager_proxy: Option, keyboard: Option, touch: Option, modifiers_tracker: Arc>, } -impl SeatData { +impl SeatData { fn receive(&mut self, evt: wl_seat::Event, seat: wl_seat::WlSeat) { match evt { wl_seat::Event::Name { .. } => (), @@ -438,7 +519,19 @@ impl SeatData { self.sink.clone(), self.store.clone(), self.modifiers_tracker.clone(), - )) + )); + + self.relative_pointer = + self.relative_pointer_manager_proxy + .as_ref() + .and_then(|manager| { + super::pointer::implement_relative_pointer( + self.sink.clone(), + self.pointer.as_ref().unwrap(), + manager, + ) + .ok() + }) } // destroy pointer if applicable if !capabilities.contains(wl_seat::Capability::Pointer) { @@ -480,13 +573,13 @@ impl SeatData { } } } - }, - _ => unreachable!() + } + _ => unreachable!(), } } } -impl Drop for SeatData { +impl Drop for SeatData { fn drop(&mut self) { if let Some(pointer) = self.pointer.take() { if pointer.as_ref().version() >= 3 { @@ -525,12 +618,12 @@ impl Clone for MonitorHandle { } impl fmt::Debug for MonitorHandle { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[derive(Debug)] struct MonitorHandle { name: Option, native_identifier: u32, - dimensions: PhysicalSize, + size: PhysicalSize, position: PhysicalPosition, hidpi_factor: i32, } @@ -538,7 +631,7 @@ impl fmt::Debug for MonitorHandle { let monitor_id_proxy = MonitorHandle { name: self.name(), native_identifier: self.native_identifier(), - dimensions: self.dimensions(), + size: self.size(), position: self.position(), hidpi_factor: self.hidpi_factor(), }; @@ -559,7 +652,7 @@ impl MonitorHandle { self.mgr.with_info(&self.proxy, |id, _| id).unwrap_or(0) } - pub fn dimensions(&self) -> PhysicalSize { + pub fn size(&self) -> PhysicalSize { match self.mgr.with_info(&self.proxy, |_, info| { info.modes .iter() @@ -568,7 +661,8 @@ impl MonitorHandle { }) { Some(Some((w, h))) => (w as u32, h as u32), _ => (0, 0), - }.into() + } + .into() } pub fn position(&self) -> PhysicalPosition { @@ -584,6 +678,19 @@ impl MonitorHandle { .with_info(&self.proxy, |_, info| info.scale_factor) .unwrap_or(1) } + + #[inline] + pub fn video_modes(&self) -> impl Iterator { + self.mgr + .with_info(&self.proxy, |_, info| info.modes.clone()) + .unwrap_or(vec![]) + .into_iter() + .map(|x| VideoMode { + size: (x.dimensions.0 as u32, x.dimensions.1 as u32), + refresh_rate: (x.refresh_rate as f32 / 1000.0).round() as u16, + bit_depth: 32, + }) + } } pub fn primary_monitor(outputs: &OutputMgr) -> MonitorHandle { diff --git a/src/platform_impl/linux/wayland/keyboard.rs b/src/platform_impl/linux/wayland/keyboard.rs index d0930949..727062ad 100644 --- a/src/platform_impl/linux/wayland/keyboard.rs +++ b/src/platform_impl/linux/wayland/keyboard.rs @@ -1,16 +1,18 @@ use std::sync::{Arc, Mutex}; use super::{make_wid, DeviceId}; -use sctk::keyboard::{ - self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind, +use smithay_client_toolkit::{ + keyboard::{ + self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind, + }, + reexports::client::protocol::{wl_keyboard, wl_seat}, }; -use sctk::reexports::client::protocol::{wl_keyboard, wl_seat}; -use event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent}; +use crate::event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent}; pub fn init_keyboard( seat: &wl_seat::WlSeat, - sink: ::calloop::channel::Sender<(::event::WindowEvent, super::WindowId)>, + sink: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, modifiers_tracker: Arc>, ) -> wl_keyboard::WlKeyboard { // { variables to be captured by the closures @@ -23,78 +25,92 @@ pub fn init_keyboard( let ret = map_keyboard_auto_with_repeat( seat, KeyRepeatKind::System, - move |evt: KbEvent, _| match evt { - KbEvent::Enter { surface, .. } => { - let wid = make_wid(&surface); - my_sink.send((WindowEvent::Focused(true), wid)).unwrap(); - *target.lock().unwrap() = Some(wid); - } - KbEvent::Leave { surface, .. } => { - let wid = make_wid(&surface); - my_sink.send((WindowEvent::Focused(false), wid)).unwrap(); - *target.lock().unwrap() = None; - } - KbEvent::Key { - rawkey, - keysym, - state, - utf8, - .. - } => { - if let Some(wid) = *target.lock().unwrap() { - let state = match state { - wl_keyboard::KeyState::Pressed => ElementState::Pressed, - wl_keyboard::KeyState::Released => ElementState::Released, - _ => unreachable!(), - }; - let vkcode = key_to_vkey(rawkey, keysym); - my_sink.send( - (WindowEvent::KeyboardInput { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - input: KeyboardInput { - state: state, - scancode: rawkey, - virtual_keycode: vkcode, - modifiers: modifiers_tracker.lock().unwrap().clone(), - }, - }, - wid) - ).unwrap(); - // send char event only on key press, not release - if let ElementState::Released = state { - return; - } - if let Some(txt) = utf8 { - for chr in txt.chars() { - my_sink.send((WindowEvent::ReceivedCharacter(chr), wid)).unwrap(); + move |evt: KbEvent<'_>, _| { + match evt { + KbEvent::Enter { surface, .. } => { + let wid = make_wid(&surface); + my_sink.send((WindowEvent::Focused(true), wid)).unwrap(); + *target.lock().unwrap() = Some(wid); + } + KbEvent::Leave { surface, .. } => { + let wid = make_wid(&surface); + my_sink.send((WindowEvent::Focused(false), wid)).unwrap(); + *target.lock().unwrap() = None; + } + KbEvent::Key { + rawkey, + keysym, + state, + utf8, + .. + } => { + if let Some(wid) = *target.lock().unwrap() { + let state = match state { + wl_keyboard::KeyState::Pressed => ElementState::Pressed, + wl_keyboard::KeyState::Released => ElementState::Released, + _ => unreachable!(), + }; + let vkcode = key_to_vkey(rawkey, keysym); + my_sink + .send(( + WindowEvent::KeyboardInput { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + input: KeyboardInput { + state, + scancode: rawkey, + virtual_keycode: vkcode, + modifiers: modifiers_tracker.lock().unwrap().clone(), + }, + }, + wid, + )) + .unwrap(); + // send char event only on key press, not release + if let ElementState::Released = state { + return; + } + if let Some(txt) = utf8 { + for chr in txt.chars() { + my_sink + .send((WindowEvent::ReceivedCharacter(chr), wid)) + .unwrap(); + } } } } + KbEvent::RepeatInfo { .. } => { /* Handled by smithay client toolkit */ } + KbEvent::Modifiers { + modifiers: event_modifiers, + } => *modifiers_tracker.lock().unwrap() = event_modifiers.into(), } - KbEvent::RepeatInfo { .. } => { /* Handled by smithay client toolkit */ } - KbEvent::Modifiers { modifiers: event_modifiers } => { - *modifiers_tracker.lock().unwrap() = event_modifiers.into() - }, }, move |repeat_event: KeyRepeatEvent, _| { if let Some(wid) = *repeat_target.lock().unwrap() { let state = ElementState::Pressed; let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym); - repeat_sink.send(( - WindowEvent::KeyboardInput { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - input: KeyboardInput { - state: state, - scancode: repeat_event.rawkey, - virtual_keycode: vkcode, - modifiers: my_modifiers.lock().unwrap().clone(), + repeat_sink + .send(( + WindowEvent::KeyboardInput { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + input: KeyboardInput { + state, + scancode: repeat_event.rawkey, + virtual_keycode: vkcode, + modifiers: my_modifiers.lock().unwrap().clone(), + }, }, - }, - wid) - ).unwrap(); + wid, + )) + .unwrap(); if let Some(txt) = repeat_event.utf8 { for chr in txt.chars() { - repeat_sink.send((WindowEvent::ReceivedCharacter(chr), wid)).unwrap(); + repeat_sink + .send((WindowEvent::ReceivedCharacter(chr), wid)) + .unwrap(); } } } @@ -111,46 +127,55 @@ pub fn init_keyboard( // In this case, we don't have the keymap information (it is // supposed to be serialized by the compositor using libxkbcommon) - // { variables to be captured by the closure - let mut target = None; - let my_sink = sink; - // } seat.get_keyboard(|keyboard| { - keyboard.implement_closure(move |evt, _| match evt { - wl_keyboard::Event::Enter { surface, .. } => { - let wid = make_wid(&surface); - my_sink.send((WindowEvent::Focused(true), wid)).unwrap(); - target = Some(wid); - } - wl_keyboard::Event::Leave { surface, .. } => { - let wid = make_wid(&surface); - my_sink.send((WindowEvent::Focused(false), wid)).unwrap(); - target = None; - } - wl_keyboard::Event::Key { key, state, .. } => { - if let Some(wid) = target { - let state = match state { - wl_keyboard::KeyState::Pressed => ElementState::Pressed, - wl_keyboard::KeyState::Released => ElementState::Released, - _ => unreachable!() - }; - my_sink.send(( - WindowEvent::KeyboardInput { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - input: KeyboardInput { - state: state, - scancode: key, - virtual_keycode: None, - modifiers: ModifiersState::default(), - }, - }, - wid, - )).unwrap(); + // { variables to be captured by the closure + let mut target = None; + let my_sink = sink; + // } + + keyboard.implement_closure( + move |evt, _| match evt { + wl_keyboard::Event::Enter { surface, .. } => { + let wid = make_wid(&surface); + my_sink.send((WindowEvent::Focused(true), wid)).unwrap(); + target = Some(wid); } - } - _ => (), - }, ()) - }).unwrap() + wl_keyboard::Event::Leave { surface, .. } => { + let wid = make_wid(&surface); + my_sink.send((WindowEvent::Focused(false), wid)).unwrap(); + target = None; + } + wl_keyboard::Event::Key { key, state, .. } => { + if let Some(wid) = target { + let state = match state { + wl_keyboard::KeyState::Pressed => ElementState::Pressed, + wl_keyboard::KeyState::Released => ElementState::Released, + _ => unreachable!(), + }; + my_sink + .send(( + WindowEvent::KeyboardInput { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + input: KeyboardInput { + state, + scancode: key, + virtual_keycode: None, + modifiers: ModifiersState::default(), + }, + }, + wid, + )) + .unwrap(); + } + } + _ => (), + }, + (), + ) + }) + .unwrap() } } } @@ -173,7 +198,7 @@ fn key_to_vkey(rawkey: u32, keysym: u32) -> Option { } fn keysym_to_vkey(keysym: u32) -> Option { - use sctk::keyboard::keysyms; + use smithay_client_toolkit::keyboard::keysyms; match keysym { // letters keysyms::XKB_KEY_A | keysyms::XKB_KEY_a => Some(VirtualKeyCode::A), diff --git a/src/platform_impl/linux/wayland/mod.rs b/src/platform_impl/linux/wayland/mod.rs index 44397ea2..aa96e276 100644 --- a/src/platform_impl/linux/wayland/mod.rs +++ b/src/platform_impl/linux/wayland/mod.rs @@ -1,15 +1,19 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] -pub use self::window::Window; -pub use self::event_loop::{EventLoop, EventLoopWindowTarget, EventLoopProxy, WindowEventsSink, MonitorHandle}; +pub use self::{ + event_loop::{ + EventLoop, EventLoopProxy, EventLoopWindowTarget, MonitorHandle, WindowEventsSink, + }, + window::Window, +}; -use sctk::reexports::client::protocol::wl_surface; +use smithay_client_toolkit::reexports::client::protocol::wl_surface; mod event_loop; +mod keyboard; mod pointer; mod touch; -mod keyboard; mod window; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/src/platform_impl/linux/wayland/pointer.rs b/src/platform_impl/linux/wayland/pointer.rs index cbada78b..7ffcdd72 100644 --- a/src/platform_impl/linux/wayland/pointer.rs +++ b/src/platform_impl/linux/wayland/pointer.rs @@ -1,191 +1,243 @@ use std::sync::{Arc, Mutex}; -use event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent, ModifiersState}; +use crate::event::{ + DeviceEvent, ElementState, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase, + WindowEvent, +}; -use super::DeviceId; -use super::event_loop::WindowEventsSink; -use super::window::WindowStore; +use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId}; -use sctk::reexports::client::protocol::wl_pointer::{self, Event as PtrEvent, WlPointer}; -use sctk::reexports::client::protocol::wl_seat; +use smithay_client_toolkit::reexports::client::protocol::{ + wl_pointer::{self, Event as PtrEvent, WlPointer}, + wl_seat, +}; -pub fn implement_pointer( +use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1::client::{ + zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, zwp_relative_pointer_v1::Event, + zwp_relative_pointer_v1::ZwpRelativePointerV1, +}; + +pub fn implement_pointer( seat: &wl_seat::WlSeat, - sink: Arc>, + sink: Arc>>, store: Arc>, modifiers_tracker: Arc>, ) -> WlPointer { - let mut mouse_focus = None; - let mut axis_buffer = None; - let mut axis_discrete_buffer = None; - let mut axis_state = TouchPhase::Ended; - seat.get_pointer(|pointer| { - pointer.implement_closure(move |evt, pointer| { - let mut sink = sink.lock().unwrap(); - let store = store.lock().unwrap(); - match evt { - PtrEvent::Enter { - surface, - surface_x, - surface_y, - .. - } => { - let wid = store.find_wid(&surface); - if let Some(wid) = wid { - mouse_focus = Some(wid); - sink.send_event( - WindowEvent::CursorEntered { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - }, - wid, - ); - sink.send_event( - WindowEvent::CursorMoved { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - position: (surface_x, surface_y).into(), - modifiers: modifiers_tracker.lock().unwrap().clone(), - }, - wid, - ); - } - } - PtrEvent::Leave { surface, .. } => { - mouse_focus = None; - let wid = store.find_wid(&surface); - if let Some(wid) = wid { - sink.send_event( - WindowEvent::CursorLeft { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - }, - wid, - ); - } - } - PtrEvent::Motion { - surface_x, - surface_y, - .. - } => { - if let Some(wid) = mouse_focus { - sink.send_event( - WindowEvent::CursorMoved { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - position: (surface_x, surface_y).into(), - modifiers: modifiers_tracker.lock().unwrap().clone(), - }, - wid, - ); - } - } - PtrEvent::Button { button, state, .. } => { - if let Some(wid) = mouse_focus { - let state = match state { - wl_pointer::ButtonState::Pressed => ElementState::Pressed, - wl_pointer::ButtonState::Released => ElementState::Released, - _ => unreachable!() - }; - let button = match button { - 0x110 => MouseButton::Left, - 0x111 => MouseButton::Right, - 0x112 => MouseButton::Middle, - // TODO figure out the translation ? - _ => return, - }; - sink.send_event( - WindowEvent::MouseInput { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - state: state, - button: button, - modifiers: modifiers_tracker.lock().unwrap().clone(), - }, - wid, - ); - } - } - PtrEvent::Axis { axis, value, .. } => { - if let Some(wid) = mouse_focus { - if pointer.as_ref().version() < 5 { - let (mut x, mut y) = (0.0, 0.0); - // old seat compatibility - match axis { - // wayland vertical sign convention is the inverse of winit - wl_pointer::Axis::VerticalScroll => y -= value as f32, - wl_pointer::Axis::HorizontalScroll => x += value as f32, - _ => unreachable!() - } - sink.send_event( - WindowEvent::MouseWheel { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - delta: MouseScrollDelta::PixelDelta((x as f64, y as f64).into()), - phase: TouchPhase::Moved, - modifiers: modifiers_tracker.lock().unwrap().clone(), + let mut mouse_focus = None; + let mut axis_buffer = None; + let mut axis_discrete_buffer = None; + let mut axis_state = TouchPhase::Ended; + + pointer.implement_closure( + move |evt, pointer| { + let mut sink = sink.lock().unwrap(); + let store = store.lock().unwrap(); + match evt { + PtrEvent::Enter { + surface, + surface_x, + surface_y, + .. + } => { + let wid = store.find_wid(&surface); + if let Some(wid) = wid { + mouse_focus = Some(wid); + sink.send_window_event( + WindowEvent::CursorEntered { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), }, wid, ); - } else { - let (mut x, mut y) = axis_buffer.unwrap_or((0.0, 0.0)); - match axis { - // wayland vertical sign convention is the inverse of winit - wl_pointer::Axis::VerticalScroll => y -= value as f32, - wl_pointer::Axis::HorizontalScroll => x += value as f32, - _ => unreachable!() - } - axis_buffer = Some((x, y)); - axis_state = match axis_state { - TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, - _ => TouchPhase::Started, - } - } - } - } - PtrEvent::Frame => { - let axis_buffer = axis_buffer.take(); - let axis_discrete_buffer = axis_discrete_buffer.take(); - if let Some(wid) = mouse_focus { - if let Some((x, y)) = axis_discrete_buffer { - sink.send_event( - WindowEvent::MouseWheel { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - delta: MouseScrollDelta::LineDelta(x as f32, y as f32), - phase: axis_state, - modifiers: modifiers_tracker.lock().unwrap().clone(), - }, - wid, - ); - } else if let Some((x, y)) = axis_buffer { - sink.send_event( - WindowEvent::MouseWheel { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - delta: MouseScrollDelta::PixelDelta((x as f64, y as f64).into()), - phase: axis_state, + sink.send_window_event( + WindowEvent::CursorMoved { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + position: (surface_x, surface_y).into(), modifiers: modifiers_tracker.lock().unwrap().clone(), }, wid, ); } } - } - PtrEvent::AxisSource { .. } => (), - PtrEvent::AxisStop { .. } => { - axis_state = TouchPhase::Ended; - } - PtrEvent::AxisDiscrete { axis, discrete } => { - let (mut x, mut y) = axis_discrete_buffer.unwrap_or((0, 0)); - match axis { - // wayland vertical sign convention is the inverse of winit - wl_pointer::Axis::VerticalScroll => y -= discrete, - wl_pointer::Axis::HorizontalScroll => x += discrete, - _ => unreachable!() + PtrEvent::Leave { surface, .. } => { + mouse_focus = None; + let wid = store.find_wid(&surface); + if let Some(wid) = wid { + sink.send_window_event( + WindowEvent::CursorLeft { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + }, + wid, + ); + } } - axis_discrete_buffer = Some((x, y)); - axis_state = match axis_state { - TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, - _ => TouchPhase::Started, + PtrEvent::Motion { + surface_x, + surface_y, + .. + } => { + if let Some(wid) = mouse_focus { + sink.send_window_event( + WindowEvent::CursorMoved { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + position: (surface_x, surface_y).into(), + modifiers: modifiers_tracker.lock().unwrap().clone(), + }, + wid, + ); + } } - }, - _ => unreachable!() - } - }, ()) - }).unwrap() + PtrEvent::Button { button, state, .. } => { + if let Some(wid) = mouse_focus { + let state = match state { + wl_pointer::ButtonState::Pressed => ElementState::Pressed, + wl_pointer::ButtonState::Released => ElementState::Released, + _ => unreachable!(), + }; + let button = match button { + 0x110 => MouseButton::Left, + 0x111 => MouseButton::Right, + 0x112 => MouseButton::Middle, + // TODO figure out the translation ? + _ => return, + }; + sink.send_window_event( + WindowEvent::MouseInput { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + state, + button, + modifiers: modifiers_tracker.lock().unwrap().clone(), + }, + wid, + ); + } + } + PtrEvent::Axis { axis, value, .. } => { + if let Some(wid) = mouse_focus { + if pointer.as_ref().version() < 5 { + let (mut x, mut y) = (0.0, 0.0); + // old seat compatibility + match axis { + // wayland vertical sign convention is the inverse of winit + wl_pointer::Axis::VerticalScroll => y -= value as f32, + wl_pointer::Axis::HorizontalScroll => x += value as f32, + _ => unreachable!(), + } + sink.send_window_event( + WindowEvent::MouseWheel { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + delta: MouseScrollDelta::PixelDelta( + (x as f64, y as f64).into(), + ), + phase: TouchPhase::Moved, + modifiers: modifiers_tracker.lock().unwrap().clone(), + }, + wid, + ); + } else { + let (mut x, mut y) = axis_buffer.unwrap_or((0.0, 0.0)); + match axis { + // wayland vertical sign convention is the inverse of winit + wl_pointer::Axis::VerticalScroll => y -= value as f32, + wl_pointer::Axis::HorizontalScroll => x += value as f32, + _ => unreachable!(), + } + axis_buffer = Some((x, y)); + axis_state = match axis_state { + TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, + _ => TouchPhase::Started, + } + } + } + } + PtrEvent::Frame => { + let axis_buffer = axis_buffer.take(); + let axis_discrete_buffer = axis_discrete_buffer.take(); + if let Some(wid) = mouse_focus { + if let Some((x, y)) = axis_discrete_buffer { + sink.send_window_event( + WindowEvent::MouseWheel { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + delta: MouseScrollDelta::LineDelta(x as f32, y as f32), + phase: axis_state, + modifiers: modifiers_tracker.lock().unwrap().clone(), + }, + wid, + ); + } else if let Some((x, y)) = axis_buffer { + sink.send_window_event( + WindowEvent::MouseWheel { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + delta: MouseScrollDelta::PixelDelta( + (x as f64, y as f64).into(), + ), + phase: axis_state, + modifiers: modifiers_tracker.lock().unwrap().clone(), + }, + wid, + ); + } + } + } + PtrEvent::AxisSource { .. } => (), + PtrEvent::AxisStop { .. } => { + axis_state = TouchPhase::Ended; + } + PtrEvent::AxisDiscrete { axis, discrete } => { + let (mut x, mut y) = axis_discrete_buffer.unwrap_or((0, 0)); + match axis { + // wayland vertical sign convention is the inverse of winit + wl_pointer::Axis::VerticalScroll => y -= discrete, + wl_pointer::Axis::HorizontalScroll => x += discrete, + _ => unreachable!(), + } + axis_discrete_buffer = Some((x, y)); + axis_state = match axis_state { + TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, + _ => TouchPhase::Started, + } + } + _ => unreachable!(), + } + }, + (), + ) + }) + .unwrap() +} + +pub fn implement_relative_pointer( + sink: Arc>>, + pointer: &WlPointer, + manager: &ZwpRelativePointerManagerV1, +) -> Result { + manager.get_relative_pointer(pointer, |rel_pointer| { + rel_pointer.implement_closure( + move |evt, _rel_pointer| { + let mut sink = sink.lock().unwrap(); + match evt { + Event::RelativeMotion { dx, dy, .. } => sink + .send_device_event(DeviceEvent::MouseMotion { delta: (dx, dy) }, DeviceId), + _ => unreachable!(), + } + }, + (), + ) + }) } diff --git a/src/platform_impl/linux/wayland/touch.rs b/src/platform_impl/linux/wayland/touch.rs index 765d524a..b72be7b8 100644 --- a/src/platform_impl/linux/wayland/touch.rs +++ b/src/platform_impl/linux/wayland/touch.rs @@ -1,13 +1,13 @@ use std::sync::{Arc, Mutex}; -use event::{TouchPhase, WindowEvent}; +use crate::event::{TouchPhase, WindowEvent}; -use super::{DeviceId, WindowId}; -use super::event_loop::WindowEventsSink; -use super::window::WindowStore; +use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId, WindowId}; -use sctk::reexports::client::protocol::wl_touch::{Event as TouchEvent, WlTouch}; -use sctk::reexports::client::protocol::wl_seat; +use smithay_client_toolkit::reexports::client::protocol::{ + wl_seat, + wl_touch::{Event as TouchEvent, WlTouch}, +}; struct TouchPoint { wid: WindowId, @@ -15,82 +15,96 @@ struct TouchPoint { id: i32, } -pub(crate) fn implement_touch( +pub(crate) fn implement_touch( seat: &wl_seat::WlSeat, - sink: Arc>, + sink: Arc>>, store: Arc>, ) -> WlTouch { let mut pending_ids = Vec::new(); seat.get_touch(|touch| { - touch.implement_closure(move |evt, _| { - let mut sink = sink.lock().unwrap(); - let store = store.lock().unwrap(); - match evt { - TouchEvent::Down { - surface, id, x, y, .. - } => { - let wid = store.find_wid(&surface); - if let Some(wid) = wid { - sink.send_event( - WindowEvent::Touch(::event::Touch { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - phase: TouchPhase::Started, - location: (x, y).into(), - id: id as u64, - }), - wid, - ); - pending_ids.push(TouchPoint { - wid: wid, - location: (x, y), - id: id, - }); + touch.implement_closure( + move |evt, _| { + let mut sink = sink.lock().unwrap(); + let store = store.lock().unwrap(); + match evt { + TouchEvent::Down { + surface, id, x, y, .. + } => { + let wid = store.find_wid(&surface); + if let Some(wid) = wid { + sink.send_window_event( + WindowEvent::Touch(crate::event::Touch { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + phase: TouchPhase::Started, + location: (x, y).into(), + id: id as u64, + }), + wid, + ); + pending_ids.push(TouchPoint { + wid, + location: (x, y), + id, + }); + } } - } - TouchEvent::Up { id, .. } => { - let idx = pending_ids.iter().position(|p| p.id == id); - if let Some(idx) = idx { - let pt = pending_ids.remove(idx); - sink.send_event( - WindowEvent::Touch(::event::Touch { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - phase: TouchPhase::Ended, - location: pt.location.into(), - id: id as u64, - }), - pt.wid, - ); + TouchEvent::Up { id, .. } => { + let idx = pending_ids.iter().position(|p| p.id == id); + if let Some(idx) = idx { + let pt = pending_ids.remove(idx); + sink.send_window_event( + WindowEvent::Touch(crate::event::Touch { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + phase: TouchPhase::Ended, + location: pt.location.into(), + id: id as u64, + }), + pt.wid, + ); + } } - } - TouchEvent::Motion { id, x, y, .. } => { - let pt = pending_ids.iter_mut().find(|p| p.id == id); - if let Some(pt) = pt { - pt.location = (x, y); - sink.send_event( - WindowEvent::Touch(::event::Touch { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - phase: TouchPhase::Moved, - location: (x, y).into(), - id: id as u64, - }), - pt.wid, - ); + TouchEvent::Motion { id, x, y, .. } => { + let pt = pending_ids.iter_mut().find(|p| p.id == id); + if let Some(pt) = pt { + pt.location = (x, y); + sink.send_window_event( + WindowEvent::Touch(crate::event::Touch { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + phase: TouchPhase::Moved, + location: (x, y).into(), + id: id as u64, + }), + pt.wid, + ); + } } + TouchEvent::Frame => (), + TouchEvent::Cancel => { + for pt in pending_ids.drain(..) { + sink.send_window_event( + WindowEvent::Touch(crate::event::Touch { + device_id: crate::event::DeviceId( + crate::platform_impl::DeviceId::Wayland(DeviceId), + ), + phase: TouchPhase::Cancelled, + location: pt.location.into(), + id: pt.id as u64, + }), + pt.wid, + ); + } + } + _ => unreachable!(), } - TouchEvent::Frame => (), - TouchEvent::Cancel => for pt in pending_ids.drain(..) { - sink.send_event( - WindowEvent::Touch(::event::Touch { - device_id: ::event::DeviceId(::platform_impl::DeviceId::Wayland(DeviceId)), - phase: TouchPhase::Cancelled, - location: pt.location.into(), - id: pt.id as u64, - }), - pt.wid, - ); - }, - _ => unreachable!() - } - }, ()) - }).unwrap() + }, + (), + ) + }) + .unwrap() } diff --git a/src/platform_impl/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs index 976caf75..773af760 100644 --- a/src/platform_impl/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -1,20 +1,31 @@ -use std::collections::VecDeque; -use std::sync::{Arc, Mutex, Weak}; +use std::{ + collections::VecDeque, + sync::{Arc, Mutex, Weak}, +}; -use dpi::{LogicalPosition, LogicalSize}; -use error::{ExternalError, NotSupportedError, OsError as RootOsError}; -use platform_impl::{MonitorHandle as PlatformMonitorHandle, PlatformSpecificWindowBuilderAttributes as PlAttributes}; -use monitor::MonitorHandle as RootMonitorHandle; -use window::{WindowAttributes, CursorIcon}; +use crate::{ + dpi::{LogicalPosition, LogicalSize}, + error::{ExternalError, NotSupportedError, OsError as RootOsError}, + monitor::MonitorHandle as RootMonitorHandle, + platform_impl::{ + MonitorHandle as PlatformMonitorHandle, + PlatformSpecificWindowBuilderAttributes as PlAttributes, + }, + window::{CursorIcon, WindowAttributes}, +}; -use sctk::surface::{get_dpi_factor, get_outputs}; -use sctk::window::{ConceptFrame, Event as WEvent, State as WState, Window as SWindow, Theme}; -use sctk::reexports::client::Display; -use sctk::reexports::client::protocol::{wl_seat, wl_surface}; -use sctk::output::OutputMgr; +use smithay_client_toolkit::{ + output::OutputMgr, + reexports::client::{ + protocol::{wl_seat, wl_surface}, + Display, + }, + surface::{get_dpi_factor, get_outputs}, + window::{ConceptFrame, Event as WEvent, State as WState, Theme, Window as SWindow}, +}; use super::{make_wid, EventLoopWindowTarget, MonitorHandle, WindowId}; -use platform_impl::platform::wayland::event_loop::{available_monitors, primary_monitor}; +use crate::platform_impl::platform::wayland::event_loop::{available_monitors, primary_monitor}; pub struct Window { surface: wl_surface::WlSurface, @@ -29,7 +40,11 @@ pub struct Window { } impl Window { - pub fn new(evlp: &EventLoopWindowTarget, attributes: WindowAttributes, pl_attribs: PlAttributes) -> Result { + pub fn new( + evlp: &EventLoopWindowTarget, + attributes: WindowAttributes, + pl_attribs: PlAttributes, + ) -> Result { let (width, height) = attributes.inner_size.map(Into::into).unwrap_or((800, 600)); // Create the window let size = Arc::new(Mutex::new((width, height))); @@ -81,7 +96,8 @@ impl Window { } } }, - ).unwrap(); + ) + .unwrap(); if let Some(app_id) = pl_attribs.app_id { frame.set_app_id(app_id); @@ -135,10 +151,10 @@ impl Window { Ok(Window { display: evlp.display.clone(), - surface: surface, - frame: frame, + surface, + frame, outputs: evlp.env.outputs.clone(), - size: size, + size, kill_switch: (kill_switch, evlp.cleanup_needed.clone()), need_frame_refresh, need_refresh, @@ -199,12 +215,18 @@ impl Window { #[inline] pub fn set_min_inner_size(&self, dimensions: Option) { - self.frame.lock().unwrap().set_min_size(dimensions.map(Into::into)); + self.frame + .lock() + .unwrap() + .set_min_size(dimensions.map(Into::into)); } #[inline] pub fn set_max_inner_size(&self, dimensions: Option) { - self.frame.lock().unwrap().set_max_size(dimensions.map(Into::into)); + self.frame + .lock() + .unwrap() + .set_max_size(dimensions.map(Into::into)); } #[inline] @@ -252,7 +274,6 @@ impl Window { } } - pub fn set_theme(&self, theme: T) { self.frame.lock().unwrap().set_theme(theme) } @@ -380,7 +401,16 @@ impl WindowStore { pub fn for_each(&mut self, mut f: F) where - F: FnMut(Option<(u32, u32)>, &mut (u32, u32), Option, bool, bool, bool, WindowId, Option<&mut SWindow>), + F: FnMut( + Option<(u32, u32)>, + &mut (u32, u32), + Option, + bool, + bool, + bool, + WindowId, + Option<&mut SWindow>, + ), { for window in &mut self.windows { let opt_arc = window.frame.upgrade(); @@ -403,4 +433,3 @@ impl WindowStore { } } } - diff --git a/src/platform_impl/linux/x11/dnd.rs b/src/platform_impl/linux/x11/dnd.rs index c8221fb4..997228cd 100644 --- a/src/platform_impl/linux/x11/dnd.rs +++ b/src/platform_impl/linux/x11/dnd.rs @@ -1,8 +1,10 @@ -use std::io; -use std::sync::Arc; -use std::path::{Path, PathBuf}; -use std::str::Utf8Error; -use std::os::raw::*; +use std::{ + io, + os::raw::*, + path::{Path, PathBuf}, + str::Utf8Error, + sync::Arc, +}; use percent_encoding::percent_decode; @@ -127,13 +129,15 @@ impl Dnd { DndState::Accepted => (1, self.atoms.action_private as c_long), DndState::Rejected => (0, self.atoms.none as c_long), }; - self.xconn.send_client_msg( - target_window, - target_window, - self.atoms.status, - None, - [this_window as c_long, accepted, 0, 0, action], - ).flush() + self.xconn + .send_client_msg( + target_window, + target_window, + self.atoms.status, + None, + [this_window as c_long, accepted, 0, 0, action], + ) + .flush() } pub unsafe fn send_finished( @@ -146,24 +150,23 @@ impl Dnd { DndState::Accepted => (1, self.atoms.action_private as c_long), DndState::Rejected => (0, self.atoms.none as c_long), }; - self.xconn.send_client_msg( - target_window, - target_window, - self.atoms.finished, - None, - [this_window as c_long, accepted, action, 0, 0], - ).flush() + self.xconn + .send_client_msg( + target_window, + target_window, + self.atoms.finished, + None, + [this_window as c_long, accepted, action, 0, 0], + ) + .flush() } pub unsafe fn get_type_list( &self, source_window: c_ulong, ) -> Result, util::GetPropertyError> { - self.xconn.get_property( - source_window, - self.atoms.type_list, - ffi::XA_ATOM, - ) + self.xconn + .get_property(source_window, self.atoms.type_list, ffi::XA_ATOM) } pub unsafe fn convert_selection(&self, window: c_ulong, time: c_ulong) { @@ -181,11 +184,8 @@ impl Dnd { &self, window: c_ulong, ) -> Result, util::GetPropertyError> { - self.xconn.get_property( - window, - self.atoms.selection, - self.atoms.uri_list, - ) + self.xconn + .get_property(window, self.atoms.selection, self.atoms.uri_list) } pub fn parse_data(&self, data: &mut Vec) -> Result, DndDataParseError> { diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 19332dc9..572889b4 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1,20 +1,18 @@ -use std::cell::RefCell; -use std::collections::HashMap; -use std::ptr; -use std::rc::Rc; -use std::slice; +use std::{cell::RefCell, collections::HashMap, ptr, rc::Rc, slice}; -use libc::{c_int, c_uint, c_ulong, c_char, c_long}; +use libc::{c_char, c_int, c_long, c_uint, c_ulong}; use super::{ - mkdid, mkwid, get_xtarget, DeviceId, WindowId, Device, ImeReceiver, XExtension, - monitor, ffi, UnownedWindow, ScrollOrientation, GenericEventCookie, - events, util, DndState, Dnd, DeviceInfo + events, ffi, get_xtarget, mkdid, mkwid, monitor, util, Device, DeviceId, DeviceInfo, Dnd, + DndState, GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId, + XExtension, }; -use event_loop::EventLoopWindowTarget as RootELW; -use event::{DeviceEvent, Event, KeyboardInput, ModifiersState, WindowEvent}; -use dpi::{LogicalPosition,LogicalSize}; +use crate::{ + dpi::{LogicalPosition, LogicalSize}, + event::{DeviceEvent, Event, KeyboardInput, ModifiersState, WindowEvent}, + event_loop::EventLoopWindowTarget as RootELW, +}; pub(super) struct EventProcessor { pub(super) dnd: Dnd, @@ -22,7 +20,7 @@ pub(super) struct EventProcessor { pub(super) randr_event_offset: c_int, pub(super) devices: RefCell>, pub(super) xi2ext: XExtension, - pub(super) target: Rc> + pub(super) target: Rc>, } impl EventProcessor { @@ -37,12 +35,14 @@ impl EventProcessor { } fn with_window(&self, window_id: ffi::Window, callback: F) -> Option - where F: Fn(&UnownedWindow) -> Ret + where + F: Fn(&UnownedWindow) -> Ret, { let mut deleted = false; let window_id = WindowId(window_id); let wt = get_xtarget(&self.target); - let result = wt.windows + let result = wt + .windows .borrow() .get(&window_id) .and_then(|window| { @@ -62,7 +62,7 @@ impl EventProcessor { self.with_window(window_id, |_| ()).is_some() } - pub(super) unsafe fn poll_one_event(&mut self, event_ptr : *mut ffi::XEvent) -> bool { + pub(super) unsafe fn poll_one_event(&mut self, event_ptr: *mut ffi::XEvent) -> bool { let wt = get_xtarget(&self.target); // This function is used to poll and remove a single event // from the Xlib event queue in a non-blocking, atomic way. @@ -73,7 +73,8 @@ impl EventProcessor { unsafe extern "C" fn predicate( _display: *mut ffi::Display, _event: *mut ffi::XEvent, - _arg : *mut c_char) -> c_int { + _arg: *mut c_char, + ) -> c_int { // This predicate always returns "true" (1) to accept all events 1 } @@ -82,31 +83,41 @@ impl EventProcessor { wt.xconn.display, event_ptr, Some(predicate), - std::ptr::null_mut()); + std::ptr::null_mut(), + ); result != 0 } pub(super) fn process_event(&mut self, xev: &mut ffi::XEvent, mut callback: F) - where F: FnMut(Event) + where + F: FnMut(Event), { let wt = get_xtarget(&self.target); // XFilterEvent tells us when an event has been discarded by the input method. // Specifically, this involves all of the KeyPress events in compose/pre-edit sequences, // along with an extra copy of the KeyRelease events. This also prevents backspace and // arrow keys from being detected twice. - if ffi::True == unsafe { (wt.xconn.xlib.XFilterEvent)( - xev, - { let xev: &ffi::XAnyEvent = xev.as_ref(); xev.window } - ) } { + if ffi::True + == unsafe { + (wt.xconn.xlib.XFilterEvent)(xev, { + let xev: &ffi::XAnyEvent = xev.as_ref(); + xev.window + }) + } + { return; } let event_type = xev.get_type(); match event_type { ffi::MappingNotify => { - unsafe { (wt.xconn.xlib.XRefreshKeyboardMapping)(xev.as_mut()); } - wt.xconn.check_errors().expect("Failed to call XRefreshKeyboardMapping"); + unsafe { + (wt.xconn.xlib.XRefreshKeyboardMapping)(xev.as_mut()); + } + wt.xconn + .check_errors() + .expect("Failed to call XRefreshKeyboardMapping"); } ffi::ClientMessage => { @@ -116,7 +127,20 @@ impl EventProcessor { let window_id = mkwid(window); if client_msg.data.get_long(0) as ffi::Atom == wt.wm_delete_window { - callback(Event::WindowEvent { window_id, event: WindowEvent::CloseRequested }); + callback(Event::WindowEvent { + window_id, + event: WindowEvent::CloseRequested, + }); + } else if client_msg.data.get_long(0) as ffi::Atom == wt.net_wm_ping { + let response_msg: &mut ffi::XClientMessageEvent = xev.as_mut(); + response_msg.window = wt.root; + wt.xconn + .send_event( + wt.root, + Some(ffi::SubstructureNotifyMask | ffi::SubstructureRedirectMask), + *response_msg, + ) + .queue(); } else if client_msg.message_type == self.dnd.atoms.enter { let source_window = client_msg.data.get_long(0) as c_ulong; let flags = client_msg.data.get_long(1); @@ -127,10 +151,11 @@ impl EventProcessor { let type_list = vec![ client_msg.data.get_long(2) as c_ulong, client_msg.data.get_long(3) as c_ulong, - client_msg.data.get_long(4) as c_ulong + client_msg.data.get_long(4) as c_ulong, ]; self.dnd.type_list = Some(type_list); - } else if let Ok(more_types) = unsafe { self.dnd.get_type_list(source_window) } { + } else if let Ok(more_types) = unsafe { self.dnd.get_type_list(source_window) } + { self.dnd.type_list = Some(more_types); } } else if client_msg.message_type == self.dnd.atoms.position { @@ -178,18 +203,21 @@ impl EventProcessor { // This results in the `SelectionNotify` event below self.dnd.convert_selection(window, time); } - self.dnd.send_status(window, source_window, DndState::Accepted) + self.dnd + .send_status(window, source_window, DndState::Accepted) .expect("Failed to send `XdndStatus` message."); } } else { unsafe { - self.dnd.send_status(window, source_window, DndState::Rejected) + self.dnd + .send_status(window, source_window, DndState::Rejected) .expect("Failed to send `XdndStatus` message."); } self.dnd.reset(); } } else if client_msg.message_type == self.dnd.atoms.drop { - let (source_window, state) = if let Some(source_window) = self.dnd.source_window { + let (source_window, state) = if let Some(source_window) = self.dnd.source_window + { if let Some(Ok(ref path_list)) = self.dnd.result { for path in path_list { callback(Event::WindowEvent { @@ -206,7 +234,8 @@ impl EventProcessor { (source_window, DndState::Rejected) }; unsafe { - self.dnd.send_finished(window, source_window, state) + self.dnd + .send_finished(window, source_window, state) .expect("Failed to send `XdndFinished` message."); } self.dnd.reset(); @@ -274,15 +303,22 @@ impl EventProcessor { let mut shared_state_lock = window.shared_state.lock(); let (mut resized, moved) = { - let resized = util::maybe_change(&mut shared_state_lock.size, new_inner_size); + let resized = + util::maybe_change(&mut shared_state_lock.size, new_inner_size); let moved = if is_synthetic { - util::maybe_change(&mut shared_state_lock.inner_position, new_inner_position) + util::maybe_change( + &mut shared_state_lock.inner_position, + new_inner_position, + ) } else { // Detect when frame extents change. // Since this isn't synthetic, as per the notes above, this position is relative to the // parent window. let rel_parent = new_inner_position; - if util::maybe_change(&mut shared_state_lock.inner_position_rel_parent, rel_parent) { + if util::maybe_change( + &mut shared_state_lock.inner_position_rel_parent, + rel_parent, + ) { // This ensures we process the next `Moved`. shared_state_lock.inner_position = None; // Extra insurance against stale frame extents. @@ -297,18 +333,22 @@ impl EventProcessor { let new_outer_position = if moved || shared_state_lock.position.is_none() { // We need to convert client area position to window position. - let frame_extents = shared_state_lock.frame_extents + let frame_extents = shared_state_lock + .frame_extents .as_ref() .cloned() .unwrap_or_else(|| { - let frame_extents = wt.xconn.get_frame_extents_heuristic(xwindow, wt.root); + let frame_extents = + wt.xconn.get_frame_extents_heuristic(xwindow, wt.root); shared_state_lock.frame_extents = Some(frame_extents.clone()); frame_extents }); - let outer = frame_extents.inner_pos_to_outer(new_inner_position.0, new_inner_position.1); + let outer = frame_extents + .inner_pos_to_outer(new_inner_position.0, new_inner_position.1); shared_state_lock.position = Some(outer); if moved { - let logical_position = LogicalPosition::from_physical(outer, monitor.hidpi_factor); + let logical_position = + LogicalPosition::from_physical(outer, monitor.hidpi_factor); events.moved = Some(WindowEvent::Moved(logical_position)); } outer @@ -319,12 +359,13 @@ impl EventProcessor { if is_synthetic { // If we don't use the existing adjusted value when available, then the user can screw up the // resizing by dragging across monitors *without* dropping the window. - let (width, height) = shared_state_lock.dpi_adjusted + let (width, height) = shared_state_lock + .dpi_adjusted .unwrap_or_else(|| (xev.width as f64, xev.height as f64)); - let last_hidpi_factor = shared_state_lock.guessed_dpi - .take() - .unwrap_or_else(|| { - shared_state_lock.last_monitor + let last_hidpi_factor = + shared_state_lock.guessed_dpi.take().unwrap_or_else(|| { + shared_state_lock + .last_monitor .as_ref() .map(|last_monitor| last_monitor.hidpi_factor) .unwrap_or(1.0) @@ -337,7 +378,8 @@ impl EventProcessor { new_hidpi_factor }; if last_hidpi_factor != new_hidpi_factor { - events.dpi_changed = Some(WindowEvent::HiDpiFactorChanged(new_hidpi_factor)); + events.dpi_changed = + Some(WindowEvent::HiDpiFactorChanged(new_hidpi_factor)); let (new_width, new_height, flusher) = window.adjust_for_dpi( last_hidpi_factor, new_hidpi_factor, @@ -357,7 +399,10 @@ impl EventProcessor { // WMs constrain the window size, making the resize fail. This would cause an endless stream of // XResizeWindow requests, making Xorg, the winit client, and the WM consume 100% of CPU. if let Some(adjusted_size) = shared_state_lock.dpi_adjusted { - let rounded_size = (adjusted_size.0.round() as u32, adjusted_size.1.round() as u32); + let rounded_size = ( + adjusted_size.0.round() as u32, + adjusted_size.1.round() as u32, + ); if new_inner_size == rounded_size || !util::wm_name_is_one_of(&["Xfwm4"]) { // When this finally happens, the event will not be synthetic. shared_state_lock.dpi_adjusted = None; @@ -374,7 +419,8 @@ impl EventProcessor { } if resized { - let logical_size = LogicalSize::from_physical(new_inner_size, monitor.hidpi_factor); + let logical_size = + LogicalSize::from_physical(new_inner_size, monitor.hidpi_factor); events.resized = Some(WindowEvent::Resized(logical_size)); } @@ -427,7 +473,10 @@ impl EventProcessor { .remove_context(window) .expect("Failed to destroy input context"); - callback(Event::WindowEvent { window_id, event: WindowEvent::Destroyed }); + callback(Event::WindowEvent { + window_id, + event: WindowEvent::Destroyed, + }); } ffi::Expose => { @@ -436,11 +485,14 @@ impl EventProcessor { let window = xev.window; let window_id = mkwid(window); - callback(Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested }); + callback(Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + }); } ffi::KeyPress | ffi::KeyRelease => { - use event::ElementState::{Pressed, Released}; + use crate::event::ElementState::{Pressed, Released}; // Note that in compose/pre-edit sequences, this will always be Released. let state = if xev.get_type() == ffi::KeyPress { @@ -493,7 +545,7 @@ impl EventProcessor { virtual_keycode, modifiers, }, - } + }, }); } @@ -515,17 +567,26 @@ impl EventProcessor { } ffi::GenericEvent => { - let guard = if let Some(e) = GenericEventCookie::from_event(&wt.xconn, *xev) { e } else { return }; + let guard = if let Some(e) = GenericEventCookie::from_event(&wt.xconn, *xev) { + e + } else { + return; + }; let xev = &guard.cookie; if self.xi2ext.opcode != xev.extension { return; } - use event::WindowEvent::{Focused, CursorEntered, MouseInput, CursorLeft, CursorMoved, MouseWheel, AxisMotion}; - use event::ElementState::{Pressed, Released}; - use event::MouseButton::{Left, Right, Middle, Other}; - use event::MouseScrollDelta::LineDelta; - use event::{Touch, TouchPhase}; + use crate::event::{ + ElementState::{Pressed, Released}, + MouseButton::{Left, Middle, Other, Right}, + MouseScrollDelta::LineDelta, + Touch, TouchPhase, + WindowEvent::{ + AxisMotion, CursorEntered, CursorLeft, CursorMoved, Focused, MouseInput, + MouseWheel, + }, + }; match xev.evtype { ffi::XI_ButtonPress | ffi::XI_ButtonRelease => { @@ -576,23 +637,25 @@ impl EventProcessor { // Suppress emulated scroll wheel clicks, since we handle the real motion events for those. // In practice, even clicky scroll wheels appear to be reported by evdev (and XInput2 in // turn) as axis motion, so we don't otherwise special-case these button presses. - 4 | 5 | 6 | 7 => if xev.flags & ffi::XIPointerEmulated == 0 { - callback(Event::WindowEvent { - window_id, - event: MouseWheel { - device_id, - delta: match xev.detail { - 4 => LineDelta(0.0, 1.0), - 5 => LineDelta(0.0, -1.0), - 6 => LineDelta(-1.0, 0.0), - 7 => LineDelta(1.0, 0.0), - _ => unreachable!(), + 4 | 5 | 6 | 7 => { + if xev.flags & ffi::XIPointerEmulated == 0 { + callback(Event::WindowEvent { + window_id, + event: MouseWheel { + device_id, + delta: match xev.detail { + 4 => LineDelta(0.0, 1.0), + 5 => LineDelta(0.0, -1.0), + 6 => LineDelta(-1.0, 0.0), + 7 => LineDelta(1.0, 0.0), + _ => unreachable!(), + }, + phase: TouchPhase::Moved, + modifiers, }, - phase: TouchPhase::Moved, - modifiers, - }, - }); - }, + }); + } + } x => callback(Event::WindowEvent { window_id, @@ -618,9 +681,8 @@ impl EventProcessor { util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos) }); if cursor_moved == Some(true) { - let dpi_factor = self.with_window(xev.event, |window| { - window.hidpi_factor() - }); + let dpi_factor = + self.with_window(xev.event, |window| window.hidpi_factor()); if let Some(dpi_factor) = dpi_factor { let position = LogicalPosition::from_physical( (xev.event_x as f64, xev.event_y as f64), @@ -644,7 +706,12 @@ impl EventProcessor { // More gymnastics, for self.devices let mut events = Vec::new(); { - let mask = unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) }; + let mask = unsafe { + slice::from_raw_parts( + xev.valuators.mask, + xev.valuators.mask_len as usize, + ) + }; let mut devices = self.devices.borrow_mut(); let physical_device = match devices.get_mut(&DeviceId(xev.sourceid)) { Some(device) => device, @@ -652,10 +719,14 @@ impl EventProcessor { }; let mut value = xev.valuators.values; - for i in 0..xev.valuators.mask_len*8 { + for i in 0..xev.valuators.mask_len * 8 { if ffi::XIMaskIsSet(mask, i) { let x = unsafe { *value }; - if let Some(&mut (_, ref mut info)) = physical_device.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == i) { + if let Some(&mut (_, ref mut info)) = physical_device + .scroll_axes + .iter_mut() + .find(|&&mut (axis, _)| axis == i) + { let delta = (x - info.position) / info.increment; info.position = x; events.push(Event::WindowEvent { @@ -663,9 +734,13 @@ impl EventProcessor { event: MouseWheel { device_id, delta: match info.orientation { - ScrollOrientation::Horizontal => LineDelta(delta as f32, 0.0), + ScrollOrientation::Horizontal => { + LineDelta(delta as f32, 0.0) + } // X11 vertical scroll coordinates are opposite to winit's - ScrollOrientation::Vertical => LineDelta(0.0, -delta as f32), + ScrollOrientation::Vertical => { + LineDelta(0.0, -delta as f32) + } }, phase: TouchPhase::Moved, modifiers, @@ -704,7 +779,8 @@ impl EventProcessor { // presumably some other WMs. On those, `XI_Enter` doesn't include // the physical device ID, so both `sourceid` and `deviceid` are // the virtual device. - || device_info.attachment == xev.sourceid { + || device_info.attachment == xev.sourceid + { let device_id = DeviceId(device_info.deviceid); if let Some(device) = devices.get_mut(&device_id) { device.reset_scroll_position(device_info); @@ -717,9 +793,9 @@ impl EventProcessor { event: CursorEntered { device_id }, }); - if let Some(dpi_factor) = self.with_window(xev.event, |window| { - window.hidpi_factor() - }) { + if let Some(dpi_factor) = + self.with_window(xev.event, |window| window.hidpi_factor()) + { let position = LogicalPosition::from_physical( (xev.event_x as f64, xev.event_y as f64), dpi_factor, @@ -732,7 +808,8 @@ impl EventProcessor { // This needs to only be done after confirming the window still exists, // since otherwise we risk getting a `BadWindow` error if the window was // dropped with queued events. - let modifiers = wt.xconn + let modifiers = wt + .xconn .query_pointer(xev.event, xev.deviceid) .expect("Failed to query pointer device") .get_modifier_state(); @@ -756,19 +833,20 @@ impl EventProcessor { if !window_closed { callback(Event::WindowEvent { window_id: mkwid(xev.event), - event: CursorLeft { device_id: mkdid(xev.deviceid) }, + event: CursorLeft { + device_id: mkdid(xev.deviceid), + }, }); } } ffi::XI_FocusIn => { let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) }; - let dpi_factor = match self.with_window(xev.event, |window| { - window.hidpi_factor() - }) { - Some(dpi_factor) => dpi_factor, - None => return, - }; + let dpi_factor = + match self.with_window(xev.event, |window| window.hidpi_factor()) { + Some(dpi_factor) => dpi_factor, + None => return, + }; let window_id = mkwid(xev.event); wt.ime @@ -776,11 +854,15 @@ impl EventProcessor { .focus(xev.event) .expect("Failed to focus input context"); - callback(Event::WindowEvent { window_id, event: Focused(true) }); + callback(Event::WindowEvent { + window_id, + event: Focused(true), + }); // The deviceid for this event is for a keyboard instead of a pointer, // so we have to do a little extra work. - let pointer_id = self.devices + let pointer_id = self + .devices .borrow() .get(&DeviceId(xev.deviceid)) .map(|device| device.attachment) @@ -796,12 +878,14 @@ impl EventProcessor { device_id: mkdid(pointer_id), position, modifiers: ModifiersState::from(xev.mods), - } + }, }); } ffi::XI_FocusOut => { let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) }; - if !self.window_exists(xev.event) { return; } + if !self.window_exists(xev.event) { + return; + } wt.ime .borrow_mut() .unfocus(xev.event) @@ -819,11 +903,10 @@ impl EventProcessor { ffi::XI_TouchBegin => TouchPhase::Started, ffi::XI_TouchUpdate => TouchPhase::Moved, ffi::XI_TouchEnd => TouchPhase::Ended, - _ => unreachable!() + _ => unreachable!(), }; - let dpi_factor = self.with_window(xev.event, |window| { - window.hidpi_factor() - }); + let dpi_factor = + self.with_window(xev.event, |window| window.hidpi_factor()); if let Some(dpi_factor) = dpi_factor { let location = LogicalPosition::from_physical( (xev.event_x as f64, xev.event_y as f64), @@ -844,14 +927,17 @@ impl EventProcessor { ffi::XI_RawButtonPress | ffi::XI_RawButtonRelease => { let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) }; if xev.flags & ffi::XIPointerEmulated == 0 { - callback(Event::DeviceEvent { device_id: mkdid(xev.deviceid), event: DeviceEvent::Button { - button: xev.detail as u32, - state: match xev.evtype { - ffi::XI_RawButtonPress => Pressed, - ffi::XI_RawButtonRelease => Released, - _ => unreachable!(), + callback(Event::DeviceEvent { + device_id: mkdid(xev.deviceid), + event: DeviceEvent::Button { + button: xev.detail as u32, + state: match xev.evtype { + ffi::XI_RawButtonPress => Pressed, + ffi::XI_RawButtonRelease => Released, + _ => unreachable!(), + }, }, - }}); + }); } } @@ -859,11 +945,16 @@ impl EventProcessor { let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) }; let did = mkdid(xev.deviceid); - let mask = unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) }; + let mask = unsafe { + slice::from_raw_parts( + xev.valuators.mask, + xev.valuators.mask_len as usize, + ) + }; let mut value = xev.raw_values; let mut mouse_delta = (0.0, 0.0); let mut scroll_delta = (0.0, 0.0); - for i in 0..xev.valuators.mask_len*8 { + for i in 0..xev.valuators.mask_len * 8 { if ffi::XIMaskIsSet(mask, i) { let x = unsafe { *value }; // We assume that every XInput2 device with analog axes is a pointing device emitting @@ -873,24 +964,31 @@ impl EventProcessor { 1 => mouse_delta.1 = x, 2 => scroll_delta.0 = x as f32, 3 => scroll_delta.1 = x as f32, - _ => {}, + _ => {} } - callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::Motion { - axis: i as u32, - value: x, - }}); + callback(Event::DeviceEvent { + device_id: did, + event: DeviceEvent::Motion { + axis: i as u32, + value: x, + }, + }); value = unsafe { value.offset(1) }; } } if mouse_delta != (0.0, 0.0) { - callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::MouseMotion { - delta: mouse_delta, - }}); + callback(Event::DeviceEvent { + device_id: did, + event: DeviceEvent::MouseMotion { delta: mouse_delta }, + }); } if scroll_delta != (0.0, 0.0) { - callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::MouseWheel { - delta: LineDelta(scroll_delta.0, scroll_delta.1), - }}); + callback(Event::DeviceEvent { + device_id: did, + event: DeviceEvent::MouseWheel { + delta: LineDelta(scroll_delta.0, scroll_delta.1), + }, + }); } } @@ -905,7 +1003,9 @@ impl EventProcessor { let device_id = xev.sourceid; let keycode = xev.detail; - if keycode < 8 { return; } + if keycode < 8 { + return; + } let scancode = (keycode - 8) as u32; let keysym = unsafe { @@ -915,7 +1015,9 @@ impl EventProcessor { 0, ) }; - wt.xconn.check_errors().expect("Failed to lookup raw keysym"); + wt.xconn + .check_errors() + .expect("Failed to lookup raw keysym"); let virtual_keycode = events::keysym_to_element(keysym as c_uint); @@ -937,12 +1039,21 @@ impl EventProcessor { ffi::XI_HierarchyChanged => { let xev: &ffi::XIHierarchyEvent = unsafe { &*(xev.data as *const _) }; - for info in unsafe { slice::from_raw_parts(xev.info, xev.num_info as usize) } { + for info in + unsafe { slice::from_raw_parts(xev.info, xev.num_info as usize) } + { if 0 != info.flags & (ffi::XISlaveAdded | ffi::XIMasterAdded) { self.init_device(info.deviceid); - callback(Event::DeviceEvent { device_id: mkdid(info.deviceid), event: DeviceEvent::Added }); - } else if 0 != info.flags & (ffi::XISlaveRemoved | ffi::XIMasterRemoved) { - callback(Event::DeviceEvent { device_id: mkdid(info.deviceid), event: DeviceEvent::Removed }); + callback(Event::DeviceEvent { + device_id: mkdid(info.deviceid), + event: DeviceEvent::Added, + }); + } else if 0 != info.flags & (ffi::XISlaveRemoved | ffi::XIMasterRemoved) + { + callback(Event::DeviceEvent { + device_id: mkdid(info.deviceid), + event: DeviceEvent::Removed, + }); let mut devices = self.devices.borrow_mut(); devices.remove(&DeviceId(info.deviceid)); } @@ -951,7 +1062,7 @@ impl EventProcessor { _ => {} } - }, + } _ => { if event_type == self.randr_event_offset { // In the future, it would be quite easy to emit monitor hotplug events. @@ -972,10 +1083,11 @@ impl EventProcessor { callback(Event::WindowEvent { window_id: mkwid(window_id.0), event: WindowEvent::HiDpiFactorChanged( - new_monitor.hidpi_factor + new_monitor.hidpi_factor, ), }); - let (width, height) = window.inner_size_physical(); + let (width, height) = + window.inner_size_physical(); let (_, _, flusher) = window.adjust_for_dpi( prev_monitor.hidpi_factor, new_monitor.hidpi_factor, @@ -991,13 +1103,13 @@ impl EventProcessor { } } } - }, + } } match self.ime_receiver.try_recv() { Ok((window_id, x, y)) => { wt.ime.borrow_mut().send_xim_spot(window_id, x, y); - }, + } Err(_) => (), } } diff --git a/src/platform_impl/linux/x11/events.rs b/src/platform_impl/linux/x11/events.rs index 254f04e1..1b4996e7 100644 --- a/src/platform_impl/linux/x11/events.rs +++ b/src/platform_impl/linux/x11/events.rs @@ -1,6 +1,6 @@ -use libc; use super::ffi; -use event::VirtualKeyCode; +use crate::event::VirtualKeyCode; +use libc; pub fn keysym_to_element(keysym: libc::c_uint) -> Option { Some(match keysym { @@ -1003,6 +1003,6 @@ pub fn keysym_to_element(keysym: libc::c_uint) -> Option { ffi::XF86XK_Copy => VirtualKeyCode::Copy, ffi::XF86XK_Paste => VirtualKeyCode::Paste, ffi::XF86XK_Cut => VirtualKeyCode::Cut, - _ => return None + _ => return None, }) } diff --git a/src/platform_impl/linux/x11/ffi.rs b/src/platform_impl/linux/x11/ffi.rs index 8399ec1f..6d7c2089 100644 --- a/src/platform_impl/linux/x11/ffi.rs +++ b/src/platform_impl/linux/x11/ffi.rs @@ -1,9 +1,4 @@ -pub use x11_dl::keysym::*; -pub use x11_dl::xcursor::*; -pub use x11_dl::xlib::*; -pub use x11_dl::xinput::*; -pub use x11_dl::xinput2::*; -pub use x11_dl::xlib_xcb::*; -pub use x11_dl::error::OpenError; -pub use x11_dl::xrandr::*; -pub use x11_dl::xrender::*; +pub use x11_dl::{ + error::OpenError, keysym::*, xcursor::*, xinput::*, xinput2::*, xlib::*, xlib_xcb::*, + xrandr::*, xrender::*, +}; diff --git a/src/platform_impl/linux/x11/ime/callbacks.rs b/src/platform_impl/linux/x11/ime/callbacks.rs index 0618b233..f254a04e 100644 --- a/src/platform_impl/linux/x11/ime/callbacks.rs +++ b/src/platform_impl/linux/x11/ime/callbacks.rs @@ -1,13 +1,12 @@ -use std::ptr; -use std::sync::Arc; -use std::collections::HashMap; -use std::os::raw::c_char; +use std::{collections::HashMap, os::raw::c_char, ptr, sync::Arc}; use super::{ffi, XConnection, XError}; -use super::inner::{close_im, ImeInner}; -use super::input_method::PotentialInputMethods; -use super::context::{ImeContextCreationError, ImeContext}; +use super::{ + context::{ImeContext, ImeContextCreationError}, + inner::{close_im, ImeInner}, + input_method::PotentialInputMethods, +}; pub unsafe fn xim_set_callback( xconn: &Arc, @@ -17,12 +16,7 @@ pub unsafe fn xim_set_callback( ) -> Result<(), XError> { // It's advisable to wrap variadic FFI functions in our own functions, as we want to minimize // access that isn't type-checked. - (xconn.xlib.XSetIMValues)( - xim, - field, - callback, - ptr::null_mut::<()>(), - ); + (xconn.xlib.XSetIMValues)(xim, field, callback, ptr::null_mut::<()>()); xconn.check_errors() } @@ -107,18 +101,14 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> { let _ = close_im(xconn, new_im.im); } result - }.map_err(ReplaceImError::SetDestroyCallbackFailed)?; + } + .map_err(ReplaceImError::SetDestroyCallbackFailed)?; let mut new_contexts = HashMap::new(); for (window, old_context) in (*inner).contexts.iter() { let spot = old_context.as_ref().map(|old_context| old_context.ic_spot); let new_context = { - let result = ImeContext::new( - xconn, - new_im.im, - *window, - spot, - ); + let result = ImeContext::new(xconn, new_im.im, *window, spot); if result.is_err() { let _ = close_im(xconn, new_im.im); } @@ -137,7 +127,7 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> { Ok(()) } -pub unsafe extern fn xim_instantiate_callback( +pub unsafe extern "C" fn xim_instantiate_callback( _display: *mut ffi::Display, client_data: ffi::XPointer, // This field is unsupplied. @@ -160,7 +150,7 @@ pub unsafe extern fn xim_instantiate_callback( // This callback is triggered when the input method is closed on the server end. When this // happens, XCloseIM/XDestroyIC doesn't need to be called, as the resources have already been // free'd (attempting to do so causes our connection to freeze). -pub unsafe extern fn xim_destroy_callback( +pub unsafe extern "C" fn xim_destroy_callback( _xim: ffi::XIM, client_data: ffi::XPointer, // This field is unsupplied. diff --git a/src/platform_impl/linux/x11/ime/context.rs b/src/platform_impl/linux/x11/ime/context.rs index 598cd486..8c2ff4cf 100644 --- a/src/platform_impl/linux/x11/ime/context.rs +++ b/src/platform_impl/linux/x11/ime/context.rs @@ -1,6 +1,8 @@ -use std::ptr; -use std::sync::Arc; -use std::os::raw::{c_short, c_void}; +use std::{ + os::raw::{c_short, c_void}, + ptr, + sync::Arc, +}; use super::{ffi, util, XConnection, XError}; @@ -22,7 +24,8 @@ unsafe fn create_pre_edit_attr<'a>( ic_spot, ptr::null_mut::<()>(), ), - ).expect("XVaCreateNestedList returned NULL") + ) + .expect("XVaCreateNestedList returned NULL") } // WARNING: this struct doesn't destroy its XIC resource when dropped. @@ -49,7 +52,9 @@ impl ImeContext { }; let ic = ic.ok_or(ImeContextCreationError::Null)?; - xconn.check_errors().map_err(ImeContextCreationError::XError)?; + xconn + .check_errors() + .map_err(ImeContextCreationError::XError)?; Ok(ImeContext { ic, diff --git a/src/platform_impl/linux/x11/ime/inner.rs b/src/platform_impl/linux/x11/ime/inner.rs index 34bfbe7b..011e22aa 100644 --- a/src/platform_impl/linux/x11/ime/inner.rs +++ b/src/platform_impl/linux/x11/ime/inner.rs @@ -1,12 +1,8 @@ -use std::mem; -use std::ptr; -use std::sync::Arc; -use std::collections::HashMap; +use std::{collections::HashMap, mem, ptr, sync::Arc}; use super::{ffi, XConnection, XError}; -use super::input_method::PotentialInputMethods; -use super::context::ImeContext; +use super::{context::ImeContext, input_method::PotentialInputMethods}; pub unsafe fn close_im(xconn: &Arc, im: ffi::XIM) -> Result<(), XError> { (xconn.xlib.XCloseIM)(im); @@ -33,10 +29,7 @@ pub struct ImeInner { } impl ImeInner { - pub fn new( - xconn: Arc, - potential_input_methods: PotentialInputMethods, - ) -> Self { + pub fn new(xconn: Arc, potential_input_methods: PotentialInputMethods) -> Self { ImeInner { xconn, im: ptr::null_mut(), diff --git a/src/platform_impl/linux/x11/ime/input_method.rs b/src/platform_impl/linux/x11/ime/input_method.rs index fee0a14f..42c4033e 100644 --- a/src/platform_impl/linux/x11/ime/input_method.rs +++ b/src/platform_impl/linux/x11/ime/input_method.rs @@ -1,9 +1,11 @@ -use std::env; -use std::fmt; -use std::ptr; -use std::sync::Arc; -use std::os::raw::c_char; -use std::ffi::{CStr, CString, IntoStringError}; +use std::{ + env, + ffi::{CStr, CString, IntoStringError}, + fmt, + os::raw::c_char, + ptr, + sync::Arc, +}; use parking_lot::Mutex; @@ -13,10 +15,7 @@ lazy_static! { static ref GLOBAL_LOCK: Mutex<()> = Default::default(); } -unsafe fn open_im( - xconn: &Arc, - locale_modifiers: &CStr, -) -> Option { +unsafe fn open_im(xconn: &Arc, locale_modifiers: &CStr) -> Option { let _lock = GLOBAL_LOCK.lock(); // XSetLocaleModifiers returns... @@ -97,11 +96,9 @@ unsafe fn get_xim_servers(xconn: &Arc) -> Result, GetXi let root = (xconn.xlib.XDefaultRootWindow)(xconn.display); - let mut atoms: Vec = xconn.get_property( - root, - servers_atom, - ffi::XA_ATOM, - ).map_err(GetXimServersError::GetPropertyError)?; + let mut atoms: Vec = xconn + .get_property(root, servers_atom, ffi::XA_ATOM) + .map_err(GetXimServersError::GetPropertyError)?; let mut names: Vec<*const c_char> = Vec::with_capacity(atoms.len()); (xconn.xlib.XGetAtomNames)( @@ -135,15 +132,12 @@ impl InputMethodName { pub fn from_string(string: String) -> Self { let c_string = CString::new(string.clone()) .expect("String used to construct CString contained null byte"); - InputMethodName { - c_string, - string, - } + InputMethodName { c_string, string } } pub fn from_str(string: &str) -> Self { - let c_string = CString::new(string) - .expect("String used to construct CString contained null byte"); + let c_string = + CString::new(string).expect("String used to construct CString contained null byte"); InputMethodName { c_string, string: string.to_owned(), @@ -152,7 +146,7 @@ impl InputMethodName { } impl fmt::Debug for InputMethodName { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.string.fmt(f) } } @@ -254,7 +248,7 @@ impl PotentialInputMethods { pub fn open_im( &mut self, xconn: &Arc, - callback: Option<&Fn() -> ()>, + callback: Option<&dyn Fn() -> ()>, ) -> InputMethodResult { use self::InputMethodResult::*; diff --git a/src/platform_impl/linux/x11/ime/mod.rs b/src/platform_impl/linux/x11/ime/mod.rs index 73aad7c9..b95da711 100644 --- a/src/platform_impl/linux/x11/ime/mod.rs +++ b/src/platform_impl/linux/x11/ime/mod.rs @@ -1,20 +1,24 @@ // Important: all XIM calls need to happen from the same thread! +mod callbacks; +mod context; mod inner; mod input_method; -mod context; -mod callbacks; -use std::sync::Arc; -use std::sync::mpsc::{Receiver, Sender}; +use std::sync::{ + mpsc::{Receiver, Sender}, + Arc, +}; use super::{ffi, util, XConnection, XError}; -use self::inner::{close_im, ImeInner}; -use self::input_method::PotentialInputMethods; -use self::context::ImeContext; -use self::callbacks::*; pub use self::context::ImeContextCreationError; +use self::{ + callbacks::*, + context::ImeContext, + inner::{close_im, ImeInner}, + input_method::PotentialInputMethods, +}; pub type ImeReceiver = Receiver<(ffi::Window, i16, i16)>; pub type ImeSender = Sender<(ffi::Window, i16, i16)>; @@ -37,10 +41,7 @@ impl Ime { let potential_input_methods = PotentialInputMethods::new(&xconn); let (mut inner, client_data) = { - let mut inner = Box::new(ImeInner::new( - xconn, - potential_input_methods, - )); + let mut inner = Box::new(ImeInner::new(xconn, potential_input_methods)); let inner_ptr = Box::into_raw(inner); let client_data = inner_ptr as _; let destroy_callback = ffi::XIMCallback { @@ -54,9 +55,12 @@ impl Ime { let xconn = Arc::clone(&inner.xconn); - let input_method = inner.potential_input_methods.open_im(&xconn, Some(&|| { - let _ = unsafe { set_instantiate_callback(&xconn, client_data) }; - })); + let input_method = inner.potential_input_methods.open_im( + &xconn, + Some(&|| { + let _ = unsafe { set_instantiate_callback(&xconn, client_data) }; + }), + ); let is_fallback = input_method.is_fallback(); if let Some(input_method) = input_method.ok() { @@ -84,19 +88,12 @@ impl Ime { // Ok(_) indicates that nothing went wrong internally // Ok(true) indicates that the action was actually performed // Ok(false) indicates that the action is not presently applicable - pub fn create_context(&mut self, window: ffi::Window) - -> Result - { + pub fn create_context(&mut self, window: ffi::Window) -> Result { let context = if self.is_destroyed() { // Create empty entry in map, so that when IME is rebuilt, this window has a context. None } else { - Some(unsafe { ImeContext::new( - &self.inner.xconn, - self.inner.im, - window, - None, - ) }?) + Some(unsafe { ImeContext::new(&self.inner.xconn, self.inner.im, window, None) }?) }; self.inner.contexts.insert(window, context); Ok(!self.is_destroyed()) diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 5339bef2..ba61e719 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -1,49 +1,58 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] -pub mod ffi; +mod dnd; +mod event_processor; mod events; +pub mod ffi; +mod ime; mod monitor; +pub mod util; mod window; mod xdisplay; -mod dnd; -mod ime; -pub mod util; -mod event_processor; -pub use self::monitor::MonitorHandle; -pub use self::window::UnownedWindow; -pub use self::xdisplay::{XConnection, XNotSupported, XError}; +pub use self::{ + monitor::MonitorHandle, + window::UnownedWindow, + xdisplay::{XConnection, XError, XNotSupported}, +}; -use std::{mem, slice}; -use std::cell::RefCell; -use std::collections::{VecDeque, HashMap, HashSet}; -use std::ffi::CStr; -use std::ops::Deref; -use std::os::raw::*; -use std::rc::Rc; -use std::sync::{Arc, mpsc, Weak, Mutex}; +use std::{ + cell::RefCell, + collections::{HashMap, HashSet, VecDeque}, + ffi::CStr, + mem, + ops::Deref, + os::raw::*, + rc::Rc, + slice, + sync::{mpsc, Arc, Mutex, Weak}, +}; use libc::{self, setlocale, LC_CTYPE}; -use error::OsError as RootOsError; -use event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}; -use event::{WindowEvent, Event}; -use platform_impl::PlatformSpecificWindowBuilderAttributes; -use platform_impl::platform::sticky_exit_callback; -use window::{WindowAttributes}; -use self::dnd::{Dnd, DndState}; -use self::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime}; -use self::event_processor::EventProcessor; +use self::{ + dnd::{Dnd, DndState}, + event_processor::EventProcessor, + ime::{Ime, ImeCreationError, ImeReceiver, ImeSender}, +}; +use crate::{ + error::OsError as RootOsError, + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, + platform_impl::{platform::sticky_exit_callback, PlatformSpecificWindowBuilderAttributes}, + window::WindowAttributes, +}; pub struct EventLoopWindowTarget { xconn: Arc, wm_delete_window: ffi::Atom, + net_wm_ping: ffi::Atom, ime_sender: ImeSender, root: ffi::Window, ime: RefCell, windows: RefCell>>, pending_redraws: Arc>>, - _marker: ::std::marker::PhantomData + _marker: ::std::marker::PhantomData, } pub struct EventLoop { @@ -53,7 +62,7 @@ pub struct EventLoop { pending_user_events: Rc>>, user_sender: ::calloop::channel::Sender, pending_events: Rc>>>, - target: Rc> + target: Rc>, } #[derive(Clone)] @@ -67,13 +76,17 @@ impl EventLoop { let wm_delete_window = unsafe { xconn.get_atom_unchecked(b"WM_DELETE_WINDOW\0") }; + let net_wm_ping = unsafe { xconn.get_atom_unchecked(b"_NET_WM_PING\0") }; + let dnd = Dnd::new(Arc::clone(&xconn)) .expect("Failed to call XInternAtoms when initializing drag and drop"); let (ime_sender, ime_receiver) = mpsc::channel(); // Input methods will open successfully without setting the locale, but it won't be // possible to actually commit pre-edit sequences. - unsafe { setlocale(LC_CTYPE, b"\0".as_ptr() as *const _); } + unsafe { + setlocale(LC_CTYPE, b"\0".as_ptr() as *const _); + } let ime = RefCell::new({ let result = Ime::new(Arc::clone(&xconn)); if let Err(ImeCreationError::OpenFailure(ref state)) = result { @@ -82,7 +95,8 @@ impl EventLoop { result.expect("Failed to set input method destruction callback") }); - let randr_event_offset = xconn.select_xrandr_input(root) + let randr_event_offset = xconn + .select_xrandr_input(root) .expect("Failed to query XRandR extension"); let xi2ext = unsafe { @@ -96,7 +110,8 @@ impl EventLoop { b"XInputExtension\0".as_ptr() as *const c_char, &mut result.opcode as *mut c_int, &mut result.first_event_id as *mut c_int, - &mut result.first_error_id as *mut c_int); + &mut result.first_error_id as *mut c_int, + ); if res == ffi::False { panic!("X server missing XInput extension"); } @@ -110,18 +125,18 @@ impl EventLoop { xconn.display, &mut xinput_major_ver, &mut xinput_minor_ver, - ) != ffi::Success as libc::c_int { + ) != ffi::Success as libc::c_int + { panic!( "X server has XInput extension {}.{} but does not support XInput2", - xinput_major_ver, - xinput_minor_ver, + xinput_major_ver, xinput_minor_ver, ); } } xconn.update_cached_wm_info(root); - let target = Rc::new(RootELW{ + let target = Rc::new(RootELW { p: super::EventLoopWindowTarget::X(EventLoopWindowTarget { ime, root, @@ -130,9 +145,10 @@ impl EventLoop { ime_sender, xconn, wm_delete_window, + net_wm_ping, pending_redraws: Default::default(), }), - _marker: ::std::marker::PhantomData + _marker: ::std::marker::PhantomData, }); // A calloop event loop to drive us @@ -144,11 +160,14 @@ impl EventLoop { let (user_sender, user_channel) = ::calloop::channel::channel(); - let _user_source = inner_loop.handle().insert_source(user_channel, move |evt, &mut()| { - if let ::calloop::channel::Event::Msg(msg) = evt { - pending_user_events2.borrow_mut().push_back(msg); - } - }).unwrap(); + let _user_source = inner_loop + .handle() + .insert_source(user_channel, move |evt, &mut ()| { + if let ::calloop::channel::Event::Msg(msg) = evt { + pending_user_events2.borrow_mut().push_back(msg); + } + }) + .unwrap(); // Handle X11 events let pending_events: Rc>> = Default::default(); @@ -164,20 +183,20 @@ impl EventLoop { // Register for device hotplug events // (The request buffer is flushed during `init_device`) - get_xtarget(&target).xconn.select_xinput_events( - root, - ffi::XIAllDevices, - ffi::XI_HierarchyChangedMask, - ).queue(); + get_xtarget(&target) + .xconn + .select_xinput_events(root, ffi::XIAllDevices, ffi::XI_HierarchyChangedMask) + .queue(); processor.init_device(ffi::XIAllDevices); // Setup the X11 event source - let mut x11_events = ::calloop::generic::Generic::from_raw_fd(get_xtarget(&target).xconn.x11_fd); + let mut x11_events = + ::calloop::generic::Generic::from_raw_fd(get_xtarget(&target).xconn.x11_fd); x11_events.set_interest(::calloop::mio::Ready::readable()); - let _x11_source = inner_loop.handle().insert_source( - x11_events, - { + let _x11_source = inner_loop + .handle() + .insert_source(x11_events, { let pending_events = pending_events.clone(); let mut callback = move |event| { pending_events.borrow_mut().push_back(event); @@ -191,8 +210,8 @@ impl EventLoop { } } } - } - ).unwrap(); + }) + .unwrap(); let result = EventLoop { inner_loop, @@ -201,7 +220,7 @@ impl EventLoop { _user_source, user_sender, pending_user_events, - target + target, }; result @@ -224,7 +243,8 @@ impl EventLoop { } pub fn run_return(&mut self, mut callback: F) - where F: FnMut(Event, &RootELW, &mut ControlFlow) + where + F: FnMut(Event, &RootELW, &mut ControlFlow), { let mut control_flow = ControlFlow::default(); let wt = get_xtarget(&self.target); @@ -243,10 +263,10 @@ impl EventLoop { let mut guard = self.pending_user_events.borrow_mut(); for evt in guard.drain(..) { sticky_exit_callback( - ::event::Event::UserEvent(evt), + crate::event::Event::UserEvent(evt), &self.target, &mut control_flow, - &mut callback + &mut callback, ); } } @@ -256,48 +276,49 @@ impl EventLoop { for wid in guard.drain() { sticky_exit_callback( Event::WindowEvent { - window_id: ::window::WindowId(super::WindowId::X(wid)), - event: WindowEvent::RedrawRequested + window_id: crate::window::WindowId(super::WindowId::X(wid)), + event: WindowEvent::RedrawRequested, }, &self.target, &mut control_flow, - &mut callback + &mut callback, ); } } // send Events cleared { sticky_exit_callback( - ::event::Event::EventsCleared, + crate::event::Event::EventsCleared, &self.target, &mut control_flow, - &mut callback + &mut callback, ); } - // flush the X11 connection - unsafe { (wt.xconn.xlib.XFlush)(wt.xconn.display); } - match control_flow { ControlFlow::Exit => break, ControlFlow::Poll => { // non-blocking dispatch - self.inner_loop.dispatch(Some(::std::time::Duration::from_millis(0)), &mut ()).unwrap(); - control_flow = ControlFlow::default(); - callback(::event::Event::NewEvents(::event::StartCause::Poll), &self.target, &mut control_flow); - }, + self.inner_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut ()) + .unwrap(); + callback( + crate::event::Event::NewEvents(crate::event::StartCause::Poll), + &self.target, + &mut control_flow, + ); + } ControlFlow::Wait => { self.inner_loop.dispatch(None, &mut ()).unwrap(); - control_flow = ControlFlow::default(); callback( - ::event::Event::NewEvents(::event::StartCause::WaitCancelled { + crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled { start: ::std::time::Instant::now(), - requested_resume: None + requested_resume: None, }), &self.target, - &mut control_flow + &mut control_flow, ); - }, + } ControlFlow::WaitUntil(deadline) => { let start = ::std::time::Instant::now(); // compute the blocking duration @@ -307,36 +328,44 @@ impl EventLoop { ::std::time::Duration::from_millis(0) }; self.inner_loop.dispatch(Some(duration), &mut ()).unwrap(); - control_flow = ControlFlow::default(); let now = std::time::Instant::now(); if now < deadline { callback( - ::event::Event::NewEvents(::event::StartCause::WaitCancelled { - start, - requested_resume: Some(deadline) - }), + crate::event::Event::NewEvents( + crate::event::StartCause::WaitCancelled { + start, + requested_resume: Some(deadline), + }, + ), &self.target, - &mut control_flow + &mut control_flow, ); } else { callback( - ::event::Event::NewEvents(::event::StartCause::ResumeTimeReached { - start, - requested_resume: deadline - }), + crate::event::Event::NewEvents( + crate::event::StartCause::ResumeTimeReached { + start, + requested_resume: deadline, + }, + ), &self.target, - &mut control_flow + &mut control_flow, ); } } } } - callback(::event::Event::LoopDestroyed, &self.target, &mut control_flow); + callback( + crate::event::Event::LoopDestroyed, + &self.target, + &mut control_flow, + ); } pub fn run(mut self, callback: F) -> ! - where F: 'static + FnMut(Event, &RootELW, &mut ControlFlow) + where + F: 'static + FnMut(Event, &RootELW, &mut ControlFlow), { self.run_return(callback); ::std::process::exit(0); @@ -345,10 +374,10 @@ impl EventLoop { fn get_xtarget(rt: &RootELW) -> &EventLoopWindowTarget { if let super::EventLoopWindowTarget::X(ref target) = rt.p { - target - } else { - unreachable!(); - } + target + } else { + unreachable!(); + } } impl EventLoopProxy { @@ -368,19 +397,17 @@ impl<'a> DeviceInfo<'a> { unsafe { let mut count = mem::uninitialized(); let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count); - xconn.check_errors() - .ok() - .and_then(|_| { - if info.is_null() || count == 0 { - None - } else { - Some(DeviceInfo { - xconn, - info, - count: count as usize, - }) - } - }) + xconn.check_errors().ok().and_then(|_| { + if info.is_null() || count == 0 { + None + } else { + Some(DeviceInfo { + xconn, + info, + count: count as usize, + }) + } + }) } } } @@ -431,10 +458,11 @@ impl Window { pub fn new( event_loop: &EventLoopWindowTarget, attribs: WindowAttributes, - pl_attribs: PlatformSpecificWindowBuilderAttributes + pl_attribs: PlatformSpecificWindowBuilderAttributes, ) -> Result { let window = Arc::new(UnownedWindow::new(&event_loop, attribs, pl_attribs)?); - event_loop.windows + event_loop + .windows .borrow_mut() .insert(window.id(), Arc::downgrade(&window)); Ok(Window(window)) @@ -457,11 +485,14 @@ impl Drop for Window { /// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed struct GenericEventCookie<'a> { xconn: &'a XConnection, - cookie: ffi::XGenericEventCookie + cookie: ffi::XGenericEventCookie, } impl<'a> GenericEventCookie<'a> { - fn from_event<'b>(xconn: &'b XConnection, event: ffi::XEvent) -> Option> { + fn from_event<'b>( + xconn: &'b XConnection, + event: ffi::XEvent, + ) -> Option> { unsafe { let mut cookie: ffi::XGenericEventCookie = From::from(event); if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == ffi::True { @@ -488,8 +519,12 @@ struct XExtension { first_error_id: c_int, } -fn mkwid(w: ffi::Window) -> ::window::WindowId { ::window::WindowId(::platform_impl::WindowId::X(WindowId(w))) } -fn mkdid(w: c_int) -> ::event::DeviceId { ::event::DeviceId(::platform_impl::DeviceId::X(DeviceId(w))) } +fn mkwid(w: ffi::Window) -> crate::window::WindowId { + crate::window::WindowId(crate::platform_impl::WindowId::X(WindowId(w))) +} +fn mkdid(w: c_int) -> crate::event::DeviceId { + crate::event::DeviceId(crate::platform_impl::DeviceId::X(DeviceId(w))) +} #[derive(Debug)] struct Device { @@ -528,23 +563,30 @@ impl Device { | ffi::XI_RawKeyPressMask | ffi::XI_RawKeyReleaseMask; // The request buffer is flushed when we poll for events - wt.xconn.select_xinput_events(wt.root, info.deviceid, mask).queue(); + wt.xconn + .select_xinput_events(wt.root, info.deviceid, mask) + .queue(); // Identify scroll axes for class_ptr in Device::classes(info) { let class = unsafe { &**class_ptr }; match class._type { ffi::XIScrollClass => { - let info = unsafe { mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIScrollClassInfo>(class) }; - scroll_axes.push((info.number, ScrollAxis { - increment: info.increment, - orientation: match info.scroll_type { - ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal, - ffi::XIScrollTypeVertical => ScrollOrientation::Vertical, - _ => { unreachable!() } + let info = unsafe { + mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIScrollClassInfo>(class) + }; + scroll_axes.push(( + info.number, + ScrollAxis { + increment: info.increment, + orientation: match info.scroll_type { + ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal, + ffi::XIScrollTypeVertical => ScrollOrientation::Vertical, + _ => unreachable!(), + }, + position: 0.0, }, - position: 0.0, - })); + )); } _ => {} } @@ -553,7 +595,7 @@ impl Device { let mut device = Device { name: name.into_owned(), - scroll_axes: scroll_axes, + scroll_axes, attachment: info.attachment, }; device.reset_scroll_position(info); @@ -566,8 +608,14 @@ impl Device { let class = unsafe { &**class_ptr }; match class._type { ffi::XIValuatorClass => { - let info = unsafe { mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIValuatorClassInfo>(class) }; - if let Some(&mut (_, ref mut axis)) = self.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == info.number) { + let info = unsafe { + mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIValuatorClassInfo>(class) + }; + if let Some(&mut (_, ref mut axis)) = self + .scroll_axes + .iter_mut() + .find(|&&mut (axis, _)| axis == info.number) + { axis.position = info.value; } } @@ -579,11 +627,18 @@ impl Device { #[inline] fn physical_device(info: &ffi::XIDeviceInfo) -> bool { - info._use == ffi::XISlaveKeyboard || info._use == ffi::XISlavePointer || info._use == ffi::XIFloatingSlave + info._use == ffi::XISlaveKeyboard + || info._use == ffi::XISlavePointer + || info._use == ffi::XIFloatingSlave } #[inline] fn classes(info: &ffi::XIDeviceInfo) -> &[*const ffi::XIAnyClassInfo] { - unsafe { slice::from_raw_parts(info.classes as *const *const ffi::XIAnyClassInfo, info.num_classes as usize) } + unsafe { + slice::from_raw_parts( + info.classes as *const *const ffi::XIAnyClassInfo, + info.num_classes as usize, + ) + } } } diff --git a/src/platform_impl/linux/x11/monitor.rs b/src/platform_impl/linux/x11/monitor.rs index 638ebce1..72026257 100644 --- a/src/platform_impl/linux/x11/monitor.rs +++ b/src/platform_impl/linux/x11/monitor.rs @@ -2,15 +2,16 @@ use std::os::raw::*; use parking_lot::Mutex; -use dpi::{PhysicalPosition, PhysicalSize}; -use super::{util, XConnection, XError}; -use super::ffi::{ - RRCrtcChangeNotifyMask, - RROutputPropertyNotifyMask, - RRScreenChangeNotifyMask, - True, - Window, - XRRScreenResources, +use super::{ + ffi::{ + RRCrtcChangeNotifyMask, RROutputPropertyNotifyMask, RRScreenChangeNotifyMask, True, Window, + XRRScreenResources, + }, + util, XConnection, XError, +}; +use crate::{ + dpi::{PhysicalPosition, PhysicalSize}, + monitor::VideoMode, }; // Used to test XRandR < 1.5 code path. This should always be committed as false. @@ -56,6 +57,8 @@ pub struct MonitorHandle { pub(crate) hidpi_factor: f64, /// Used to determine which windows are on this monitor pub(crate) rect: util::AaRect, + /// Supported video modes on this monitor + video_modes: Vec, } impl MonitorHandle { @@ -66,8 +69,8 @@ impl MonitorHandle { repr: util::MonitorRepr, primary: bool, ) -> Option { - let (name, hidpi_factor) = unsafe { xconn.get_output_info(resources, &repr)? }; - let (dimensions, position) = unsafe { (repr.dimensions(), repr.position()) }; + let (name, hidpi_factor, video_modes) = unsafe { xconn.get_output_info(resources, &repr)? }; + let (dimensions, position) = unsafe { (repr.size(), repr.position()) }; let rect = util::AaRect::new(position, dimensions); Some(MonitorHandle { id, @@ -77,6 +80,7 @@ impl MonitorHandle { position, primary, rect, + video_modes, }) } @@ -89,7 +93,7 @@ impl MonitorHandle { self.id as u32 } - pub fn dimensions(&self) -> PhysicalSize { + pub fn size(&self) -> PhysicalSize { self.dimensions.into() } @@ -101,6 +105,11 @@ impl MonitorHandle { pub fn hidpi_factor(&self) -> f64 { self.hidpi_factor } + + #[inline] + pub fn video_modes(&self) -> impl Iterator { + self.video_modes.clone().into_iter() + } } impl XConnection { @@ -151,7 +160,8 @@ impl XConnection { // videowalls. let xrandr_1_5 = self.xrandr_1_5.as_ref().unwrap(); let mut monitor_count = 0; - let monitors = (xrandr_1_5.XRRGetMonitors)(self.display, root, 1, &mut monitor_count); + let monitors = + (xrandr_1_5.XRRGetMonitors)(self.display, root, 1, &mut monitor_count); assert!(monitor_count >= 0); available = Vec::with_capacity(monitor_count as usize); for monitor_index in 0..monitor_count { @@ -164,7 +174,8 @@ impl XConnection { monitor_index as u32, monitor.into(), is_primary, - ).map(|monitor_id| available.push(monitor_id)); + ) + .map(|monitor_id| available.push(monitor_id)); } (xrandr_1_5.XRRFreeMonitors)(monitors); } else { @@ -181,13 +192,8 @@ impl XConnection { let crtc = util::MonitorRepr::from(crtc); let is_primary = crtc.get_output() == primary; has_primary |= is_primary; - MonitorHandle::from_repr( - self, - resources, - crtc_id as u32, - crtc, - is_primary, - ).map(|monitor_id| available.push(monitor_id)); + MonitorHandle::from_repr(self, resources, crtc_id as u32, crtc, is_primary) + .map(|monitor_id| available.push(monitor_id)); } (self.xrandr.XRRFreeCrtcInfo)(crtc); } @@ -235,13 +241,8 @@ impl XConnection { if version_lock.is_none() { let mut major = 0; let mut minor = 0; - let has_extension = unsafe { - (self.xrandr.XRRQueryVersion)( - self.display, - &mut major, - &mut minor, - ) - }; + let has_extension = + unsafe { (self.xrandr.XRRQueryVersion)(self.display, &mut major, &mut minor) }; if has_extension != True { panic!("[winit] XRandR extension not available."); } @@ -252,11 +253,7 @@ impl XConnection { let mut event_offset = 0; let mut error_offset = 0; let status = unsafe { - (self.xrandr.XRRQueryExtension)( - self.display, - &mut event_offset, - &mut error_offset, - ) + (self.xrandr.XRRQueryExtension)(self.display, &mut event_offset, &mut error_offset) }; if status != True { @@ -264,9 +261,7 @@ impl XConnection { unreachable!("[winit] `XRRQueryExtension` failed but no error was received."); } - let mask = RRCrtcChangeNotifyMask - | RROutputPropertyNotifyMask - | RRScreenChangeNotifyMask; + let mask = RRCrtcChangeNotifyMask | RROutputPropertyNotifyMask | RRScreenChangeNotifyMask; unsafe { (self.xrandr.XRRSelectInput)(self.display, root, mask) }; Ok(event_offset) diff --git a/src/platform_impl/linux/x11/util/atom.rs b/src/platform_impl/linux/x11/util/atom.rs index fe97d3ae..c311c5d2 100644 --- a/src/platform_impl/linux/x11/util/atom.rs +++ b/src/platform_impl/linux/x11/util/atom.rs @@ -1,7 +1,9 @@ -use std::collections::HashMap; -use std::ffi::{CStr, CString}; -use std::fmt::Debug; -use std::os::raw::*; +use std::{ + collections::HashMap, + ffi::{CStr, CString}, + fmt::Debug, + os::raw::*, +}; use parking_lot::Mutex; @@ -21,11 +23,9 @@ impl XConnection { if let Some(atom) = cached_atom { atom } else { - let atom = unsafe { (self.xlib.XInternAtom)( - self.display, - name.as_ptr() as *const c_char, - ffi::False, - ) }; + let atom = unsafe { + (self.xlib.XInternAtom)(self.display, name.as_ptr() as *const c_char, ffi::False) + }; if atom == 0 { let msg = format!( "`XInternAtom` failed, which really shouldn't happen. Atom: {:?}, Error: {:#?}", @@ -52,7 +52,7 @@ impl XConnection { // Note: this doesn't use caching, for the sake of simplicity. // If you're dealing with this many atoms, you'll usually want to cache them locally anyway. - pub unsafe fn get_atoms(&self, names: &[*mut c_char]) -> Result, XError> { + pub unsafe fn get_atoms(&self, names: &[*mut c_char]) -> Result, XError> { let mut atoms = Vec::with_capacity(names.len()); (self.xlib.XInternAtoms)( self.display, diff --git a/src/platform_impl/linux/x11/util/client_msg.rs b/src/platform_impl/linux/x11/util/client_msg.rs index 399db4f1..4c72665a 100644 --- a/src/platform_impl/linux/x11/util/client_msg.rs +++ b/src/platform_impl/linux/x11/util/client_msg.rs @@ -8,7 +8,7 @@ impl XConnection { target_window: c_ulong, event_mask: Option, event: T, - ) -> Flusher { + ) -> Flusher<'_> { let event_mask = event_mask.unwrap_or(ffi::NoEventMask); unsafe { (self.xlib.XSendEvent)( @@ -24,12 +24,12 @@ impl XConnection { pub fn send_client_msg( &self, - window: c_ulong, // The window this is "about"; not necessarily this window + window: c_ulong, // The window this is "about"; not necessarily this window target_window: c_ulong, // The window we're sending to message_type: ffi::Atom, event_mask: Option, data: ClientMsgPayload, - ) -> Flusher { + ) -> Flusher<'_> { let mut event: ffi::XClientMessageEvent = unsafe { mem::uninitialized() }; event.type_ = ffi::ClientMessage; event.display = self.display; @@ -45,12 +45,12 @@ impl XConnection { // to send more than one message worth of data. pub fn send_client_msg_multi( &self, - window: c_ulong, // The window this is "about"; not necessarily this window + window: c_ulong, // The window this is "about"; not necessarily this window target_window: c_ulong, // The window we're sending to message_type: ffi::Atom, event_mask: Option, data: &[T], - ) -> Flusher { + ) -> Flusher<'_> { let format = T::FORMAT; let size_of_t = mem::size_of::(); debug_assert_eq!(size_of_t, format.get_actual_size()); diff --git a/src/platform_impl/linux/x11/util/format.rs b/src/platform_impl/linux/x11/util/format.rs index 1be8b647..6090c65d 100644 --- a/src/platform_impl/linux/x11/util/format.rs +++ b/src/platform_impl/linux/x11/util/format.rs @@ -1,6 +1,4 @@ -use std::fmt::Debug; -use std::mem; -use std::os::raw::*; +use std::{fmt::Debug, mem, os::raw::*}; // This isn't actually the number of the bits in the format. // X11 does a match on this value to determine which type to call sizeof on. @@ -50,9 +48,21 @@ pub trait Formattable: Debug + Clone + Copy + PartialEq + PartialOrd { } // You might be surprised by the absence of c_int, but not as surprised as X11 would be by the presence of it. -impl Formattable for c_schar { const FORMAT: Format = Format::Char; } -impl Formattable for c_uchar { const FORMAT: Format = Format::Char; } -impl Formattable for c_short { const FORMAT: Format = Format::Short; } -impl Formattable for c_ushort { const FORMAT: Format = Format::Short; } -impl Formattable for c_long { const FORMAT: Format = Format::Long; } -impl Formattable for c_ulong { const FORMAT: Format = Format::Long; } +impl Formattable for c_schar { + const FORMAT: Format = Format::Char; +} +impl Formattable for c_uchar { + const FORMAT: Format = Format::Char; +} +impl Formattable for c_short { + const FORMAT: Format = Format::Short; +} +impl Formattable for c_ushort { + const FORMAT: Format = Format::Short; +} +impl Formattable for c_long { + const FORMAT: Format = Format::Long; +} +impl Formattable for c_ulong { + const FORMAT: Format = Format::Long; +} diff --git a/src/platform_impl/linux/x11/util/geometry.rs b/src/platform_impl/linux/x11/util/geometry.rs index f3bd1281..e66606af 100644 --- a/src/platform_impl/linux/x11/util/geometry.rs +++ b/src/platform_impl/linux/x11/util/geometry.rs @@ -1,7 +1,7 @@ use std::cmp; use super::*; -use dpi::{LogicalPosition, LogicalSize}; +use crate::dpi::{LogicalPosition, LogicalSize}; // Friendly neighborhood axis-aligned rectangle #[derive(Debug, Clone, PartialEq, Eq)] @@ -16,7 +16,12 @@ impl AaRect { pub fn new((x, y): (i32, i32), (width, height): (u32, u32)) -> Self { let (x, y) = (x as i64, y as i64); let (width, height) = (width as i64, height as i64); - AaRect { x, y, width, height } + AaRect { + x, + y, + width, + height, + } } pub fn contains_point(&self, x: i64, y: i64) -> bool { @@ -73,7 +78,12 @@ pub struct FrameExtents { impl FrameExtents { pub fn new(left: c_ulong, right: c_ulong, top: c_ulong, bottom: c_ulong) -> Self { - FrameExtents { left, right, top, bottom } + FrameExtents { + left, + right, + top, + bottom, + } } pub fn from_border(border: c_ulong) -> Self { @@ -116,13 +126,20 @@ impl FrameExtentsHeuristic { pub fn inner_pos_to_outer(&self, x: i32, y: i32) -> (i32, i32) { use self::FrameExtentsHeuristicPath::*; if self.heuristic_path != UnsupportedBordered { - (x - self.frame_extents.left as i32, y - self.frame_extents.top as i32) + ( + x - self.frame_extents.left as i32, + y - self.frame_extents.top as i32, + ) } else { (x, y) } } - pub fn inner_pos_to_outer_logical(&self, mut logical: LogicalPosition, factor: f64) -> LogicalPosition { + pub fn inner_pos_to_outer_logical( + &self, + mut logical: LogicalPosition, + factor: f64, + ) -> LogicalPosition { use self::FrameExtentsHeuristicPath::*; if self.heuristic_path != UnsupportedBordered { let frame_extents = self.frame_extents.as_logical(factor); @@ -135,15 +152,23 @@ impl FrameExtentsHeuristic { pub fn inner_size_to_outer(&self, width: u32, height: u32) -> (u32, u32) { ( width.saturating_add( - self.frame_extents.left.saturating_add(self.frame_extents.right) as u32 + self.frame_extents + .left + .saturating_add(self.frame_extents.right) as u32, ), height.saturating_add( - self.frame_extents.top.saturating_add(self.frame_extents.bottom) as u32 + self.frame_extents + .top + .saturating_add(self.frame_extents.bottom) as u32, ), ) } - pub fn inner_size_to_outer_logical(&self, mut logical: LogicalSize, factor: f64) -> LogicalSize { + pub fn inner_size_to_outer_logical( + &self, + mut logical: LogicalSize, + factor: f64, + ) -> LogicalSize { let frame_extents = self.frame_extents.as_logical(factor); logical.width += frame_extents.left + frame_extents.right; logical.height += frame_extents.top + frame_extents.bottom; @@ -153,7 +178,11 @@ impl FrameExtentsHeuristic { impl XConnection { // This is adequate for inner_position - pub fn translate_coords(&self, window: ffi::Window, root: ffi::Window) -> Result { + pub fn translate_coords( + &self, + window: ffi::Window, + root: ffi::Window, + ) -> Result { let mut translated_coords: TranslatedCoords = unsafe { mem::uninitialized() }; unsafe { (self.xlib.XTranslateCoordinates)( @@ -201,11 +230,9 @@ impl XConnection { // Of the WMs tested, xmonad, i3, dwm, IceWM (1.3.x and earlier), and blackbox don't // support this. As this is part of EWMH (Extended Window Manager Hints), it's likely to // be unsupported by many smaller WMs. - let extents: Option> = self.get_property( - window, - extents_atom, - ffi::XA_CARDINAL, - ).ok(); + let extents: Option> = self + .get_property(window, extents_atom, ffi::XA_CARDINAL) + .ok(); extents.and_then(|extents| { if extents.len() >= 4 { @@ -228,11 +255,9 @@ impl XConnection { return None; } - let client_list: Option> = self.get_property( - root, - client_list_atom, - ffi::XA_WINDOW, - ).ok(); + let client_list: Option> = self + .get_property(root, client_list_atom, ffi::XA_WINDOW) + .ok(); client_list.map(|client_list| client_list.contains(&window)) } @@ -264,7 +289,11 @@ impl XConnection { self.check_errors().map(|_| parent) } - fn climb_hierarchy(&self, window: ffi::Window, root: ffi::Window) -> Result { + fn climb_hierarchy( + &self, + window: ffi::Window, + root: ffi::Window, + ) -> Result { let mut outer_window = window; loop { let candidate = self.get_parent_window(outer_window)?; @@ -276,7 +305,11 @@ impl XConnection { Ok(outer_window) } - pub fn get_frame_extents_heuristic(&self, window: ffi::Window, root: ffi::Window) -> FrameExtentsHeuristic { + pub fn get_frame_extents_heuristic( + &self, + window: ffi::Window, + root: ffi::Window, + ) -> FrameExtentsHeuristic { use self::FrameExtentsHeuristicPath::*; // Position relative to root window. @@ -284,15 +317,16 @@ impl XConnection { // isn't nested are outlined in the comments throghout this function, but in addition to // that, fullscreen windows often aren't nested. let (inner_y_rel_root, child) = { - let coords = self.translate_coords(window, root).expect("Failed to translate window coordinates"); - ( - coords.y_rel_root, - coords.child, - ) + let coords = self + .translate_coords(window, root) + .expect("Failed to translate window coordinates"); + (coords.y_rel_root, coords.child) }; let (width, height, border) = { - let inner_geometry = self.get_geometry(window).expect("Failed to get inner window geometry"); + let inner_geometry = self + .get_geometry(window) + .expect("Failed to get inner window geometry"); ( inner_geometry.width, inner_geometry.height, @@ -343,9 +377,13 @@ impl XConnection { // If the position value we have is for a nested window used as the client area, we'll // just climb up the hierarchy and get the geometry of the outermost window we're // nested in. - let outer_window = self.climb_hierarchy(window, root).expect("Failed to climb window hierarchy"); + let outer_window = self + .climb_hierarchy(window, root) + .expect("Failed to climb window hierarchy"); let (outer_y, outer_width, outer_height) = { - let outer_geometry = self.get_geometry(outer_window).expect("Failed to get outer window geometry"); + let outer_geometry = self + .get_geometry(outer_window) + .expect("Failed to get outer window geometry"); ( outer_geometry.y_rel_parent, outer_geometry.width, @@ -364,12 +402,8 @@ impl XConnection { let top = offset_y; let bottom = diff_y.saturating_sub(offset_y); - let frame_extents = FrameExtents::new( - left.into(), - right.into(), - top.into(), - bottom.into(), - ); + let frame_extents = + FrameExtents::new(left.into(), right.into(), top.into(), bottom.into()); FrameExtentsHeuristic { frame_extents, heuristic_path: UnsupportedNested, diff --git a/src/platform_impl/linux/x11/util/hint.rs b/src/platform_impl/linux/x11/util/hint.rs index 5405e5e5..a71d75e0 100644 --- a/src/platform_impl/linux/x11/util/hint.rs +++ b/src/platform_impl/linux/x11/util/hint.rs @@ -1,9 +1,8 @@ +use std::slice; use std::sync::Arc; use super::*; -pub const MWM_HINTS_DECORATIONS: c_ulong = 2; - #[derive(Debug)] pub enum StateOperation { Remove = 0, // _NET_WM_STATE_REMOVE @@ -93,13 +92,101 @@ impl WindowType { } } +pub struct MotifHints { + hints: MwmHints, +} + +#[repr(C)] +struct MwmHints { + flags: c_ulong, + functions: c_ulong, + decorations: c_ulong, + input_mode: c_long, + status: c_ulong, +} + +#[allow(dead_code)] +mod mwm { + use libc::c_ulong; + + // Motif WM hints are obsolete, but still widely supported. + // https://stackoverflow.com/a/1909708 + pub const MWM_HINTS_FUNCTIONS: c_ulong = 1 << 0; + pub const MWM_HINTS_DECORATIONS: c_ulong = 1 << 1; + + pub const MWM_FUNC_ALL: c_ulong = 1 << 0; + pub const MWM_FUNC_RESIZE: c_ulong = 1 << 1; + pub const MWM_FUNC_MOVE: c_ulong = 1 << 2; + pub const MWM_FUNC_MINIMIZE: c_ulong = 1 << 3; + pub const MWM_FUNC_MAXIMIZE: c_ulong = 1 << 4; + pub const MWM_FUNC_CLOSE: c_ulong = 1 << 5; +} + +impl MotifHints { + pub fn new() -> MotifHints { + MotifHints { + hints: MwmHints { + flags: 0, + functions: 0, + decorations: 0, + input_mode: 0, + status: 0, + }, + } + } + + pub fn set_decorations(&mut self, decorations: bool) { + self.hints.flags |= mwm::MWM_HINTS_DECORATIONS; + self.hints.decorations = decorations as c_ulong; + } + + pub fn set_maximizable(&mut self, maximizable: bool) { + if maximizable { + self.add_func(mwm::MWM_FUNC_MAXIMIZE); + } else { + self.remove_func(mwm::MWM_FUNC_MAXIMIZE); + } + } + + fn add_func(&mut self, func: c_ulong) { + if self.hints.flags & mwm::MWM_HINTS_FUNCTIONS != 0 { + if self.hints.functions & mwm::MWM_FUNC_ALL != 0 { + self.hints.functions &= !func; + } else { + self.hints.functions |= func; + } + } + } + + fn remove_func(&mut self, func: c_ulong) { + if self.hints.flags & mwm::MWM_HINTS_FUNCTIONS == 0 { + self.hints.flags |= mwm::MWM_HINTS_FUNCTIONS; + self.hints.functions = mwm::MWM_FUNC_ALL; + } + + if self.hints.functions & mwm::MWM_FUNC_ALL != 0 { + self.hints.functions |= func; + } else { + self.hints.functions &= !func; + } + } +} + +impl MwmHints { + fn as_slice(&self) -> &[c_ulong] { + unsafe { slice::from_raw_parts(self as *const _ as *const c_ulong, 5) } + } +} + pub struct NormalHints<'a> { size_hints: XSmartPointer<'a, ffi::XSizeHints>, } impl<'a> NormalHints<'a> { pub fn new(xconn: &'a XConnection) -> Self { - NormalHints { size_hints: xconn.alloc_size_hints() } + NormalHints { + size_hints: xconn.alloc_size_hints(), + } } pub fn has_flag(&self, flag: c_long) -> bool { @@ -130,7 +217,11 @@ impl<'a> NormalHints<'a> { } pub fn get_max_size(&self) -> Option<(u32, u32)> { - self.getter(ffi::PMaxSize, &self.size_hints.max_width, &self.size_hints.max_height) + self.getter( + ffi::PMaxSize, + &self.size_hints.max_width, + &self.size_hints.max_height, + ) } pub fn set_max_size(&mut self, max_size: Option<(u32, u32)>) { @@ -144,7 +235,11 @@ impl<'a> NormalHints<'a> { } pub fn get_min_size(&self) -> Option<(u32, u32)> { - self.getter(ffi::PMinSize, &self.size_hints.min_width, &self.size_hints.min_height) + self.getter( + ffi::PMinSize, + &self.size_hints.min_width, + &self.size_hints.min_height, + ) } pub fn set_min_size(&mut self, min_size: Option<(u32, u32)>) { @@ -158,7 +253,11 @@ impl<'a> NormalHints<'a> { } pub fn get_resize_increments(&self) -> Option<(u32, u32)> { - self.getter(ffi::PResizeInc, &self.size_hints.width_inc, &self.size_hints.height_inc) + self.getter( + ffi::PResizeInc, + &self.size_hints.width_inc, + &self.size_hints.height_inc, + ) } pub fn set_resize_increments(&mut self, resize_increments: Option<(u32, u32)>) { @@ -172,7 +271,11 @@ impl<'a> NormalHints<'a> { } pub fn get_base_size(&self) -> Option<(u32, u32)> { - self.getter(ffi::PBaseSize, &self.size_hints.base_width, &self.size_hints.base_height) + self.getter( + ffi::PBaseSize, + &self.size_hints.base_width, + &self.size_hints.base_height, + ) } pub fn set_base_size(&mut self, base_size: Option<(u32, u32)>) { @@ -187,7 +290,10 @@ impl<'a> NormalHints<'a> { } impl XConnection { - pub fn get_wm_hints(&self, window: ffi::Window) -> Result, XError> { + pub fn get_wm_hints( + &self, + window: ffi::Window, + ) -> Result, XError> { let wm_hints = unsafe { (self.xlib.XGetWMHints)(self.display, window) }; self.check_errors()?; let wm_hints = if wm_hints.is_null() { @@ -198,18 +304,18 @@ impl XConnection { Ok(wm_hints) } - pub fn set_wm_hints(&self, window: ffi::Window, wm_hints: XSmartPointer) -> Flusher { + pub fn set_wm_hints( + &self, + window: ffi::Window, + wm_hints: XSmartPointer<'_, ffi::XWMHints>, + ) -> Flusher<'_> { unsafe { - (self.xlib.XSetWMHints)( - self.display, - window, - wm_hints.ptr, - ); + (self.xlib.XSetWMHints)(self.display, window, wm_hints.ptr); } Flusher::new(self) } - pub fn get_normal_hints(&self, window: ffi::Window) -> Result { + pub fn get_normal_hints(&self, window: ffi::Window) -> Result, XError> { let size_hints = self.alloc_size_hints(); let mut supplied_by_user: c_long = unsafe { mem::uninitialized() }; unsafe { @@ -223,14 +329,42 @@ impl XConnection { self.check_errors().map(|_| NormalHints { size_hints }) } - pub fn set_normal_hints(&self, window: ffi::Window, normal_hints: NormalHints) -> Flusher { + pub fn set_normal_hints( + &self, + window: ffi::Window, + normal_hints: NormalHints<'_>, + ) -> Flusher<'_> { unsafe { - (self.xlib.XSetWMNormalHints)( - self.display, - window, - normal_hints.size_hints.ptr, - ); + (self.xlib.XSetWMNormalHints)(self.display, window, normal_hints.size_hints.ptr); } Flusher::new(self) } + + pub fn get_motif_hints(&self, window: ffi::Window) -> MotifHints { + let motif_hints = unsafe { self.get_atom_unchecked(b"_MOTIF_WM_HINTS\0") }; + + let mut hints = MotifHints::new(); + + if let Ok(props) = self.get_property::(window, motif_hints, motif_hints) { + hints.hints.flags = props.get(0).cloned().unwrap_or(0); + hints.hints.functions = props.get(1).cloned().unwrap_or(0); + hints.hints.decorations = props.get(2).cloned().unwrap_or(0); + hints.hints.input_mode = props.get(3).cloned().unwrap_or(0) as c_long; + hints.hints.status = props.get(4).cloned().unwrap_or(0); + } + + hints + } + + pub fn set_motif_hints(&self, window: ffi::Window, hints: &MotifHints) -> Flusher<'_> { + let motif_hints = unsafe { self.get_atom_unchecked(b"_MOTIF_WM_HINTS\0") }; + + self.change_property( + window, + motif_hints, + motif_hints, + PropMode::Replace, + hints.hints.as_slice(), + ) + } } diff --git a/src/platform_impl/linux/x11/util/icon.rs b/src/platform_impl/linux/x11/util/icon.rs index 9bcaf952..5334d4a9 100644 --- a/src/platform_impl/linux/x11/util/icon.rs +++ b/src/platform_impl/linux/x11/util/icon.rs @@ -1,5 +1,5 @@ -use window::{Icon, Pixel, PIXEL_SIZE}; use super::*; +use crate::window::{Icon, Pixel, PIXEL_SIZE}; impl Pixel { pub fn to_packed_argb(&self) -> Cardinal { diff --git a/src/platform_impl/linux/x11/util/input.rs b/src/platform_impl/linux/x11/util/input.rs index aa530e77..8f2e9833 100644 --- a/src/platform_impl/linux/x11/util/input.rs +++ b/src/platform_impl/linux/x11/util/input.rs @@ -1,7 +1,7 @@ use std::str; use super::*; -use event::ModifiersState; +use crate::event::ModifiersState; pub const VIRTUAL_CORE_POINTER: c_int = 2; pub const VIRTUAL_CORE_KEYBOARD: c_int = 3; @@ -55,7 +55,12 @@ impl<'a> Drop for PointerState<'a> { } impl XConnection { - pub fn select_xinput_events(&self, window: c_ulong, device_id: c_int, mask: i32) -> Flusher { + pub fn select_xinput_events( + &self, + window: c_ulong, + device_id: c_int, + mask: i32, + ) -> Flusher<'_> { let mut event_mask = ffi::XIEventMask { deviceid: device_id, mask: &mask as *const _ as *mut c_uchar, @@ -73,15 +78,8 @@ impl XConnection { } #[allow(dead_code)] - pub fn select_xkb_events(&self, device_id: c_uint, mask: c_ulong) -> Option { - let status = unsafe { - (self.xlib.XkbSelectEvents)( - self.display, - device_id, - mask, - mask, - ) - }; + pub fn select_xkb_events(&self, device_id: c_uint, mask: c_ulong) -> Option> { + let status = unsafe { (self.xlib.XkbSelectEvents)(self.display, device_id, mask, mask) }; if status == ffi::True { Some(Flusher::new(self)) } else { @@ -89,9 +87,13 @@ impl XConnection { } } - pub fn query_pointer(&self, window: ffi::Window, device_id: c_int) -> Result { + pub fn query_pointer( + &self, + window: ffi::Window, + device_id: c_int, + ) -> Result, XError> { unsafe { - let mut pointer_state: PointerState = mem::uninitialized(); + let mut pointer_state: PointerState<'_> = mem::uninitialized(); pointer_state.xconn = self; pointer_state.relative_to_window = (self.xinput2.XIQueryPointer)( self.display, diff --git a/src/platform_impl/linux/x11/util/memory.rs b/src/platform_impl/linux/x11/util/memory.rs index eef0bdc9..c85cc371 100644 --- a/src/platform_impl/linux/x11/util/memory.rs +++ b/src/platform_impl/linux/x11/util/memory.rs @@ -12,10 +12,7 @@ impl<'a, T> XSmartPointer<'a, T> { // Returns None if ptr is null. pub fn new(xconn: &'a XConnection, ptr: *mut T) -> Option { if !ptr.is_null() { - Some(XSmartPointer { - xconn, - ptr, - }) + Some(XSmartPointer { xconn, ptr }) } else { None } @@ -45,17 +42,17 @@ impl<'a, T> Drop for XSmartPointer<'a, T> { } impl XConnection { - pub fn alloc_class_hint(&self) -> XSmartPointer { + pub fn alloc_class_hint(&self) -> XSmartPointer<'_, ffi::XClassHint> { XSmartPointer::new(self, unsafe { (self.xlib.XAllocClassHint)() }) .expect("`XAllocClassHint` returned null; out of memory") } - pub fn alloc_size_hints(&self) -> XSmartPointer { + pub fn alloc_size_hints(&self) -> XSmartPointer<'_, ffi::XSizeHints> { XSmartPointer::new(self, unsafe { (self.xlib.XAllocSizeHints)() }) .expect("`XAllocSizeHints` returned null; out of memory") } - pub fn alloc_wm_hints(&self) -> XSmartPointer { + pub fn alloc_wm_hints(&self) -> XSmartPointer<'_, ffi::XWMHints> { XSmartPointer::new(self, unsafe { (self.xlib.XAllocWMHints)() }) .expect("`XAllocWMHints` returned null; out of memory") } diff --git a/src/platform_impl/linux/x11/util/mod.rs b/src/platform_impl/linux/x11/util/mod.rs index ccef6e40..920205be 100644 --- a/src/platform_impl/linux/x11/util/mod.rs +++ b/src/platform_impl/linux/x11/util/mod.rs @@ -13,22 +13,12 @@ mod randr; mod window_property; mod wm; -pub use self::atom::*; -pub use self::client_msg::*; -pub use self::format::*; -pub use self::geometry::*; -pub use self::hint::*; -pub use self::icon::*; -pub use self::input::*; -pub use self::memory::*; -pub use self::randr::*; -pub use self::window_property::*; -pub use self::wm::*; +pub use self::{ + atom::*, client_msg::*, format::*, geometry::*, hint::*, icon::*, input::*, memory::*, + randr::*, window_property::*, wm::*, +}; -use std::mem; -use std::ptr; -use std::ops::BitAnd; -use std::os::raw::*; +use std::{mem, ops::BitAnd, os::raw::*, ptr}; use super::{ffi, XConnection, XError}; @@ -48,8 +38,8 @@ pub fn maybe_change(field: &mut Option, value: T) -> bool { } pub fn has_flag(bitset: T, flag: T) -> bool -where T: - Copy + PartialEq + BitAnd +where + T: Copy + PartialEq + BitAnd, { bitset & flag == flag } diff --git a/src/platform_impl/linux/x11/util/randr.rs b/src/platform_impl/linux/x11/util/randr.rs index 3abbf849..1e9a41c6 100644 --- a/src/platform_impl/linux/x11/util/randr.rs +++ b/src/platform_impl/linux/x11/util/randr.rs @@ -1,8 +1,7 @@ -use std::{env, slice}; -use std::str::FromStr; +use std::{env, slice, str::FromStr}; -use dpi::validate_hidpi_factor; use super::*; +use crate::{dpi::validate_hidpi_factor, monitor::VideoMode}; pub fn calc_dpi_factor( (width_px, height_px): (u32, u32), @@ -23,14 +22,12 @@ pub fn calc_dpi_factor( } // See http://xpra.org/trac/ticket/728 for more information. - if width_mm == 0 || width_mm == 0 { + if width_mm == 0 || height_mm == 0 { warn!("XRandR reported that the display's 0mm in size, which is certifiably insane"); return 1.0; } - let ppmm = ( - (width_px as f64 * height_px as f64) / (width_mm as f64 * height_mm as f64) - ).sqrt(); + let ppmm = ((width_px as f64 * height_px as f64) / (width_mm as f64 * height_mm as f64)).sqrt(); // Quantize 1/12 step size let dpi_factor = ((ppmm * (12.0 * 25.4 / 96.0)).round() / 12.0).max(1.0); assert!(validate_hidpi_factor(dpi_factor)); @@ -51,7 +48,7 @@ impl MonitorRepr { } } - pub unsafe fn dimensions(&self) -> (u32, u32) { + pub unsafe fn size(&self) -> (u32, u32) { match *self { MonitorRepr::Monitor(monitor) => ((*monitor).width as u32, (*monitor).height as u32), MonitorRepr::Crtc(crtc) => ((*crtc).width as u32, (*crtc).height as u32), @@ -87,7 +84,7 @@ impl XConnection { return None; } if let Ok(res) = ::std::ffi::CStr::from_ptr(resource_manager_str).to_str() { - let name : &str = "Xft.dpi:\t"; + let name: &str = "Xft.dpi:\t"; for pair in res.split("\n") { if pair.starts_with(&name) { let res = &pair[name.len()..]; @@ -101,12 +98,9 @@ impl XConnection { &self, resources: *mut ffi::XRRScreenResources, repr: &MonitorRepr, - ) -> Option<(String, f64)> { - let output_info = (self.xrandr.XRRGetOutputInfo)( - self.display, - resources, - repr.get_output(), - ); + ) -> Option<(String, f64, Vec)> { + let output_info = + (self.xrandr.XRRGetOutputInfo)(self.display, resources, repr.get_output()); if output_info.is_null() { // When calling `XRRGetOutputInfo` on a virtual monitor (versus a physical display) // it's possible for it to return null. @@ -114,6 +108,33 @@ impl XConnection { let _ = self.check_errors(); // discard `BadRROutput` error return None; } + + let screen = (self.xlib.XDefaultScreen)(self.display); + let bit_depth = (self.xlib.XDefaultDepth)(self.display, screen); + + let output_modes = + slice::from_raw_parts((*output_info).modes, (*output_info).nmode as usize); + let resource_modes = slice::from_raw_parts((*resources).modes, (*resources).nmode as usize); + + let modes = resource_modes + .iter() + // XRROutputInfo contains an array of mode ids that correspond to + // modes in the array in XRRScreenResources + .filter(|x| output_modes.iter().any(|id| x.id == *id)) + .map(|x| { + let refresh_rate = if x.dotClock > 0 && x.hTotal > 0 && x.vTotal > 0 { + x.dotClock as u64 * 1000 / (x.hTotal as u64 * x.vTotal as u64) + } else { + 0 + }; + + VideoMode { + size: (x.width, x.height), + refresh_rate: (refresh_rate as f32 / 1000.0).round() as u16, + bit_depth: bit_depth as u16, + } + }); + let name_slice = slice::from_raw_parts( (*output_info).name as *mut u8, (*output_info).nameLen as usize, @@ -123,12 +144,15 @@ impl XConnection { dpi / 96. } else { calc_dpi_factor( - repr.dimensions(), - ((*output_info).mm_width as u64, (*output_info).mm_height as u64), + repr.size(), + ( + (*output_info).mm_width as u64, + (*output_info).mm_height as u64, + ), ) }; (self.xrandr.XRRFreeOutputInfo)(output_info); - Some((name, hidpi_factor)) + Some((name, hidpi_factor, modes.collect())) } } diff --git a/src/platform_impl/linux/x11/util/window_property.rs b/src/platform_impl/linux/x11/util/window_property.rs index 81d65eba..d719ea70 100644 --- a/src/platform_impl/linux/x11/util/window_property.rs +++ b/src/platform_impl/linux/x11/util/window_property.rs @@ -84,10 +84,8 @@ impl XConnection { if !buf.is_null() { offset += PROPERTY_BUFFER_SIZE; - let new_data = std::slice::from_raw_parts( - buf as *mut T, - quantity_returned as usize, - ); + let new_data = + std::slice::from_raw_parts(buf as *mut T, quantity_returned as usize); /*println!( "XGetWindowProperty prop:{:?} fmt:{:02} len:{:02} off:{:02} out:{:02}, buf:{:?}", property, diff --git a/src/platform_impl/linux/x11/util/wm.rs b/src/platform_impl/linux/x11/util/wm.rs index 738ab76d..693bc5c0 100644 --- a/src/platform_impl/linux/x11/util/wm.rs +++ b/src/platform_impl/linux/x11/util/wm.rs @@ -28,11 +28,8 @@ impl XConnection { fn get_supported_hints(&self, root: ffi::Window) -> Vec { let supported_atom = unsafe { self.get_atom_unchecked(b"_NET_SUPPORTED\0") }; - self.get_property( - root, - supported_atom, - ffi::XA_ATOM, - ).unwrap_or_else(|_| Vec::with_capacity(0)) + self.get_property(root, supported_atom, ffi::XA_ATOM) + .unwrap_or_else(|_| Vec::with_capacity(0)) } fn get_wm_name(&self, root: ffi::Window) -> Option { @@ -61,15 +58,9 @@ impl XConnection { // Querying this property on the root window will give us the ID of a child window created by // the WM. let root_window_wm_check = { - let result = self.get_property( - root, - check_atom, - ffi::XA_WINDOW, - ); + let result = self.get_property(root, check_atom, ffi::XA_WINDOW); - let wm_check = result - .ok() - .and_then(|wm_check| wm_check.get(0).cloned()); + let wm_check = result.ok().and_then(|wm_check| wm_check.get(0).cloned()); if let Some(wm_check) = wm_check { wm_check @@ -81,15 +72,9 @@ impl XConnection { // Querying the same property on the child window we were given, we should get this child // window's ID again. let child_window_wm_check = { - let result = self.get_property( - root_window_wm_check, - check_atom, - ffi::XA_WINDOW, - ); + let result = self.get_property(root_window_wm_check, check_atom, ffi::XA_WINDOW); - let wm_check = result - .ok() - .and_then(|wm_check| wm_check.get(0).cloned()); + let wm_check = result.ok().and_then(|wm_check| wm_check.get(0).cloned()); if let Some(wm_check) = wm_check { wm_check @@ -107,11 +92,7 @@ impl XConnection { let wm_name = { let utf8_string_atom = unsafe { self.get_atom_unchecked(b"UTF8_STRING\0") }; - let result = self.get_property( - root_window_wm_check, - wm_name_atom, - utf8_string_atom, - ); + let result = self.get_property(root_window_wm_check, wm_name_atom, utf8_string_atom); // IceWM requires this. IceWM was also the only WM tested that returns a null-terminated // string. For more fun trivia, IceWM is also unique in including version and uname @@ -126,15 +107,12 @@ impl XConnection { }; if no_utf8 { - self.get_property( - root_window_wm_check, - wm_name_atom, - ffi::XA_STRING, - ) + self.get_property(root_window_wm_check, wm_name_atom, ffi::XA_STRING) } else { result } - }.ok(); + } + .ok(); wm_name.and_then(|wm_name| String::from_utf8(wm_name).ok()) } diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 1e5330c7..2211c29b 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -1,23 +1,20 @@ -use std::{cmp, env, mem}; -use std::collections::HashSet; -use std::ffi::CString; -use std::os::raw::*; -use std::path::Path; -use std::sync::Arc; +use std::{cmp, collections::HashSet, env, ffi::CString, mem, os::raw::*, path::Path, sync::Arc}; use libc; use parking_lot::Mutex; -use error::{ExternalError, NotSupportedError, OsError as RootOsError}; -use window::{Icon, CursorIcon, WindowAttributes}; -use dpi::{LogicalPosition, LogicalSize}; -use platform_impl::MonitorHandle as PlatformMonitorHandle; -use platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes}; -use platform_impl::x11::ime::ImeContextCreationError; -use platform_impl::x11::MonitorHandle as X11MonitorHandle; -use monitor::MonitorHandle as RootMonitorHandle; +use crate::{ + dpi::{LogicalPosition, LogicalSize}, + error::{ExternalError, NotSupportedError, OsError as RootOsError}, + monitor::MonitorHandle as RootMonitorHandle, + platform_impl::{ + x11::{ime::ImeContextCreationError, MonitorHandle as X11MonitorHandle}, + MonitorHandle as PlatformMonitorHandle, OsError, PlatformSpecificWindowBuilderAttributes, + }, + window::{CursorIcon, Icon, WindowAttributes}, +}; -use super::{ffi, util, ImeSender, XConnection, XError, WindowId, EventLoopWindowTarget}; +use super::{ffi, util, EventLoopWindowTarget, ImeSender, WindowId, XConnection, XError}; unsafe extern "C" fn visibility_predicate( _display: *mut ffi::Display, @@ -60,9 +57,9 @@ unsafe impl Sync for UnownedWindow {} pub struct UnownedWindow { pub xconn: Arc, // never changes - xwindow: ffi::Window, // never changes - root: ffi::Window, // never changes - screen_id: i32, // never changes + xwindow: ffi::Window, // never changes + root: ffi::Window, // never changes + screen_id: i32, // never changes cursor: Mutex, cursor_grabbed: Mutex, cursor_visible: Mutex, @@ -89,7 +86,8 @@ impl UnownedWindow { } } dpi_factor.unwrap_or_else(|| { - xconn.query_pointer(root, util::VIRTUAL_CORE_POINTER) + xconn + .query_pointer(root, util::VIRTUAL_CORE_POINTER) .ok() .and_then(|pointer_state| { let (x, y) = (pointer_state.root_x as i64, pointer_state.root_y as i64); @@ -110,17 +108,18 @@ impl UnownedWindow { info!("Guessed window DPI factor: {}", dpi_factor); - let max_inner_size: Option<(u32, u32)> = window_attrs.max_inner_size.map(|size| { - size.to_physical(dpi_factor).into() - }); - let min_inner_size: Option<(u32, u32)> = window_attrs.min_inner_size.map(|size| { - size.to_physical(dpi_factor).into() - }); + let max_inner_size: Option<(u32, u32)> = window_attrs + .max_inner_size + .map(|size| size.to_physical(dpi_factor).into()); + let min_inner_size: Option<(u32, u32)> = window_attrs + .min_inner_size + .map(|size| size.to_physical(dpi_factor).into()); let dimensions = { // x11 only applies constraints when the window is actively resized // by the user, so we have to manually apply the initial constraints - let mut dimensions: (u32, u32) = window_attrs.inner_size + let mut dimensions: (u32, u32) = window_attrs + .inner_size .or_else(|| Some((800, 600).into())) .map(|size| size.to_physical(dpi_factor)) .map(Into::into) @@ -133,7 +132,10 @@ impl UnownedWindow { dimensions.0 = cmp::max(dimensions.0, min.0); dimensions.1 = cmp::max(dimensions.1, min.1); } - debug!("Calculated physical dimensions: {}x{}", dimensions.0, dimensions.1); + debug!( + "Calculated physical dimensions: {}x{}", + dimensions.0, dimensions.1 + ); dimensions }; @@ -150,7 +152,9 @@ impl UnownedWindow { let visual = vi.visual; (xconn.xlib.XCreateColormap)(xconn.display, root, visual, ffi::AllocNone) } - } else { 0 }; + } else { + 0 + }; swa.event_mask = ffi::ExposureMask | ffi::StructureNotifyMask | ffi::VisibilityChangeMask @@ -220,7 +224,9 @@ impl UnownedWindow { // title to determine placement/etc., so doing this after mapping would cause the WM to // act on the wrong title state. window.set_title_inner(&window_attrs.title).queue(); - window.set_decorations_inner(window_attrs.decorations).queue(); + window + .set_decorations_inner(window_attrs.decorations) + .queue(); { // Enable drag and drop (TODO: extend API to make this toggleable) @@ -234,15 +240,16 @@ impl UnownedWindow { util::PropMode::Replace, version, ) - }.queue(); + } + .queue(); // WM_CLASS must be set *before* mapping the window, as per ICCCM! { let (class, instance) = if let Some((instance, class)) = pl_attribs.class { let instance = CString::new(instance.as_str()) .expect("`WM_CLASS` instance contained null byte"); - let class = CString::new(class.as_str()) - .expect("`WM_CLASS` class contained null byte"); + let class = + CString::new(class.as_str()).expect("`WM_CLASS` class contained null byte"); (instance, class) } else { let class = env::args() @@ -269,12 +276,8 @@ impl UnownedWindow { (*class_hint).res_class = instance.as_ptr() as *mut c_char; unsafe { - (xconn.xlib.XSetClassHint)( - xconn.display, - window.xwindow, - class_hint.ptr, - ); - }//.queue(); + (xconn.xlib.XSetClassHint)(xconn.display, window.xwindow, class_hint.ptr); + } //.queue(); } window.set_pid().map(|flusher| flusher.queue()); @@ -289,9 +292,11 @@ impl UnownedWindow { // set size hints { - let mut min_inner_size = window_attrs.min_inner_size + let mut min_inner_size = window_attrs + .min_inner_size .map(|size| size.to_physical(dpi_factor)); - let mut max_inner_size = window_attrs.max_inner_size + let mut max_inner_size = window_attrs + .max_inner_size .map(|size| size.to_physical(dpi_factor)); if !window_attrs.resizable { if util::wm_name_is_one_of(&["Xfwm4"]) { @@ -325,16 +330,17 @@ impl UnownedWindow { (xconn.xlib.XSetWMProtocols)( xconn.display, window.xwindow, - &event_loop.wm_delete_window as *const ffi::Atom as *mut ffi::Atom, - 1, + &[event_loop.wm_delete_window, event_loop.net_wm_ping] as *const ffi::Atom + as *mut ffi::Atom, + 2, ); - }//.queue(); + } //.queue(); // Set visibility (map window) if window_attrs.visible { unsafe { (xconn.xlib.XMapRaised)(xconn.display, window.xwindow); - }//.queue(); + } //.queue(); } // Attempt to make keyboard input repeat detectable @@ -346,7 +352,9 @@ impl UnownedWindow { &mut supported_ptr, ); if supported_ptr == ffi::False { - return Err(os_error!(OsError::XMisc("`XkbSetDetectableAutoRepeat` failed"))); + return Err(os_error!(OsError::XMisc( + "`XkbSetDetectableAutoRepeat` failed" + ))); } } @@ -366,16 +374,18 @@ impl UnownedWindow { | ffi::XI_TouchEndMask; mask }; - xconn.select_xinput_events(window.xwindow, ffi::XIAllMasterDevices, mask).queue(); + xconn + .select_xinput_events(window.xwindow, ffi::XIAllMasterDevices, mask) + .queue(); { - let result = event_loop.ime - .borrow_mut() - .create_context(window.xwindow); + let result = event_loop.ime.borrow_mut().create_context(window.xwindow); if let Err(err) = result { let e = match err { ImeContextCreationError::XError(err) => OsError::XError(err), - ImeContextCreationError::Null => OsError::XMisc("IME Context creation failed"), + ImeContextCreationError::Null => { + OsError::XMisc("IME Context creation failed") + } }; return Err(os_error!(e)); } @@ -386,10 +396,14 @@ impl UnownedWindow { window.set_maximized_inner(window_attrs.maximized).queue(); } if window_attrs.fullscreen.is_some() { - window.set_fullscreen_inner(window_attrs.fullscreen.clone()).queue(); + window + .set_fullscreen_inner(window_attrs.fullscreen.clone()) + .queue(); } if window_attrs.always_on_top { - window.set_always_on_top_inner(window_attrs.always_on_top).queue(); + window + .set_always_on_top_inner(window_attrs.always_on_top) + .queue(); } if window_attrs.visible { @@ -397,7 +411,8 @@ impl UnownedWindow { // XSetInputFocus generates an error if the window is not visible, so we wait // until we receive VisibilityNotify. let mut event = mem::uninitialized(); - (xconn.xlib.XIfEvent)( // This will flush the request buffer IF it blocks. + (xconn.xlib.XIfEvent)( + // This will flush the request buffer IF it blocks. xconn.display, &mut event as *mut ffi::XEvent, Some(visibility_predicate), @@ -414,7 +429,8 @@ impl UnownedWindow { } // We never want to give the user a broken window, since by then, it's too late to handle. - xconn.sync_with_server() + xconn + .sync_with_server() .map(|_| window) .map_err(|x_err| os_error!(OsError::XError(x_err))) } @@ -429,7 +445,7 @@ impl UnownedWindow { LogicalSize::from_physical((width, height), dpi) } - fn set_pid(&self) -> Option { + fn set_pid(&self) -> Option> { let pid_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_PID\0") }; let client_machine_atom = unsafe { self.xconn.get_atom_unchecked(b"WM_CLIENT_MACHINE\0") }; unsafe { @@ -439,18 +455,22 @@ impl UnownedWindow { const MAXHOSTNAMELEN: usize = 256; let mut hostname: [c_char; MAXHOSTNAMELEN] = mem::uninitialized(); let status = libc::gethostname(hostname.as_mut_ptr(), hostname.len()); - if status != 0 { return None; } + if status != 0 { + return None; + } hostname[MAXHOSTNAMELEN - 1] = '\0' as c_char; // a little extra safety let hostname_length = libc::strlen(hostname.as_ptr()); (hostname, hostname_length as usize) }; - self.xconn.change_property( - self.xwindow, - pid_atom, - ffi::XA_CARDINAL, - util::PropMode::Replace, - &[libc::getpid() as util::Cardinal], - ).queue(); + self.xconn + .change_property( + self.xwindow, + pid_atom, + ffi::XA_CARDINAL, + util::PropMode::Replace, + &[libc::getpid() as util::Cardinal], + ) + .queue(); let flusher = self.xconn.change_property( self.xwindow, client_machine_atom, @@ -462,7 +482,7 @@ impl UnownedWindow { } } - fn set_window_type(&self, window_type: util::WindowType) -> util::Flusher { + fn set_window_type(&self, window_type: util::WindowType) -> util::Flusher<'_> { let hint_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE\0") }; let window_type_atom = window_type.as_atom(&self.xconn); self.xconn.change_property( @@ -474,7 +494,7 @@ impl UnownedWindow { ) } - fn set_gtk_theme_variant(&self, variant: String) -> util::Flusher { + fn set_gtk_theme_variant(&self, variant: String) -> util::Flusher<'_> { let hint_atom = unsafe { self.xconn.get_atom_unchecked(b"_GTK_THEME_VARIANT\0") }; let utf8_atom = unsafe { self.xconn.get_atom_unchecked(b"UTF8_STRING\0") }; let variant = CString::new(variant).expect("`_GTK_THEME_VARIANT` contained null byte"); @@ -489,20 +509,26 @@ impl UnownedWindow { #[inline] pub fn set_urgent(&self, is_urgent: bool) { - let mut wm_hints = self.xconn.get_wm_hints(self.xwindow).expect("`XGetWMHints` failed"); + let mut wm_hints = self + .xconn + .get_wm_hints(self.xwindow) + .expect("`XGetWMHints` failed"); if is_urgent { (*wm_hints).flags |= ffi::XUrgencyHint; } else { (*wm_hints).flags &= !ffi::XUrgencyHint; } - self.xconn.set_wm_hints(self.xwindow, wm_hints).flush().expect("Failed to set urgency hint"); + self.xconn + .set_wm_hints(self.xwindow, wm_hints) + .flush() + .expect("Failed to set urgency hint"); } fn set_netwm( &self, operation: util::StateOperation, properties: (c_long, c_long, c_long, c_long), - ) -> util::Flusher { + ) -> util::Flusher<'_> { let state_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE\0") }; self.xconn.send_client_msg( self.xwindow, @@ -519,12 +545,13 @@ impl UnownedWindow { ) } - fn set_fullscreen_hint(&self, fullscreen: bool) -> util::Flusher { - let fullscreen_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_FULLSCREEN\0") }; + fn set_fullscreen_hint(&self, fullscreen: bool) -> util::Flusher<'_> { + let fullscreen_atom = + unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_FULLSCREEN\0") }; self.set_netwm(fullscreen.into(), (fullscreen_atom as c_long, 0, 0, 0)) } - fn set_fullscreen_inner(&self, monitor: Option) -> util::Flusher { + fn set_fullscreen_inner(&self, monitor: Option) -> util::Flusher<'_> { match monitor { None => { let flusher = self.set_fullscreen_hint(false); @@ -532,12 +559,15 @@ impl UnownedWindow { self.set_position_inner(position.0, position.1).queue(); } flusher - }, - Some(RootMonitorHandle { inner: PlatformMonitorHandle::X(monitor) }) => { + } + Some(RootMonitorHandle { + inner: PlatformMonitorHandle::X(monitor), + }) => { let window_position = self.outer_position_physical(); self.shared_state.lock().restore_position = Some(window_position); let monitor_origin: (i32, i32) = monitor.position().into(); - self.set_position_inner(monitor_origin.0, monitor_origin.1).queue(); + self.set_position_inner(monitor_origin.0, monitor_origin.1) + .queue(); self.set_fullscreen_hint(true) } _ => unreachable!(), @@ -567,17 +597,15 @@ impl UnownedWindow { #[inline] pub fn current_monitor(&self) -> X11MonitorHandle { - let monitor = self.shared_state - .lock() - .last_monitor - .as_ref() - .cloned(); - monitor - .unwrap_or_else(|| { - let monitor = self.xconn.get_monitor_for_window(Some(self.get_rect())).to_owned(); - self.shared_state.lock().last_monitor = Some(monitor.clone()); - monitor - }) + let monitor = self.shared_state.lock().last_monitor.as_ref().cloned(); + monitor.unwrap_or_else(|| { + let monitor = self + .xconn + .get_monitor_for_window(Some(self.get_rect())) + .to_owned(); + self.shared_state.lock().last_monitor = Some(monitor.clone()); + monitor + }) } pub fn available_monitors(&self) -> Vec { @@ -588,10 +616,19 @@ impl UnownedWindow { self.xconn.primary_monitor() } - fn set_maximized_inner(&self, maximized: bool) -> util::Flusher { - let horz_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_HORZ\0") }; - let vert_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_VERT\0") }; - self.set_netwm(maximized.into(), (horz_atom as c_long, vert_atom as c_long, 0, 0)) + fn set_maximized_inner(&self, maximized: bool) -> util::Flusher<'_> { + let horz_atom = unsafe { + self.xconn + .get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_HORZ\0") + }; + let vert_atom = unsafe { + self.xconn + .get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_VERT\0") + }; + self.set_netwm( + maximized.into(), + (horz_atom as c_long, vert_atom as c_long, 0, 0), + ) } #[inline] @@ -602,7 +639,7 @@ impl UnownedWindow { self.invalidate_cached_frame_extents(); } - fn set_title_inner(&self, title: &str) -> util::Flusher { + fn set_title_inner(&self, title: &str) -> util::Flusher<'_> { let wm_name_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_NAME\0") }; let utf8_atom = unsafe { self.xconn.get_atom_unchecked(b"UTF8_STRING\0") }; let title = CString::new(title).expect("Window title contained null byte"); @@ -629,21 +666,12 @@ impl UnownedWindow { .expect("Failed to set window title"); } - fn set_decorations_inner(&self, decorations: bool) -> util::Flusher { - let wm_hints = unsafe { self.xconn.get_atom_unchecked(b"_MOTIF_WM_HINTS\0") }; - self.xconn.change_property( - self.xwindow, - wm_hints, - wm_hints, - util::PropMode::Replace, - &[ - util::MWM_HINTS_DECORATIONS, // flags - 0, // functions - decorations as c_ulong, // decorations - 0, // input mode - 0, // status - ], - ) + fn set_decorations_inner(&self, decorations: bool) -> util::Flusher<'_> { + let mut hints = self.xconn.get_motif_hints(self.xwindow); + + hints.set_decorations(decorations); + + self.xconn.set_motif_hints(self.xwindow, &hints) } #[inline] @@ -654,7 +682,15 @@ impl UnownedWindow { self.invalidate_cached_frame_extents(); } - fn set_always_on_top_inner(&self, always_on_top: bool) -> util::Flusher { + fn set_maximizable_inner(&self, maximizable: bool) -> util::Flusher<'_> { + let mut hints = self.xconn.get_motif_hints(self.xwindow); + + hints.set_maximizable(maximizable); + + self.xconn.set_motif_hints(self.xwindow, &hints) + } + + fn set_always_on_top_inner(&self, always_on_top: bool) -> util::Flusher<'_> { let above_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_ABOVE\0") }; self.set_netwm(always_on_top.into(), (above_atom as c_long, 0, 0, 0)) } @@ -666,7 +702,7 @@ impl UnownedWindow { .expect("Failed to set always-on-top state"); } - fn set_icon_inner(&self, icon: Icon) -> util::Flusher { + fn set_icon_inner(&self, icon: Icon) -> util::Flusher<'_> { let icon_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_ICON\0") }; let data = icon.to_cardinals(); self.xconn.change_property( @@ -678,7 +714,7 @@ impl UnownedWindow { ) } - fn unset_icon_inner(&self) -> util::Flusher { + fn unset_icon_inner(&self) -> util::Flusher<'_> { let icon_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_ICON\0") }; let empty_data: [util::Cardinal; 0] = []; self.xconn.change_property( @@ -695,7 +731,9 @@ impl UnownedWindow { match icon { Some(icon) => self.set_icon_inner(icon), None => self.unset_icon_inner(), - }.flush().expect("Failed to set icons"); + } + .flush() + .expect("Failed to set icons"); } #[inline] @@ -703,19 +741,23 @@ impl UnownedWindow { match visible { true => unsafe { (self.xconn.xlib.XMapRaised)(self.xconn.display, self.xwindow); - self.xconn.flush_requests() + self.xconn + .flush_requests() .expect("Failed to call XMapRaised"); }, false => unsafe { (self.xconn.xlib.XUnmapWindow)(self.xconn.display, self.xwindow); - self.xconn.flush_requests() + self.xconn + .flush_requests() .expect("Failed to call XUnmapWindow"); - } + }, } } fn update_cached_frame_extents(&self) { - let extents = self.xconn.get_frame_extents_heuristic(self.xwindow, self.root); + let extents = self + .xconn + .get_frame_extents_heuristic(self.xwindow, self.root); (*self.shared_state.lock()).frame_extents = Some(extents); } @@ -749,7 +791,8 @@ impl UnownedWindow { pub(crate) fn inner_position_physical(&self) -> (i32, i32) { // This should be okay to unwrap since the only error XTranslateCoordinates can return // is BadWindow, and if the window handle is bad we have bigger problems. - self.xconn.translate_coords(self.xwindow, self.root) + self.xconn + .translate_coords(self.xwindow, self.root) .map(|coords| (coords.x_rel_root, coords.y_rel_root)) .unwrap() } @@ -759,7 +802,7 @@ impl UnownedWindow { Ok(self.logicalize_coords(self.inner_position_physical())) } - pub(crate) fn set_position_inner(&self, mut x: i32, mut y: i32) -> util::Flusher { + pub(crate) fn set_position_inner(&self, mut x: i32, mut y: i32) -> util::Flusher<'_> { // There are a few WMs that set client area position rather than window position, so // we'll translate for consistency. if util::wm_name_is_one_of(&["Enlightenment", "FVWM"]) { @@ -773,12 +816,7 @@ impl UnownedWindow { } } unsafe { - (self.xconn.xlib.XMoveWindow)( - self.xconn.display, - self.xwindow, - x as c_int, - y as c_int, - ); + (self.xconn.xlib.XMoveWindow)(self.xconn.display, self.xwindow, x as c_int, y as c_int); } util::Flusher::new(&self.xconn) } @@ -798,7 +836,8 @@ impl UnownedWindow { pub(crate) fn inner_size_physical(&self) -> (u32, u32) { // This should be okay to unwrap since the only error XGetGeometry can return // is BadWindow, and if the window handle is bad we have bigger problems. - self.xconn.get_geometry(self.xwindow) + self.xconn + .get_geometry(self.xwindow) .map(|geo| (geo.width, geo.height)) .unwrap() } @@ -840,7 +879,8 @@ impl UnownedWindow { height as c_uint, ); self.xconn.flush_requests() - }.expect("Failed to call `XResizeWindow`"); + } + .expect("Failed to call `XResizeWindow`"); } #[inline] @@ -851,11 +891,14 @@ impl UnownedWindow { } fn update_normal_hints(&self, callback: F) -> Result<(), XError> - where F: FnOnce(&mut util::NormalHints) -> () + where + F: FnOnce(&mut util::NormalHints<'_>) -> (), { let mut normal_hints = self.xconn.get_normal_hints(self.xwindow)?; callback(&mut normal_hints); - self.xconn.set_normal_hints(self.xwindow, normal_hints).flush() + self.xconn + .set_normal_hints(self.xwindow, normal_hints) + .flush() } pub(crate) fn set_min_inner_size_physical(&self, dimensions: Option<(u32, u32)>) { @@ -866,9 +909,8 @@ impl UnownedWindow { #[inline] pub fn set_min_inner_size(&self, logical_dimensions: Option) { self.shared_state.lock().min_inner_size = logical_dimensions; - let physical_dimensions = logical_dimensions.map(|logical_dimensions| { - logical_dimensions.to_physical(self.hidpi_factor()).into() - }); + let physical_dimensions = logical_dimensions + .map(|logical_dimensions| logical_dimensions.to_physical(self.hidpi_factor()).into()); self.set_min_inner_size_physical(physical_dimensions); } @@ -880,9 +922,8 @@ impl UnownedWindow { #[inline] pub fn set_max_inner_size(&self, logical_dimensions: Option) { self.shared_state.lock().max_inner_size = logical_dimensions; - let physical_dimensions = logical_dimensions.map(|logical_dimensions| { - logical_dimensions.to_physical(self.hidpi_factor()).into() - }); + let physical_dimensions = logical_dimensions + .map(|logical_dimensions| logical_dimensions.to_physical(self.hidpi_factor()).into()); self.set_max_inner_size_physical(physical_dimensions); } @@ -892,7 +933,7 @@ impl UnownedWindow { new_dpi_factor: f64, width: f64, height: f64, - ) -> (f64, f64, util::Flusher) { + ) -> (f64, f64, util::Flusher<'_>) { let scale_factor = new_dpi_factor / old_dpi_factor; let new_width = width * scale_factor; let new_height = height * scale_factor; @@ -910,7 +951,8 @@ impl UnownedWindow { normal_hints.set_min_size(min_size); normal_hints.set_resize_increments(resize_increments); normal_hints.set_base_size(base_size); - }).expect("Failed to update normal hints"); + }) + .expect("Failed to update normal hints"); unsafe { (self.xconn.xlib.XResizeWindow)( self.xconn.display, @@ -933,12 +975,17 @@ impl UnownedWindow { let (logical_min, logical_max) = if resizable { let shared_state_lock = self.shared_state.lock(); - (shared_state_lock.min_inner_size, shared_state_lock.max_inner_size) + ( + shared_state_lock.min_inner_size, + shared_state_lock.max_inner_size, + ) } else { let window_size = Some(self.inner_size()); (window_size.clone(), window_size) }; + self.set_maximizable_inner(resizable).queue(); + let dpi_factor = self.hidpi_factor(); let min_inner_size = logical_min .map(|logical_size| logical_size.to_physical(dpi_factor)) @@ -949,7 +996,8 @@ impl UnownedWindow { self.update_normal_hints(|normal_hints| { normal_hints.set_min_size(min_inner_size); normal_hints.set_max_size(max_inner_size); - }).expect("Failed to call `XSetWMNormalHints`"); + }) + .expect("Failed to call `XSetWMNormalHints`"); } #[inline] @@ -974,9 +1022,7 @@ impl UnownedWindow { #[inline] pub fn xcb_connection(&self) -> *mut c_void { - unsafe { - (self.xconn.xlib_xcb.XGetXCBConnection)(self.xconn.display) as *mut _ - } + unsafe { (self.xconn.xlib_xcb.XGetXCBConnection)(self.xconn.display) as *mut _ } } fn load_cursor(&self, name: &[u8]) -> ffi::Cursor { @@ -999,13 +1045,9 @@ impl UnownedWindow { } fn get_cursor(&self, cursor: CursorIcon) -> ffi::Cursor { - let load = |name: &[u8]| { - self.load_cursor(name) - }; + let load = |name: &[u8]| self.load_cursor(name); - let loadn = |names: &[&[u8]]| { - self.load_first_existing_cursor(names) - }; + let loadn = |names: &[&[u8]]| self.load_first_existing_cursor(names); // Try multiple names in some cases where the name // differs on the desktop environments or themes. @@ -1030,7 +1072,6 @@ impl UnownedWindow { CursorIcon::NoDrop => loadn(&[b"no-drop\0", b"circle\0"]), CursorIcon::NotAllowed => load(b"crossed_circle\0"), - // Resize cursors CursorIcon::EResize => load(b"right_side\0"), CursorIcon::NResize => load(b"top_side\0"), @@ -1063,7 +1104,9 @@ impl UnownedWindow { if cursor != 0 { (self.xconn.xlib.XFreeCursor)(self.xconn.display, cursor); } - self.xconn.flush_requests().expect("Failed to set or free the cursor"); + self.xconn + .flush_requests() + .expect("Failed to set or free the cursor"); } } @@ -1081,13 +1124,7 @@ impl UnownedWindow { fn create_empty_cursor(&self) -> Option { let data = 0; let pixmap = unsafe { - (self.xconn.xlib.XCreateBitmapFromData)( - self.xconn.display, - self.xwindow, - &data, - 1, - 1, - ) + (self.xconn.xlib.XCreateBitmapFromData)(self.xconn.display, self.xwindow, &data, 1, 1) }; if pixmap == 0 { // Failed to allocate @@ -1116,7 +1153,9 @@ impl UnownedWindow { #[inline] pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> { let mut grabbed_lock = self.cursor_grabbed.lock(); - if grab == *grabbed_lock { return Ok(()); } + if grab == *grabbed_lock { + return Ok(()); + } unsafe { // We ungrab before grabbing to prevent passive grabs from causing `AlreadyGrabbed`. // Therefore, this is common to both codepaths. @@ -1128,8 +1167,7 @@ impl UnownedWindow { self.xconn.display, self.xwindow, ffi::True, - ( - ffi::ButtonPressMask + (ffi::ButtonPressMask | ffi::ButtonReleaseMask | ffi::EnterWindowMask | ffi::LeaveWindowMask @@ -1141,8 +1179,7 @@ impl UnownedWindow { | ffi::Button4MotionMask | ffi::Button5MotionMask | ffi::ButtonMotionMask - | ffi::KeymapStateMask - ) as c_uint, + | ffi::KeymapStateMask) as c_uint, ffi::GrabModeAsync, ffi::GrabModeAsync, self.xwindow, @@ -1153,14 +1190,20 @@ impl UnownedWindow { match result { ffi::GrabSuccess => Ok(()), - ffi::AlreadyGrabbed => Err("Cursor could not be grabbed: already grabbed by another client"), + ffi::AlreadyGrabbed => { + Err("Cursor could not be grabbed: already grabbed by another client") + } ffi::GrabInvalidTime => Err("Cursor could not be grabbed: invalid time"), - ffi::GrabNotViewable => Err("Cursor could not be grabbed: grab location not viewable"), + ffi::GrabNotViewable => { + Err("Cursor could not be grabbed: grab location not viewable") + } ffi::GrabFrozen => Err("Cursor could not be grabbed: frozen by another client"), _ => unreachable!(), - }.map_err(|err| ExternalError::Os(os_error!(OsError::XMisc(err)))) + } + .map_err(|err| ExternalError::Os(os_error!(OsError::XMisc(err)))) } else { - self.xconn.flush_requests() + self.xconn + .flush_requests() .map_err(|err| ExternalError::Os(os_error!(OsError::XError(err)))) }; if result.is_ok() { @@ -1172,11 +1215,14 @@ impl UnownedWindow { #[inline] pub fn set_cursor_visible(&self, visible: bool) { let mut visible_lock = self.cursor_visible.lock(); - if visible == *visible_lock {return; } + if visible == *visible_lock { + return; + } let cursor = if visible { self.get_cursor(*self.cursor.lock()) } else { - self.create_empty_cursor().expect("Failed to create empty cursor") + self.create_empty_cursor() + .expect("Failed to create empty cursor") }; *visible_lock = visible; drop(visible_lock); @@ -1190,29 +1236,25 @@ impl UnownedWindow { pub fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), ExternalError> { unsafe { - (self.xconn.xlib.XWarpPointer)( - self.xconn.display, - 0, - self.xwindow, - 0, - 0, - 0, - 0, - x, - y, - ); - self.xconn.flush_requests().map_err(|e| ExternalError::Os(os_error!(OsError::XError(e)))) + (self.xconn.xlib.XWarpPointer)(self.xconn.display, 0, self.xwindow, 0, 0, 0, 0, x, y); + self.xconn + .flush_requests() + .map_err(|e| ExternalError::Os(os_error!(OsError::XError(e)))) } } #[inline] - pub fn set_cursor_position(&self, logical_position: LogicalPosition) -> Result<(), ExternalError> { + pub fn set_cursor_position( + &self, + logical_position: LogicalPosition, + ) -> Result<(), ExternalError> { let (x, y) = logical_position.to_physical(self.hidpi_factor()).into(); self.set_cursor_position_physical(x, y) } pub(crate) fn set_ime_position_physical(&self, x: i32, y: i32) { - let _ = self.ime_sender + let _ = self + .ime_sender .lock() .send((self.xwindow, x as i16, y as i16)); } @@ -1224,10 +1266,15 @@ impl UnownedWindow { } #[inline] - pub fn id(&self) -> WindowId { WindowId(self.xwindow) } + pub fn id(&self) -> WindowId { + WindowId(self.xwindow) + } #[inline] pub fn request_redraw(&self) { - self.pending_redraws.lock().unwrap().insert(WindowId(self.xwindow)); + self.pending_redraws + .lock() + .unwrap() + .insert(WindowId(self.xwindow)); } } diff --git a/src/platform_impl/linux/x11/xdisplay.rs b/src/platform_impl/linux/x11/xdisplay.rs index 61e441bd..79ace84f 100644 --- a/src/platform_impl/linux/x11/xdisplay.rs +++ b/src/platform_impl/linux/x11/xdisplay.rs @@ -1,7 +1,4 @@ -use std::ptr; -use std::fmt; -use std::error::Error; -use std::os::raw::c_int; +use std::{error::Error, fmt, os::raw::c_int, ptr}; use libc; use parking_lot::Mutex; @@ -27,7 +24,8 @@ pub struct XConnection { unsafe impl Send for XConnection {} unsafe impl Sync for XConnection {} -pub type XErrorHandler = Option libc::c_int>; +pub type XErrorHandler = + Option libc::c_int>; impl XConnection { pub fn new(error_handler: XErrorHandler) -> Result { @@ -53,9 +51,7 @@ impl XConnection { }; // Get X11 socket file descriptor - let fd = unsafe { - (xlib.XConnectionNumber)(display) - }; + let fd = unsafe { (xlib.XConnectionNumber)(display) }; Ok(XConnection { xlib, @@ -90,7 +86,7 @@ impl XConnection { } impl fmt::Debug for XConnection { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.display.fmt(f) } } @@ -119,9 +115,12 @@ impl Error for XError { } impl fmt::Display for XError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(formatter, "X error: {} (code: {}, request code: {}, minor code: {})", - self.description, self.error_code, self.request_code, self.minor_code) + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + write!( + formatter, + "X error: {} (code: {}, request code: {}, minor code: {})", + self.description, self.error_code, self.request_code, self.minor_code + ) } } @@ -131,7 +130,7 @@ pub enum XNotSupported { /// Failed to load one or several shared libraries. LibraryOpenError(ffi::OpenError), /// Connecting to the X server with `XOpenDisplay` failed. - XOpenDisplayFailed, // TODO: add better message + XOpenDisplayFailed, // TODO: add better message } impl From for XNotSupported { @@ -151,16 +150,16 @@ impl Error for XNotSupported { } #[inline] - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { match *self { XNotSupported::LibraryOpenError(ref err) => Some(err), - _ => None + _ => None, } } } impl fmt::Display for XNotSupported { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { formatter.write_str(self.description()) } } diff --git a/src/platform_impl/macos/app.rs b/src/platform_impl/macos/app.rs index 2699eedc..3278cb13 100644 --- a/src/platform_impl/macos/app.rs +++ b/src/platform_impl/macos/app.rs @@ -1,10 +1,18 @@ use std::collections::VecDeque; -use cocoa::{appkit::{self, NSEvent}, base::id}; -use objc::{declare::ClassDecl, runtime::{Class, Object, Sel}}; +use cocoa::{ + appkit::{self, NSEvent}, + base::id, +}; +use objc::{ + declare::ClassDecl, + runtime::{Class, Object, Sel}, +}; -use event::{DeviceEvent, Event}; -use platform_impl::platform::{app_state::AppState, DEVICE_ID, util}; +use crate::{ + event::{DeviceEvent, ElementState, Event}, + platform_impl::platform::{app_state::AppState, util, DEVICE_ID}, +}; pub struct AppClass(pub *const Class); unsafe impl Send for AppClass {} @@ -17,7 +25,7 @@ lazy_static! { decl.add_method( sel!(sendEvent:), - send_event as extern fn(&Object, Sel, id), + send_event as extern "C" fn(&Object, Sel, id), ); AppClass(decl.register()) @@ -27,23 +35,25 @@ lazy_static! { // Normally, holding Cmd + any key never sends us a `keyUp` event for that key. // Overriding `sendEvent:` like this fixes that. (https://stackoverflow.com/a/15294196) // Fun fact: Firefox still has this bug! (https://bugzilla.mozilla.org/show_bug.cgi?id=1299553) -extern fn send_event(this: &Object, _sel: Sel, event: id) { +extern "C" fn send_event(this: &Object, _sel: Sel, event: id) { unsafe { // For posterity, there are some undocumented event types // (https://github.com/servo/cocoa-rs/issues/155) // but that doesn't really matter here. let event_type = event.eventType(); let modifier_flags = event.modifierFlags(); - if event_type == appkit::NSKeyUp && util::has_flag( - modifier_flags, - appkit::NSEventModifierFlags::NSCommandKeyMask, - ) { + if event_type == appkit::NSKeyUp + && util::has_flag( + modifier_flags, + appkit::NSEventModifierFlags::NSCommandKeyMask, + ) + { let key_window: id = msg_send![this, keyWindow]; - let _: () = msg_send![key_window, sendEvent:event]; + let _: () = msg_send![key_window, sendEvent: event]; } else { maybe_dispatch_device_event(event); let superclass = util::superclass(this); - let _: () = msg_send![super(this, superclass), sendEvent:event]; + let _: () = msg_send![super(this, superclass), sendEvent: event]; } } } @@ -51,10 +61,10 @@ extern fn send_event(this: &Object, _sel: Sel, event: id) { unsafe fn maybe_dispatch_device_event(event: id) { let event_type = event.eventType(); match event_type { - appkit::NSMouseMoved | - appkit::NSLeftMouseDragged | - appkit::NSOtherMouseDragged | - appkit::NSRightMouseDragged => { + appkit::NSMouseMoved + | appkit::NSLeftMouseDragged + | appkit::NSOtherMouseDragged + | appkit::NSRightMouseDragged => { let mut events = VecDeque::with_capacity(3); let delta_x = event.deltaX() as f64; @@ -63,26 +73,60 @@ unsafe fn maybe_dispatch_device_event(event: id) { if delta_x != 0.0 { events.push_back(Event::DeviceEvent { device_id: DEVICE_ID, - event: DeviceEvent::Motion { axis: 0, value: delta_x }, + event: DeviceEvent::Motion { + axis: 0, + value: delta_x, + }, }); } if delta_y != 0.0 { events.push_back(Event::DeviceEvent { device_id: DEVICE_ID, - event: DeviceEvent::Motion { axis: 1, value: delta_y }, + event: DeviceEvent::Motion { + axis: 1, + value: delta_y, + }, }); } if delta_x != 0.0 || delta_y != 0.0 { events.push_back(Event::DeviceEvent { device_id: DEVICE_ID, - event: DeviceEvent::MouseMotion { delta: (delta_x, delta_y) }, + event: DeviceEvent::MouseMotion { + delta: (delta_x, delta_y), + }, }); } AppState::queue_events(events); - }, + } + appkit::NSLeftMouseDown | appkit::NSRightMouseDown | appkit::NSOtherMouseDown => { + let mut events = VecDeque::with_capacity(1); + + events.push_back(Event::DeviceEvent { + device_id: DEVICE_ID, + event: DeviceEvent::Button { + button: event.buttonNumber() as u32, + state: ElementState::Pressed, + }, + }); + + AppState::queue_events(events); + } + appkit::NSLeftMouseUp | appkit::NSRightMouseUp | appkit::NSOtherMouseUp => { + let mut events = VecDeque::with_capacity(1); + + events.push_back(Event::DeviceEvent { + device_id: DEVICE_ID, + event: DeviceEvent::Button { + button: event.buttonNumber() as u32, + state: ElementState::Released, + }, + }); + + AppState::queue_events(events); + } _ => (), } } diff --git a/src/platform_impl/macos/app_delegate.rs b/src/platform_impl/macos/app_delegate.rs index 8e4ab19d..c0c3a121 100644 --- a/src/platform_impl/macos/app_delegate.rs +++ b/src/platform_impl/macos/app_delegate.rs @@ -1,7 +1,10 @@ use cocoa::base::id; -use objc::{runtime::{Class, Object, Sel, BOOL, YES}, declare::ClassDecl}; +use objc::{ + declare::ClassDecl, + runtime::{Class, Object, Sel, BOOL, YES}, +}; -use platform_impl::platform::app_state::AppState; +use crate::platform_impl::platform::app_state::AppState; pub struct AppDelegateClass(pub *const Class); unsafe impl Send for AppDelegateClass {} @@ -14,67 +17,67 @@ lazy_static! { decl.add_method( sel!(applicationDidFinishLaunching:), - did_finish_launching as extern fn(&Object, Sel, id) -> BOOL, + did_finish_launching as extern "C" fn(&Object, Sel, id) -> BOOL, ); decl.add_method( sel!(applicationDidBecomeActive:), - did_become_active as extern fn(&Object, Sel, id), + did_become_active as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(applicationWillResignActive:), - will_resign_active as extern fn(&Object, Sel, id), + will_resign_active as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(applicationWillEnterForeground:), - will_enter_foreground as extern fn(&Object, Sel, id), + will_enter_foreground as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(applicationDidEnterBackground:), - did_enter_background as extern fn(&Object, Sel, id), + did_enter_background as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(applicationWillTerminate:), - will_terminate as extern fn(&Object, Sel, id), + will_terminate as extern "C" fn(&Object, Sel, id), ); AppDelegateClass(decl.register()) }; } -extern fn did_finish_launching(_: &Object, _: Sel, _: id) -> BOOL { +extern "C" fn did_finish_launching(_: &Object, _: Sel, _: id) -> BOOL { trace!("Triggered `didFinishLaunching`"); AppState::launched(); trace!("Completed `didFinishLaunching`"); YES } -extern fn did_become_active(_: &Object, _: Sel, _: id) { +extern "C" fn did_become_active(_: &Object, _: Sel, _: id) { trace!("Triggered `didBecomeActive`"); /*unsafe { - HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(false)) + HANDLER.lock().unwrap().handle_nonuser_event(Event::Resumed) }*/ trace!("Completed `didBecomeActive`"); } -extern fn will_resign_active(_: &Object, _: Sel, _: id) { +extern "C" fn will_resign_active(_: &Object, _: Sel, _: id) { trace!("Triggered `willResignActive`"); /*unsafe { - HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(true)) + HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended) }*/ trace!("Completed `willResignActive`"); } -extern fn will_enter_foreground(_: &Object, _: Sel, _: id) { +extern "C" fn will_enter_foreground(_: &Object, _: Sel, _: id) { trace!("Triggered `willEnterForeground`"); trace!("Completed `willEnterForeground`"); } -extern fn did_enter_background(_: &Object, _: Sel, _: id) { +extern "C" fn did_enter_background(_: &Object, _: Sel, _: id) { trace!("Triggered `didEnterBackground`"); trace!("Completed `didEnterBackground`"); } -extern fn will_terminate(_: &Object, _: Sel, _: id) { +extern "C" fn will_terminate(_: &Object, _: Sel, _: id) { trace!("Triggered `willTerminate`"); /*unsafe { let app: id = msg_send![class!(UIApplication), sharedApplication]; diff --git a/src/platform_impl/macos/app_state.rs b/src/platform_impl/macos/app_state.rs index cc9d4b22..cccbb098 100644 --- a/src/platform_impl/macos/app_state.rs +++ b/src/platform_impl/macos/app_state.rs @@ -1,17 +1,23 @@ use std::{ - collections::VecDeque, fmt::{self, Debug, Formatter}, - hint::unreachable_unchecked, mem, - sync::{atomic::{AtomicBool, Ordering}, Mutex, MutexGuard}, time::Instant, + collections::VecDeque, + fmt::{self, Debug}, + hint::unreachable_unchecked, + mem, + sync::{ + atomic::{AtomicBool, Ordering}, + Mutex, MutexGuard, + }, + time::Instant, }; use cocoa::{appkit::NSApp, base::nil}; -use { +use crate::{ event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoopWindowTarget as RootWindowTarget}, + platform_impl::platform::{observer::EventLoopWaker, util::Never}, window::WindowId, }; -use platform_impl::platform::{observer::EventLoopWaker, util::Never}; lazy_static! { static ref HANDLER: Handler = Default::default(); @@ -38,8 +44,9 @@ struct EventLoopHandler { } impl Debug for EventLoopHandler { - fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.debug_struct("EventLoopHandler") + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("EventLoopHandler") .field("window_target", &self.window_target) .finish() } @@ -51,11 +58,7 @@ where T: 'static, { fn handle_nonuser_event(&mut self, event: Event, control_flow: &mut ControlFlow) { - (self.callback)( - event.userify(), - &self.window_target, - control_flow, - ); + (self.callback)(event.userify(), &self.window_target, control_flow); self.will_exit |= *control_flow == ControlFlow::Exit; if self.will_exit { *control_flow = ControlFlow::Exit; @@ -65,11 +68,7 @@ where fn handle_user_events(&mut self, control_flow: &mut ControlFlow) { let mut will_exit = self.will_exit; for event in self.window_target.p.receiver.try_iter() { - (self.callback)( - Event::UserEvent(event), - &self.window_target, - control_flow, - ); + (self.callback)(Event::UserEvent(event), &self.window_target, control_flow); will_exit |= *control_flow == ControlFlow::Exit; if will_exit { *control_flow = ControlFlow::Exit; @@ -167,18 +166,13 @@ impl Handler { fn handle_nonuser_event(&self, event: Event) { if let Some(ref mut callback) = *self.callback.lock().unwrap() { - callback.handle_nonuser_event( - event, - &mut *self.control_flow.lock().unwrap(), - ); + callback.handle_nonuser_event(event, &mut *self.control_flow.lock().unwrap()); } } fn handle_user_events(&self) { if let Some(ref mut callback) = *self.callback.lock().unwrap() { - callback.handle_user_events( - &mut *self.control_flow.lock().unwrap(), - ); + callback.handle_user_events(&mut *self.control_flow.lock().unwrap()); } } } @@ -213,7 +207,9 @@ impl AppState { } pub fn wakeup() { - if !HANDLER.is_ready() { return } + if !HANDLER.is_ready() { + return; + } let start = HANDLER.get_start_time().unwrap(); let cause = match HANDLER.get_control_flow_and_update_prev() { ControlFlow::Poll => StartCause::Poll, @@ -233,8 +229,8 @@ impl AppState { requested_resume: Some(requested_resume), } } - }, - ControlFlow::Exit => StartCause::Poll,//panic!("unexpected `ControlFlow::Exit`"), + } + ControlFlow::Exit => StartCause::Poll, //panic!("unexpected `ControlFlow::Exit`"), }; HANDLER.set_in_callback(true); HANDLER.handle_nonuser_event(Event::NewEvents(cause)); @@ -278,7 +274,9 @@ impl AppState { } pub fn cleared() { - if !HANDLER.is_ready() { return } + if !HANDLER.is_ready() { + return; + } if !HANDLER.get_in_callback() { HANDLER.set_in_callback(true); HANDLER.handle_user_events(); @@ -295,8 +293,8 @@ impl AppState { HANDLER.set_in_callback(false); } if HANDLER.should_exit() { - let _: () = unsafe { msg_send![NSApp(), stop:nil] }; - return + let _: () = unsafe { msg_send![NSApp(), stop: nil] }; + return; } HANDLER.update_start_time(); match HANDLER.get_old_and_new_control_flow() { diff --git a/src/platform_impl/macos/event.rs b/src/platform_impl/macos/event.rs index c19c5300..02d6b9c2 100644 --- a/src/platform_impl/macos/event.rs +++ b/src/platform_impl/macos/event.rs @@ -1,12 +1,14 @@ use std::os::raw::c_ushort; -use cocoa::{appkit::{NSEvent, NSEventModifierFlags}, base::id}; - -use event::{ - ElementState, KeyboardInput, - ModifiersState, VirtualKeyCode, WindowEvent, +use cocoa::{ + appkit::{NSEvent, NSEventModifierFlags}, + base::id, +}; + +use crate::{ + event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent}, + platform_impl::platform::DEVICE_ID, }; -use platform_impl::platform::DEVICE_ID; pub fn char_to_keycode(c: char) -> Option { // We only translate keys that are affected by keyboard layout. @@ -57,9 +59,9 @@ pub fn char_to_keycode(c: char) -> Option { '-' | '_' => VirtualKeyCode::Minus, ']' | '}' => VirtualKeyCode::RBracket, '[' | '{' => VirtualKeyCode::LBracket, - '\''| '"' => VirtualKeyCode::Apostrophe, + '\'' | '"' => VirtualKeyCode::Apostrophe, ';' | ':' => VirtualKeyCode::Semicolon, - '\\'| '|' => VirtualKeyCode::Backslash, + '\\' | '|' => VirtualKeyCode::Backslash, ',' | '<' => VirtualKeyCode::Comma, '/' | '?' => VirtualKeyCode::Slash, '.' | '>' => VirtualKeyCode::Period, @@ -198,7 +200,6 @@ pub fn scancode_to_keycode(scancode: c_ushort) -> Option { 0x7d => VirtualKeyCode::Down, 0x7e => VirtualKeyCode::Up, //0x7f => unkown, - 0xa => VirtualKeyCode::Caret, _ => return None, }) @@ -215,16 +216,14 @@ pub fn check_function_keys(string: &String) -> Option { 0xf71a => VirtualKeyCode::F23, 0xf71b => VirtualKeyCode::F24, _ => return None, - }) + }); } None } pub fn event_mods(event: id) -> ModifiersState { - let flags = unsafe { - NSEvent::modifierFlags(event) - }; + let flags = unsafe { NSEvent::modifierFlags(event) }; ModifiersState { shift: flags.contains(NSEventModifierFlags::NSShiftKeyMask), ctrl: flags.contains(NSEventModifierFlags::NSControlKeyMask), @@ -238,9 +237,7 @@ pub fn get_scancode(event: cocoa::base::id) -> c_ushort { // and there is no easy way to navtively retrieve the layout-dependent character. // In winit, we use keycode to refer to the key's character, and so this function aligns // AppKit's terminology with ours. - unsafe { - msg_send![event, keyCode] - } + unsafe { msg_send![event, keyCode] } } pub unsafe fn modifier_event( @@ -249,7 +246,8 @@ pub unsafe fn modifier_event( was_key_pressed: bool, ) -> Option { if !was_key_pressed && NSEvent::modifierFlags(ns_event).contains(keymask) - || was_key_pressed && !NSEvent::modifierFlags(ns_event).contains(keymask) { + || was_key_pressed && !NSEvent::modifierFlags(ns_event).contains(keymask) + { let state = if was_key_pressed { ElementState::Released } else { diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index 510dd84b..2ad17e1d 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -1,17 +1,24 @@ use std::{ - collections::VecDeque, mem, os::raw::c_void, process, ptr, sync::mpsc, marker::PhantomData + collections::VecDeque, marker::PhantomData, mem, os::raw::c_void, process, ptr, sync::mpsc, }; -use cocoa::{appkit::NSApp, base::{id, nil}, foundation::NSAutoreleasePool}; +use cocoa::{ + appkit::NSApp, + base::{id, nil}, + foundation::NSAutoreleasePool, +}; -use { +use crate::{ event::Event, event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootWindowTarget}, -}; -use platform_impl::platform::{ - app::APP_CLASS, app_delegate::APP_DELEGATE_CLASS, - app_state::AppState, monitor::{self, MonitorHandle}, - observer::*, util::IdRef, + platform_impl::platform::{ + app::APP_CLASS, + app_delegate::APP_DELEGATE_CLASS, + app_state::AppState, + monitor::{self, MonitorHandle}, + observer::*, + util::IdRef, + }, }; pub struct EventLoopWindowTarget { @@ -75,7 +82,8 @@ impl EventLoop { } pub fn run(self, callback: F) -> ! - where F: 'static + FnMut(Event, &RootWindowTarget, &mut ControlFlow), + where + F: 'static + FnMut(Event, &RootWindowTarget, &mut ControlFlow), { unsafe { let _pool = NSAutoreleasePool::new(nil); @@ -89,7 +97,8 @@ impl EventLoop { } pub fn run_return(&mut self, _callback: F) - where F: FnMut(Event, &RootWindowTarget, &mut ControlFlow), + where + F: FnMut(Event, &RootWindowTarget, &mut ControlFlow), { unimplemented!(); } @@ -119,11 +128,8 @@ impl Proxy { let rl = CFRunLoopGetMain(); let mut context: CFRunLoopSourceContext = mem::zeroed(); context.perform = event_loop_proxy_handler; - let source = CFRunLoopSourceCreate( - ptr::null_mut(), - CFIndex::max_value() - 1, - &mut context, - ); + let source = + CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context); CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes); CFRunLoopWakeUp(rl); diff --git a/src/platform_impl/macos/ffi.rs b/src/platform_impl/macos/ffi.rs index d199ebb6..7ddcdf6f 100644 --- a/src/platform_impl/macos/ffi.rs +++ b/src/platform_impl/macos/ffi.rs @@ -2,8 +2,10 @@ #![allow(dead_code, non_snake_case, non_upper_case_globals)] -use cocoa::base::id; -use cocoa::foundation::{NSInteger, NSUInteger}; +use cocoa::{ + base::id, + foundation::{NSInteger, NSUInteger}, +}; use objc; pub const NSNotFound: NSInteger = NSInteger::max_value(); @@ -53,11 +55,11 @@ impl NSMutableAttributedString for id { } unsafe fn initWithString(self, string: id) -> id { - msg_send![self, initWithString:string] + msg_send![self, initWithString: string] } unsafe fn initWithAttributedString(self, string: id) -> id { - msg_send![self, initWithAttributedString:string] + msg_send![self, initWithAttributedString: string] } unsafe fn string(self) -> id { diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index 2b5d9f5d..02b63515 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -15,16 +15,13 @@ mod window_delegate; use std::{fmt, ops::Deref, sync::Arc}; -use { - event::DeviceId as RootDeviceId, window::WindowAttributes, - error::OsError as RootOsError, -}; pub use self::{ event_loop::{EventLoop, EventLoopWindowTarget, Proxy as EventLoopProxy}, monitor::MonitorHandle, - window::{ - Id as WindowId, PlatformSpecificWindowBuilderAttributes, UnownedWindow, - }, + window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, UnownedWindow}, +}; +use crate::{ + error::OsError as RootOsError, event::DeviceId as RootDeviceId, window::WindowAttributes, }; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -48,7 +45,7 @@ pub struct Window { #[derive(Debug)] pub enum OsError { CGError(core_graphics::base::CGError), - CreationError(&'static str) + CreationError(&'static str), } unsafe impl Send for Window {} @@ -74,7 +71,7 @@ impl Window { } impl fmt::Display for OsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { OsError::CGError(e) => f.pad(&format!("CGError {}", e)), OsError::CreationError(e) => f.pad(e), diff --git a/src/platform_impl/macos/monitor.rs b/src/platform_impl/macos/monitor.rs index 78e4e3ec..cf74c644 100644 --- a/src/platform_impl/macos/monitor.rs +++ b/src/platform_impl/macos/monitor.rs @@ -1,10 +1,21 @@ use std::{collections::VecDeque, fmt}; -use cocoa::{appkit::NSScreen, base::{id, nil}, foundation::{NSString, NSUInteger}}; -use core_graphics::display::{CGDirectDisplayID, CGDisplay, CGDisplayBounds}; +use cocoa::{ + appkit::NSScreen, + base::{id, nil}, + foundation::{NSString, NSUInteger}, +}; +use core_graphics::display::{CGDirectDisplayID, CGDisplay, CGDisplayBounds, CGDisplayMode}; +use core_video_sys::{ + kCVReturnSuccess, kCVTimeIsIndefinite, CVDisplayLinkCreateWithCGDisplay, + CVDisplayLinkGetNominalOutputVideoRefreshPeriod, CVDisplayLinkRelease, +}; -use dpi::{PhysicalPosition, PhysicalSize}; -use platform_impl::platform::util::IdRef; +use crate::{ + dpi::{PhysicalPosition, PhysicalSize}, + monitor::VideoMode, + platform_impl::platform::util::IdRef, +}; #[derive(Clone, PartialEq)] pub struct MonitorHandle(CGDirectDisplayID); @@ -26,13 +37,13 @@ pub fn primary_monitor() -> MonitorHandle { } impl fmt::Debug for MonitorHandle { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // TODO: Do this using the proper fmt API #[derive(Debug)] struct MonitorHandle { name: Option, native_identifier: u32, - dimensions: PhysicalSize, + size: PhysicalSize, position: PhysicalPosition, hidpi_factor: f64, } @@ -40,7 +51,7 @@ impl fmt::Debug for MonitorHandle { let monitor_id_proxy = MonitorHandle { name: self.name(), native_identifier: self.native_identifier(), - dimensions: self.dimensions(), + size: self.size(), position: self.position(), hidpi_factor: self.hidpi_factor(), }; @@ -65,15 +76,12 @@ impl MonitorHandle { self.0 } - pub fn dimensions(&self) -> PhysicalSize { + pub fn size(&self) -> PhysicalSize { let MonitorHandle(display_id) = *self; let display = CGDisplay::new(display_id); let height = display.pixels_high(); let width = display.pixels_wide(); - PhysicalSize::from_logical( - (width as f64, height as f64), - self.hidpi_factor(), - ) + PhysicalSize::from_logical((width as f64, height as f64), self.hidpi_factor()) } #[inline] @@ -86,14 +94,52 @@ impl MonitorHandle { } pub fn hidpi_factor(&self) -> f64 { - let screen = match self.nsscreen() { + let screen = match self.ns_screen() { Some(screen) => screen, None => return 1.0, // default to 1.0 when we can't find the screen }; unsafe { NSScreen::backingScaleFactor(screen) as f64 } } - pub(crate) fn nsscreen(&self) -> Option { + pub fn video_modes(&self) -> impl Iterator { + let cv_refresh_rate = unsafe { + let mut display_link = std::ptr::null_mut(); + assert_eq!( + CVDisplayLinkCreateWithCGDisplay(self.0, &mut display_link), + kCVReturnSuccess + ); + let time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(display_link); + CVDisplayLinkRelease(display_link); + + // This value is indefinite if an invalid display link was specified + assert!(time.flags & kCVTimeIsIndefinite == 0); + + time.timeScale as i64 / time.timeValue + }; + + CGDisplayMode::all_display_modes(self.0, std::ptr::null()) + .expect("failed to obtain list of display modes") + .into_iter() + .map(move |mode| { + let cg_refresh_rate = mode.refresh_rate().round() as i64; + + // CGDisplayModeGetRefreshRate returns 0.0 for any display that + // isn't a CRT + let refresh_rate = if cg_refresh_rate > 0 { + cg_refresh_rate + } else { + cv_refresh_rate + }; + + VideoMode { + size: (mode.width() as u32, mode.height() as u32), + refresh_rate: refresh_rate as u16, + bit_depth: mode.bit_depth() as u16, + } + }) + } + + pub(crate) fn ns_screen(&self) -> Option { unsafe { let native_id = self.native_identifier(); let screens = NSScreen::screens(nil); diff --git a/src/platform_impl/macos/observer.rs b/src/platform_impl/macos/observer.rs index 79b4c997..ddd20a8f 100644 --- a/src/platform_impl/macos/observer.rs +++ b/src/platform_impl/macos/observer.rs @@ -1,9 +1,9 @@ -use std::{self, ptr, os::raw::*, time::Instant}; +use std::{self, os::raw::*, ptr, time::Instant}; -use platform_impl::platform::app_state::AppState; +use crate::platform_impl::platform::app_state::AppState; #[link(name = "CoreFoundation", kind = "framework")] -extern { +extern "C" { pub static kCFRunLoopDefaultMode: CFRunLoopMode; pub static kCFRunLoopCommonModes: CFRunLoopMode; @@ -33,15 +33,8 @@ extern { callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext, ) -> CFRunLoopTimerRef; - pub fn CFRunLoopAddTimer( - rl: CFRunLoopRef, - timer: CFRunLoopTimerRef, - mode: CFRunLoopMode, - ); - pub fn CFRunLoopTimerSetNextFireDate( - timer: CFRunLoopTimerRef, - fireDate: CFAbsoluteTime, - ); + pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFRunLoopMode); + pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime); pub fn CFRunLoopTimerInvalidate(time: CFRunLoopTimerRef); pub fn CFRunLoopSourceCreate( @@ -49,11 +42,8 @@ extern { order: CFIndex, context: *mut CFRunLoopSourceContext, ) -> CFRunLoopSourceRef; - pub fn CFRunLoopAddSource( - rl: CFRunLoopRef, - source: CFRunLoopSourceRef, - mode: CFRunLoopMode, - ); + pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFRunLoopMode); + #[allow(dead_code)] pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef); pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef); @@ -62,6 +52,7 @@ extern { } pub type Boolean = u8; +#[allow(dead_code)] const FALSE: Boolean = 0; const TRUE: Boolean = 1; @@ -87,24 +78,23 @@ pub type CFRunLoopActivity = CFOptionFlags; pub type CFAbsoluteTime = CFTimeInterval; pub type CFTimeInterval = f64; +#[allow(non_upper_case_globals)] pub const kCFRunLoopEntry: CFRunLoopActivity = 0; +#[allow(non_upper_case_globals)] pub const kCFRunLoopBeforeWaiting: CFRunLoopActivity = 1 << 5; +#[allow(non_upper_case_globals)] pub const kCFRunLoopAfterWaiting: CFRunLoopActivity = 1 << 6; +#[allow(non_upper_case_globals)] pub const kCFRunLoopExit: CFRunLoopActivity = 1 << 7; -pub type CFRunLoopObserverCallBack = extern "C" fn( - observer: CFRunLoopObserverRef, - activity: CFRunLoopActivity, - info: *mut c_void, -); -pub type CFRunLoopTimerCallBack = extern "C" fn( - timer: CFRunLoopTimerRef, - info: *mut c_void -); +pub type CFRunLoopObserverCallBack = + extern "C" fn(observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void); +pub type CFRunLoopTimerCallBack = extern "C" fn(timer: CFRunLoopTimerRef, info: *mut c_void); pub enum CFRunLoopObserverContext {} pub enum CFRunLoopTimerContext {} +#[allow(non_snake_case)] #[repr(C)] pub struct CFRunLoopSourceContext { pub version: CFIndex, @@ -120,7 +110,7 @@ pub struct CFRunLoopSourceContext { } // begin is queued with the highest priority to ensure it is processed before other observers -extern fn control_flow_begin_handler( +extern "C" fn control_flow_begin_handler( _: CFRunLoopObserverRef, activity: CFRunLoopActivity, _: *mut c_void, @@ -131,7 +121,7 @@ extern fn control_flow_begin_handler( //trace!("Triggered `CFRunLoopAfterWaiting`"); AppState::wakeup(); //trace!("Completed `CFRunLoopAfterWaiting`"); - }, + } kCFRunLoopEntry => unimplemented!(), // not expected to ever happen _ => unreachable!(), } @@ -139,7 +129,7 @@ extern fn control_flow_begin_handler( // end is queued with the lowest priority to ensure it is processed after other observers // without that, LoopDestroyed would get sent after EventsCleared -extern fn control_flow_end_handler( +extern "C" fn control_flow_end_handler( _: CFRunLoopObserverRef, activity: CFRunLoopActivity, _: *mut c_void, @@ -150,8 +140,8 @@ extern fn control_flow_end_handler( //trace!("Triggered `CFRunLoopBeforeWaiting`"); AppState::cleared(); //trace!("Completed `CFRunLoopBeforeWaiting`"); - }, - kCFRunLoopExit => (),//unimplemented!(), // not expected to ever happen + } + kCFRunLoopExit => (), //unimplemented!(), // not expected to ever happen _ => unreachable!(), } } @@ -172,7 +162,7 @@ impl RunLoop { let observer = CFRunLoopObserverCreate( ptr::null_mut(), flags, - TRUE, // Indicates we want this to run repeatedly + TRUE, // Indicates we want this to run repeatedly priority, // The lower the value, the sooner this will run handler, ptr::null_mut(), @@ -197,7 +187,6 @@ pub fn setup_control_flow_observers() { } } - pub struct EventLoopWaker { timer: CFRunLoopTimerRef, } @@ -213,7 +202,7 @@ impl Drop for EventLoopWaker { impl Default for EventLoopWaker { fn default() -> EventLoopWaker { - extern fn wakeup_main_loop(_timer: CFRunLoopTimerRef, _info: *mut c_void) {} + extern "C" fn wakeup_main_loop(_timer: CFRunLoopTimerRef, _info: *mut c_void) {} unsafe { // create a timer with a 1µs interval (1ns does not work) to mimic polling. // it is initially setup with a first fire time really far into the @@ -250,8 +239,8 @@ impl EventLoopWaker { unsafe { let current = CFAbsoluteTimeGetCurrent(); let duration = instant - now; - let fsecs = duration.subsec_nanos() as f64 / 1_000_000_000.0 - + duration.as_secs() as f64; + let fsecs = + duration.subsec_nanos() as f64 / 1_000_000_000.0 + duration.as_secs() as f64; CFRunLoopTimerSetNextFireDate(self.timer, current + fsecs) } } diff --git a/src/platform_impl/macos/util/async.rs b/src/platform_impl/macos/util/async.rs index 4ececc03..bb8655fc 100644 --- a/src/platform_impl/macos/util/async.rs +++ b/src/platform_impl/macos/util/async.rs @@ -1,42 +1,47 @@ -use std::{os::raw::c_void, sync::{Mutex, Weak}}; +use std::{ + os::raw::c_void, + sync::{Mutex, Weak}, +}; use cocoa::{ - appkit::{CGFloat, NSWindow, NSWindowStyleMask}, + appkit::{CGFloat, NSScreen, NSWindow, NSWindowStyleMask}, base::{id, nil}, - foundation::{NSAutoreleasePool, NSPoint, NSSize}, + foundation::{NSAutoreleasePool, NSPoint, NSSize, NSString}, }; use dispatch::ffi::{dispatch_async_f, dispatch_get_main_queue, dispatch_sync_f}; -use dpi::LogicalSize; -use platform_impl::platform::{ffi, window::SharedState}; +use crate::{ + dpi::LogicalSize, + platform_impl::platform::{ffi, util::IdRef, window::SharedState}, +}; -unsafe fn set_style_mask(nswindow: id, nsview: id, mask: NSWindowStyleMask) { - nswindow.setStyleMask_(mask); +unsafe fn set_style_mask(ns_window: id, ns_view: id, mask: NSWindowStyleMask) { + ns_window.setStyleMask_(mask); // If we don't do this, key handling will break // (at least until the window is clicked again/etc.) - nswindow.makeFirstResponder_(nsview); + ns_window.makeFirstResponder_(ns_view); } struct SetStyleMaskData { - nswindow: id, - nsview: id, + ns_window: id, + ns_view: id, mask: NSWindowStyleMask, } impl SetStyleMaskData { - fn new_ptr( - nswindow: id, - nsview: id, - mask: NSWindowStyleMask, - ) -> *mut Self { - Box::into_raw(Box::new(SetStyleMaskData { nswindow, nsview, mask })) + fn new_ptr(ns_window: id, ns_view: id, mask: NSWindowStyleMask) -> *mut Self { + Box::into_raw(Box::new(SetStyleMaskData { + ns_window, + ns_view, + mask, + })) } } -extern fn set_style_mask_callback(context: *mut c_void) { +extern "C" fn set_style_mask_callback(context: *mut c_void) { unsafe { let context_ptr = context as *mut SetStyleMaskData; { let context = &*context_ptr; - set_style_mask(context.nswindow, context.nsview, context.mask); + set_style_mask(context.ns_window, context.ns_view, context.mask); } Box::from_raw(context_ptr); } @@ -45,16 +50,16 @@ extern fn set_style_mask_callback(context: *mut c_void) { // `setStyleMask:` isn't thread-safe, so we have to use Grand Central Dispatch. // Otherwise, this would vomit out errors about not being on the main thread // and fail to do anything. -pub unsafe fn set_style_mask_async(nswindow: id, nsview: id, mask: NSWindowStyleMask) { - let context = SetStyleMaskData::new_ptr(nswindow, nsview, mask); +pub unsafe fn set_style_mask_async(ns_window: id, ns_view: id, mask: NSWindowStyleMask) { + let context = SetStyleMaskData::new_ptr(ns_window, ns_view, mask); dispatch_async_f( dispatch_get_main_queue(), context as *mut _, set_style_mask_callback, ); } -pub unsafe fn set_style_mask_sync(nswindow: id, nsview: id, mask: NSWindowStyleMask) { - let context = SetStyleMaskData::new_ptr(nswindow, nsview, mask); +pub unsafe fn set_style_mask_sync(ns_window: id, ns_view: id, mask: NSWindowStyleMask) { + let context = SetStyleMaskData::new_ptr(ns_window, ns_view, mask); dispatch_sync_f( dispatch_get_main_queue(), context as *mut _, @@ -63,24 +68,21 @@ pub unsafe fn set_style_mask_sync(nswindow: id, nsview: id, mask: NSWindowStyleM } struct SetContentSizeData { - nswindow: id, + ns_window: id, size: LogicalSize, } impl SetContentSizeData { - fn new_ptr( - nswindow: id, - size: LogicalSize, - ) -> *mut Self { - Box::into_raw(Box::new(SetContentSizeData { nswindow, size })) + fn new_ptr(ns_window: id, size: LogicalSize) -> *mut Self { + Box::into_raw(Box::new(SetContentSizeData { ns_window, size })) } } -extern fn set_content_size_callback(context: *mut c_void) { +extern "C" fn set_content_size_callback(context: *mut c_void) { unsafe { let context_ptr = context as *mut SetContentSizeData; { let context = &*context_ptr; NSWindow::setContentSize_( - context.nswindow, + context.ns_window, NSSize::new( context.size.width as CGFloat, context.size.height as CGFloat, @@ -92,8 +94,8 @@ extern fn set_content_size_callback(context: *mut c_void) { } // `setContentSize:` isn't thread-safe either, though it doesn't log any errors // and just fails silently. Anyway, GCD to the rescue! -pub unsafe fn set_content_size_async(nswindow: id, size: LogicalSize) { - let context = SetContentSizeData::new_ptr(nswindow, size); +pub unsafe fn set_content_size_async(ns_window: id, size: LogicalSize) { + let context = SetContentSizeData::new_ptr(ns_window, size); dispatch_async_f( dispatch_get_main_queue(), context as *mut _, @@ -102,31 +104,28 @@ pub unsafe fn set_content_size_async(nswindow: id, size: LogicalSize) { } struct SetFrameTopLeftPointData { - nswindow: id, + ns_window: id, point: NSPoint, } impl SetFrameTopLeftPointData { - fn new_ptr( - nswindow: id, - point: NSPoint, - ) -> *mut Self { - Box::into_raw(Box::new(SetFrameTopLeftPointData { nswindow, point })) + fn new_ptr(ns_window: id, point: NSPoint) -> *mut Self { + Box::into_raw(Box::new(SetFrameTopLeftPointData { ns_window, point })) } } -extern fn set_frame_top_left_point_callback(context: *mut c_void) { +extern "C" fn set_frame_top_left_point_callback(context: *mut c_void) { unsafe { let context_ptr = context as *mut SetFrameTopLeftPointData; { let context = &*context_ptr; - NSWindow::setFrameTopLeftPoint_(context.nswindow, context.point); + NSWindow::setFrameTopLeftPoint_(context.ns_window, context.point); } Box::from_raw(context_ptr); } } // `setFrameTopLeftPoint:` isn't thread-safe, but fortunately has the courtesy // to log errors. -pub unsafe fn set_frame_top_left_point_async(nswindow: id, point: NSPoint) { - let context = SetFrameTopLeftPointData::new_ptr(nswindow, point); +pub unsafe fn set_frame_top_left_point_async(ns_window: id, point: NSPoint) { + let context = SetFrameTopLeftPointData::new_ptr(ns_window, point); dispatch_async_f( dispatch_get_main_queue(), context as *mut _, @@ -135,30 +134,27 @@ pub unsafe fn set_frame_top_left_point_async(nswindow: id, point: NSPoint) { } struct SetLevelData { - nswindow: id, + ns_window: id, level: ffi::NSWindowLevel, } impl SetLevelData { - fn new_ptr( - nswindow: id, - level: ffi::NSWindowLevel, - ) -> *mut Self { - Box::into_raw(Box::new(SetLevelData { nswindow, level })) + fn new_ptr(ns_window: id, level: ffi::NSWindowLevel) -> *mut Self { + Box::into_raw(Box::new(SetLevelData { ns_window, level })) } } -extern fn set_level_callback(context: *mut c_void) { +extern "C" fn set_level_callback(context: *mut c_void) { unsafe { let context_ptr = context as *mut SetLevelData; { let context = &*context_ptr; - context.nswindow.setLevel_(context.level as _); + context.ns_window.setLevel_(context.level as _); } Box::from_raw(context_ptr); } } // `setFrameTopLeftPoint:` isn't thread-safe, and fails silently. -pub unsafe fn set_level_async(nswindow: id, level: ffi::NSWindowLevel) { - let context = SetLevelData::new_ptr(nswindow, level); +pub unsafe fn set_level_async(ns_window: id, level: ffi::NSWindowLevel) { + let context = SetLevelData::new_ptr(ns_window, level); dispatch_async_f( dispatch_get_main_queue(), context as *mut _, @@ -167,27 +163,27 @@ pub unsafe fn set_level_async(nswindow: id, level: ffi::NSWindowLevel) { } struct ToggleFullScreenData { - nswindow: id, - nsview: id, + ns_window: id, + ns_view: id, not_fullscreen: bool, shared_state: Weak>, } impl ToggleFullScreenData { fn new_ptr( - nswindow: id, - nsview: id, + ns_window: id, + ns_view: id, not_fullscreen: bool, shared_state: Weak>, ) -> *mut Self { Box::into_raw(Box::new(ToggleFullScreenData { - nswindow, - nsview, + ns_window, + ns_view, not_fullscreen, shared_state, })) } } -extern fn toggle_full_screen_callback(context: *mut c_void) { +extern "C" fn toggle_full_screen_callback(context: *mut c_void) { unsafe { let context_ptr = context as *mut ToggleFullScreenData; { @@ -197,11 +193,11 @@ extern fn toggle_full_screen_callback(context: *mut c_void) { // set a normal style temporarily. The previous state will be // restored in `WindowDelegate::window_did_exit_fullscreen`. if context.not_fullscreen { - let curr_mask = context.nswindow.styleMask(); + let curr_mask = context.ns_window.styleMask(); let required = NSWindowStyleMask::NSTitledWindowMask | NSWindowStyleMask::NSResizableWindowMask; if !curr_mask.contains(required) { - set_style_mask(context.nswindow, context.nsview, required); + set_style_mask(context.ns_window, context.ns_view, required); if let Some(shared_state) = context.shared_state.upgrade() { trace!("Locked shared state in `toggle_full_screen_callback`"); let mut shared_state_lock = shared_state.lock().unwrap(); @@ -211,7 +207,7 @@ extern fn toggle_full_screen_callback(context: *mut c_void) { } } - context.nswindow.toggleFullScreen_(nil); + context.ns_window.toggleFullScreen_(nil); } Box::from_raw(context_ptr); } @@ -219,17 +215,12 @@ extern fn toggle_full_screen_callback(context: *mut c_void) { // `toggleFullScreen` is thread-safe, but our additional logic to account for // window styles isn't. pub unsafe fn toggle_full_screen_async( - nswindow: id, - nsview: id, + ns_window: id, + ns_view: id, not_fullscreen: bool, shared_state: Weak>, ) { - let context = ToggleFullScreenData::new_ptr( - nswindow, - nsview, - not_fullscreen, - shared_state, - ); + let context = ToggleFullScreenData::new_ptr(ns_window, ns_view, not_fullscreen, shared_state); dispatch_async_f( dispatch_get_main_queue(), context as *mut _, @@ -237,28 +228,105 @@ pub unsafe fn toggle_full_screen_async( ); } -struct OrderOutData { - nswindow: id, +struct SetMaximizedData { + ns_window: id, + is_zoomed: bool, + maximized: bool, + shared_state: Weak>, } -impl OrderOutData { - fn new_ptr(nswindow: id) -> *mut Self { - Box::into_raw(Box::new(OrderOutData { nswindow })) +impl SetMaximizedData { + fn new_ptr( + ns_window: id, + is_zoomed: bool, + maximized: bool, + shared_state: Weak>, + ) -> *mut Self { + Box::into_raw(Box::new(SetMaximizedData { + ns_window, + is_zoomed, + maximized, + shared_state, + })) } } -extern fn order_out_callback(context: *mut c_void) { +extern "C" fn set_maximized_callback(context: *mut c_void) { + unsafe { + let context_ptr = context as *mut SetMaximizedData; + { + let context = &*context_ptr; + + if let Some(shared_state) = context.shared_state.upgrade() { + trace!("Locked shared state in `set_maximized`"); + let mut shared_state_lock = shared_state.lock().unwrap(); + + // Save the standard frame sized if it is not zoomed + if !context.is_zoomed { + shared_state_lock.standard_frame = Some(NSWindow::frame(context.ns_window)); + } + + shared_state_lock.maximized = context.maximized; + + let curr_mask = context.ns_window.styleMask(); + if shared_state_lock.fullscreen.is_some() { + // Handle it in window_did_exit_fullscreen + return; + } else if curr_mask.contains(NSWindowStyleMask::NSResizableWindowMask) { + // Just use the native zoom if resizable + context.ns_window.zoom_(nil); + } else { + // if it's not resizable, we set the frame directly + let new_rect = if context.maximized { + let screen = NSScreen::mainScreen(nil); + NSScreen::visibleFrame(screen) + } else { + shared_state_lock.saved_standard_frame() + }; + context.ns_window.setFrame_display_(new_rect, 0); + } + + trace!("Unlocked shared state in `set_maximized`"); + } + } + Box::from_raw(context_ptr); + } +} +// `setMaximized` is not thread-safe +pub unsafe fn set_maximized_async( + ns_window: id, + is_zoomed: bool, + maximized: bool, + shared_state: Weak>, +) { + let context = SetMaximizedData::new_ptr(ns_window, is_zoomed, maximized, shared_state); + dispatch_async_f( + dispatch_get_main_queue(), + context as *mut _, + set_maximized_callback, + ); +} + +struct OrderOutData { + ns_window: id, +} +impl OrderOutData { + fn new_ptr(ns_window: id) -> *mut Self { + Box::into_raw(Box::new(OrderOutData { ns_window })) + } +} +extern "C" fn order_out_callback(context: *mut c_void) { unsafe { let context_ptr = context as *mut OrderOutData; { let context = &*context_ptr; - context.nswindow.orderOut_(nil); + context.ns_window.orderOut_(nil); } Box::from_raw(context_ptr); } } // `orderOut:` isn't thread-safe. Calling it from another thread actually works, // but with an odd delay. -pub unsafe fn order_out_async(nswindow: id) { - let context = OrderOutData::new_ptr(nswindow); +pub unsafe fn order_out_async(ns_window: id) { + let context = OrderOutData::new_ptr(ns_window); dispatch_async_f( dispatch_get_main_queue(), context as *mut _, @@ -267,27 +335,27 @@ pub unsafe fn order_out_async(nswindow: id) { } struct MakeKeyAndOrderFrontData { - nswindow: id, + ns_window: id, } impl MakeKeyAndOrderFrontData { - fn new_ptr(nswindow: id) -> *mut Self { - Box::into_raw(Box::new(MakeKeyAndOrderFrontData { nswindow })) + fn new_ptr(ns_window: id) -> *mut Self { + Box::into_raw(Box::new(MakeKeyAndOrderFrontData { ns_window })) } } -extern fn make_key_and_order_front_callback(context: *mut c_void) { +extern "C" fn make_key_and_order_front_callback(context: *mut c_void) { unsafe { let context_ptr = context as *mut MakeKeyAndOrderFrontData; { let context = &*context_ptr; - context.nswindow.makeKeyAndOrderFront_(nil); + context.ns_window.makeKeyAndOrderFront_(nil); } Box::from_raw(context_ptr); } } // `makeKeyAndOrderFront:` isn't thread-safe. Calling it from another thread // actually works, but with an odd delay. -pub unsafe fn make_key_and_order_front_async(nswindow: id) { - let context = MakeKeyAndOrderFrontData::new_ptr(nswindow); +pub unsafe fn make_key_and_order_front_async(ns_window: id) { + let context = MakeKeyAndOrderFrontData::new_ptr(ns_window); dispatch_async_f( dispatch_get_main_queue(), context as *mut _, @@ -295,21 +363,53 @@ pub unsafe fn make_key_and_order_front_async(nswindow: id) { ); } -struct CloseData { - nswindow: id, +struct SetTitleData { + ns_window: id, + title: String, } -impl CloseData { - fn new_ptr(nswindow: id) -> *mut Self { - Box::into_raw(Box::new(CloseData { nswindow })) +impl SetTitleData { + fn new_ptr(ns_window: id, title: String) -> *mut Self { + Box::into_raw(Box::new(SetTitleData { ns_window, title })) } } -extern fn close_callback(context: *mut c_void) { +extern "C" fn set_title_callback(context: *mut c_void) { + unsafe { + let context_ptr = context as *mut SetTitleData; + { + let context = &*context_ptr; + let title = IdRef::new(NSString::alloc(nil).init_str(&context.title)); + context.ns_window.setTitle_(*title); + } + Box::from_raw(context_ptr); + } +} +// `setTitle:` isn't thread-safe. Calling it from another thread invalidates the +// window drag regions, which throws an exception when not done in the main +// thread +pub unsafe fn set_title_async(ns_window: id, title: String) { + let context = SetTitleData::new_ptr(ns_window, title); + dispatch_async_f( + dispatch_get_main_queue(), + context as *mut _, + set_title_callback, + ); +} + +struct CloseData { + ns_window: id, +} +impl CloseData { + fn new_ptr(ns_window: id) -> *mut Self { + Box::into_raw(Box::new(CloseData { ns_window })) + } +} +extern "C" fn close_callback(context: *mut c_void) { unsafe { let context_ptr = context as *mut CloseData; { let context = &*context_ptr; let pool = NSAutoreleasePool::new(nil); - context.nswindow.close(); + context.ns_window.close(); pool.drain(); } Box::from_raw(context_ptr); @@ -317,11 +417,7 @@ extern fn close_callback(context: *mut c_void) { } // `close:` is thread-safe, but we want the event to be triggered from the main // thread. Though, it's a good idea to look into that more... -pub unsafe fn close_async(nswindow: id) { - let context = CloseData::new_ptr(nswindow); - dispatch_async_f( - dispatch_get_main_queue(), - context as *mut _, - close_callback, - ); +pub unsafe fn close_async(ns_window: id) { + let context = CloseData::new_ptr(ns_window); + dispatch_async_f(dispatch_get_main_queue(), context as *mut _, close_callback); } diff --git a/src/platform_impl/macos/util/cursor.rs b/src/platform_impl/macos/util/cursor.rs index 9d93762d..e3e3bcf0 100644 --- a/src/platform_impl/macos/util/cursor.rs +++ b/src/platform_impl/macos/util/cursor.rs @@ -1,10 +1,11 @@ use cocoa::{ - appkit::NSImage, base::{id, nil}, + appkit::NSImage, + base::{id, nil}, foundation::{NSDictionary, NSPoint, NSString}, }; use objc::runtime::Sel; -use window::CursorIcon; +use crate::window::CursorIcon; pub enum Cursor { Native(&'static str), @@ -22,7 +23,9 @@ impl From for Cursor { CursorIcon::VerticalText => Cursor::Native("IBeamCursorForVerticalLayout"), CursorIcon::Copy => Cursor::Native("dragCopyCursor"), CursorIcon::Alias => Cursor::Native("dragLinkCursor"), - CursorIcon::NotAllowed | CursorIcon::NoDrop => Cursor::Native("operationNotAllowedCursor"), + CursorIcon::NotAllowed | CursorIcon::NoDrop => { + Cursor::Native("operationNotAllowedCursor") + } CursorIcon::ContextMenu => Cursor::Native("contextualMenuCursor"), CursorIcon::Crosshair => Cursor::Native("crosshairCursor"), CursorIcon::EResize => Cursor::Native("resizeRightCursor"), @@ -52,7 +55,9 @@ impl From for Cursor { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=522349 // This is the wrong semantics for `Wait`, but it's the same as // what's used in Safari and Chrome. - CursorIcon::Wait | CursorIcon::Progress => Cursor::Undocumented("busyButClickableCursor"), + CursorIcon::Wait | CursorIcon::Progress => { + Cursor::Undocumented("busyButClickableCursor") + } // For the rest, we can just snatch the cursors from WebKit... // They fit the style of the native cursors, and will seem @@ -75,19 +80,19 @@ impl Cursor { match self { Cursor::Native(cursor_name) => { let sel = Sel::register(cursor_name); - msg_send![class!(NSCursor), performSelector:sel] - }, + msg_send![class!(NSCursor), performSelector: sel] + } Cursor::Undocumented(cursor_name) => { let class = class!(NSCursor); let sel = Sel::register(cursor_name); - let sel = if msg_send![class, respondsToSelector:sel] { + let sel = if msg_send![class, respondsToSelector: sel] { sel } else { warn!("Cursor `{}` appears to be invalid", cursor_name); sel!(arrowCursor) }; - msg_send![class, performSelector:sel] - }, + msg_send![class, performSelector: sel] + } Cursor::WebKit(cursor_name) => load_webkit_cursor(cursor_name), } } @@ -104,27 +109,15 @@ pub unsafe fn load_webkit_cursor(cursor_name: &str) -> id { let key_x = NSString::alloc(nil).init_str("hotx"); let key_y = NSString::alloc(nil).init_str("hoty"); - let cursor_path: id = msg_send![cursor_root, - stringByAppendingPathComponent:cursor_name - ]; - let pdf_path: id = msg_send![cursor_path, - stringByAppendingPathComponent:cursor_pdf - ]; - let info_path: id = msg_send![cursor_path, - stringByAppendingPathComponent:cursor_plist - ]; + let cursor_path: id = msg_send![cursor_root, stringByAppendingPathComponent: cursor_name]; + let pdf_path: id = msg_send![cursor_path, stringByAppendingPathComponent: cursor_pdf]; + let info_path: id = msg_send![cursor_path, stringByAppendingPathComponent: cursor_plist]; let image = NSImage::alloc(nil).initByReferencingFile_(pdf_path); - let info = NSDictionary::dictionaryWithContentsOfFile_( - nil, - info_path, - ); + let info = NSDictionary::dictionaryWithContentsOfFile_(nil, info_path); let x = info.valueForKey_(key_x); let y = info.valueForKey_(key_y); - let point = NSPoint::new( - msg_send![x, doubleValue], - msg_send![y, doubleValue], - ); + let point = NSPoint::new(msg_send![x, doubleValue], msg_send![y, doubleValue]); let cursor: id = msg_send![class!(NSCursor), alloc]; msg_send![cursor, initWithImage:image diff --git a/src/platform_impl/macos/util/into_option.rs b/src/platform_impl/macos/util/into_option.rs deleted file mode 100644 index 4fd32e73..00000000 --- a/src/platform_impl/macos/util/into_option.rs +++ /dev/null @@ -1,14 +0,0 @@ -use cocoa::base::{id, nil}; - -pub trait IntoOption: Sized { - fn into_option(self) -> Option; -} - -impl IntoOption for id { - fn into_option(self) -> Option { - match self != nil { - true => Some(self), - false => None, - } - } -} diff --git a/src/platform_impl/macos/util/mod.rs b/src/platform_impl/macos/util/mod.rs index a8d6a83b..238c9e5d 100644 --- a/src/platform_impl/macos/util/mod.rs +++ b/src/platform_impl/macos/util/mod.rs @@ -1,10 +1,9 @@ -mod async; +mod r#async; mod cursor; -pub use self::{async::*, cursor::*}; +pub use self::{cursor::*, r#async::*}; -use std::ops::Deref; -use std::ops::BitAnd; +use std::ops::{BitAnd, Deref}; use cocoa::{ appkit::{NSApp, NSWindowStyleMask}, @@ -12,17 +11,17 @@ use cocoa::{ foundation::{NSAutoreleasePool, NSRect, NSUInteger}, }; use core_graphics::display::CGDisplay; -use objc::runtime::{BOOL, Class, Object, Sel, YES}; +use objc::runtime::{Class, Object, Sel, BOOL, YES}; -use platform_impl::platform::ffi; +use crate::platform_impl::platform::ffi; // Replace with `!` once stable #[derive(Debug)] pub enum Never {} pub fn has_flag(bitset: T, flag: T) -> bool -where T: - Copy + PartialEq + BitAnd +where + T: Copy + PartialEq + BitAnd, { bitset & flag == flag } @@ -48,7 +47,11 @@ impl IdRef { } pub fn non_nil(self) -> Option { - if self.0 == nil { None } else { Some(self) } + if self.0 == nil { + None + } else { + Some(self) + } } } @@ -94,16 +97,16 @@ pub unsafe fn superclass<'a>(this: &'a Object) -> &'a Class { pub unsafe fn create_input_context(view: id) -> IdRef { let input_context: id = msg_send![class!(NSTextInputContext), alloc]; - let input_context: id = msg_send![input_context, initWithClient:view]; + let input_context: id = msg_send![input_context, initWithClient: view]; IdRef::new(input_context) } #[allow(dead_code)] pub unsafe fn open_emoji_picker() { - let () = msg_send![NSApp(), orderFrontCharacterPalette:nil]; + let () = msg_send![NSApp(), orderFrontCharacterPalette: nil]; } -pub extern fn yes(_: &Object, _: Sel) -> BOOL { +pub extern "C" fn yes(_: &Object, _: Sel) -> BOOL { YES } @@ -120,4 +123,3 @@ pub unsafe fn toggle_style_mask(window: id, view: id, mask: NSWindowStyleMask, o // If we don't do this, key handling will break. Therefore, never call `setStyleMask` directly! window.makeFirstResponder_(view); } - diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index 481087ff..5a0fff9a 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -1,26 +1,39 @@ use std::{ - boxed::Box, collections::VecDeque, os::raw::*, slice, str, + boxed::Box, + collections::VecDeque, + os::raw::*, + slice, str, sync::{Arc, Mutex, Weak}, }; use cocoa::{ appkit::{NSApp, NSEvent, NSEventModifierFlags, NSEventPhase, NSView, NSWindow}, - base::{id, nil}, foundation::{NSPoint, NSRect, NSSize, NSString, NSUInteger}, + base::{id, nil}, + foundation::{NSPoint, NSRect, NSSize, NSString, NSUInteger}, +}; +use objc::{ + declare::ClassDecl, + runtime::{Class, Object, Protocol, Sel, BOOL, NO, YES}, }; -use objc::{declare::ClassDecl, runtime::{BOOL, Class, NO, Object, Protocol, Sel, YES}}; -use { +use crate::{ event::{ - DeviceEvent, ElementState, Event, KeyboardInput, MouseButton, - MouseScrollDelta, TouchPhase, VirtualKeyCode, WindowEvent, + DeviceEvent, ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, + VirtualKeyCode, WindowEvent, + }, + platform_impl::platform::{ + app_state::AppState, + event::{ + char_to_keycode, check_function_keys, event_mods, get_scancode, modifier_event, + scancode_to_keycode, + }, + ffi::*, + util::{self, IdRef}, + window::get_window_id, + DEVICE_ID, }, window::WindowId, }; -use platform_impl::platform::{ - app_state::AppState, DEVICE_ID, - event::{check_function_keys, event_mods, modifier_event, char_to_keycode, get_scancode, scancode_to_keycode}, - util::{self, IdRef}, ffi::*, window::get_window_id, -}; #[derive(Default)] struct Modifiers { @@ -31,7 +44,7 @@ struct Modifiers { } struct ViewState { - nswindow: id, + ns_window: id, pub cursor: Arc>, ime_spot: Option<(f64, f64)>, raw_characters: Option, @@ -39,11 +52,11 @@ struct ViewState { modifiers: Modifiers, } -pub fn new_view(nswindow: id) -> (IdRef, Weak>) { +pub fn new_view(ns_window: id) -> (IdRef, Weak>) { let cursor = Default::default(); let cursor_access = Arc::downgrade(&cursor); let state = ViewState { - nswindow, + ns_window, cursor, ime_spot: None, raw_characters: None, @@ -53,18 +66,19 @@ pub fn new_view(nswindow: id) -> (IdRef, Weak>) { unsafe { // This is free'd in `dealloc` let state_ptr = Box::into_raw(Box::new(state)) as *mut c_void; - let nsview: id = msg_send![VIEW_CLASS.0, alloc]; - (IdRef::new(msg_send![nsview, initWithWinit:state_ptr]), cursor_access) + let ns_view: id = msg_send![VIEW_CLASS.0, alloc]; + ( + IdRef::new(msg_send![ns_view, initWithWinit: state_ptr]), + cursor_access, + ) } } -pub unsafe fn set_ime_position(nsview: id, input_context: id, x: f64, y: f64) { - let state_ptr: *mut c_void = *(*nsview).get_mut_ivar("winitState"); +pub unsafe fn set_ime_position(ns_view: id, input_context: id, x: f64, y: f64) { + let state_ptr: *mut c_void = *(*ns_view).get_mut_ivar("winitState"); let state = &mut *(state_ptr as *mut ViewState); - let content_rect = NSWindow::contentRectForFrameRect_( - state.nswindow, - NSWindow::frame(state.nswindow), - ); + let content_rect = + NSWindow::contentRectForFrameRect_(state.ns_window, NSWindow::frame(state.ns_window)); let base_x = content_rect.origin.x as f64; let base_y = (content_rect.origin.y + content_rect.size.height) as f64; state.ime_spot = Some((base_x + x, base_y - y)); @@ -79,161 +93,148 @@ lazy_static! { static ref VIEW_CLASS: ViewClass = unsafe { let superclass = class!(NSView); let mut decl = ClassDecl::new("WinitView", superclass).unwrap(); - decl.add_method( - sel!(dealloc), - dealloc as extern fn(&Object, Sel), - ); + decl.add_method(sel!(dealloc), dealloc as extern "C" fn(&Object, Sel)); decl.add_method( sel!(initWithWinit:), - init_with_winit as extern fn(&Object, Sel, *mut c_void) -> id, + init_with_winit as extern "C" fn(&Object, Sel, *mut c_void) -> id, ); decl.add_method( sel!(viewDidMoveToWindow), - view_did_move_to_window as extern fn(&Object, Sel), + view_did_move_to_window as extern "C" fn(&Object, Sel), ); decl.add_method( sel!(drawRect:), - draw_rect as extern fn(&Object, Sel, id), + draw_rect as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(acceptsFirstResponder), - accepts_first_responder as extern fn(&Object, Sel) -> BOOL, + accepts_first_responder as extern "C" fn(&Object, Sel) -> BOOL, ); decl.add_method( sel!(touchBar), - touch_bar as extern fn(&Object, Sel) -> BOOL, + touch_bar as extern "C" fn(&Object, Sel) -> BOOL, ); decl.add_method( sel!(resetCursorRects), - reset_cursor_rects as extern fn(&Object, Sel), + reset_cursor_rects as extern "C" fn(&Object, Sel), ); decl.add_method( sel!(hasMarkedText), - has_marked_text as extern fn(&Object, Sel) -> BOOL, + has_marked_text as extern "C" fn(&Object, Sel) -> BOOL, ); decl.add_method( sel!(markedRange), - marked_range as extern fn(&Object, Sel) -> NSRange, + marked_range as extern "C" fn(&Object, Sel) -> NSRange, ); decl.add_method( sel!(selectedRange), - selected_range as extern fn(&Object, Sel) -> NSRange, + selected_range as extern "C" fn(&Object, Sel) -> NSRange, ); decl.add_method( sel!(setMarkedText:selectedRange:replacementRange:), - set_marked_text as extern fn(&mut Object, Sel, id, NSRange, NSRange), - ); - decl.add_method( - sel!(unmarkText), - unmark_text as extern fn(&Object, Sel), + set_marked_text as extern "C" fn(&mut Object, Sel, id, NSRange, NSRange), ); + decl.add_method(sel!(unmarkText), unmark_text as extern "C" fn(&Object, Sel)); decl.add_method( sel!(validAttributesForMarkedText), - valid_attributes_for_marked_text as extern fn(&Object, Sel) -> id, + valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id, ); decl.add_method( sel!(attributedSubstringForProposedRange:actualRange:), - attributed_substring_for_proposed_range as extern fn(&Object, Sel, NSRange, *mut c_void) -> id, + attributed_substring_for_proposed_range + as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> id, ); decl.add_method( sel!(insertText:replacementRange:), - insert_text as extern fn(&Object, Sel, id, NSRange), + insert_text as extern "C" fn(&Object, Sel, id, NSRange), ); decl.add_method( sel!(characterIndexForPoint:), - character_index_for_point as extern fn(&Object, Sel, NSPoint) -> NSUInteger, + character_index_for_point as extern "C" fn(&Object, Sel, NSPoint) -> NSUInteger, ); decl.add_method( sel!(firstRectForCharacterRange:actualRange:), - first_rect_for_character_range as extern fn(&Object, Sel, NSRange, *mut c_void) -> NSRect, + first_rect_for_character_range + as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> NSRect, ); decl.add_method( sel!(doCommandBySelector:), - do_command_by_selector as extern fn(&Object, Sel, Sel), - ); - decl.add_method( - sel!(keyDown:), - key_down as extern fn(&Object, Sel, id), - ); - decl.add_method( - sel!(keyUp:), - key_up as extern fn(&Object, Sel, id), + do_command_by_selector as extern "C" fn(&Object, Sel, Sel), ); + decl.add_method(sel!(keyDown:), key_down as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(keyUp:), key_up as extern "C" fn(&Object, Sel, id)); decl.add_method( sel!(flagsChanged:), - flags_changed as extern fn(&Object, Sel, id), + flags_changed as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(insertTab:), - insert_tab as extern fn(&Object, Sel, id), + insert_tab as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(insertBackTab:), - insert_back_tab as extern fn(&Object, Sel, id), + insert_back_tab as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(mouseDown:), - mouse_down as extern fn(&Object, Sel, id), - ); - decl.add_method( - sel!(mouseUp:), - mouse_up as extern fn(&Object, Sel, id), + mouse_down as extern "C" fn(&Object, Sel, id), ); + decl.add_method(sel!(mouseUp:), mouse_up as extern "C" fn(&Object, Sel, id)); decl.add_method( sel!(rightMouseDown:), - right_mouse_down as extern fn(&Object, Sel, id), + right_mouse_down as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(rightMouseUp:), - right_mouse_up as extern fn(&Object, Sel, id), + right_mouse_up as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(otherMouseDown:), - other_mouse_down as extern fn(&Object, Sel, id), + other_mouse_down as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(otherMouseUp:), - other_mouse_up as extern fn(&Object, Sel, id), + other_mouse_up as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(mouseMoved:), - mouse_moved as extern fn(&Object, Sel, id), + mouse_moved as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(mouseDragged:), - mouse_dragged as extern fn(&Object, Sel, id), + mouse_dragged as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(rightMouseDragged:), - right_mouse_dragged as extern fn(&Object, Sel, id), + right_mouse_dragged as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(otherMouseDragged:), - other_mouse_dragged as extern fn(&Object, Sel, id), + other_mouse_dragged as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(mouseEntered:), - mouse_entered as extern fn(&Object, Sel, id), + mouse_entered as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(mouseExited:), - mouse_exited as extern fn(&Object, Sel, id), + mouse_exited as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(scrollWheel:), - scroll_wheel as extern fn(&Object, Sel, id), + scroll_wheel as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(pressureChangeWithEvent:), - pressure_change_with_event as extern fn(&Object, Sel, id), + pressure_change_with_event as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(_wantsKeyDownForEvent:), - wants_key_down_for_event as extern fn(&Object, Sel, id) -> BOOL, + wants_key_down_for_event as extern "C" fn(&Object, Sel, id) -> BOOL, ); decl.add_method( sel!(cancelOperation:), - cancel_operation as extern fn(&Object, Sel, id), + cancel_operation as extern "C" fn(&Object, Sel, id), ); decl.add_ivar::<*mut c_void>("winitState"); decl.add_ivar::("markedText"); @@ -243,7 +244,7 @@ lazy_static! { }; } -extern fn dealloc(this: &Object, _sel: Sel) { +extern "C" fn dealloc(this: &Object, _sel: Sel) { unsafe { let state: *mut c_void = *this.get_ivar("winitState"); let marked_text: id = *this.get_ivar("markedText"); @@ -252,21 +253,20 @@ extern fn dealloc(this: &Object, _sel: Sel) { } } -extern fn init_with_winit(this: &Object, _sel: Sel, state: *mut c_void) -> id { +extern "C" fn init_with_winit(this: &Object, _sel: Sel, state: *mut c_void) -> id { unsafe { let this: id = msg_send![this, init]; if this != nil { (*this).set_ivar("winitState", state); - let marked_text = ::init( - NSMutableAttributedString::alloc(nil), - ); + let marked_text = + ::init(NSMutableAttributedString::alloc(nil)); (*this).set_ivar("markedText", marked_text); } this } } -extern fn view_did_move_to_window(this: &Object, _sel: Sel) { +extern "C" fn view_did_move_to_window(this: &Object, _sel: Sel) { trace!("Triggered `viewDidMoveToWindow`"); unsafe { let rect: NSRect = msg_send![this, visibleRect]; @@ -280,30 +280,30 @@ extern fn view_did_move_to_window(this: &Object, _sel: Sel) { trace!("Completed `viewDidMoveToWindow`"); } -extern fn draw_rect(this: &Object, _sel: Sel, rect: id) { +extern "C" fn draw_rect(this: &Object, _sel: Sel, rect: id) { unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state = &mut *(state_ptr as *mut ViewState); - AppState::queue_redraw(WindowId(get_window_id(state.nswindow))); + AppState::queue_redraw(WindowId(get_window_id(state.ns_window))); let superclass = util::superclass(this); - let () = msg_send![super(this, superclass), drawRect:rect]; + let () = msg_send![super(this, superclass), drawRect: rect]; } } -extern fn accepts_first_responder(_this: &Object, _sel: Sel) -> BOOL { +extern "C" fn accepts_first_responder(_this: &Object, _sel: Sel) -> BOOL { YES } // This is necessary to prevent a beefy terminal error on MacBook Pros: // IMKInputSession [0x7fc573576ff0 presentFunctionRowItemTextInputViewWithEndpoint:completionHandler:] : [self textInputContext]=0x7fc573558e10 *NO* NSRemoteViewController to client, NSError=Error Domain=NSCocoaErrorDomain Code=4099 "The connection from pid 0 was invalidated from this process." UserInfo={NSDebugDescription=The connection from pid 0 was invalidated from this process.}, com.apple.inputmethod.EmojiFunctionRowItem // TODO: Add an API extension for using `NSTouchBar` -extern fn touch_bar(_this: &Object, _sel: Sel) -> BOOL { +extern "C" fn touch_bar(_this: &Object, _sel: Sel) -> BOOL { NO } -extern fn reset_cursor_rects(this: &Object, _sel: Sel) { +extern "C" fn reset_cursor_rects(this: &Object, _sel: Sel) { unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state = &mut *(state_ptr as *mut ViewState); @@ -317,8 +317,7 @@ extern fn reset_cursor_rects(this: &Object, _sel: Sel) { } } - -extern fn has_marked_text(this: &Object, _sel: Sel) -> BOOL { +extern "C" fn has_marked_text(this: &Object, _sel: Sel) -> BOOL { unsafe { trace!("Triggered `hasMarkedText`"); let marked_text: id = *this.get_ivar("markedText"); @@ -327,7 +326,7 @@ extern fn has_marked_text(this: &Object, _sel: Sel) -> BOOL { } } -extern fn marked_range(this: &Object, _sel: Sel) -> NSRange { +extern "C" fn marked_range(this: &Object, _sel: Sel) -> NSRange { unsafe { trace!("Triggered `markedRange`"); let marked_text: id = *this.get_ivar("markedText"); @@ -341,13 +340,13 @@ extern fn marked_range(this: &Object, _sel: Sel) -> NSRange { } } -extern fn selected_range(_this: &Object, _sel: Sel) -> NSRange { +extern "C" fn selected_range(_this: &Object, _sel: Sel) -> NSRange { trace!("Triggered `selectedRange`"); trace!("Completed `selectedRange`"); util::EMPTY_RANGE } -extern fn set_marked_text( +extern "C" fn set_marked_text( this: &mut Object, _sel: Sel, string: id, @@ -359,7 +358,7 @@ extern fn set_marked_text( let marked_text_ref: &mut id = this.get_mut_ivar("markedText"); let _: () = msg_send![(*marked_text_ref), release]; let marked_text = NSMutableAttributedString::alloc(nil); - let has_attr = msg_send![string, isKindOfClass:class!(NSAttributedString)]; + let has_attr = msg_send![string, isKindOfClass: class!(NSAttributedString)]; if has_attr { marked_text.initWithAttributedString(string); } else { @@ -370,7 +369,7 @@ extern fn set_marked_text( trace!("Completed `setMarkedText`"); } -extern fn unmark_text(this: &Object, _sel: Sel) { +extern "C" fn unmark_text(this: &Object, _sel: Sel) { trace!("Triggered `unmarkText`"); unsafe { let marked_text: id = *this.get_ivar("markedText"); @@ -382,13 +381,13 @@ extern fn unmark_text(this: &Object, _sel: Sel) { trace!("Completed `unmarkText`"); } -extern fn valid_attributes_for_marked_text(_this: &Object, _sel: Sel) -> id { +extern "C" fn valid_attributes_for_marked_text(_this: &Object, _sel: Sel) -> id { trace!("Triggered `validAttributesForMarkedText`"); trace!("Completed `validAttributesForMarkedText`"); unsafe { msg_send![class!(NSArray), array] } } -extern fn attributed_substring_for_proposed_range( +extern "C" fn attributed_substring_for_proposed_range( _this: &Object, _sel: Sel, _range: NSRange, @@ -399,13 +398,13 @@ extern fn attributed_substring_for_proposed_range( nil } -extern fn character_index_for_point(_this: &Object, _sel: Sel, _point: NSPoint) -> NSUInteger { +extern "C" fn character_index_for_point(_this: &Object, _sel: Sel, _point: NSPoint) -> NSUInteger { trace!("Triggered `characterIndexForPoint`"); trace!("Completed `characterIndexForPoint`"); 0 } -extern fn first_rect_for_character_range( +extern "C" fn first_rect_for_character_range( this: &Object, _sel: Sel, _range: NSRange, @@ -417,28 +416,25 @@ extern fn first_rect_for_character_range( let state = &mut *(state_ptr as *mut ViewState); let (x, y) = state.ime_spot.unwrap_or_else(|| { let content_rect = NSWindow::contentRectForFrameRect_( - state.nswindow, - NSWindow::frame(state.nswindow), + state.ns_window, + NSWindow::frame(state.ns_window), ); let x = content_rect.origin.x; let y = util::bottom_left_to_top_left(content_rect); (x, y) }); trace!("Completed `firstRectForCharacterRange`"); - NSRect::new( - NSPoint::new(x as _, y as _), - NSSize::new(0.0, 0.0), - ) + NSRect::new(NSPoint::new(x as _, y as _), NSSize::new(0.0, 0.0)) } } -extern fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range: NSRange) { +extern "C" fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range: NSRange) { trace!("Triggered `insertText`"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state = &mut *(state_ptr as *mut ViewState); - let has_attr = msg_send![string, isKindOfClass:class!(NSAttributedString)]; + let has_attr = msg_send![string, isKindOfClass: class!(NSAttributedString)]; let characters = if has_attr { // This is a *mut NSAttributedString msg_send![string, string] @@ -447,10 +443,8 @@ extern fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range: string }; - let slice = slice::from_raw_parts( - characters.UTF8String() as *const c_uchar, - characters.len(), - ); + let slice = + slice::from_raw_parts(characters.UTF8String() as *const c_uchar, characters.len()); let string = str::from_utf8_unchecked(slice); state.is_key_down = true; @@ -460,7 +454,7 @@ extern fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range: let mut events = VecDeque::with_capacity(characters.len()); for character in string.chars() { events.push_back(Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::ReceivedCharacter(character), }); } @@ -470,7 +464,7 @@ extern fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range: trace!("Completed `insertText`"); } -extern fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) { +extern "C" fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) { trace!("Triggered `doCommandBySelector`"); // Basically, we're sent this message whenever a keyboard event that doesn't generate a "human readable" character // happens, i.e. newlines, tabs, and Ctrl+C. @@ -484,7 +478,7 @@ extern fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) { // 1) as a reminder for how `doCommandBySelector` works // 2) to make our use of carriage return explicit events.push_back(Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::ReceivedCharacter('\r'), }); } else { @@ -492,7 +486,7 @@ extern fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) { if let Some(raw_characters) = raw_characters { for character in raw_characters.chars() { events.push_back(Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::ReceivedCharacter(character), }); } @@ -513,10 +507,8 @@ fn get_characters(event: id, ignore_modifiers: bool) -> String { }; assert_ne!(characters, nil); - let slice = slice::from_raw_parts( - characters.UTF8String() as *const c_uchar, - characters.len(), - ); + let slice = + slice::from_raw_parts(characters.UTF8String() as *const c_uchar, characters.len()); let string = str::from_utf8_unchecked(slice); string.to_owned() @@ -528,15 +520,15 @@ fn retrieve_keycode(event: id) -> Option { #[inline] fn get_code(ev: id, raw: bool) -> Option { let characters = get_characters(ev, raw); - characters.chars().next().map_or(None, |c| char_to_keycode(c)) + characters + .chars() + .next() + .map_or(None, |c| char_to_keycode(c)) } // Cmd switches Roman letters for Dvorak-QWERTY layout, so we try modified characters first. // If we don't get a match, then we fall back to unmodified characters. - let code = get_code(event, false) - .or_else(|| { - get_code(event, true) - }); + let code = get_code(event, false).or_else(|| get_code(event, true)); // We've checked all layout related keys, so fall through to scancode. // Reaching this code means that the key is layout-independent (e.g. Backspace, Return). @@ -546,19 +538,16 @@ fn retrieve_keycode(event: id) -> Option { // in characters property. code.or_else(|| { let scancode = get_scancode(event); - scancode_to_keycode(scancode) - .or_else(|| { - check_function_keys(&get_characters(event, true)) - }) + scancode_to_keycode(scancode).or_else(|| check_function_keys(&get_characters(event, true))) }) } -extern fn key_down(this: &Object, _sel: Sel, event: id) { +extern "C" fn key_down(this: &Object, _sel: Sel, event: id) { trace!("Triggered `keyDown`"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state = &mut *(state_ptr as *mut ViewState); - let window_id = WindowId(get_window_id(state.nswindow)); + let window_id = WindowId(get_window_id(state.ns_window)); let characters = get_characters(event, false); state.raw_characters = Some(characters.clone()); @@ -601,14 +590,14 @@ extern fn key_down(this: &Object, _sel: Sel, event: id) { // Some keys (and only *some*, with no known reason) don't trigger `insertText`, while others do... // So, we don't give repeats the opportunity to trigger that, since otherwise our hack will cause some // keys to generate twice as many characters. - let array: id = msg_send![class!(NSArray), arrayWithObject:event]; - let _: () = msg_send![this, interpretKeyEvents:array]; + let array: id = msg_send![class!(NSArray), arrayWithObject: event]; + let _: () = msg_send![this, interpretKeyEvents: array]; } } trace!("Completed `keyDown`"); } -extern fn key_up(this: &Object, _sel: Sel, event: id) { +extern "C" fn key_up(this: &Object, _sel: Sel, event: id) { trace!("Triggered `keyUp`"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); @@ -620,7 +609,7 @@ extern fn key_up(this: &Object, _sel: Sel, event: id) { let virtual_keycode = retrieve_keycode(event); let window_event = Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::KeyboardInput { device_id: DEVICE_ID, input: KeyboardInput { @@ -637,7 +626,7 @@ extern fn key_up(this: &Object, _sel: Sel, event: id) { trace!("Completed `keyUp`"); } -extern fn flags_changed(this: &Object, _sel: Sel, event: id) { +extern "C" fn flags_changed(this: &Object, _sel: Sel, event: id) { trace!("Triggered `flagsChanged`"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); @@ -683,7 +672,7 @@ extern fn flags_changed(this: &Object, _sel: Sel, event: id) { for event in events { AppState::queue_event(Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event, }); } @@ -691,31 +680,31 @@ extern fn flags_changed(this: &Object, _sel: Sel, event: id) { trace!("Completed `flagsChanged`"); } -extern fn insert_tab(this: &Object, _sel: Sel, _sender: id) { +extern "C" fn insert_tab(this: &Object, _sel: Sel, _sender: id) { unsafe { let window: id = msg_send![this, window]; let first_responder: id = msg_send![window, firstResponder]; let this_ptr = this as *const _ as *mut _; if first_responder == this_ptr { - let (): _ = msg_send![window, selectNextKeyView:this]; + let (): _ = msg_send![window, selectNextKeyView: this]; } } } -extern fn insert_back_tab(this: &Object, _sel: Sel, _sender: id) { +extern "C" fn insert_back_tab(this: &Object, _sel: Sel, _sender: id) { unsafe { let window: id = msg_send![this, window]; let first_responder: id = msg_send![window, firstResponder]; let this_ptr = this as *const _ as *mut _; if first_responder == this_ptr { - let (): _ = msg_send![window, selectPreviousKeyView:this]; + let (): _ = msg_send![window, selectPreviousKeyView: this]; } } } // Allows us to receive Cmd-. (the shortcut for closing a dialog) // https://bugs.eclipse.org/bugs/show_bug.cgi?id=300620#c6 -extern fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { +extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { trace!("Triggered `cancelOperation`"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); @@ -728,7 +717,7 @@ extern fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { let event: id = msg_send![NSApp(), currentEvent]; let window_event = Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::KeyboardInput { device_id: DEVICE_ID, input: KeyboardInput { @@ -751,7 +740,7 @@ fn mouse_click(this: &Object, event: id, button: MouseButton, button_state: Elem let state = &mut *(state_ptr as *mut ViewState); let window_event = Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::MouseInput { device_id: DEVICE_ID, state: button_state, @@ -764,27 +753,27 @@ fn mouse_click(this: &Object, event: id, button: MouseButton, button_state: Elem } } -extern fn mouse_down(this: &Object, _sel: Sel, event: id) { +extern "C" fn mouse_down(this: &Object, _sel: Sel, event: id) { mouse_click(this, event, MouseButton::Left, ElementState::Pressed); } -extern fn mouse_up(this: &Object, _sel: Sel, event: id) { +extern "C" fn mouse_up(this: &Object, _sel: Sel, event: id) { mouse_click(this, event, MouseButton::Left, ElementState::Released); } -extern fn right_mouse_down(this: &Object, _sel: Sel, event: id) { +extern "C" fn right_mouse_down(this: &Object, _sel: Sel, event: id) { mouse_click(this, event, MouseButton::Right, ElementState::Pressed); } -extern fn right_mouse_up(this: &Object, _sel: Sel, event: id) { +extern "C" fn right_mouse_up(this: &Object, _sel: Sel, event: id) { mouse_click(this, event, MouseButton::Right, ElementState::Released); } -extern fn other_mouse_down(this: &Object, _sel: Sel, event: id) { +extern "C" fn other_mouse_down(this: &Object, _sel: Sel, event: id) { mouse_click(this, event, MouseButton::Middle, ElementState::Pressed); } -extern fn other_mouse_up(this: &Object, _sel: Sel, event: id) { +extern "C" fn other_mouse_up(this: &Object, _sel: Sel, event: id) { mouse_click(this, event, MouseButton::Middle, ElementState::Released); } @@ -801,9 +790,10 @@ fn mouse_motion(this: &Object, event: id) { let view_rect = NSView::frame(view); if view_point.x.is_sign_negative() - || view_point.y.is_sign_negative() - || view_point.x > view_rect.size.width - || view_point.y > view_rect.size.height { + || view_point.y.is_sign_negative() + || view_point.x > view_rect.size.width + || view_point.y > view_rect.size.height + { // Point is outside of the client area (view) return; } @@ -812,7 +802,7 @@ fn mouse_motion(this: &Object, event: id) { let y = view_rect.size.height as f64 - view_point.y as f64; let window_event = Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::CursorMoved { device_id: DEVICE_ID, position: (x, y).into(), @@ -824,31 +814,33 @@ fn mouse_motion(this: &Object, event: id) { } } -extern fn mouse_moved(this: &Object, _sel: Sel, event: id) { +extern "C" fn mouse_moved(this: &Object, _sel: Sel, event: id) { mouse_motion(this, event); } -extern fn mouse_dragged(this: &Object, _sel: Sel, event: id) { +extern "C" fn mouse_dragged(this: &Object, _sel: Sel, event: id) { mouse_motion(this, event); } -extern fn right_mouse_dragged(this: &Object, _sel: Sel, event: id) { +extern "C" fn right_mouse_dragged(this: &Object, _sel: Sel, event: id) { mouse_motion(this, event); } -extern fn other_mouse_dragged(this: &Object, _sel: Sel, event: id) { +extern "C" fn other_mouse_dragged(this: &Object, _sel: Sel, event: id) { mouse_motion(this, event); } -extern fn mouse_entered(this: &Object, _sel: Sel, event: id) { +extern "C" fn mouse_entered(this: &Object, _sel: Sel, event: id) { trace!("Triggered `mouseEntered`"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state = &mut *(state_ptr as *mut ViewState); let enter_event = Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), - event: WindowEvent::CursorEntered { device_id: DEVICE_ID }, + window_id: WindowId(get_window_id(state.ns_window)), + event: WindowEvent::CursorEntered { + device_id: DEVICE_ID, + }, }; let move_event = { @@ -861,12 +853,12 @@ extern fn mouse_entered(this: &Object, _sel: Sel, event: id) { let x = view_point.x as f64; let y = (view_rect.size.height - view_point.y) as f64; Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::CursorMoved { device_id: DEVICE_ID, position: (x, y).into(), modifiers: event_mods(event), - } + }, } }; @@ -876,15 +868,17 @@ extern fn mouse_entered(this: &Object, _sel: Sel, event: id) { trace!("Completed `mouseEntered`"); } -extern fn mouse_exited(this: &Object, _sel: Sel, _event: id) { +extern "C" fn mouse_exited(this: &Object, _sel: Sel, _event: id) { trace!("Triggered `mouseExited`"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state = &mut *(state_ptr as *mut ViewState); let window_event = Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), - event: WindowEvent::CursorLeft { device_id: DEVICE_ID }, + window_id: WindowId(get_window_id(state.ns_window)), + event: WindowEvent::CursorLeft { + device_id: DEVICE_ID, + }, }; AppState::queue_event(window_event); @@ -892,7 +886,7 @@ extern fn mouse_exited(this: &Object, _sel: Sel, _event: id) { trace!("Completed `mouseExited`"); } -extern fn scroll_wheel(this: &Object, _sel: Sel, event: id) { +extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) { trace!("Triggered `scrollWheel`"); unsafe { let delta = { @@ -904,7 +898,9 @@ extern fn scroll_wheel(this: &Object, _sel: Sel, event: id) { } }; let phase = match event.phase() { - NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => TouchPhase::Started, + NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { + TouchPhase::Started + } NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, _ => TouchPhase::Moved, }; @@ -918,7 +914,7 @@ extern fn scroll_wheel(this: &Object, _sel: Sel, event: id) { let state = &mut *(state_ptr as *mut ViewState); let window_event = Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta, @@ -933,7 +929,7 @@ extern fn scroll_wheel(this: &Object, _sel: Sel, event: id) { trace!("Completed `scrollWheel`"); } -extern fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) { +extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) { trace!("Triggered `pressureChangeWithEvent`"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); @@ -943,7 +939,7 @@ extern fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) { let stage = event.stage(); let window_event = Event::WindowEvent { - window_id: WindowId(get_window_id(state.nswindow)), + window_id: WindowId(get_window_id(state.ns_window)), event: WindowEvent::TouchpadPressure { device_id: DEVICE_ID, pressure, @@ -959,6 +955,6 @@ extern fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) { // Allows us to receive Ctrl-Tab and Ctrl-Esc. // Note that this *doesn't* help with any missing Cmd inputs. // https://github.com/chromium/chromium/blob/a86a8a6bcfa438fa3ac2eba6f02b3ad1f8e0756f/ui/views/cocoa/bridged_content_view.mm#L816 -extern fn wants_key_down_for_event(_this: &Object, _sel: Sel, _event: id) -> BOOL { +extern "C" fn wants_key_down_for_event(_this: &Object, _sel: Sel, _event: id) -> BOOL { YES } diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index 143d77e2..4f6bf255 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -1,34 +1,44 @@ use std::{ - collections::VecDeque, f64, os::raw::c_void, - sync::{Arc, atomic::{Ordering, AtomicBool}, Mutex, Weak}, + collections::VecDeque, + f64, + os::raw::c_void, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, Mutex, Weak, + }, }; use cocoa::{ appkit::{ self, CGFloat, NSApp, NSApplication, NSApplicationActivationPolicy, - NSColor, NSRequestUserAttentionType, NSScreen, NSView, NSWindow, - NSWindowButton, NSWindowStyleMask, NSApplicationPresentationOptions + NSApplicationPresentationOptions, NSColor, NSRequestUserAttentionType, NSScreen, NSView, + NSWindow, NSWindowButton, NSWindowStyleMask, }, base::{id, nil}, foundation::{NSAutoreleasePool, NSDictionary, NSPoint, NSRect, NSSize, NSString}, }; use core_graphics::display::CGDisplay; -use objc::{runtime::{Class, Object, Sel, BOOL, YES, NO}, declare::ClassDecl}; - -use { - dpi::{LogicalPosition, LogicalSize}, icon::Icon, - error::{ExternalError, NotSupportedError, OsError as RootOsError}, - monitor::MonitorHandle as RootMonitorHandle, - window::{ - CursorIcon, WindowAttributes, WindowId as RootWindowId, - }, +use objc::{ + declare::ClassDecl, + runtime::{Class, Object, Sel, BOOL, NO, YES}, }; -use platform::macos::{ActivationPolicy, WindowExtMacOS}; -use platform_impl::platform::{ - OsError, - app_state::AppState, ffi, monitor::{self, MonitorHandle}, - util::{self, IdRef}, view::{self, new_view}, - window_delegate::new_delegate, + +use crate::{ + dpi::{LogicalPosition, LogicalSize}, + error::{ExternalError, NotSupportedError, OsError as RootOsError}, + icon::Icon, + monitor::MonitorHandle as RootMonitorHandle, + platform::macos::{ActivationPolicy, RequestUserAttentionType, WindowExtMacOS}, + platform_impl::platform::{ + app_state::AppState, + ffi, + monitor::{self, MonitorHandle}, + util::{self, IdRef}, + view::{self, new_view}, + window_delegate::new_delegate, + OsError, + }, + window::{CursorIcon, WindowAttributes, WindowId as RootWindowId}, }; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -60,26 +70,26 @@ pub struct PlatformSpecificWindowBuilderAttributes { fn create_app(activation_policy: ActivationPolicy) -> Option { unsafe { - let nsapp = NSApp(); - if nsapp == nil { + let ns_app = NSApp(); + if ns_app == nil { None } else { use self::NSApplicationActivationPolicy::*; - nsapp.setActivationPolicy_(match activation_policy { + ns_app.setActivationPolicy_(match activation_policy { ActivationPolicy::Regular => NSApplicationActivationPolicyRegular, ActivationPolicy::Accessory => NSApplicationActivationPolicyAccessory, ActivationPolicy::Prohibited => NSApplicationActivationPolicyProhibited, }); - nsapp.finishLaunching(); - Some(nsapp) + ns_app.finishLaunching(); + Some(ns_app) } } } -unsafe fn create_view(nswindow: id) -> Option<(IdRef, Weak>)> { - let (nsview, cursor) = new_view(nswindow); - nsview.non_nil().map(|nsview| { - nsview.setWantsBestResolutionOpenGLSurface_(YES); +unsafe fn create_view(ns_window: id) -> Option<(IdRef, Weak>)> { + let (ns_view, cursor) = new_view(ns_window); + ns_view.non_nil().map(|ns_view| { + ns_view.setWantsBestResolutionOpenGLSurface_(YES); // On Mojave, views automatically become layer-backed shortly after being added to // a window. Changing the layer-backedness of a view breaks the association between @@ -87,12 +97,12 @@ unsafe fn create_view(nswindow: id) -> Option<(IdRef, Weak>) // explicitly make the view layer-backed up front so that AppKit doesn't do it // itself and break the association with its context. if f64::floor(appkit::NSAppKitVersionNumber) > appkit::NSAppKitVersionNumber10_12 { - nsview.setWantsLayer(YES); + ns_view.setWantsLayer(YES); } - nswindow.setContentView_(*nsview); - nswindow.makeFirstResponder_(*nsview); - (nsview, cursor) + ns_window.setContentView_(*ns_view); + ns_window.makeFirstResponder_(*ns_view); + (ns_view, cursor) }) } @@ -104,36 +114,35 @@ fn create_window( let pool = NSAutoreleasePool::new(nil); let screen = match attrs.fullscreen { Some(ref monitor_id) => { - let monitor_screen = monitor_id.inner.nsscreen(); + let monitor_screen = monitor_id.inner.ns_screen(); Some(monitor_screen.unwrap_or(appkit::NSScreen::mainScreen(nil))) - }, + } _ => None, }; let frame = match screen { Some(screen) => appkit::NSScreen::frame(screen), None => { - let (width, height) = attrs.inner_size + let (width, height) = attrs + .inner_size .map(|logical| (logical.width, logical.height)) .unwrap_or_else(|| (800.0, 600.0)); NSRect::new(NSPoint::new(0.0, 0.0), NSSize::new(width, height)) - }, + } }; let mut masks = if !attrs.decorations && !screen.is_some() { // Resizable UnownedWindow without a titlebar or borders // if decorations is set to false, ignore pl_attrs - NSWindowStyleMask::NSBorderlessWindowMask - | NSWindowStyleMask::NSResizableWindowMask + NSWindowStyleMask::NSBorderlessWindowMask | NSWindowStyleMask::NSResizableWindowMask } else if pl_attrs.titlebar_hidden { // if the titlebar is hidden, ignore other pl_attrs - NSWindowStyleMask::NSBorderlessWindowMask | - NSWindowStyleMask::NSResizableWindowMask + NSWindowStyleMask::NSBorderlessWindowMask | NSWindowStyleMask::NSResizableWindowMask } else { // default case, resizable window with titlebar and titlebar buttons - NSWindowStyleMask::NSClosableWindowMask | - NSWindowStyleMask::NSMiniaturizableWindowMask | - NSWindowStyleMask::NSResizableWindowMask | - NSWindowStyleMask::NSTitledWindowMask + NSWindowStyleMask::NSClosableWindowMask + | NSWindowStyleMask::NSMiniaturizableWindowMask + | NSWindowStyleMask::NSResizableWindowMask + | NSWindowStyleMask::NSTitledWindowMask }; if !attrs.resizable { @@ -144,24 +153,24 @@ fn create_window( masks |= NSWindowStyleMask::NSFullSizeContentViewWindowMask; } - let nswindow: id = msg_send![WINDOW_CLASS.0, alloc]; - let nswindow = IdRef::new(nswindow.initWithContentRect_styleMask_backing_defer_( + let ns_window: id = msg_send![WINDOW_CLASS.0, alloc]; + let ns_window = IdRef::new(ns_window.initWithContentRect_styleMask_backing_defer_( frame, masks, appkit::NSBackingStoreBuffered, NO, )); - let res = nswindow.non_nil().map(|nswindow| { + let res = ns_window.non_nil().map(|ns_window| { let title = IdRef::new(NSString::alloc(nil).init_str(&attrs.title)); - nswindow.setReleasedWhenClosed_(NO); - nswindow.setTitle_(*title); - nswindow.setAcceptsMouseMovedEvents_(YES); + ns_window.setReleasedWhenClosed_(NO); + ns_window.setTitle_(*title); + ns_window.setAcceptsMouseMovedEvents_(YES); if pl_attrs.titlebar_transparent { - nswindow.setTitlebarAppearsTransparent_(YES); + ns_window.setTitlebarAppearsTransparent_(YES); } if pl_attrs.title_hidden { - nswindow.setTitleVisibility_(appkit::NSWindowTitleVisibility::NSWindowTitleHidden); + ns_window.setTitleVisibility_(appkit::NSWindowTitleVisibility::NSWindowTitleHidden); } if pl_attrs.titlebar_buttons_hidden { for titlebar_button in &[ @@ -170,28 +179,31 @@ fn create_window( NSWindowButton::NSWindowCloseButton, NSWindowButton::NSWindowZoomButton, ] { - let button = nswindow.standardWindowButton_(*titlebar_button); - let _: () = msg_send![button, setHidden:YES]; + let button = ns_window.standardWindowButton_(*titlebar_button); + let _: () = msg_send![button, setHidden: YES]; } } if pl_attrs.movable_by_window_background { - nswindow.setMovableByWindowBackground_(YES); + ns_window.setMovableByWindowBackground_(YES); } if attrs.always_on_top { - let _: () = msg_send![*nswindow, setLevel:ffi::NSWindowLevel::NSFloatingWindowLevel]; + let _: () = msg_send![ + *ns_window, + setLevel: ffi::NSWindowLevel::NSFloatingWindowLevel + ]; } if let Some(increments) = pl_attrs.resize_increments { let (x, y) = (increments.width, increments.height); if x >= 1.0 && y >= 1.0 { let size = NSSize::new(x as CGFloat, y as CGFloat); - nswindow.setResizeIncrements_(size); + ns_window.setResizeIncrements_(size); } } - nswindow.center(); - nswindow + ns_window.center(); + ns_window }); pool.drain(); res @@ -206,8 +218,14 @@ lazy_static! { static ref WINDOW_CLASS: WindowClass = unsafe { let window_superclass = class!(NSWindow); let mut decl = ClassDecl::new("WinitWindow", window_superclass).unwrap(); - decl.add_method(sel!(canBecomeMainWindow), util::yes as extern fn(&Object, Sel) -> BOOL); - decl.add_method(sel!(canBecomeKeyWindow), util::yes as extern fn(&Object, Sel) -> BOOL); + decl.add_method( + sel!(canBecomeMainWindow), + util::yes as extern "C" fn(&Object, Sel) -> BOOL, + ); + decl.add_method( + sel!(canBecomeKeyWindow), + util::yes as extern "C" fn(&Object, Sel) -> BOOL, + ); WindowClass(decl.register()) }; } @@ -217,12 +235,19 @@ pub struct SharedState { pub resizable: bool, pub fullscreen: Option, pub maximized: bool, - standard_frame: Option, + pub standard_frame: Option, is_simple_fullscreen: bool, pub saved_style: Option, save_presentation_opts: Option, } +impl SharedState { + pub fn saved_standard_frame(&self) -> NSRect { + self.standard_frame + .unwrap_or_else(|| NSRect::new(NSPoint::new(50.0, 50.0), NSSize::new(800.0, 600.0))) + } +} + impl From for SharedState { fn from(attribs: WindowAttributes) -> Self { SharedState { @@ -235,14 +260,14 @@ impl From for SharedState { // identical, resulting in a no-op. fullscreen: None, maximized: attribs.maximized, - .. Default::default() + ..Default::default() } } } pub struct UnownedWindow { - pub nswindow: IdRef, // never changes - pub nsview: IdRef, // never changes + pub ns_window: IdRef, // never changes + pub ns_view: IdRef, // never changes input_context: IdRef, // never changes pub shared_state: Arc>, decorations: AtomicBool, @@ -266,40 +291,45 @@ impl UnownedWindow { let pool = unsafe { NSAutoreleasePool::new(nil) }; - let nsapp = create_app(pl_attribs.activation_policy).ok_or_else(|| { + let ns_app = create_app(pl_attribs.activation_policy).ok_or_else(|| { unsafe { pool.drain() }; os_error!(OsError::CreationError("Couldn't create `NSApplication`")) })?; - let nswindow = create_window(&win_attribs, &pl_attribs).ok_or_else(|| { + let ns_window = create_window(&win_attribs, &pl_attribs).ok_or_else(|| { unsafe { pool.drain() }; os_error!(OsError::CreationError("Couldn't create `NSWindow`")) })?; - let (nsview, cursor) = unsafe { create_view(*nswindow) }.ok_or_else(|| { + let (ns_view, cursor) = unsafe { create_view(*ns_window) }.ok_or_else(|| { unsafe { pool.drain() }; os_error!(OsError::CreationError("Couldn't create `NSView`")) })?; - let input_context = unsafe { util::create_input_context(*nsview) }; + let input_context = unsafe { util::create_input_context(*ns_view) }; unsafe { if win_attribs.transparent { - nswindow.setOpaque_(NO); - nswindow.setBackgroundColor_(NSColor::clearColor(nil)); + ns_window.setOpaque_(NO); + ns_window.setBackgroundColor_(NSColor::clearColor(nil)); } - nsapp.activateIgnoringOtherApps_(YES); + ns_app.activateIgnoringOtherApps_(YES); - win_attribs.min_inner_size.map(|dim| set_min_inner_size(*nswindow, dim)); - win_attribs.max_inner_size.map(|dim| set_max_inner_size(*nswindow, dim)); + win_attribs + .min_inner_size + .map(|dim| set_min_inner_size(*ns_window, dim)); + win_attribs + .max_inner_size + .map(|dim| set_max_inner_size(*ns_window, dim)); use cocoa::foundation::NSArray; // register for drag and drop operations. - let () = msg_send![*nswindow, registerForDraggedTypes:NSArray::arrayWithObject( - nil, - appkit::NSFilenamesPboardType, - )]; + let () = msg_send![ + *ns_window, + registerForDraggedTypes: + NSArray::arrayWithObject(nil, appkit::NSFilenamesPboardType) + ]; } // Since `win_attribs` is put into a mutex below, we'll just copy these @@ -313,8 +343,8 @@ impl UnownedWindow { let decorations = win_attribs.decorations; let window = Arc::new(UnownedWindow { - nsview, - nswindow, + ns_view, + ns_window, input_context, shared_state: Arc::new(Mutex::new(win_attribs.into())), decorations: AtomicBool::new(decorations), @@ -341,9 +371,9 @@ impl UnownedWindow { // before it transitions. unsafe { if visible { - window.nswindow.makeKeyAndOrderFront_(nil); + window.ns_window.makeKeyAndOrderFront_(nil); } else { - window.nswindow.makeKeyWindow(); + window.ns_window.makeKeyWindow(); } } @@ -357,36 +387,27 @@ impl UnownedWindow { } fn set_style_mask_async(&self, mask: NSWindowStyleMask) { - unsafe { util::set_style_mask_async( - *self.nswindow, - *self.nsview, - mask, - ) }; + unsafe { util::set_style_mask_async(*self.ns_window, *self.ns_view, mask) }; } fn set_style_mask_sync(&self, mask: NSWindowStyleMask) { - unsafe { util::set_style_mask_sync( - *self.nswindow, - *self.nsview, - mask, - ) }; + unsafe { util::set_style_mask_sync(*self.ns_window, *self.ns_view, mask) }; } pub fn id(&self) -> Id { - get_window_id(*self.nswindow) + get_window_id(*self.ns_window) } pub fn set_title(&self, title: &str) { unsafe { - let title = IdRef::new(NSString::alloc(nil).init_str(title)); - self.nswindow.setTitle_(*title); + util::set_title_async(*self.ns_window, title.to_string()); } } pub fn set_visible(&self, visible: bool) { match visible { - true => unsafe { util::make_key_and_order_front_async(*self.nswindow) }, - false => unsafe { util::order_out_async(*self.nswindow) }, + true => unsafe { util::make_key_and_order_front_async(*self.ns_window) }, + false => unsafe { util::order_out_async(*self.ns_window) }, } } @@ -395,24 +416,23 @@ impl UnownedWindow { } pub fn outer_position(&self) -> Result { - let frame_rect = unsafe { NSWindow::frame(*self.nswindow) }; + let frame_rect = unsafe { NSWindow::frame(*self.ns_window) }; Ok(( frame_rect.origin.x as f64, util::bottom_left_to_top_left(frame_rect), - ).into()) + ) + .into()) } pub fn inner_position(&self) -> Result { let content_rect = unsafe { - NSWindow::contentRectForFrameRect_( - *self.nswindow, - NSWindow::frame(*self.nswindow), - ) + NSWindow::contentRectForFrameRect_(*self.ns_window, NSWindow::frame(*self.ns_window)) }; Ok(( content_rect.origin.x as f64, util::bottom_left_to_top_left(content_rect), - ).into()) + ) + .into()) } pub fn set_outer_position(&self, position: LogicalPosition) { @@ -426,40 +446,40 @@ impl UnownedWindow { NSSize::new(0f64, 0f64), ); unsafe { - util::set_frame_top_left_point_async(*self.nswindow, dummy.origin); + util::set_frame_top_left_point_async(*self.ns_window, dummy.origin); } } #[inline] pub fn inner_size(&self) -> LogicalSize { - let view_frame = unsafe { NSView::frame(*self.nsview) }; + let view_frame = unsafe { NSView::frame(*self.ns_view) }; (view_frame.size.width as f64, view_frame.size.height as f64).into() } #[inline] pub fn outer_size(&self) -> LogicalSize { - let view_frame = unsafe { NSWindow::frame(*self.nswindow) }; + let view_frame = unsafe { NSWindow::frame(*self.ns_window) }; (view_frame.size.width as f64, view_frame.size.height as f64).into() } #[inline] pub fn set_inner_size(&self, size: LogicalSize) { unsafe { - util::set_content_size_async(*self.nswindow, size); + util::set_content_size_async(*self.ns_window, size); } } pub fn set_min_inner_size(&self, dimensions: Option) { unsafe { let dimensions = dimensions.unwrap_or_else(|| (0, 0).into()); - set_min_inner_size(*self.nswindow, dimensions); + set_min_inner_size(*self.ns_window, dimensions); } } pub fn set_max_inner_size(&self, dimensions: Option) { unsafe { let dimensions = dimensions.unwrap_or_else(|| (!0, !0).into()); - set_max_inner_size(*self.nswindow, dimensions); + set_max_inner_size(*self.ns_window, dimensions); } } @@ -473,7 +493,7 @@ impl UnownedWindow { shared_state_lock.fullscreen.is_some() }; if !fullscreen { - let mut mask = unsafe { self.nswindow.styleMask() }; + let mut mask = unsafe { self.ns_window.styleMask() }; if resizable { mask |= NSWindowStyleMask::NSResizableWindowMask; } else { @@ -489,8 +509,8 @@ impl UnownedWindow { *cursor_access.lock().unwrap() = cursor; } unsafe { - let _: () = msg_send![*self.nswindow, - invalidateCursorRectsForView:*self.nsview + let _: () = msg_send![*self.ns_window, + invalidateCursorRectsForView:*self.ns_view ]; } } @@ -519,11 +539,14 @@ impl UnownedWindow { #[inline] pub fn hidpi_factor(&self) -> f64 { - unsafe { NSWindow::backingScaleFactor(*self.nswindow) as _ } + unsafe { NSWindow::backingScaleFactor(*self.ns_window) as _ } } #[inline] - pub fn set_cursor_position(&self, cursor_position: LogicalPosition) -> Result<(), ExternalError> { + pub fn set_cursor_position( + &self, + cursor_position: LogicalPosition, + ) -> Result<(), ExternalError> { let window_position = self.inner_position().unwrap(); let point = appkit::CGPoint { x: (cursor_position.x + window_position.x) as CGFloat, @@ -540,16 +563,16 @@ impl UnownedWindow { pub(crate) fn is_zoomed(&self) -> bool { // because `isZoomed` doesn't work if the window's borderless, // we make it resizable temporalily. - let curr_mask = unsafe { self.nswindow.styleMask() }; + let curr_mask = unsafe { self.ns_window.styleMask() }; - let required = NSWindowStyleMask::NSTitledWindowMask - | NSWindowStyleMask::NSResizableWindowMask; + let required = + NSWindowStyleMask::NSTitledWindowMask | NSWindowStyleMask::NSResizableWindowMask; let needs_temp_mask = !curr_mask.contains(required); if needs_temp_mask { self.set_style_mask_sync(required); } - let is_zoomed: BOOL = unsafe { msg_send![*self.nswindow, isZoomed] }; + let is_zoomed: BOOL = unsafe { msg_send![*self.ns_window, isZoomed] }; // Roll back temp styles if needs_temp_mask { @@ -560,9 +583,10 @@ impl UnownedWindow { } fn saved_style(&self, shared_state: &mut SharedState) -> NSWindowStyleMask { - let base_mask = shared_state.saved_style + let base_mask = shared_state + .saved_style .take() - .unwrap_or_else(|| unsafe { self.nswindow.styleMask() }); + .unwrap_or_else(|| unsafe { self.ns_window.styleMask() }); if shared_state.resizable { base_mask | NSWindowStyleMask::NSResizableWindowMask } else { @@ -570,13 +594,6 @@ impl UnownedWindow { } } - fn saved_standard_frame(shared_state: &mut SharedState) -> NSRect { - shared_state.standard_frame.unwrap_or_else(|| NSRect::new( - NSPoint::new(50.0, 50.0), - NSSize::new(800.0, 600.0), - )) - } - pub(crate) fn restore_state_from_fullscreen(&self) { let maximized = { trace!("Locked shared state in `restore_state_from_fullscreen`"); @@ -596,42 +613,17 @@ impl UnownedWindow { #[inline] pub fn set_maximized(&self, maximized: bool) { let is_zoomed = self.is_zoomed(); - if is_zoomed == maximized { return }; - - trace!("Locked shared state in `set_maximized`"); - let mut shared_state_lock = self.shared_state.lock().unwrap(); - - // Save the standard frame sized if it is not zoomed - if !is_zoomed { - unsafe { - shared_state_lock.standard_frame = Some(NSWindow::frame(*self.nswindow)); - } - } - - shared_state_lock.maximized = maximized; - - let curr_mask = unsafe { self.nswindow.styleMask() }; - if shared_state_lock.fullscreen.is_some() { - // Handle it in window_did_exit_fullscreen + if is_zoomed == maximized { return; - } else if curr_mask.contains(NSWindowStyleMask::NSResizableWindowMask) { - // Just use the native zoom if resizable - unsafe { self.nswindow.zoom_(nil) }; - } else { - // if it's not resizable, we set the frame directly - unsafe { - let new_rect = if maximized { - let screen = NSScreen::mainScreen(nil); - NSScreen::visibleFrame(screen) - } else { - Self::saved_standard_frame(&mut *shared_state_lock) - }; - // This probably isn't thread-safe! - self.nswindow.setFrame_display_(new_rect, 0); - } + }; + unsafe { + util::set_maximized_async( + *self.ns_window, + is_zoomed, + maximized, + Arc::downgrade(&self.shared_state), + ); } - - trace!("Unlocked shared state in `set_maximized`"); } #[inline] @@ -646,7 +638,7 @@ impl UnownedWindow { pub fn set_fullscreen(&self, monitor: Option) { let shared_state_lock = self.shared_state.lock().unwrap(); if shared_state_lock.is_simple_fullscreen { - return + return; } let not_fullscreen = { @@ -657,7 +649,7 @@ impl UnownedWindow { // Our best bet is probably to move to the origin of the // target monitor. unimplemented!() - }, + } (&None, None) | (&Some(_), Some(_)) => return, _ => (), } @@ -665,12 +657,14 @@ impl UnownedWindow { current.is_none() }; - unsafe { util::toggle_full_screen_async( - *self.nswindow, - *self.nsview, - not_fullscreen, - Arc::downgrade(&self.shared_state), - ) }; + unsafe { + util::toggle_full_screen_async( + *self.ns_window, + *self.ns_view, + not_fullscreen, + Arc::downgrade(&self.shared_state), + ) + }; } #[inline] @@ -690,7 +684,9 @@ impl UnownedWindow { // If we're in fullscreen mode, we wait to apply decoration changes // until we're in `window_did_exit_fullscreen`. - if fullscreen { return } + if fullscreen { + return; + } let new_mask = { let mut new_mask = if decorations { @@ -718,7 +714,7 @@ impl UnownedWindow { } else { ffi::NSWindowLevel::NSNormalWindowLevel }; - unsafe { util::set_level_async(*self.nswindow, level) }; + unsafe { util::set_level_async(*self.ns_window, level) }; } #[inline] @@ -737,7 +733,7 @@ impl UnownedWindow { pub fn set_ime_position(&self, logical_spot: LogicalPosition) { unsafe { view::set_ime_position( - *self.nsview, + *self.ns_view, *self.input_context, logical_spot.x, logical_spot.y, @@ -748,12 +744,14 @@ impl UnownedWindow { #[inline] pub fn current_monitor(&self) -> RootMonitorHandle { unsafe { - let screen: id = msg_send![*self.nswindow, screen]; + let screen: id = msg_send![*self.ns_window, screen]; let desc = NSScreen::deviceDescription(screen); let key = IdRef::new(NSString::alloc(nil).init_str("NSScreenNumber")); let value = NSDictionary::valueForKey_(desc, *key); let display_id = msg_send![value, unsignedIntegerValue]; - RootMonitorHandle { inner: MonitorHandle::new(display_id) } + RootMonitorHandle { + inner: MonitorHandle::new(display_id), + } } } @@ -770,21 +768,23 @@ impl UnownedWindow { impl WindowExtMacOS for UnownedWindow { #[inline] - fn nswindow(&self) -> *mut c_void { - *self.nswindow as *mut _ + fn ns_window(&self) -> *mut c_void { + *self.ns_window as *mut _ } #[inline] - fn nsview(&self) -> *mut c_void { - *self.nsview as *mut _ + fn ns_view(&self) -> *mut c_void { + *self.ns_view as *mut _ } #[inline] - fn request_user_attention(&self, is_critical: bool) { + fn request_user_attention(&self, request_type: RequestUserAttentionType) { unsafe { - NSApp().requestUserAttention_(match is_critical { - true => NSRequestUserAttentionType::NSCriticalRequest, - false => NSRequestUserAttentionType::NSInformationalRequest, + NSApp().requestUserAttention_(match request_type { + RequestUserAttentionType::Critical => NSRequestUserAttentionType::NSCriticalRequest, + RequestUserAttentionType::Informational => { + NSRequestUserAttentionType::NSInformationalRequest + } }); } } @@ -805,14 +805,17 @@ impl WindowExtMacOS for UnownedWindow { let is_simple_fullscreen = shared_state_lock.is_simple_fullscreen; // Do nothing if native fullscreen is active. - if is_native_fullscreen || (fullscreen && is_simple_fullscreen) || (!fullscreen && !is_simple_fullscreen) { + if is_native_fullscreen + || (fullscreen && is_simple_fullscreen) + || (!fullscreen && !is_simple_fullscreen) + { return false; } if fullscreen { // Remember the original window's settings - shared_state_lock.standard_frame = Some(NSWindow::frame(*self.nswindow)); - shared_state_lock.saved_style = Some(self.nswindow.styleMask()); + shared_state_lock.standard_frame = Some(NSWindow::frame(*self.ns_window)); + shared_state_lock.saved_style = Some(self.ns_window.styleMask()); shared_state_lock.save_presentation_opts = Some(app.presentationOptions_()); // Tell our window's state that we're in fullscreen @@ -825,17 +828,32 @@ impl WindowExtMacOS for UnownedWindow { app.setPresentationOptions_(presentation_options); // Hide the titlebar - util::toggle_style_mask(*self.nswindow, *self.nsview, NSWindowStyleMask::NSTitledWindowMask, false); + util::toggle_style_mask( + *self.ns_window, + *self.ns_view, + NSWindowStyleMask::NSTitledWindowMask, + false, + ); // Set the window frame to the screen frame size - let screen = self.nswindow.screen(); + let screen = self.ns_window.screen(); let screen_frame = NSScreen::frame(screen); - NSWindow::setFrame_display_(*self.nswindow, screen_frame, YES); + NSWindow::setFrame_display_(*self.ns_window, screen_frame, YES); // Fullscreen windows can't be resized, minimized, or moved - util::toggle_style_mask(*self.nswindow, *self.nsview, NSWindowStyleMask::NSMiniaturizableWindowMask, false); - util::toggle_style_mask(*self.nswindow, *self.nsview, NSWindowStyleMask::NSResizableWindowMask, false); - NSWindow::setMovable_(*self.nswindow, NO); + util::toggle_style_mask( + *self.ns_window, + *self.ns_view, + NSWindowStyleMask::NSMiniaturizableWindowMask, + false, + ); + util::toggle_style_mask( + *self.ns_window, + *self.ns_view, + NSWindowStyleMask::NSResizableWindowMask, + false, + ); + NSWindow::setMovable_(*self.ns_window, NO); true } else { @@ -847,9 +865,9 @@ impl WindowExtMacOS for UnownedWindow { app.setPresentationOptions_(presentation_opts); } - let frame = Self::saved_standard_frame(&mut *shared_state_lock); - NSWindow::setFrame_display_(*self.nswindow, frame, YES); - NSWindow::setMovable_(*self.nswindow, YES); + let frame = shared_state_lock.saved_standard_frame(); + NSWindow::setFrame_display_(*self.ns_window, frame, YES); + NSWindow::setMovable_(*self.ns_window, YES); true } @@ -861,8 +879,8 @@ impl Drop for UnownedWindow { fn drop(&mut self) { trace!("Dropping `UnownedWindow` ({:?})", self as *mut _); // Close the window if it has not yet been closed. - if *self.nswindow != nil { - unsafe { util::close_async(*self.nswindow) }; + if *self.ns_window != nil { + unsafe { util::close_async(*self.ns_window) }; } } } diff --git a/src/platform_impl/macos/window_delegate.rs b/src/platform_impl/macos/window_delegate.rs index 46460c34..c9680d89 100644 --- a/src/platform_impl/macos/window_delegate.rs +++ b/src/platform_impl/macos/window_delegate.rs @@ -1,20 +1,33 @@ -use std::{f64, os::raw::c_void, sync::{Arc, Weak}}; +use std::{ + f64, + os::raw::c_void, + sync::{Arc, Weak}, +}; use cocoa::{ - appkit::{self, NSView, NSWindow}, base::{id, nil}, + appkit::{self, NSView, NSWindow}, + base::{id, nil}, foundation::NSAutoreleasePool, }; -use objc::{runtime::{Class, Object, Sel, BOOL, YES, NO}, declare::ClassDecl}; +use objc::{ + declare::ClassDecl, + runtime::{Class, Object, Sel, BOOL, NO, YES}, +}; -use {dpi::LogicalSize, event::{Event, WindowEvent}, window::WindowId}; -use platform_impl::platform::{ - app_state::AppState, util::{self, IdRef}, - window::{get_window_id, UnownedWindow}, +use crate::{ + dpi::LogicalSize, + event::{Event, WindowEvent}, + platform_impl::platform::{ + app_state::AppState, + util::{self, IdRef}, + window::{get_window_id, UnownedWindow}, + }, + window::WindowId, }; pub struct WindowDelegateState { - nswindow: IdRef, // never changes - nsview: IdRef, // never changes + ns_window: IdRef, // never changes + ns_view: IdRef, // never changes window: Weak, @@ -33,15 +46,12 @@ pub struct WindowDelegateState { } impl WindowDelegateState { - pub fn new( - window: &Arc, - initial_fullscreen: bool, - ) -> Self { + pub fn new(window: &Arc, initial_fullscreen: bool) -> Self { let dpi_factor = window.hidpi_factor(); let mut delegate_state = WindowDelegateState { - nswindow: window.nswindow.clone(), - nsview: window.nsview.clone(), + ns_window: window.ns_window.clone(), + ns_view: window.ns_view.clone(), window: Arc::downgrade(&window), initial_fullscreen, previous_position: None, @@ -57,33 +67,32 @@ impl WindowDelegateState { } fn with_window(&mut self, callback: F) -> Option - where F: FnOnce(&UnownedWindow) -> T + where + F: FnOnce(&UnownedWindow) -> T, { - self.window - .upgrade() - .map(|ref window| callback(window)) + self.window.upgrade().map(|ref window| callback(window)) } pub fn emit_event(&mut self, event: WindowEvent) { let event = Event::WindowEvent { - window_id: WindowId(get_window_id(*self.nswindow)), + window_id: WindowId(get_window_id(*self.ns_window)), event, }; AppState::queue_event(event); } pub fn emit_resize_event(&mut self) { - let rect = unsafe { NSView::frame(*self.nsview) }; + let rect = unsafe { NSView::frame(*self.ns_view) }; let size = LogicalSize::new(rect.size.width as f64, rect.size.height as f64); let event = Event::WindowEvent { - window_id: WindowId(get_window_id(*self.nswindow)), + window_id: WindowId(get_window_id(*self.ns_window)), event: WindowEvent::Resized(size), }; AppState::send_event_immediately(event); } fn emit_move_event(&mut self) { - let rect = unsafe { NSWindow::frame(*self.nswindow) }; + let rect = unsafe { NSWindow::frame(*self.ns_window) }; let x = rect.origin.x as f64; let y = util::bottom_left_to_top_left(rect); let moved = self.previous_position != Some((x, y)); @@ -100,7 +109,7 @@ pub fn new_delegate(window: &Arc, initial_fullscreen: bool) -> Id // This is free'd in `dealloc` let state_ptr = Box::into_raw(Box::new(state)) as *mut c_void; let delegate: id = msg_send![WINDOW_DELEGATE_CLASS.0, alloc]; - IdRef::new(msg_send![delegate, initWithWinit:state_ptr]) + IdRef::new(msg_send![delegate, initWithWinit: state_ptr]) } } @@ -113,83 +122,81 @@ lazy_static! { let superclass = class!(NSResponder); let mut decl = ClassDecl::new("WinitWindowDelegate", superclass).unwrap(); - decl.add_method( - sel!(dealloc), - dealloc as extern fn(&Object, Sel), - ); + decl.add_method(sel!(dealloc), dealloc as extern "C" fn(&Object, Sel)); decl.add_method( sel!(initWithWinit:), - init_with_winit as extern fn(&Object, Sel, *mut c_void) -> id, + init_with_winit as extern "C" fn(&Object, Sel, *mut c_void) -> id, ); decl.add_method( sel!(windowShouldClose:), - window_should_close as extern fn(&Object, Sel, id) -> BOOL, + window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL, ); decl.add_method( sel!(windowWillClose:), - window_will_close as extern fn(&Object, Sel, id), + window_will_close as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(windowDidResize:), - window_did_resize as extern fn(&Object, Sel, id), + window_did_resize as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(windowDidMove:), - window_did_move as extern fn(&Object, Sel, id)); + window_did_move as extern "C" fn(&Object, Sel, id), + ); decl.add_method( sel!(windowDidChangeScreen:), - window_did_change_screen as extern fn(&Object, Sel, id), + window_did_change_screen as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(windowDidChangeBackingProperties:), - window_did_change_backing_properties as extern fn(&Object, Sel, id), + window_did_change_backing_properties as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(windowDidBecomeKey:), - window_did_become_key as extern fn(&Object, Sel, id), + window_did_become_key as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(windowDidResignKey:), - window_did_resign_key as extern fn(&Object, Sel, id), + window_did_resign_key as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(draggingEntered:), - dragging_entered as extern fn(&Object, Sel, id) -> BOOL, + dragging_entered as extern "C" fn(&Object, Sel, id) -> BOOL, ); decl.add_method( sel!(prepareForDragOperation:), - prepare_for_drag_operation as extern fn(&Object, Sel, id) -> BOOL, + prepare_for_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, ); decl.add_method( sel!(performDragOperation:), - perform_drag_operation as extern fn(&Object, Sel, id) -> BOOL, + perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, ); decl.add_method( sel!(concludeDragOperation:), - conclude_drag_operation as extern fn(&Object, Sel, id), + conclude_drag_operation as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(draggingExited:), - dragging_exited as extern fn(&Object, Sel, id), + dragging_exited as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(windowDidEnterFullScreen:), - window_did_enter_fullscreen as extern fn(&Object, Sel, id), + window_did_enter_fullscreen as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(windowWillEnterFullScreen:), - window_will_enter_fullscreen as extern fn(&Object, Sel, id), + window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(windowDidExitFullScreen:), - window_did_exit_fullscreen as extern fn(&Object, Sel, id), + window_did_exit_fullscreen as extern "C" fn(&Object, Sel, id), ); decl.add_method( sel!(windowDidFailToEnterFullScreen:), - window_did_fail_to_enter_fullscreen as extern fn(&Object, Sel, id), + window_did_fail_to_enter_fullscreen as extern "C" fn(&Object, Sel, id), ); decl.add_ivar::<*mut c_void>("winitState"); @@ -207,47 +214,47 @@ fn with_state T, T>(this: &Object, callba callback(state_ptr); } -extern fn dealloc(this: &Object, _sel: Sel) { +extern "C" fn dealloc(this: &Object, _sel: Sel) { with_state(this, |state| unsafe { Box::from_raw(state as *mut WindowDelegateState); }); } -extern fn init_with_winit(this: &Object, _sel: Sel, state: *mut c_void) -> id { +extern "C" fn init_with_winit(this: &Object, _sel: Sel, state: *mut c_void) -> id { unsafe { let this: id = msg_send![this, init]; if this != nil { (*this).set_ivar("winitState", state); with_state(&*this, |state| { - let () = msg_send![*state.nswindow, setDelegate:this]; + let () = msg_send![*state.ns_window, setDelegate: this]; }); } this } } -extern fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL { +extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL { trace!("Triggered `windowShouldClose:`"); with_state(this, |state| state.emit_event(WindowEvent::CloseRequested)); trace!("Completed `windowShouldClose:`"); NO } -extern fn window_will_close(this: &Object, _: Sel, _: id) { +extern "C" fn window_will_close(this: &Object, _: Sel, _: id) { trace!("Triggered `windowWillClose:`"); with_state(this, |state| unsafe { // `setDelegate:` retains the previous value and then autoreleases it let pool = NSAutoreleasePool::new(nil); // Since El Capitan, we need to be careful that delegate methods can't // be called after the window closes. - let () = msg_send![*state.nswindow, setDelegate:nil]; + let () = msg_send![*state.ns_window, setDelegate: nil]; pool.drain(); state.emit_event(WindowEvent::Destroyed); }); trace!("Completed `windowWillClose:`"); } -extern fn window_did_resize(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidResize:`"); with_state(this, |state| { state.emit_resize_event(); @@ -257,7 +264,7 @@ extern fn window_did_resize(this: &Object, _: Sel, _: id) { } // This won't be triggered if the move was part of a resize. -extern fn window_did_move(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidMove:`"); with_state(this, |state| { state.emit_move_event(); @@ -265,12 +272,10 @@ extern fn window_did_move(this: &Object, _: Sel, _: id) { trace!("Completed `windowDidMove:`"); } -extern fn window_did_change_screen(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidChangeScreen:`"); with_state(this, |state| { - let dpi_factor = unsafe { - NSWindow::backingScaleFactor(*state.nswindow) - } as f64; + let dpi_factor = unsafe { NSWindow::backingScaleFactor(*state.ns_window) } as f64; if state.previous_dpi_factor != dpi_factor { state.previous_dpi_factor = dpi_factor; state.emit_event(WindowEvent::HiDpiFactorChanged(dpi_factor)); @@ -281,12 +286,10 @@ extern fn window_did_change_screen(this: &Object, _: Sel, _: id) { } // This will always be called before `window_did_change_screen`. -extern fn window_did_change_backing_properties(this: &Object, _:Sel, _:id) { +extern "C" fn window_did_change_backing_properties(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidChangeBackingProperties:`"); with_state(this, |state| { - let dpi_factor = unsafe { - NSWindow::backingScaleFactor(*state.nswindow) - } as f64; + let dpi_factor = unsafe { NSWindow::backingScaleFactor(*state.ns_window) } as f64; if state.previous_dpi_factor != dpi_factor { state.previous_dpi_factor = dpi_factor; state.emit_event(WindowEvent::HiDpiFactorChanged(dpi_factor)); @@ -296,7 +299,7 @@ extern fn window_did_change_backing_properties(this: &Object, _:Sel, _:id) { trace!("Completed `windowDidChangeBackingProperties:`"); } -extern fn window_did_become_key(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_become_key(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidBecomeKey:`"); with_state(this, |state| { // TODO: center the cursor if the window had mouse grab when it @@ -306,7 +309,7 @@ extern fn window_did_become_key(this: &Object, _: Sel, _: id) { trace!("Completed `windowDidBecomeKey:`"); } -extern fn window_did_resign_key(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_resign_key(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidResignKey:`"); with_state(this, |state| { state.emit_event(WindowEvent::Focused(false)); @@ -315,11 +318,10 @@ extern fn window_did_resign_key(this: &Object, _: Sel, _: id) { } /// Invoked when the dragged image enters destination bounds or frame -extern fn dragging_entered(this: &Object, _: Sel, sender: id) -> BOOL { +extern "C" fn dragging_entered(this: &Object, _: Sel, sender: id) -> BOOL { trace!("Triggered `draggingEntered:`"); - use cocoa::appkit::NSPasteboard; - use cocoa::foundation::NSFastEnumeration; + use cocoa::{appkit::NSPasteboard, foundation::NSFastEnumeration}; use std::path::PathBuf; let pb: id = unsafe { msg_send![sender, draggingPasteboard] }; @@ -337,25 +339,24 @@ extern fn dragging_entered(this: &Object, _: Sel, sender: id) -> BOOL { state.emit_event(WindowEvent::HoveredFile(PathBuf::from(path))); }); } - }; + } trace!("Completed `draggingEntered:`"); YES } /// Invoked when the image is released -extern fn prepare_for_drag_operation(_: &Object, _: Sel, _: id) -> BOOL { +extern "C" fn prepare_for_drag_operation(_: &Object, _: Sel, _: id) -> BOOL { trace!("Triggered `prepareForDragOperation:`"); trace!("Completed `prepareForDragOperation:`"); YES } /// Invoked after the released image has been removed from the screen -extern fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL { +extern "C" fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL { trace!("Triggered `performDragOperation:`"); - use cocoa::appkit::NSPasteboard; - use cocoa::foundation::NSFastEnumeration; + use cocoa::{appkit::NSPasteboard, foundation::NSFastEnumeration}; use std::path::PathBuf; let pb: id = unsafe { msg_send![sender, draggingPasteboard] }; @@ -373,38 +374,42 @@ extern fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL { state.emit_event(WindowEvent::DroppedFile(PathBuf::from(path))); }); } - }; + } trace!("Completed `performDragOperation:`"); YES } /// Invoked when the dragging operation is complete -extern fn conclude_drag_operation(_: &Object, _: Sel, _: id) { +extern "C" fn conclude_drag_operation(_: &Object, _: Sel, _: id) { trace!("Triggered `concludeDragOperation:`"); trace!("Completed `concludeDragOperation:`"); } /// Invoked when the dragging operation is cancelled -extern fn dragging_exited(this: &Object, _: Sel, _: id) { +extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) { trace!("Triggered `draggingExited:`"); - with_state(this, |state| state.emit_event(WindowEvent::HoveredFileCancelled)); + with_state(this, |state| { + state.emit_event(WindowEvent::HoveredFileCancelled) + }); trace!("Completed `draggingExited:`"); } /// Invoked when before enter fullscreen -extern fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { +extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { trace!("Triggered `windowWillEnterFullscreen:`"); - with_state(this, |state| state.with_window(|window| { - trace!("Locked shared state in `window_will_enter_fullscreen`"); - window.shared_state.lock().unwrap().maximized = window.is_zoomed(); - trace!("Unlocked shared state in `window_will_enter_fullscreen`"); - })); + with_state(this, |state| { + state.with_window(|window| { + trace!("Locked shared state in `window_will_enter_fullscreen`"); + window.shared_state.lock().unwrap().maximized = window.is_zoomed(); + trace!("Unlocked shared state in `window_will_enter_fullscreen`"); + }) + }); trace!("Completed `windowWillEnterFullscreen:`"); } /// Invoked when entered fullscreen -extern fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidEnterFullscreen:`"); with_state(this, |state| { state.with_window(|window| { @@ -419,11 +424,13 @@ extern fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) { } /// Invoked when exited fullscreen -extern fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidExitFullscreen:`"); - with_state(this, |state| state.with_window(|window| { - window.restore_state_from_fullscreen(); - })); + with_state(this, |state| { + state.with_window(|window| { + window.restore_state_from_fullscreen(); + }) + }); trace!("Completed `windowDidExitFullscreen:`"); } @@ -443,15 +450,17 @@ extern fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) { /// due to being in the midst of handling some other animation or user gesture. /// This method indicates that there was an error, and you should clean up any /// work you may have done to prepare to enter full-screen mode. -extern fn window_did_fail_to_enter_fullscreen(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_fail_to_enter_fullscreen(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidFailToEnterFullscreen:`"); with_state(this, |state| { if state.initial_fullscreen { - let _: () = unsafe { msg_send![*state.nswindow, - performSelector:sel!(toggleFullScreen:) - withObject:nil - afterDelay: 0.5 - ] }; + let _: () = unsafe { + msg_send![*state.ns_window, + performSelector:sel!(toggleFullScreen:) + withObject:nil + afterDelay: 0.5 + ] + }; } else { state.with_window(|window| window.restore_state_from_fullscreen()); } diff --git a/src/platform_impl/windows/dpi.rs b/src/platform_impl/windows/dpi.rs index 4bf31f39..12186182 100644 --- a/src/platform_impl/windows/dpi.rs +++ b/src/platform_impl/windows/dpi.rs @@ -1,45 +1,39 @@ #![allow(non_snake_case, unused_unsafe)] -use std::mem; -use std::os::raw::c_void; -use std::sync::{Once, ONCE_INIT}; +use std::{mem, os::raw::c_void, sync::Once}; -use winapi::shared::minwindef::{BOOL, UINT, FALSE}; -use winapi::shared::windef::{ - DPI_AWARENESS_CONTEXT, - DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, - HMONITOR, - HWND, +use winapi::{ + shared::{ + minwindef::{BOOL, FALSE, UINT}, + windef::{DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, HMONITOR, HWND}, + winerror::S_OK, + }, + um::{ + libloaderapi::{GetProcAddress, LoadLibraryA}, + shellscalingapi::{ + MDT_EFFECTIVE_DPI, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS, + PROCESS_PER_MONITOR_DPI_AWARE, + }, + wingdi::{GetDeviceCaps, LOGPIXELSX}, + winnt::{HRESULT, LPCSTR}, + winuser::{self, MONITOR_DEFAULTTONEAREST}, + }, }; -use winapi::shared::winerror::S_OK; -use winapi::um::libloaderapi::{GetProcAddress, LoadLibraryA}; -use winapi::um::shellscalingapi::{ - MDT_EFFECTIVE_DPI, - MONITOR_DPI_TYPE, - PROCESS_DPI_AWARENESS, - PROCESS_PER_MONITOR_DPI_AWARE, -}; -use winapi::um::wingdi::{GetDeviceCaps, LOGPIXELSX}; -use winapi::um::winnt::{HRESULT, LPCSTR}; -use winapi::um::winuser::{self, MONITOR_DEFAULTTONEAREST}; const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: DPI_AWARENESS_CONTEXT = -4isize as _; -type SetProcessDPIAware = unsafe extern "system" fn () -> BOOL; -type SetProcessDpiAwareness = unsafe extern "system" fn ( - value: PROCESS_DPI_AWARENESS, -) -> HRESULT; -type SetProcessDpiAwarenessContext = unsafe extern "system" fn ( - value: DPI_AWARENESS_CONTEXT, -) -> BOOL; -type GetDpiForWindow = unsafe extern "system" fn (hwnd: HWND) -> UINT; -type GetDpiForMonitor = unsafe extern "system" fn ( +type SetProcessDPIAware = unsafe extern "system" fn() -> BOOL; +type SetProcessDpiAwareness = unsafe extern "system" fn(value: PROCESS_DPI_AWARENESS) -> HRESULT; +type SetProcessDpiAwarenessContext = + unsafe extern "system" fn(value: DPI_AWARENESS_CONTEXT) -> BOOL; +type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> UINT; +type GetDpiForMonitor = unsafe extern "system" fn( hmonitor: HMONITOR, dpi_type: MONITOR_DPI_TYPE, dpi_x: *mut UINT, dpi_y: *mut UINT, ) -> HRESULT; -type EnableNonClientDpiScaling = unsafe extern "system" fn (hwnd: HWND) -> BOOL; +type EnableNonClientDpiScaling = unsafe extern "system" fn(hwnd: HWND) -> BOOL; // Helper function to dynamically load function pointer. // `library` and `function` must be zero-terminated. @@ -65,53 +59,48 @@ macro_rules! get_function { ($lib:expr, $func:ident) => { get_function_impl(concat!($lib, '\0'), concat!(stringify!($func), '\0')) .map(|f| unsafe { mem::transmute::<*const _, $func>(f) }) - } + }; } lazy_static! { - static ref GET_DPI_FOR_WINDOW: Option = get_function!( - "user32.dll", - GetDpiForWindow - ); - static ref GET_DPI_FOR_MONITOR: Option = get_function!( - "shcore.dll", - GetDpiForMonitor - ); - static ref ENABLE_NON_CLIENT_DPI_SCALING: Option = get_function!( - "user32.dll", - EnableNonClientDpiScaling - ); + static ref GET_DPI_FOR_WINDOW: Option = + get_function!("user32.dll", GetDpiForWindow); + static ref GET_DPI_FOR_MONITOR: Option = + get_function!("shcore.dll", GetDpiForMonitor); + static ref ENABLE_NON_CLIENT_DPI_SCALING: Option = + get_function!("user32.dll", EnableNonClientDpiScaling); } pub fn become_dpi_aware(enable: bool) { - if !enable { return; } - static ENABLE_DPI_AWARENESS: Once = ONCE_INIT; - ENABLE_DPI_AWARENESS.call_once(|| { unsafe { - if let Some(SetProcessDpiAwarenessContext) = get_function!( - "user32.dll", - SetProcessDpiAwarenessContext - ) { - // We are on Windows 10 Anniversary Update (1607) or later. - if SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) - == FALSE { - // V2 only works with Windows 10 Creators Update (1703). Try using the older - // V1 if we can't set V2. - SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); + if !enable { + return; + } + static ENABLE_DPI_AWARENESS: Once = Once::new(); + ENABLE_DPI_AWARENESS.call_once(|| { + unsafe { + if let Some(SetProcessDpiAwarenessContext) = + get_function!("user32.dll", SetProcessDpiAwarenessContext) + { + // We are on Windows 10 Anniversary Update (1607) or later. + if SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) + == FALSE + { + // V2 only works with Windows 10 Creators Update (1703). Try using the older + // V1 if we can't set V2. + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); + } + } else if let Some(SetProcessDpiAwareness) = + get_function!("shcore.dll", SetProcessDpiAwareness) + { + // We are on Windows 8.1 or later. + SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); + } else if let Some(SetProcessDPIAware) = get_function!("user32.dll", SetProcessDPIAware) + { + // We are on Vista or later. + SetProcessDPIAware(); } - } else if let Some(SetProcessDpiAwareness) = get_function!( - "shcore.dll", - SetProcessDpiAwareness - ) { - // We are on Windows 8.1 or later. - SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); - } else if let Some(SetProcessDPIAware) = get_function!( - "user32.dll", - SetProcessDPIAware - ) { - // We are on Vista or later. - SetProcessDPIAware(); } - } }); + }); } pub fn enable_non_client_dpi_scaling(hwnd: HWND) { @@ -132,7 +121,7 @@ pub fn get_monitor_dpi(hmonitor: HMONITOR) -> Option { // MSDN says that "the values of *dpiX and *dpiY are identical. You only need to // record one of the values to determine the DPI and respond appropriately". // https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx - return Some(dpi_x as u32) + return Some(dpi_x as u32); } } } diff --git a/src/platform_impl/windows/drop_handler.rs b/src/platform_impl/windows/drop_handler.rs index 6895bf30..feec2639 100644 --- a/src/platform_impl/windows/drop_handler.rs +++ b/src/platform_impl/windows/drop_handler.rs @@ -1,32 +1,39 @@ -use std::ffi::OsString; -use std::os::windows::ffi::OsStringExt; -use std::path::PathBuf; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::{mem, ptr}; +use std::{ + ffi::OsString, + os::windows::ffi::OsStringExt, + path::PathBuf, + ptr, + sync::atomic::{AtomicUsize, Ordering}, +}; -use winapi::ctypes::c_void; -use winapi::shared::guiddef::REFIID; -use winapi::shared::minwindef::{DWORD, MAX_PATH, UINT, ULONG}; -use winapi::shared::windef::{HWND, POINTL}; -use winapi::shared::winerror::S_OK; -use winapi::um::objidl::IDataObject; -use winapi::um::oleidl::{DROPEFFECT_COPY, DROPEFFECT_NONE, IDropTarget, IDropTargetVtbl}; -use winapi::um::winnt::HRESULT; -use winapi::um::{shellapi, unknwnbase}; +use winapi::{ + ctypes::c_void, + shared::{ + guiddef::REFIID, + minwindef::{DWORD, UINT, ULONG}, + windef::{HWND, POINTL}, + winerror::S_OK, + }, + um::{ + objidl::IDataObject, + oleidl::{IDropTarget, IDropTargetVtbl, DROPEFFECT_COPY, DROPEFFECT_NONE}, + shellapi, unknwnbase, + winnt::HRESULT, + }, +}; -use platform_impl::platform::WindowId; +use crate::platform_impl::platform::WindowId; -use event::Event; -use window::WindowId as SuperWindowId; +use crate::{event::Event, window::WindowId as SuperWindowId}; #[repr(C)] pub struct FileDropHandlerData { pub interface: IDropTarget, refcount: AtomicUsize, window: HWND, - send_event: Box)>, + send_event: Box)>, cursor_effect: DWORD, - hovered_is_valid: bool, // If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted + hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted */ } pub struct FileDropHandler { @@ -35,7 +42,7 @@ pub struct FileDropHandler { #[allow(non_snake_case)] impl FileDropHandler { - pub fn new(window: HWND, send_event: Box)>) -> FileDropHandler { + pub fn new(window: HWND, send_event: Box)>) -> FileDropHandler { let data = Box::new(FileDropHandlerData { interface: IDropTarget { lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl, @@ -85,7 +92,7 @@ impl FileDropHandler { _pt: *const POINTL, pdwEffect: *mut DWORD, ) -> HRESULT { - use event::WindowEvent::HoveredFile; + use crate::event::WindowEvent::HoveredFile; let drop_handler = Self::from_interface(this); let hdrop = Self::iterate_filenames(pDataObj, |filename| { drop_handler.send_event(Event::WindowEvent { @@ -117,7 +124,7 @@ impl FileDropHandler { } pub unsafe extern "system" fn DragLeave(this: *mut IDropTarget) -> HRESULT { - use event::WindowEvent::HoveredFileCancelled; + use crate::event::WindowEvent::HoveredFileCancelled; let drop_handler = Self::from_interface(this); if drop_handler.hovered_is_valid { drop_handler.send_event(Event::WindowEvent { @@ -136,7 +143,7 @@ impl FileDropHandler { _pt: *const POINTL, _pdwEffect: *mut DWORD, ) -> HRESULT { - use event::WindowEvent::DroppedFile; + use crate::event::WindowEvent::DroppedFile; let drop_handler = Self::from_interface(this); let hdrop = Self::iterate_filenames(pDataObj, |filename| { drop_handler.send_event(Event::WindowEvent { @@ -155,16 +162,24 @@ impl FileDropHandler { &mut *(this as *mut _) } - unsafe fn iterate_filenames(data_obj: *const IDataObject, callback: F) -> Option + unsafe fn iterate_filenames( + data_obj: *const IDataObject, + callback: F, + ) -> Option where F: Fn(PathBuf), { - use winapi::ctypes::wchar_t; - use winapi::shared::winerror::{SUCCEEDED, DV_E_FORMATETC}; - use winapi::shared::wtypes::{CLIPFORMAT, DVASPECT_CONTENT}; - use winapi::um::objidl::{FORMATETC, TYMED_HGLOBAL}; - use winapi::um::shellapi::DragQueryFileW; - use winapi::um::winuser::CF_HDROP; + use winapi::{ + shared::{ + winerror::{DV_E_FORMATETC, SUCCEEDED}, + wtypes::{CLIPFORMAT, DVASPECT_CONTENT}, + }, + um::{ + objidl::{FORMATETC, TYMED_HGLOBAL}, + shellapi::DragQueryFileW, + winuser::CF_HDROP, + }, + }; let mut drop_format = FORMATETC { cfFormat: CF_HDROP as CLIPFORMAT, @@ -174,7 +189,7 @@ impl FileDropHandler { tymed: TYMED_HGLOBAL, }; - let mut medium = mem::uninitialized(); + let mut medium = std::mem::zeroed(); let get_data_result = (*data_obj).GetData(&mut drop_format, &mut medium); if SUCCEEDED(get_data_result) { let hglobal = (*medium.u).hGlobal(); @@ -183,15 +198,19 @@ impl FileDropHandler { // The second parameter (0xFFFFFFFF) instructs the function to return the item count let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0); - let mut pathbuf: [wchar_t; MAX_PATH] = mem::uninitialized(); - for i in 0..item_count { - let character_count = - DragQueryFileW(hdrop, i, pathbuf.as_mut_ptr(), MAX_PATH as UINT) as usize; + // Get the length of the path string NOT including the terminating null character. + // Previously, this was using a fixed size array of MAX_PATH length, but the + // Windows API allows longer paths under certain circumstances. + let character_count = DragQueryFileW(hdrop, i, ptr::null_mut(), 0) as usize; + let str_len = character_count + 1; - if character_count > 0 { - callback(OsString::from_wide(&pathbuf[0..character_count]).into()); - } + // Fill path_buf with the null-terminated file name + let mut path_buf = Vec::with_capacity(str_len); + DragQueryFileW(hdrop, i, path_buf.as_mut_ptr(), str_len as UINT); + path_buf.set_len(str_len); + + callback(OsString::from_wide(&path_buf[0..character_count]).into()); } return Some(hdrop); diff --git a/src/platform_impl/windows/event.rs b/src/platform_impl/windows/event.rs index a3d733d2..89171874 100644 --- a/src/platform_impl/windows/event.rs +++ b/src/platform_impl/windows/event.rs @@ -1,16 +1,19 @@ -use std::{char, ptr}; -use std::os::raw::c_int; -use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; +use std::{ + char, + os::raw::c_int, + ptr, + sync::atomic::{AtomicBool, AtomicPtr, Ordering}, +}; -use event::{ScanCode, ModifiersState, VirtualKeyCode}; +use crate::event::{ModifiersState, ScanCode, VirtualKeyCode}; -use winapi::shared::minwindef::{WPARAM, LPARAM, UINT, HKL, HKL__}; -use winapi::um::winuser; +use winapi::{ + shared::minwindef::{HKL, HKL__, LPARAM, UINT, WPARAM}, + um::winuser, +}; fn key_pressed(vkey: c_int) -> bool { - unsafe { - (winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15) - } + unsafe { (winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15) } } pub fn get_key_mods() -> ModifiersState { @@ -26,9 +29,19 @@ pub fn get_key_mods() -> ModifiersState { unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option { let mut unicode_bytes = [0u16; 5]; - let len = winuser::ToUnicodeEx(v_key, 0, keyboard_state.as_ptr(), unicode_bytes.as_mut_ptr(), unicode_bytes.len() as _, 0, hkl); + let len = winuser::ToUnicodeEx( + v_key, + 0, + keyboard_state.as_ptr(), + unicode_bytes.as_mut_ptr(), + unicode_bytes.len() as _, + 0, + hkl, + ); if len >= 1 { - char::decode_utf16(unicode_bytes.into_iter().cloned()).next().and_then(|c| c.ok()) + char::decode_utf16(unicode_bytes.into_iter().cloned()) + .next() + .and_then(|c| c.ok()) } else { None } @@ -239,7 +252,7 @@ pub fn vkey_to_winit_vkey(vkey: c_int) -> Option { winuser::VK_OEM_5 => map_text_keys(vkey), winuser::VK_OEM_6 => map_text_keys(vkey), winuser::VK_OEM_7 => map_text_keys(vkey), - /*winuser::VK_OEM_8 => Some(VirtualKeyCode::Oem_8), */ + /* winuser::VK_OEM_8 => Some(VirtualKeyCode::Oem_8), */ winuser::VK_OEM_102 => Some(VirtualKeyCode::OEM102), /*winuser::VK_PROCESSKEY => Some(VirtualKeyCode::Processkey), winuser::VK_PACKET => Some(VirtualKeyCode::Packet), @@ -252,49 +265,61 @@ pub fn vkey_to_winit_vkey(vkey: c_int) -> Option { winuser::VK_NONAME => Some(VirtualKeyCode::Noname), winuser::VK_PA1 => Some(VirtualKeyCode::Pa1), winuser::VK_OEM_CLEAR => Some(VirtualKeyCode::Oem_clear),*/ - _ => None + _ => None, } } -pub fn handle_extended_keys(vkey: c_int, mut scancode: UINT, extended: bool) -> Option<(c_int, UINT)> { +pub fn handle_extended_keys( + vkey: c_int, + mut scancode: UINT, + extended: bool, +) -> Option<(c_int, UINT)> { // Welcome to hell https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/ let vkey = match vkey { - winuser::VK_SHIFT => unsafe { winuser::MapVirtualKeyA( - scancode, - winuser::MAPVK_VSC_TO_VK_EX, - ) as _ }, - winuser::VK_CONTROL => if extended { - winuser::VK_RCONTROL - } else { - winuser::VK_LCONTROL + winuser::VK_SHIFT => unsafe { + winuser::MapVirtualKeyA(scancode, winuser::MAPVK_VSC_TO_VK_EX) as _ }, - winuser::VK_MENU => if extended { - winuser::VK_RMENU - } else { - winuser::VK_LMENU - }, - _ => match scancode { - // This is only triggered when using raw input. Without this check, we get two events whenever VK_PAUSE is - // pressed, the first one having scancode 0x1D but vkey VK_PAUSE... - 0x1D if vkey == winuser::VK_PAUSE => return None, - // ...and the second having scancode 0x45 but an unmatched vkey! - 0x45 => winuser::VK_PAUSE, - // VK_PAUSE and VK_SCROLL have the same scancode when using modifiers, alongside incorrect vkey values. - 0x46 => { - if extended { - scancode = 0x45; - winuser::VK_PAUSE - } else { - winuser::VK_SCROLL + winuser::VK_CONTROL => { + if extended { + winuser::VK_RCONTROL + } else { + winuser::VK_LCONTROL + } + } + winuser::VK_MENU => { + if extended { + winuser::VK_RMENU + } else { + winuser::VK_LMENU + } + } + _ => { + match scancode { + // This is only triggered when using raw input. Without this check, we get two events whenever VK_PAUSE is + // pressed, the first one having scancode 0x1D but vkey VK_PAUSE... + 0x1D if vkey == winuser::VK_PAUSE => return None, + // ...and the second having scancode 0x45 but an unmatched vkey! + 0x45 => winuser::VK_PAUSE, + // VK_PAUSE and VK_SCROLL have the same scancode when using modifiers, alongside incorrect vkey values. + 0x46 => { + if extended { + scancode = 0x45; + winuser::VK_PAUSE + } else { + winuser::VK_SCROLL + } } - }, - _ => vkey, - }, + _ => vkey, + } + } }; Some((vkey, scancode)) } -pub fn process_key_params(wparam: WPARAM, lparam: LPARAM) -> Option<(ScanCode, Option)> { +pub fn process_key_params( + wparam: WPARAM, + lparam: LPARAM, +) -> Option<(ScanCode, Option)> { let scancode = ((lparam >> 16) & 0xff) as UINT; let extended = (lparam & 0x01000000) != 0; handle_extended_keys(wparam as _, scancode, extended) @@ -304,7 +329,9 @@ pub fn process_key_params(wparam: WPARAM, lparam: LPARAM) -> Option<(ScanCode, O // This is needed as windows doesn't properly distinguish // some virtual key codes for different keyboard layouts fn map_text_keys(win_virtual_key: i32) -> Option { - let char_key = unsafe { winuser::MapVirtualKeyA(win_virtual_key as u32, winuser::MAPVK_VK_TO_CHAR) } & 0x7FFF; + let char_key = + unsafe { winuser::MapVirtualKeyA(win_virtual_key as u32, winuser::MAPVK_VK_TO_CHAR) } + & 0x7FFF; match char::from_u32(char_key) { Some(';') => Some(VirtualKeyCode::Semicolon), Some('/') => Some(VirtualKeyCode::Slash), @@ -313,6 +340,6 @@ fn map_text_keys(win_virtual_key: i32) -> Option { Some(']') => Some(VirtualKeyCode::RBracket), Some('\'') => Some(VirtualKeyCode::Apostrophe), Some('\\') => Some(VirtualKeyCode::Backslash), - _ => None + _ => None, } } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 1d49060d..b53d3add 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -12,53 +12,55 @@ //! The closure passed to the `execute_in_thread` method takes an `Inserter` that you can use to //! add a `WindowState` entry to a list of window to be used by the callback. -use winapi::shared::basetsd::DWORD_PTR; -use winapi::shared::basetsd::UINT_PTR; -use std::{mem, panic, ptr}; -use std::any::Any; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::mpsc::{self, Sender, Receiver}; -use std::time::{Duration, Instant}; -use std::rc::Rc; -use std::cell::RefCell; -use std::collections::VecDeque; -use std::marker::PhantomData; use parking_lot::Mutex; - -use winapi::ctypes::c_int; -use winapi::shared::minwindef::{ - BOOL, - DWORD, - HIWORD, - INT, - LOWORD, - LPARAM, - LRESULT, - UINT, - WPARAM, +use std::{ + any::Any, + cell::RefCell, + collections::VecDeque, + marker::PhantomData, + mem, panic, ptr, + rc::Rc, + sync::{ + atomic::{AtomicBool, Ordering}, + mpsc::{self, Receiver, Sender}, + Arc, + }, + time::{Duration, Instant}, }; -use winapi::shared::windef::{HWND, POINT, RECT}; -use winapi::shared::{windowsx, winerror}; -use winapi::um::{winuser, winbase, ole2, processthreadsapi, commctrl, libloaderapi}; -use winapi::um::winnt::{LONG, LPCSTR, SHORT}; +use winapi::shared::basetsd::{DWORD_PTR, UINT_PTR}; -use window::WindowId as RootWindowId; -use event_loop::{ControlFlow, EventLoopWindowTarget as RootELW, EventLoopClosed}; -use dpi::{LogicalPosition, LogicalSize, PhysicalSize}; -use event::{DeviceEvent, Touch, TouchPhase, StartCause, KeyboardInput, Event, WindowEvent}; -use platform_impl::platform::{event, WindowId, DEVICE_ID, wrap_device_id, util}; -use platform_impl::platform::dpi::{ - become_dpi_aware, - dpi_to_scale_factor, - enable_non_client_dpi_scaling, - hwnd_scale_factor, +use winapi::{ + ctypes::c_int, + shared::{ + minwindef::{BOOL, DWORD, HIWORD, INT, LOWORD, LPARAM, LRESULT, UINT, WPARAM}, + windef::{HWND, POINT, RECT}, + windowsx, winerror, + }, + um::{ + commctrl, libloaderapi, ole2, processthreadsapi, winbase, + winnt::{LONG, LPCSTR, SHORT}, + winuser, + }, +}; + +use crate::{ + dpi::{LogicalPosition, LogicalSize, PhysicalSize}, + event::{DeviceEvent, Event, KeyboardInput, StartCause, Touch, TouchPhase, WindowEvent}, + event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, + platform_impl::platform::{ + dpi::{ + become_dpi_aware, dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_scale_factor, + }, + drop_handler::FileDropHandler, + event::{self, handle_extended_keys, process_key_params, vkey_to_winit_vkey}, + raw_input::{get_raw_input_data, get_raw_mouse_button_state}, + util, + window::adjust_size, + window_state::{CursorFlags, WindowFlags, WindowState}, + wrap_device_id, WindowId, DEVICE_ID, + }, + window::WindowId as RootWindowId, }; -use platform_impl::platform::drop_handler::FileDropHandler; -use platform_impl::platform::event::{handle_extended_keys, process_key_params, vkey_to_winit_vkey}; -use platform_impl::platform::raw_input::{get_raw_input_data, get_raw_mouse_button_state}; -use platform_impl::platform::window::adjust_size; -use platform_impl::platform::window_state::{CursorFlags, WindowFlags, WindowState}; pub(crate) struct SubclassInput { pub window_state: Arc>, @@ -112,7 +114,8 @@ impl EventLoop { runner: RefCell::new(None), buffer: RefCell::new(VecDeque::new()), }); - let (thread_msg_target, thread_msg_sender) = thread_event_target_window(runner_shared.clone()); + let (thread_msg_target, thread_msg_sender) = + thread_event_target_window(runner_shared.clone()); EventLoop { thread_msg_sender, @@ -129,44 +132,57 @@ impl EventLoop { } pub fn run(mut self, event_handler: F) -> ! - where F: 'static + FnMut(Event, &RootELW, &mut ControlFlow) + where + F: 'static + FnMut(Event, &RootELW, &mut ControlFlow), { self.run_return(event_handler); ::std::process::exit(0); } pub fn run_return(&mut self, mut event_handler: F) - where F: FnMut(Event, &RootELW, &mut ControlFlow) + where + F: FnMut(Event, &RootELW, &mut ControlFlow), { - unsafe{ winuser::IsGUIThread(1); } + unsafe { + winuser::IsGUIThread(1); + } let event_loop_windows_ref = &self.window_target; - let mut runner = unsafe{ EventLoopRunner::new( - self, - move |event, control_flow| { + let mut runner = unsafe { + EventLoopRunner::new(self, move |event, control_flow| { event_handler(event, event_loop_windows_ref, control_flow) - } - ) }; + }) + }; { let runner_shared = self.window_target.p.runner_shared.clone(); let mut runner_ref = runner_shared.runner.borrow_mut(); loop { let event = runner_shared.buffer.borrow_mut().pop_front(); match event { - Some(e) => { runner.process_event(e); }, - None => break + Some(e) => { + runner.process_event(e); + } + None => break, } } *runner_ref = Some(runner); } macro_rules! runner { - () => { self.window_target.p.runner_shared.runner.borrow_mut().as_mut().unwrap() }; + () => { + self.window_target + .p + .runner_shared + .runner + .borrow_mut() + .as_mut() + .unwrap() + }; } unsafe { - let mut msg = mem::uninitialized(); + let mut msg = mem::zeroed(); let mut msg_unprocessed = false; 'main: loop { @@ -179,6 +195,7 @@ impl EventLoop { } winuser::TranslateMessage(&mut msg); winuser::DispatchMessageW(&mut msg); + msg_unprocessed = false; } runner!().events_cleared(); @@ -186,19 +203,21 @@ impl EventLoop { panic::resume_unwind(payload); } - let control_flow = runner!().control_flow; - match control_flow { - ControlFlow::Exit => break 'main, - ControlFlow::Wait => { - if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { - break 'main + if !msg_unprocessed { + let control_flow = runner!().control_flow; + match control_flow { + ControlFlow::Exit => break 'main, + ControlFlow::Wait => { + if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { + break 'main; + } + msg_unprocessed = true; } - msg_unprocessed = true; + ControlFlow::WaitUntil(resume_time) => { + wait_until_time_or_msg(resume_time); + } + ControlFlow::Poll => (), } - ControlFlow::WaitUntil(resume_time) => { - wait_until_time_or_msg(resume_time); - }, - ControlFlow::Poll => () } } } @@ -237,10 +256,11 @@ pub(crate) struct EventLoopRunner { runner_state: RunnerState, modal_redraw_window: HWND, in_modal_loop: bool, - event_handler: Box, &mut ControlFlow)>, + in_repaint: bool, + event_handler: Box, &mut ControlFlow)>, panic_error: Option, } -type PanicError = Box; +type PanicError = Box; impl ELRShared { pub(crate) unsafe fn send_event(&self, event: Event) { @@ -257,7 +277,7 @@ impl ELRShared { let buffered_event_opt = self.buffer.borrow_mut().pop_front(); match buffered_event_opt { Some(event) => runner.process_event(event), - None => break + None => break, } } @@ -288,17 +308,23 @@ enum RunnerState { impl EventLoopRunner { unsafe fn new(event_loop: &EventLoop, f: F) -> EventLoopRunner - where F: FnMut(Event, &mut ControlFlow) + where + F: FnMut(Event, &mut ControlFlow), { EventLoopRunner { - trigger_newevents_on_redraw: event_loop.window_target.p.trigger_newevents_on_redraw.clone(), + trigger_newevents_on_redraw: event_loop + .window_target + .p + .trigger_newevents_on_redraw + .clone(), control_flow: ControlFlow::default(), runner_state: RunnerState::New, in_modal_loop: false, + in_repaint: false, modal_redraw_window: event_loop.window_target.p.thread_msg_target, event_handler: mem::transmute::< - Box, &mut ControlFlow)>, - Box, &mut ControlFlow)> + Box, &mut ControlFlow)>, + Box, &mut ControlFlow)>, >(Box::new(f)), panic_error: None, } @@ -308,14 +334,13 @@ impl EventLoopRunner { self.runner_state = match self.runner_state { // If we're already handling events or have deferred `NewEvents`, we don't need to do // do any processing. - RunnerState::HandlingEvents | - RunnerState::DeferredNewEvents(..) => self.runner_state, + RunnerState::HandlingEvents | RunnerState::DeferredNewEvents(..) => self.runner_state, // Send the `Init` `NewEvents` and immediately move into event processing. RunnerState::New => { self.call_event_handler(Event::NewEvents(StartCause::Init)); RunnerState::HandlingEvents - }, + } // When `NewEvents` gets sent after an idle depends on the control flow... RunnerState::Idle(wait_start) => { @@ -367,7 +392,7 @@ impl EventLoopRunner { self.modal_redraw_window, ptr::null(), ptr::null_mut(), - winuser::RDW_INTERNALPAINT + winuser::RDW_INTERNALPAINT, ); } } @@ -380,15 +405,12 @@ impl EventLoopRunner { // deferred. if let RunnerState::DeferredNewEvents(wait_start) = self.runner_state { match self.control_flow { - ControlFlow::Exit | - ControlFlow::Wait => { - self.call_event_handler( - Event::NewEvents(StartCause::WaitCancelled { - start: wait_start, - requested_resume: None, - }) - ) - }, + ControlFlow::Exit | ControlFlow::Wait => { + self.call_event_handler(Event::NewEvents(StartCause::WaitCancelled { + start: wait_start, + requested_resume: None, + })) + } ControlFlow::WaitUntil(resume_time) => { let start_cause = match Instant::now() >= resume_time { // If the current time is later than the requested resume time, the resume time @@ -404,30 +426,43 @@ impl EventLoopRunner { }, }; self.call_event_handler(Event::NewEvents(start_cause)); - }, + } // This can be reached if the control flow is changed to poll during a `RedrawRequested` // that was sent after `EventsCleared`. - ControlFlow::Poll => { - self.call_event_handler(Event::NewEvents(StartCause::Poll)) - }, + ControlFlow::Poll => self.call_event_handler(Event::NewEvents(StartCause::Poll)), } } self.runner_state = RunnerState::HandlingEvents; - self.call_event_handler(event); + match (self.in_repaint, &event) { + ( + true, + Event::WindowEvent { + event: WindowEvent::RedrawRequested, + .. + }, + ) + | (false, _) => self.call_event_handler(event), + (true, _) => { + self.events_cleared(); + self.new_events(); + self.process_event(event); + } + } } fn events_cleared(&mut self) { + self.in_repaint = false; + match self.runner_state { // If we were handling events, send the EventsCleared message. RunnerState::HandlingEvents => { self.call_event_handler(Event::EventsCleared); self.runner_state = RunnerState::Idle(Instant::now()); - }, + } // If we *weren't* handling events, we don't have to do anything. - RunnerState::New | - RunnerState::Idle(..) => (), + RunnerState::New | RunnerState::Idle(..) => (), // Some control flows require a NewEvents call even if no events were received. This // branch handles those. @@ -437,37 +472,45 @@ impl EventLoopRunner { ControlFlow::Poll => { self.call_event_handler(Event::NewEvents(StartCause::Poll)); self.call_event_handler(Event::EventsCleared); - }, + } // If we had deferred a WaitUntil and the resume time has since been reached, // send the resume notification and EventsCleared event. ControlFlow::WaitUntil(resume_time) => { if Instant::now() >= resume_time { - self.call_event_handler(Event::NewEvents(StartCause::ResumeTimeReached { - start: wait_start, - requested_resume: resume_time, - })); + self.call_event_handler(Event::NewEvents( + StartCause::ResumeTimeReached { + start: wait_start, + requested_resume: resume_time, + }, + )); self.call_event_handler(Event::EventsCleared); } - }, + } // If we deferred a wait and no events were received, the user doesn't have to // get an event. - ControlFlow::Wait | - ControlFlow::Exit => () + ControlFlow::Wait | ControlFlow::Exit => (), } // Mark that we've entered an idle state. self.runner_state = RunnerState::Idle(wait_start) - }, + } } } fn call_event_handler(&mut self, event: Event) { match event { - Event::NewEvents(_) => self.trigger_newevents_on_redraw.store(true, Ordering::Relaxed), - Event::EventsCleared => self.trigger_newevents_on_redraw.store(false, Ordering::Relaxed), - _ => () + Event::NewEvents(_) => self + .trigger_newevents_on_redraw + .store(true, Ordering::Relaxed), + Event::EventsCleared => self + .trigger_newevents_on_redraw + .store(false, Ordering::Relaxed), + Event::WindowEvent { + event: WindowEvent::RedrawRequested, + .. + } => self.in_repaint = true, + _ => (), } - if self.panic_error.is_none() { let EventLoopRunner { ref mut panic_error, @@ -481,14 +524,15 @@ impl EventLoopRunner { } else { (*event_handler)(event, &mut ControlFlow::Exit); } - })).err(); + })) + .err(); } } } // Returns true if the wait time was reached, and false if a message must be processed. unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool { - let mut msg = mem::uninitialized(); + let mut msg = mem::zeroed(); let now = Instant::now(); if now <= wait_until { // MsgWaitForMultipleObjects tends to overshoot just a little bit. We subtract 1 millisecond @@ -498,7 +542,7 @@ unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool { ptr::null(), dur2timeout(wait_until - now).saturating_sub(1), winuser::QS_ALLEVENTS, - winuser::MWMO_INPUTAVAILABLE + winuser::MWMO_INPUTAVAILABLE, ); if resume_reason == winerror::WAIT_TIMEOUT { @@ -521,17 +565,24 @@ fn dur2timeout(dur: Duration) -> DWORD { // * Nanosecond precision is rounded up // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE // (never time out). - dur.as_secs().checked_mul(1000).and_then(|ms| { - ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000) - }).and_then(|ms| { - ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 {1} else {0}) - }).map(|ms| { - if ms > DWORD::max_value() as u64 { - winbase::INFINITE - } else { - ms as DWORD - } - }).unwrap_or(winbase::INFINITE) + dur.as_secs() + .checked_mul(1000) + .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)) + .and_then(|ms| { + ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { + 1 + } else { + 0 + }) + }) + .map(|ms| { + if ms > DWORD::max_value() as u64 { + winbase::INFINITE + } else { + ms as DWORD + } + }) + .unwrap_or(winbase::INFINITE) } impl Drop for EventLoop { @@ -576,21 +627,24 @@ impl EventLoopThreadExecutor { /// Note that we use a FnMut instead of a FnOnce because we're too lazy to create an equivalent /// to the unstable FnBox. pub(super) fn execute_in_thread(&self, mut function: F) - where F: FnMut() + Send + 'static + where + F: FnMut() + Send + 'static, { unsafe { if self.in_event_loop_thread() { function(); } else { // We double-box because the first box is a fat pointer. - let boxed = Box::new(function) as Box; + let boxed = Box::new(function) as Box; let boxed2: ThreadExecFn = Box::new(boxed); let raw = Box::into_raw(boxed2); let res = winuser::PostMessageW( - self.target_window, *EXEC_MSG_ID, - raw as *mut () as usize as WPARAM, 0 + self.target_window, + *EXEC_MSG_ID, + raw as *mut () as usize as WPARAM, + 0, ); assert!(res != 0, "PostMessage failed ; is the messages queue full?"); } @@ -598,7 +652,7 @@ impl EventLoopThreadExecutor { } } -type ThreadExecFn = Box>; +type ThreadExecFn = Box>; #[derive(Clone)] pub struct EventLoopProxy { @@ -629,7 +683,7 @@ lazy_static! { } }; // Message sent when we want to execute a closure in the thread. - // WPARAM contains a Box> that must be retrieved with `Box::from_raw`, + // WPARAM contains a Box> that must be retrieved with `Box::from_raw`, // and LPARAM is unused. static ref EXEC_MSG_ID: u32 = { unsafe { @@ -698,12 +752,14 @@ fn thread_event_target_window(event_loop_runner: EventLoopRunnerShared) -> THREAD_EVENT_TARGET_WINDOW_CLASS.as_ptr(), ptr::null_mut(), 0, - 0, 0, - 0, 0, + 0, + 0, + 0, + 0, ptr::null_mut(), ptr::null_mut(), libloaderapi::GetModuleHandleW(ptr::null()), - ptr::null_mut() + ptr::null_mut(), ); winuser::SetWindowLongPtrW( window, @@ -711,7 +767,7 @@ fn thread_event_target_window(event_loop_runner: EventLoopRunnerShared) -> // The window technically has to be visible to receive WM_PAINT messages (which are used // for delivering events during resizes), but it isn't displayed to the user because of // the LAYERED style. - (winuser::WS_VISIBLE | winuser::WS_POPUP) as _ + (winuser::WS_VISIBLE | winuser::WS_POPUP) as _, ); let (tx, rx) = mpsc::channel(); @@ -725,7 +781,7 @@ fn thread_event_target_window(event_loop_runner: EventLoopRunnerShared) -> window, Some(thread_event_target_callback::), THREAD_EVENT_TARGET_SUBCLASS_ID, - input_ptr as DWORD_PTR + input_ptr as DWORD_PTR, ); assert_eq!(subclass_result, 1); @@ -753,12 +809,14 @@ const WINDOW_SUBCLASS_ID: UINT_PTR = 0; const THREAD_EVENT_TARGET_SUBCLASS_ID: UINT_PTR = 1; pub(crate) fn subclass_window(window: HWND, subclass_input: SubclassInput) { let input_ptr = Box::into_raw(Box::new(subclass_input)); - let subclass_result = unsafe{ commctrl::SetWindowSubclass( - window, - Some(public_window_callback::), - WINDOW_SUBCLASS_ID, - input_ptr as DWORD_PTR - ) }; + let subclass_result = unsafe { + commctrl::SetWindowSubclass( + window, + Some(public_window_callback::), + WINDOW_SUBCLASS_ID, + input_ptr as DWORD_PTR, + ) + }; assert_eq!(subclass_result, 1); } @@ -775,9 +833,9 @@ unsafe extern "system" fn public_window_callback( wparam: WPARAM, lparam: LPARAM, _: UINT_PTR, - subclass_input_ptr: DWORD_PTR + subclass_input_ptr: DWORD_PTR, ) -> LRESULT { - let subclass_input = &mut*(subclass_input_ptr as *mut SubclassInput); + let subclass_input = &mut *(subclass_input_ptr as *mut SubclassInput); match msg { winuser::WM_ENTERSIZEMOVE => { @@ -786,18 +844,18 @@ unsafe extern "system" fn public_window_callback( runner.in_modal_loop = true; } 0 - }, + } winuser::WM_EXITSIZEMOVE => { let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); if let Some(ref mut runner) = *runner { runner.in_modal_loop = false; } 0 - }, + } winuser::WM_NCCREATE => { enable_non_client_dpi_scaling(window); commctrl::DefSubclassProc(window, msg, wparam, lparam) - }, + } winuser::WM_NCLBUTTONDOWN => { // jumpstart the modal loop @@ -805,25 +863,25 @@ unsafe extern "system" fn public_window_callback( window, ptr::null(), ptr::null_mut(), - winuser::RDW_INTERNALPAINT + winuser::RDW_INTERNALPAINT, ); if wparam == winuser::HTCAPTION as _ { winuser::PostMessageW(window, winuser::WM_MOUSEMOVE, 0, 0); } commctrl::DefSubclassProc(window, msg, wparam, lparam) - }, + } winuser::WM_CLOSE => { - use event::WindowEvent::CloseRequested; + use crate::event::WindowEvent::CloseRequested; subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: CloseRequested, }); 0 - }, + } winuser::WM_DESTROY => { - use event::WindowEvent::Destroyed; + use crate::event::WindowEvent::Destroyed; ole2::RevokeDragDrop(window); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -833,17 +891,17 @@ unsafe extern "system" fn public_window_callback( Box::from_raw(subclass_input); drop(subclass_input); 0 - }, + } _ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => { - use event::WindowEvent::RedrawRequested; + use crate::event::WindowEvent::RedrawRequested; let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); + subclass_input.window_state.lock().queued_out_of_band_redraw = false; if let Some(ref mut runner) = *runner { // This check makes sure that calls to `request_redraw()` during `EventsCleared` // handling dispatch `RedrawRequested` immediately after `EventsCleared`, without // spinning up a new event loop iteration. We do this because that's what the API // says to do. - let control_flow = runner.control_flow; let runner_state = runner.runner_state; let mut request_redraw = || { runner.call_event_handler(Event::WindowEvent { @@ -852,44 +910,38 @@ unsafe extern "system" fn public_window_callback( }); }; match runner_state { - RunnerState::Idle(..) | - RunnerState::DeferredNewEvents(..) => request_redraw(), + RunnerState::Idle(..) | RunnerState::DeferredNewEvents(..) => request_redraw(), RunnerState::HandlingEvents => { - match control_flow { - ControlFlow::Poll => request_redraw(), - ControlFlow::WaitUntil(resume_time) => { - if resume_time <= Instant::now() { - request_redraw() - } - }, - _ => () - } + winuser::RedrawWindow( + window, + ptr::null(), + ptr::null_mut(), + winuser::RDW_INTERNALPAINT, + ); } - _ => () + _ => (), } } 0 - }, + } winuser::WM_PAINT => { - use event::WindowEvent::RedrawRequested; + use crate::event::WindowEvent::RedrawRequested; subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: RedrawRequested, }); commctrl::DefSubclassProc(window, msg, wparam, lparam) - }, + } // WM_MOVE supplies client area positions, so we send Moved here instead. winuser::WM_WINDOWPOSCHANGED => { - use event::WindowEvent::Moved; + use crate::event::WindowEvent::Moved; let windowpos = lparam as *const winuser::WINDOWPOS; if (*windowpos).flags & winuser::SWP_NOMOVE != winuser::SWP_NOMOVE { let dpi_factor = hwnd_scale_factor(window); - let logical_position = LogicalPosition::from_physical( - ((*windowpos).x, (*windowpos).y), - dpi_factor, - ); + let logical_position = + LogicalPosition::from_physical(((*windowpos).x, (*windowpos).y), dpi_factor); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: Moved(logical_position), @@ -898,10 +950,10 @@ unsafe extern "system" fn public_window_callback( // This is necessary for us to still get sent WM_SIZE. commctrl::DefSubclassProc(window, msg, wparam, lparam) - }, + } winuser::WM_SIZE => { - use event::WindowEvent::Resized; + use crate::event::WindowEvent::Resized; let w = LOWORD(lparam as DWORD) as u32; let h = HIWORD(lparam as DWORD) as u32; @@ -915,7 +967,10 @@ unsafe extern "system" fn public_window_callback( { let mut w = subclass_input.window_state.lock(); // See WindowFlags::MARKER_RETAIN_STATE_ON_SIZE docs for info on why this `if` check exists. - if !w.window_flags().contains(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE) { + if !w + .window_flags() + .contains(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE) + { let maximized = wparam == winuser::SIZE_MAXIMIZED; w.set_window_flags_in_place(|f| f.set(WindowFlags::MAXIMIZED, maximized)); } @@ -923,40 +978,42 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(event); 0 - }, + } winuser::WM_CHAR => { - use event::WindowEvent::ReceivedCharacter; + use crate::event::WindowEvent::ReceivedCharacter; let chr: char = mem::transmute(wparam as u32); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: ReceivedCharacter(chr), }); 0 - }, + } // Prevents default windows menu hotkeys playing unwanted // "ding" sounds. Alternatively could check for WM_SYSCOMMAND // with wparam being SC_KEYMENU, but this may prevent some // other unwanted default hotkeys as well. - winuser::WM_SYSCHAR => { - 0 - } + winuser::WM_SYSCHAR => 0, winuser::WM_MOUSEMOVE => { - use event::WindowEvent::{CursorEntered, CursorMoved}; + use crate::event::WindowEvent::{CursorEntered, CursorMoved}; let mouse_was_outside_window = { let mut w = subclass_input.window_state.lock(); let was_outside_window = !w.mouse.cursor_flags().contains(CursorFlags::IN_WINDOW); - w.mouse.set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, true)).ok(); + w.mouse + .set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, true)) + .ok(); was_outside_window }; if mouse_was_outside_window { subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: CursorEntered { device_id: DEVICE_ID }, + event: CursorEntered { + device_id: DEVICE_ID, + }, }); // Calling TrackMouseEvent in order to receive mouse leave events. @@ -975,29 +1032,37 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() }, + event: CursorMoved { + device_id: DEVICE_ID, + position, + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_MOUSELEAVE => { - use event::WindowEvent::CursorLeft; + use crate::event::WindowEvent::CursorLeft; { let mut w = subclass_input.window_state.lock(); - w.mouse.set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, false)).ok(); + w.mouse + .set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, false)) + .ok(); } subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: CursorLeft { device_id: DEVICE_ID }, + event: CursorLeft { + device_id: DEVICE_ID, + }, }); 0 - }, + } winuser::WM_MOUSEWHEEL => { - use event::MouseScrollDelta::LineDelta; + use crate::event::MouseScrollDelta::LineDelta; let value = (wparam >> 16) as i16; let value = value as i32; @@ -1005,14 +1070,19 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved, modifiers: event::get_key_mods() }, + event: WindowEvent::MouseWheel { + device_id: DEVICE_ID, + delta: LineDelta(0.0, value), + phase: TouchPhase::Moved, + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_MOUSEHWHEEL => { - use event::MouseScrollDelta::LineDelta; + use crate::event::MouseScrollDelta::LineDelta; let value = (wparam >> 16) as i16; let value = value as i32; @@ -1020,15 +1090,19 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(value, 0.0), phase: TouchPhase::Moved, modifiers: event::get_key_mods() }, + event: WindowEvent::MouseWheel { + device_id: DEVICE_ID, + delta: LineDelta(value, 0.0), + phase: TouchPhase::Moved, + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN => { - use event::ElementState::Pressed; - use event::VirtualKeyCode; + use crate::event::{ElementState::Pressed, VirtualKeyCode}; if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 { commctrl::DefSubclassProc(window, msg, wparam, lparam) } else { @@ -1039,7 +1113,7 @@ unsafe extern "system" fn public_window_callback( device_id: DEVICE_ID, input: KeyboardInput { state: Pressed, - scancode: scancode, + scancode, virtual_keycode: vkey, modifiers: event::get_key_mods(), }, @@ -1056,10 +1130,10 @@ unsafe extern "system" fn public_window_callback( } 0 } - }, + } winuser::WM_KEYUP | winuser::WM_SYSKEYUP => { - use event::ElementState::Released; + use crate::event::ElementState::Released; if let Some((scancode, vkey)) = process_key_params(wparam, lparam) { subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1067,7 +1141,7 @@ unsafe extern "system" fn public_window_callback( device_id: DEVICE_ID, input: KeyboardInput { state: Released, - scancode: scancode, + scancode, virtual_keycode: vkey, modifiers: event::get_key_mods(), }, @@ -1075,121 +1149,159 @@ unsafe extern "system" fn public_window_callback( }); } 0 - }, + } winuser::WM_LBUTTONDOWN => { - use event::WindowEvent::MouseInput; - use event::MouseButton::Left; - use event::ElementState::Pressed; + use crate::event::{ElementState::Pressed, MouseButton::Left, WindowEvent::MouseInput}; capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() }, + event: MouseInput { + device_id: DEVICE_ID, + state: Pressed, + button: Left, + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_LBUTTONUP => { - use event::WindowEvent::MouseInput; - use event::MouseButton::Left; - use event::ElementState::Released; + use crate::event::{ + ElementState::Released, MouseButton::Left, WindowEvent::MouseInput, + }; release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() }, + event: MouseInput { + device_id: DEVICE_ID, + state: Released, + button: Left, + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_RBUTTONDOWN => { - use event::WindowEvent::MouseInput; - use event::MouseButton::Right; - use event::ElementState::Pressed; + use crate::event::{ + ElementState::Pressed, MouseButton::Right, WindowEvent::MouseInput, + }; capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() }, + event: MouseInput { + device_id: DEVICE_ID, + state: Pressed, + button: Right, + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_RBUTTONUP => { - use event::WindowEvent::MouseInput; - use event::MouseButton::Right; - use event::ElementState::Released; + use crate::event::{ + ElementState::Released, MouseButton::Right, WindowEvent::MouseInput, + }; release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() }, + event: MouseInput { + device_id: DEVICE_ID, + state: Released, + button: Right, + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_MBUTTONDOWN => { - use event::WindowEvent::MouseInput; - use event::MouseButton::Middle; - use event::ElementState::Pressed; + use crate::event::{ + ElementState::Pressed, MouseButton::Middle, WindowEvent::MouseInput, + }; capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() }, + event: MouseInput { + device_id: DEVICE_ID, + state: Pressed, + button: Middle, + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_MBUTTONUP => { - use event::WindowEvent::MouseInput; - use event::MouseButton::Middle; - use event::ElementState::Released; + use crate::event::{ + ElementState::Released, MouseButton::Middle, WindowEvent::MouseInput, + }; release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() }, + event: MouseInput { + device_id: DEVICE_ID, + state: Released, + button: Middle, + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_XBUTTONDOWN => { - use event::WindowEvent::MouseInput; - use event::MouseButton::Other; - use event::ElementState::Pressed; + use crate::event::{ + ElementState::Pressed, MouseButton::Other, WindowEvent::MouseInput, + }; let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() }, + event: MouseInput { + device_id: DEVICE_ID, + state: Pressed, + button: Other(xbutton as u8), + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_XBUTTONUP => { - use event::WindowEvent::MouseInput; - use event::MouseButton::Other; - use event::ElementState::Released; + use crate::event::{ + ElementState::Released, MouseButton::Other, WindowEvent::MouseInput, + }; let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() }, + event: MouseInput { + device_id: DEVICE_ID, + state: Released, + button: Other(xbutton as u8), + modifiers: event::get_key_mods(), + }, }); 0 - }, + } winuser::WM_INPUT_DEVICE_CHANGE => { let event = match wparam as _ { @@ -1204,12 +1316,14 @@ unsafe extern "system" fn public_window_callback( }); 0 - }, + } winuser::WM_INPUT => { - use event::DeviceEvent::{Motion, MouseMotion, MouseWheel, Button, Key}; - use event::MouseScrollDelta::LineDelta; - use event::ElementState::{Pressed, Released}; + use crate::event::{ + DeviceEvent::{Button, Key, Motion, MouseMotion, MouseWheel}, + ElementState::{Pressed, Released}, + MouseScrollDelta::LineDelta, + }; if let Some(data) = get_raw_input_data(lparam as _) { let device_id = wrap_device_id(data.header.hDevice as _); @@ -1247,7 +1361,9 @@ unsafe extern "system" fn public_window_callback( let delta = mouse.usButtonData as SHORT / winuser::WHEEL_DELTA; subclass_input.send_event(Event::DeviceEvent { device_id, - event: MouseWheel { delta: LineDelta(0.0, delta as f32) }, + event: MouseWheel { + delta: LineDelta(0.0, delta as f32), + }, }); } @@ -1261,10 +1377,7 @@ unsafe extern "system" fn public_window_callback( let button = (index + 1) as _; subclass_input.send_event(Event::DeviceEvent { device_id, - event: Button { - button, - state, - }, + event: Button { button, state }, }); } } @@ -1277,20 +1390,14 @@ unsafe extern "system" fn public_window_callback( || keyboard.Message == winuser::WM_SYSKEYUP; if pressed || released { - let state = if pressed { - Pressed - } else { - Released - }; + let state = if pressed { Pressed } else { Released }; let scancode = keyboard.MakeCode as _; let extended = util::has_flag(keyboard.Flags, winuser::RI_KEY_E0 as _) | util::has_flag(keyboard.Flags, winuser::RI_KEY_E1 as _); - if let Some((vkey, scancode)) = handle_extended_keys( - keyboard.VKey as _, - scancode, - extended, - ) { + if let Some((vkey, scancode)) = + handle_extended_keys(keyboard.VKey as _, scancode, extended) + { let virtual_keycode = vkey_to_winit_vkey(vkey); subclass_input.send_event(Event::DeviceEvent { @@ -1308,29 +1415,29 @@ unsafe extern "system" fn public_window_callback( } commctrl::DefSubclassProc(window, msg, wparam, lparam) - }, + } winuser::WM_TOUCH => { - let pcount = LOWORD( wparam as DWORD ) as usize; - let mut inputs = Vec::with_capacity( pcount ); - inputs.set_len( pcount ); + let pcount = LOWORD(wparam as DWORD) as usize; + let mut inputs = Vec::with_capacity(pcount); + inputs.set_len(pcount); let htouch = lparam as winuser::HTOUCHINPUT; if winuser::GetTouchInputInfo( htouch, pcount as UINT, inputs.as_mut_ptr(), mem::size_of::() as INT, - ) > 0 { + ) > 0 + { let dpi_factor = hwnd_scale_factor(window); for input in &inputs { let x = (input.x as f64) / 100f64; let y = (input.y as f64) / 100f64; let location = LogicalPosition::from_physical((x, y), dpi_factor); - subclass_input.send_event( Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: WindowEvent::Touch(Touch { - phase: - if input.dwFlags & winuser::TOUCHEVENTF_DOWN != 0 { + phase: if input.dwFlags & winuser::TOUCHEVENTF_DOWN != 0 { TouchPhase::Started } else if input.dwFlags & winuser::TOUCHEVENTF_UP != 0 { TouchPhase::Ended @@ -1346,33 +1453,37 @@ unsafe extern "system" fn public_window_callback( }); } } - winuser::CloseTouchInputHandle( htouch ); + winuser::CloseTouchInputHandle(htouch); 0 } winuser::WM_SETFOCUS => { - use event::WindowEvent::Focused; + use crate::event::WindowEvent::Focused; subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: Focused(true), }); 0 - }, + } winuser::WM_KILLFOCUS => { - use event::WindowEvent::Focused; + use crate::event::WindowEvent::Focused; subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: Focused(false), }); 0 - }, + } winuser::WM_SETCURSOR => { let set_cursor_to = { let window_state = subclass_input.window_state.lock(); - if window_state.mouse.cursor_flags().contains(CursorFlags::IN_WINDOW) { + if window_state + .mouse + .cursor_flags() + .contains(CursorFlags::IN_WINDOW) + { Some(window_state.mouse.cursor) } else { None @@ -1381,21 +1492,18 @@ unsafe extern "system" fn public_window_callback( match set_cursor_to { Some(cursor) => { - let cursor = winuser::LoadCursorW( - ptr::null_mut(), - cursor.to_windows_cursor(), - ); + let cursor = winuser::LoadCursorW(ptr::null_mut(), cursor.to_windows_cursor()); winuser::SetCursor(cursor); 0 - }, - None => winuser::DefWindowProcW(window, msg, wparam, lparam) + } + None => winuser::DefWindowProcW(window, msg, wparam, lparam), } - }, + } winuser::WM_DROPFILES => { // See `FileDropHandler` for implementation. 0 - }, + } winuser::WM_GETMINMAXINFO => { let mmi = lparam as *mut winuser::MINMAXINFO; @@ -1408,22 +1516,28 @@ unsafe extern "system" fn public_window_callback( if let Some(min_size) = window_state.min_size { let min_size = min_size.to_physical(window_state.dpi_factor); let (width, height) = adjust_size(min_size, style, ex_style); - (*mmi).ptMinTrackSize = POINT { x: width as i32, y: height as i32 }; + (*mmi).ptMinTrackSize = POINT { + x: width as i32, + y: height as i32, + }; } if let Some(max_size) = window_state.max_size { let max_size = max_size.to_physical(window_state.dpi_factor); let (width, height) = adjust_size(max_size, style, ex_style); - (*mmi).ptMaxTrackSize = POINT { x: width as i32, y: height as i32 }; + (*mmi).ptMaxTrackSize = POINT { + x: width as i32, + y: height as i32, + }; } } 0 - }, + } // Only sent on Windows 8.1 or newer. On Windows 7 and older user has to log out to change // DPI, therefore all applications are closed while DPI is changing. winuser::WM_DPICHANGED => { - use event::WindowEvent::HiDpiFactorChanged; + use crate::event::WindowEvent::HiDpiFactorChanged; // This message actually provides two DPI values - x and y. However MSDN says that // "you only need to use either the X-axis or the Y-axis value when scaling your @@ -1462,7 +1576,7 @@ unsafe extern "system" fn public_window_callback( }); 0 - }, + } _ => { if msg == *DESTROY_MSG_ID { @@ -1470,10 +1584,12 @@ unsafe extern "system" fn public_window_callback( 0 } else if msg == *SET_RETAIN_STATE_ON_SIZE_MSG_ID { let mut window_state = subclass_input.window_state.lock(); - window_state.set_window_flags_in_place(|f| f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam != 0)); + window_state.set_window_flags_in_place(|f| { + f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam != 0) + }); 0 } else if msg == *INITIAL_DPI_MSG_ID { - use event::WindowEvent::HiDpiFactorChanged; + use crate::event::WindowEvent::HiDpiFactorChanged; let scale_factor = dpi_to_scale_factor(wparam as u32); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1482,10 +1598,8 @@ unsafe extern "system" fn public_window_callback( // Automatically resize for actual DPI let width = LOWORD(lparam as DWORD) as u32; let height = HIWORD(lparam as DWORD) as u32; - let (adjusted_width, adjusted_height): (u32, u32) = PhysicalSize::from_logical( - (width, height), - scale_factor, - ).into(); + let (adjusted_width, adjusted_height): (u32, u32) = + PhysicalSize::from_logical((width, height), scale_factor).into(); // We're not done yet! `SetWindowPos` needs the window size, not the client area size. let mut rect = RECT { top: 0, @@ -1507,9 +1621,9 @@ unsafe extern "system" fn public_window_callback( outer_x, outer_y, winuser::SWP_NOMOVE - | winuser::SWP_NOREPOSITION - | winuser::SWP_NOZORDER - | winuser::SWP_NOACTIVATE, + | winuser::SWP_NOREPOSITION + | winuser::SWP_NOZORDER + | winuser::SWP_NOACTIVATE, ); 0 } else { @@ -1525,15 +1639,15 @@ unsafe extern "system" fn thread_event_target_callback( wparam: WPARAM, lparam: LPARAM, _: UINT_PTR, - subclass_input_ptr: DWORD_PTR + subclass_input_ptr: DWORD_PTR, ) -> LRESULT { - let subclass_input = &mut*(subclass_input_ptr as *mut ThreadMsgTargetSubclassInput); + let subclass_input = &mut *(subclass_input_ptr as *mut ThreadMsgTargetSubclassInput); match msg { winuser::WM_DESTROY => { Box::from_raw(subclass_input); drop(subclass_input); 0 - }, + } // Because WM_PAINT comes after all other messages, we use it during modal loops to detect // when the event queue has been emptied. See `process_event` for more details. winuser::WM_PAINT => { @@ -1543,7 +1657,7 @@ unsafe extern "system" fn thread_event_target_callback( window, ptr::null(), ptr::null_mut(), - winuser::RDW_INTERNALPAINT + winuser::RDW_INTERNALPAINT, ); }; let in_modal_loop = { @@ -1555,7 +1669,7 @@ unsafe extern "system" fn thread_event_target_callback( } }; if in_modal_loop { - let mut msg = mem::uninitialized(); + let mut msg = mem::zeroed(); loop { if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) { break; @@ -1563,8 +1677,7 @@ unsafe extern "system" fn thread_event_target_callback( // Clear all paint/timer messages from the queue before sending the events cleared message. match msg.message { // Flush the event queue of WM_PAINT messages. - winuser::WM_PAINT | - winuser::WM_TIMER => { + winuser::WM_PAINT | winuser::WM_TIMER => { // Remove the message from the message queue. winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1); @@ -1572,7 +1685,7 @@ unsafe extern "system" fn thread_event_target_callback( winuser::TranslateMessage(&mut msg); winuser::DispatchMessageW(&mut msg); } - }, + } // If the message isn't one of those three, it may be handled by the modal // loop so we should return control flow to it. _ => { @@ -1587,13 +1700,12 @@ unsafe extern "system" fn thread_event_target_callback( runner.events_cleared(); match runner.control_flow { // Waiting is handled by the modal loop. - ControlFlow::Exit | - ControlFlow::Wait => runner.new_events(), + ControlFlow::Exit | ControlFlow::Wait => runner.new_events(), ControlFlow::WaitUntil(resume_time) => { wait_until_time_or_msg(resume_time); runner.new_events(); queue_call_again(); - }, + } ControlFlow::Poll => { runner.new_events(); queue_call_again(); @@ -1614,6 +1726,6 @@ unsafe extern "system" fn thread_event_target_callback( function(); 0 } - _ => commctrl::DefSubclassProc(window, msg, wparam, lparam) + _ => commctrl::DefSubclassProc(window, msg, wparam, lparam), } } diff --git a/src/platform_impl/windows/icon.rs b/src/platform_impl/windows/icon.rs index 3a617ceb..c865053d 100644 --- a/src/platform_impl/windows/icon.rs +++ b/src/platform_impl/windows/icon.rs @@ -1,13 +1,15 @@ -use std::{mem, ptr, io}; -use std::os::windows::ffi::OsStrExt; -use std::path::Path; +use std::{io, mem, os::windows::ffi::OsStrExt, path::Path, ptr}; -use winapi::ctypes::{c_int, wchar_t}; -use winapi::shared::minwindef::{BYTE, LPARAM, WPARAM}; -use winapi::shared::windef::{HICON, HWND}; -use winapi::um::winuser; +use winapi::{ + ctypes::{c_int, wchar_t}, + shared::{ + minwindef::{BYTE, LPARAM, WPARAM}, + windef::{HICON, HWND}, + }, + um::winuser, +}; -use icon::{Pixel, PIXEL_SIZE, Icon}; +use crate::icon::{Icon, Pixel, PIXEL_SIZE}; impl Pixel { fn to_bgra(&mut self) { @@ -103,11 +105,6 @@ impl Drop for WinIcon { pub fn unset_for_window(hwnd: HWND, icon_type: IconType) { unsafe { - winuser::SendMessageW( - hwnd, - winuser::WM_SETICON, - icon_type as WPARAM, - 0 as LPARAM, - ); + winuser::SendMessageW(hwnd, winuser::WM_SETICON, icon_type as WPARAM, 0 as LPARAM); } } diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 307423c3..58d86faf 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -1,14 +1,14 @@ #![cfg(target_os = "windows")] -use winapi; -use winapi::shared::windef::HWND; +use winapi::{self, shared::windef::HWND}; -pub use self::event_loop::{EventLoop, EventLoopWindowTarget, EventLoopProxy}; -pub use self::monitor::MonitorHandle; -pub use self::window::Window; +pub use self::{ + event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}, + monitor::MonitorHandle, + window::Window, +}; -use window::Icon; -use event::DeviceId as RootDeviceId; +use crate::{event::DeviceId as RootDeviceId, window::Icon}; #[derive(Clone, Default)] pub struct PlatformSpecificWindowBuilderAttributes { diff --git a/src/platform_impl/windows/monitor.rs b/src/platform_impl/windows/monitor.rs index ccbe581b..addb0175 100644 --- a/src/platform_impl/windows/monitor.rs +++ b/src/platform_impl/windows/monitor.rs @@ -1,21 +1,34 @@ -use winapi::shared::minwindef::{BOOL, DWORD, LPARAM, TRUE}; -use winapi::shared::windef::{HDC, HMONITOR, HWND, LPRECT, POINT}; -use winapi::um::winnt::LONG; -use winapi::um::winuser; +use winapi::{ + shared::{ + minwindef::{BOOL, DWORD, LPARAM, TRUE, WORD}, + windef::{HDC, HMONITOR, HWND, LPRECT, POINT}, + }, + um::{wingdi, winnt::LONG, winuser}, +}; -use std::{mem, ptr, io}; -use std::collections::VecDeque; +use std::{ + collections::{HashSet, VecDeque}, + io, mem, ptr, +}; -use super::{EventLoop, util}; -use dpi::{PhysicalPosition, PhysicalSize}; -use platform_impl::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi}; -use platform_impl::platform::window::Window; +use super::{util, EventLoop}; +use crate::{ + dpi::{PhysicalPosition, PhysicalSize}, + monitor::VideoMode, + platform_impl::platform::{ + dpi::{dpi_to_scale_factor, get_monitor_dpi}, + window::Window, + }, +}; /// Win32 implementation of the main `MonitorHandle` object. -#[derive(Debug, Clone)] +#[derive(Derivative)] +#[derivative(Debug, Clone)] pub struct MonitorHandle { /// Monitor handle. hmonitor: HMonitor, + #[derivative(Debug = "ignore")] + monitor_info: winuser::MONITORINFOEXW, /// The system name of the monitor. monitor_name: String, /// True if this is the primary monitor. @@ -65,16 +78,12 @@ pub fn available_monitors() -> VecDeque { pub fn primary_monitor() -> MonitorHandle { const ORIGIN: POINT = POINT { x: 0, y: 0 }; - let hmonitor = unsafe { - winuser::MonitorFromPoint(ORIGIN, winuser::MONITOR_DEFAULTTOPRIMARY) - }; + let hmonitor = unsafe { winuser::MonitorFromPoint(ORIGIN, winuser::MONITOR_DEFAULTTOPRIMARY) }; MonitorHandle::from_hmonitor(hmonitor) } pub fn current_monitor(hwnd: HWND) -> MonitorHandle { - let hmonitor = unsafe { - winuser::MonitorFromWindow(hwnd, winuser::MONITOR_DEFAULTTONEAREST) - }; + let hmonitor = unsafe { winuser::MonitorFromWindow(hwnd, winuser::MONITOR_DEFAULTTONEAREST) }; MonitorHandle::from_hmonitor(hmonitor) } @@ -100,7 +109,7 @@ impl Window { } pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result { - let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::uninitialized() }; + let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::zeroed() }; monitor_info.cbSize = mem::size_of::() as DWORD; let status = unsafe { winuser::GetMonitorInfoW( @@ -130,6 +139,7 @@ impl MonitorHandle { position: (place.left as i32, place.top as i32), dimensions, hidpi_factor: dpi_to_scale_factor(get_monitor_dpi(hmonitor).unwrap_or(96)), + monitor_info, } } @@ -157,7 +167,7 @@ impl MonitorHandle { } #[inline] - pub fn dimensions(&self) -> PhysicalSize { + pub fn size(&self) -> PhysicalSize { self.dimensions.into() } @@ -170,4 +180,39 @@ impl MonitorHandle { pub fn hidpi_factor(&self) -> f64 { self.hidpi_factor } + + #[inline] + pub fn video_modes(&self) -> impl Iterator { + // EnumDisplaySettingsExW can return duplicate values (or some of the + // fields are probably changing, but we aren't looking at those fields + // anyway), so we're using a HashSet deduplicate + let mut modes = HashSet::new(); + let mut i = 0; + + loop { + unsafe { + let device_name = self.monitor_info.szDevice.as_ptr(); + let mut mode: wingdi::DEVMODEW = mem::zeroed(); + mode.dmSize = mem::size_of_val(&mode) as WORD; + if winuser::EnumDisplaySettingsExW(device_name, i, &mut mode, 0) == 0 { + break; + } + i += 1; + + const REQUIRED_FIELDS: DWORD = wingdi::DM_BITSPERPEL + | wingdi::DM_PELSWIDTH + | wingdi::DM_PELSHEIGHT + | wingdi::DM_DISPLAYFREQUENCY; + assert!(mode.dmFields & REQUIRED_FIELDS == REQUIRED_FIELDS); + + modes.insert(VideoMode { + size: (mode.dmPelsWidth, mode.dmPelsHeight), + bit_depth: mode.dmBitsPerPel as u16, + refresh_rate: mode.dmDisplayFrequency as u16, + }); + } + } + + modes.into_iter() + } } diff --git a/src/platform_impl/windows/raw_input.rs b/src/platform_impl/windows/raw_input.rs index 03c26d11..73b136a8 100644 --- a/src/platform_impl/windows/raw_input.rs +++ b/src/platform_impl/windows/raw_input.rs @@ -1,49 +1,35 @@ -use std::mem::{self, size_of}; -use std::ptr; - -use winapi::ctypes::wchar_t; -use winapi::shared::minwindef::{UINT, USHORT, TRUE}; -use winapi::shared::hidusage::{ - HID_USAGE_PAGE_GENERIC, - HID_USAGE_GENERIC_MOUSE, - HID_USAGE_GENERIC_KEYBOARD, -}; -use winapi::shared::windef::HWND; -use winapi::um::winnt::HANDLE; -use winapi::um::winuser::{ - self, - RAWINPUTDEVICELIST, - RID_DEVICE_INFO, - RID_DEVICE_INFO_MOUSE, - RID_DEVICE_INFO_KEYBOARD, - RID_DEVICE_INFO_HID, - RIM_TYPEMOUSE, - RIM_TYPEKEYBOARD, - RIM_TYPEHID, - RIDI_DEVICEINFO, - RIDI_DEVICENAME, - RAWINPUTDEVICE, - RIDEV_DEVNOTIFY, - RIDEV_INPUTSINK, - HRAWINPUT, - RAWINPUT, - RAWINPUTHEADER, - RID_INPUT, +use std::{ + mem::{self, size_of}, + ptr, }; -use platform_impl::platform::util; -use event::ElementState; +use winapi::{ + ctypes::wchar_t, + shared::{ + hidusage::{HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC}, + minwindef::{TRUE, UINT, USHORT}, + windef::HWND, + }, + um::{ + winnt::HANDLE, + winuser::{ + self, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST, RAWINPUTHEADER, + RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDI_DEVICEINFO, RIDI_DEVICENAME, RID_DEVICE_INFO, + RID_DEVICE_INFO_HID, RID_DEVICE_INFO_KEYBOARD, RID_DEVICE_INFO_MOUSE, RID_INPUT, + RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE, + }, + }, +}; + +use crate::{event::ElementState, platform_impl::platform::util}; #[allow(dead_code)] pub fn get_raw_input_device_list() -> Option> { let list_size = size_of::() as UINT; let mut num_devices = 0; - let status = unsafe { winuser::GetRawInputDeviceList( - ptr::null_mut(), - &mut num_devices, - list_size, - ) }; + let status = + unsafe { winuser::GetRawInputDeviceList(ptr::null_mut(), &mut num_devices, list_size) }; if status == UINT::max_value() { return None; @@ -51,11 +37,9 @@ pub fn get_raw_input_device_list() -> Option> { let mut buffer = Vec::with_capacity(num_devices as _); - let num_stored = unsafe { winuser::GetRawInputDeviceList( - buffer.as_ptr() as _, - &mut num_devices, - list_size, - ) }; + let num_stored = unsafe { + winuser::GetRawInputDeviceList(buffer.as_ptr() as _, &mut num_devices, list_size) + }; if num_stored == UINT::max_value() { return None; @@ -90,18 +74,20 @@ impl From for RawDeviceInfo { #[allow(dead_code)] pub fn get_raw_input_device_info(handle: HANDLE) -> Option { - let mut info: RID_DEVICE_INFO = unsafe { mem::uninitialized() }; + let mut info: RID_DEVICE_INFO = unsafe { mem::zeroed() }; let info_size = size_of::() as UINT; info.cbSize = info_size; let mut minimum_size = 0; - let status = unsafe { winuser::GetRawInputDeviceInfoW( - handle, - RIDI_DEVICEINFO, - &mut info as *mut _ as _, - &mut minimum_size, - ) }; + let status = unsafe { + winuser::GetRawInputDeviceInfoW( + handle, + RIDI_DEVICEINFO, + &mut info as *mut _ as _, + &mut minimum_size, + ) + }; if status == UINT::max_value() || status == 0 { return None; @@ -114,12 +100,9 @@ pub fn get_raw_input_device_info(handle: HANDLE) -> Option { pub fn get_raw_input_device_name(handle: HANDLE) -> Option { let mut minimum_size = 0; - let status = unsafe { winuser::GetRawInputDeviceInfoW( - handle, - RIDI_DEVICENAME, - ptr::null_mut(), - &mut minimum_size, - ) }; + let status = unsafe { + winuser::GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, ptr::null_mut(), &mut minimum_size) + }; if status != 0 { return None; @@ -127,12 +110,14 @@ pub fn get_raw_input_device_name(handle: HANDLE) -> Option { let mut name: Vec = Vec::with_capacity(minimum_size as _); - let status = unsafe { winuser::GetRawInputDeviceInfoW( - handle, - RIDI_DEVICENAME, - name.as_ptr() as _, - &mut minimum_size, - ) }; + let status = unsafe { + winuser::GetRawInputDeviceInfoW( + handle, + RIDI_DEVICENAME, + name.as_ptr() as _, + &mut minimum_size, + ) + }; if status == UINT::max_value() || status == 0 { return None; @@ -148,11 +133,9 @@ pub fn get_raw_input_device_name(handle: HANDLE) -> Option { pub fn register_raw_input_devices(devices: &[RAWINPUTDEVICE]) -> bool { let device_size = size_of::() as UINT; - let success = unsafe { winuser::RegisterRawInputDevices( - devices.as_ptr() as _, - devices.len() as _, - device_size, - ) }; + let success = unsafe { + winuser::RegisterRawInputDevices(devices.as_ptr() as _, devices.len() as _, device_size) + }; success == TRUE } @@ -181,17 +164,19 @@ pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> boo } pub fn get_raw_input_data(handle: HRAWINPUT) -> Option { - let mut data: RAWINPUT = unsafe { mem::uninitialized() }; + let mut data: RAWINPUT = unsafe { mem::zeroed() }; let mut data_size = size_of::() as UINT; let header_size = size_of::() as UINT; - let status = unsafe { winuser::GetRawInputData( - handle, - RID_INPUT, - &mut data as *mut _ as _, - &mut data_size, - header_size, - ) }; + let status = unsafe { + winuser::GetRawInputData( + handle, + RID_INPUT, + &mut data as *mut _ as _, + &mut data_size, + header_size, + ) + }; if status == UINT::max_value() || status == 0 { return None; @@ -200,10 +185,11 @@ pub fn get_raw_input_data(handle: HRAWINPUT) -> Option { Some(data) } - -fn button_flags_to_element_state(button_flags: USHORT, down_flag: USHORT, up_flag: USHORT) - -> Option -{ +fn button_flags_to_element_state( + button_flags: USHORT, + down_flag: USHORT, + up_flag: USHORT, +) -> Option { // We assume the same button won't be simultaneously pressed and released. if util::has_flag(button_flags, down_flag) { Some(ElementState::Pressed) diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index a46c44bd..28513d30 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -1,17 +1,23 @@ -use std::{mem, ptr, slice, io}; -use std::ops::BitAnd; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::{ + io, mem, + ops::BitAnd, + ptr, slice, + sync::atomic::{AtomicBool, Ordering}, +}; -use window::CursorIcon; -use winapi::ctypes::wchar_t; -use winapi::shared::minwindef::{BOOL, DWORD}; -use winapi::shared::windef::{HWND, POINT, RECT}; -use winapi::um::winbase::lstrlenW; -use winapi::um::winuser; +use crate::window::CursorIcon; +use winapi::{ + ctypes::wchar_t, + shared::{ + minwindef::{BOOL, DWORD}, + windef::{HWND, POINT, RECT}, + }, + um::{winbase::lstrlenW, winuser}, +}; pub fn has_flag(bitset: T, flag: T) -> bool -where T: - Copy + PartialEq + BitAnd +where + T: Copy + PartialEq + BitAnd, { bitset & flag == flag } @@ -27,7 +33,7 @@ pub fn wchar_ptr_to_string(wchar: *const wchar_t) -> String { } pub unsafe fn status_map BOOL>(mut fun: F) -> Option { - let mut data: T = mem::uninitialized(); + let mut data: T = mem::zeroed(); if fun(&mut data) != 0 { Some(data) } else { @@ -53,7 +59,7 @@ pub fn get_window_rect(hwnd: HWND) -> Option { pub fn get_client_rect(hwnd: HWND) -> Result { unsafe { - let mut rect = mem::uninitialized(); + let mut rect = mem::zeroed(); let mut top_left = mem::zeroed(); win_to_err(|| winuser::ClientToScreen(hwnd, &mut top_left))?; @@ -75,32 +81,42 @@ pub fn adjust_window_rect(hwnd: HWND, rect: RECT) -> Option { } } -pub fn adjust_window_rect_with_styles(hwnd: HWND, style: DWORD, style_ex: DWORD, rect: RECT) -> Option { - unsafe { status_map(|r| { - *r = rect; +pub fn adjust_window_rect_with_styles( + hwnd: HWND, + style: DWORD, + style_ex: DWORD, + rect: RECT, +) -> Option { + unsafe { + status_map(|r| { + *r = rect; - let b_menu = !winuser::GetMenu(hwnd).is_null() as BOOL; - winuser::AdjustWindowRectEx(r, style as _ , b_menu, style_ex as _) - }) } + let b_menu = !winuser::GetMenu(hwnd).is_null() as BOOL; + winuser::AdjustWindowRectEx(r, style as _, b_menu, style_ex as _) + }) + } } pub fn set_cursor_hidden(hidden: bool) { static HIDDEN: AtomicBool = AtomicBool::new(false); let changed = HIDDEN.swap(hidden, Ordering::SeqCst) ^ hidden; if changed { - unsafe{ winuser::ShowCursor(!hidden as BOOL) }; + unsafe { winuser::ShowCursor(!hidden as BOOL) }; } } pub fn set_cursor_clip(rect: Option) -> Result<(), io::Error> { unsafe { - let rect_ptr = rect.as_ref().map(|r| r as *const RECT).unwrap_or(ptr::null()); + let rect_ptr = rect + .as_ref() + .map(|r| r as *const RECT) + .unwrap_or(ptr::null()); win_to_err(|| winuser::ClipCursor(rect_ptr)) } } pub fn is_focused(window: HWND) -> bool { - window == unsafe{ winuser::GetActiveWindow() } + window == unsafe { winuser::GetActiveWindow() } } impl CursorIcon { @@ -111,16 +127,23 @@ impl CursorIcon { CursorIcon::Crosshair => winuser::IDC_CROSS, CursorIcon::Text | CursorIcon::VerticalText => winuser::IDC_IBEAM, CursorIcon::NotAllowed | CursorIcon::NoDrop => winuser::IDC_NO, - CursorIcon::Grab | CursorIcon::Grabbing | - CursorIcon::Move | CursorIcon::AllScroll => winuser::IDC_SIZEALL, - CursorIcon::EResize | CursorIcon::WResize | - CursorIcon::EwResize | CursorIcon::ColResize => winuser::IDC_SIZEWE, - CursorIcon::NResize | CursorIcon::SResize | - CursorIcon::NsResize | CursorIcon::RowResize => winuser::IDC_SIZENS, - CursorIcon::NeResize | CursorIcon::SwResize | - CursorIcon::NeswResize => winuser::IDC_SIZENESW, - CursorIcon::NwResize | CursorIcon::SeResize | - CursorIcon::NwseResize => winuser::IDC_SIZENWSE, + CursorIcon::Grab | CursorIcon::Grabbing | CursorIcon::Move | CursorIcon::AllScroll => { + winuser::IDC_SIZEALL + } + CursorIcon::EResize + | CursorIcon::WResize + | CursorIcon::EwResize + | CursorIcon::ColResize => winuser::IDC_SIZEWE, + CursorIcon::NResize + | CursorIcon::SResize + | CursorIcon::NsResize + | CursorIcon::RowResize => winuser::IDC_SIZENS, + CursorIcon::NeResize | CursorIcon::SwResize | CursorIcon::NeswResize => { + winuser::IDC_SIZENESW + } + CursorIcon::NwResize | CursorIcon::SeResize | CursorIcon::NwseResize => { + winuser::IDC_SIZENWSE + } CursorIcon::Wait => winuser::IDC_WAIT, CursorIcon::Progress => winuser::IDC_APPSTARTING, CursorIcon::Help => winuser::IDC_HELP, diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 351ffc1c..577ecfd7 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -1,37 +1,52 @@ #![cfg(target_os = "windows")] -use std::{io, mem, ptr}; -use std::cell::Cell; -use std::ffi::OsStr; -use std::os::windows::ffi::OsStrExt; -use std::sync::Arc; -use std::sync::mpsc::channel; use parking_lot::Mutex; +use std::{ + cell::Cell, + ffi::OsStr, + io, mem, + os::windows::ffi::OsStrExt, + ptr, + sync::{mpsc::channel, Arc}, +}; -use winapi::ctypes::c_int; -use winapi::shared::minwindef::{DWORD, LPARAM, UINT, WORD, WPARAM}; -use winapi::shared::windef::{HWND, POINT, RECT}; -use winapi::um::{combaseapi, dwmapi, libloaderapi, ole2, winuser}; -use winapi::um::objbase::COINIT_APARTMENTTHREADED; -use winapi::um::shobjidl_core::{CLSID_TaskbarList, ITaskbarList2}; -use winapi::um::wingdi::{CreateRectRgn, DeleteObject}; -use winapi::um::oleidl::LPDROPTARGET; -use winapi::um::winnt::{LONG, LPCWSTR}; +use winapi::{ + ctypes::c_int, + shared::{ + minwindef::{DWORD, LPARAM, UINT, WORD, WPARAM}, + windef::{HWND, POINT, RECT}, + }, + um::{ + combaseapi, dwmapi, libloaderapi, + objbase::COINIT_APARTMENTTHREADED, + ole2, + oleidl::LPDROPTARGET, + shobjidl_core::{CLSID_TaskbarList, ITaskbarList2}, + wingdi::{CreateRectRgn, DeleteObject}, + winnt::{LONG, LPCWSTR}, + winuser, + }, +}; -use window::{Icon, CursorIcon, WindowAttributes}; -use error::{ExternalError, NotSupportedError, OsError as RootOsError}; -use dpi::{LogicalPosition, LogicalSize, PhysicalSize}; -use monitor::MonitorHandle as RootMonitorHandle; -use platform_impl::platform::{ - {PlatformSpecificWindowBuilderAttributes, WindowId}, - dpi::{dpi_to_scale_factor, hwnd_dpi}, - drop_handler::FileDropHandler, - event_loop::{self, EventLoopWindowTarget, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}, - icon::{self, IconType, WinIcon}, - monitor, - raw_input::register_all_mice_and_keyboards_for_raw_input, - util, - window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState}, +use crate::{ + dpi::{LogicalPosition, LogicalSize, PhysicalSize}, + error::{ExternalError, NotSupportedError, OsError as RootOsError}, + monitor::MonitorHandle as RootMonitorHandle, + platform_impl::platform::{ + dpi::{dpi_to_scale_factor, hwnd_dpi}, + drop_handler::FileDropHandler, + event_loop::{ + self, EventLoopWindowTarget, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, + REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, + }, + icon::{self, IconType, WinIcon}, + monitor, + raw_input::register_all_mice_and_keyboards_for_raw_input, + util, + window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState}, + PlatformSpecificWindowBuilderAttributes, WindowId, + }, + window::{CursorIcon, Icon, WindowAttributes}, }; /// The Win32 implementation of the main `Window` object. @@ -73,11 +88,19 @@ impl Window { let file_drop_runner = event_loop.runner_shared.clone(); let file_drop_handler = FileDropHandler::new( win.window.0, - Box::new(move |event| if let Ok(e) = event.map_nonuser_event() {file_drop_runner.send_event(e)}) + Box::new(move |event| { + if let Ok(e) = event.map_nonuser_event() { + file_drop_runner.send_event(e) + } + }), ); - let handler_interface_ptr = &mut (*file_drop_handler.data).interface as LPDROPTARGET; + let handler_interface_ptr = + &mut (*file_drop_handler.data).interface as LPDROPTARGET; - assert_eq!(ole2::RegisterDragDrop(win.window.0, handler_interface_ptr), S_OK); + assert_eq!( + ole2::RegisterDragDrop(win.window.0, handler_interface_ptr), + S_OK + ); file_drop_handler }; @@ -106,8 +129,12 @@ impl Window { #[inline] pub fn set_visible(&self, visible: bool) { match visible { - true => unsafe { winuser::ShowWindow(self.window.0, winuser::SW_SHOW); }, - false => unsafe { winuser::ShowWindow(self.window.0, winuser::SW_HIDE); }, + true => unsafe { + winuser::ShowWindow(self.window.0, winuser::SW_SHOW); + }, + false => unsafe { + winuser::ShowWindow(self.window.0, winuser::SW_HIDE); + }, } } @@ -119,10 +146,14 @@ impl Window { self.window.0, ptr::null(), ptr::null_mut(), - winuser::RDW_INTERNALPAINT + winuser::RDW_INTERNALPAINT, ); } else { - winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0); + let mut window_state = self.window_state.lock(); + if !window_state.queued_out_of_band_redraw { + window_state.queued_out_of_band_redraw = true; + winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0); + } } } } @@ -137,7 +168,10 @@ impl Window { pub fn outer_position(&self) -> Result { let physical_position = self.outer_position_physical(); let dpi_factor = self.hidpi_factor(); - Ok(LogicalPosition::from_physical(physical_position, dpi_factor)) + Ok(LogicalPosition::from_physical( + physical_position, + dpi_factor, + )) } pub(crate) fn inner_position_physical(&self) -> (i32, i32) { @@ -152,7 +186,10 @@ impl Window { pub fn inner_position(&self) -> Result { let physical_position = self.inner_position_physical(); let dpi_factor = self.hidpi_factor(); - Ok(LogicalPosition::from_physical(physical_position, dpi_factor)) + Ok(LogicalPosition::from_physical( + physical_position, + dpi_factor, + )) } pub(crate) fn set_position_physical(&self, x: i32, y: i32) { @@ -178,7 +215,7 @@ impl Window { } pub(crate) fn inner_size_physical(&self) -> (u32, u32) { - let mut rect: RECT = unsafe { mem::uninitialized() }; + let mut rect: RECT = unsafe { mem::zeroed() }; if unsafe { winuser::GetClientRect(self.window.0, &mut rect) } == 0 { panic!("Unexpected GetClientRect failure: please report this error to https://github.com/rust-windowing/winit") } @@ -197,10 +234,12 @@ impl Window { pub(crate) fn outer_size_physical(&self) -> (u32, u32) { util::get_window_rect(self.window.0) - .map(|rect| ( - (rect.right - rect.left) as u32, - (rect.bottom - rect.top) as u32, - )) + .map(|rect| { + ( + (rect.right - rect.left) as u32, + (rect.bottom - rect.top) as u32, + ) + }) .unwrap() } @@ -220,8 +259,9 @@ impl Window { left: 0, bottom: y as LONG, right: x as LONG, - } - ).expect("adjust_window_rect failed"); + }, + ) + .expect("adjust_window_rect failed"); let outer_x = (rect.right - rect.left).abs() as c_int; let outer_y = (rect.top - rect.bottom).abs() as c_int; @@ -233,9 +273,10 @@ impl Window { outer_x, outer_y, winuser::SWP_ASYNCWINDOWPOS - | winuser::SWP_NOZORDER - | winuser::SWP_NOREPOSITION - | winuser::SWP_NOMOVE, + | winuser::SWP_NOZORDER + | winuser::SWP_NOREPOSITION + | winuser::SWP_NOMOVE + | winuser::SWP_NOACTIVATE, ); winuser::UpdateWindow(self.window.0); } @@ -286,12 +327,9 @@ impl Window { let window_state = Arc::clone(&self.window_state); self.thread_executor.execute_in_thread(move || { - WindowState::set_window_flags( - window_state.lock(), - window.0, - None, - |f| f.set(WindowFlags::RESIZABLE, resizable), - ); + WindowState::set_window_flags(window_state.lock(), window.0, None, |f| { + f.set(WindowFlags::RESIZABLE, resizable) + }); }); } @@ -305,10 +343,7 @@ impl Window { pub fn set_cursor_icon(&self, cursor: CursorIcon) { self.window_state.lock().mouse.cursor = cursor; self.thread_executor.execute_in_thread(move || unsafe { - let cursor = winuser::LoadCursorW( - ptr::null_mut(), - cursor.to_windows_cursor(), - ); + let cursor = winuser::LoadCursorW(ptr::null_mut(), cursor.to_windows_cursor()); winuser::SetCursor(cursor); }); } @@ -320,7 +355,9 @@ impl Window { let (tx, rx) = channel(); self.thread_executor.execute_in_thread(move || { - let result = window_state.lock().mouse + let result = window_state + .lock() + .mouse .set_cursor_flags(window.0, |f| f.set(CursorFlags::GRABBED, grab)) .map_err(|e| ExternalError::Os(os_error!(e))); let _ = tx.send(result); @@ -335,7 +372,9 @@ impl Window { let (tx, rx) = channel(); self.thread_executor.execute_in_thread(move || { - let result = window_state.lock().mouse + let result = window_state + .lock() + .mouse .set_cursor_flags(window.0, |f| f.set(CursorFlags::HIDDEN, !visible)) .map_err(|e| e.to_string()); let _ = tx.send(result); @@ -362,7 +401,10 @@ impl Window { } #[inline] - pub fn set_cursor_position(&self, logical_position: LogicalPosition) -> Result<(), ExternalError> { + pub fn set_cursor_position( + &self, + logical_position: LogicalPosition, + ) -> Result<(), ExternalError> { let dpi_factor = self.hidpi_factor(); let (x, y) = logical_position.to_physical(dpi_factor).into(); self.set_cursor_position_physical(x, y) @@ -379,12 +421,9 @@ impl Window { let window_state = Arc::clone(&self.window_state); self.thread_executor.execute_in_thread(move || { - WindowState::set_window_flags( - window_state.lock(), - window.0, - None, - |f| f.set(WindowFlags::MAXIMIZED, maximized), - ); + WindowState::set_window_flags(window_state.lock(), window.0, None, |f| { + f.set(WindowFlags::MAXIMIZED, maximized) + }); }); } @@ -403,16 +442,17 @@ impl Window { match &monitor { &Some(RootMonitorHandle { ref inner }) => { let (x, y): (i32, i32) = inner.position().into(); - let (width, height): (u32, u32) = inner.dimensions().into(); + let (width, height): (u32, u32) = inner.size().into(); let mut monitor = monitor.clone(); self.thread_executor.execute_in_thread(move || { let mut window_state_lock = window_state.lock(); - let client_rect = util::get_client_rect(window.0).expect("get client rect failed!"); + let client_rect = + util::get_client_rect(window.0).expect("get client rect failed!"); window_state_lock.saved_window = Some(SavedWindow { client_rect, - dpi_factor: window_state_lock.dpi_factor + dpi_factor: window_state_lock.dpi_factor, }); window_state_lock.fullscreen = monitor.take(); @@ -424,7 +464,7 @@ impl Window { top: y, right: x + width as c_int, bottom: y + height as c_int, - }) + }), ); mark_fullscreen(window.0, true); @@ -435,14 +475,18 @@ impl Window { let mut window_state_lock = window_state.lock(); window_state_lock.fullscreen = None; - if let Some(SavedWindow{client_rect, dpi_factor}) = window_state_lock.saved_window { + if let Some(SavedWindow { + client_rect, + dpi_factor, + }) = window_state_lock.saved_window + { window_state_lock.dpi_factor = dpi_factor; window_state_lock.saved_window = None; WindowState::refresh_window_state( window_state_lock, window.0, - Some(client_rect) + Some(client_rect), ); } @@ -460,12 +504,9 @@ impl Window { self.thread_executor.execute_in_thread(move || { let client_rect = util::get_client_rect(window.0).expect("get client rect failed!"); - WindowState::set_window_flags( - window_state.lock(), - window.0, - Some(client_rect), - |f| f.set(WindowFlags::DECORATIONS, decorations), - ); + WindowState::set_window_flags(window_state.lock(), window.0, Some(client_rect), |f| { + f.set(WindowFlags::DECORATIONS, decorations) + }); }); } @@ -475,12 +516,9 @@ impl Window { let window_state = Arc::clone(&self.window_state); self.thread_executor.execute_in_thread(move || { - WindowState::set_window_flags( - window_state.lock(), - window.0, - None, - |f| f.set(WindowFlags::ALWAYS_ON_TOP, always_on_top), - ); + WindowState::set_window_flags(window_state.lock(), window.0, None, |f| { + f.set(WindowFlags::ALWAYS_ON_TOP, always_on_top) + }); }); } @@ -573,9 +611,7 @@ unsafe fn init( .collect::>(); let window_icon = { - let icon = attributes.window_icon - .take() - .map(WinIcon::from_icon); + let icon = attributes.window_icon.take().map(WinIcon::from_icon); if let Some(icon) = icon { Some(icon.map_err(|e| os_error!(e))?) } else { @@ -583,9 +619,7 @@ unsafe fn init( } }; let taskbar_icon = { - let icon = attributes.window_icon - .take() - .map(WinIcon::from_icon); + let icon = attributes.window_icon.take().map(WinIcon::from_icon); if let Some(icon) = icon { Some(icon.map_err(|e| os_error!(e))?) } else { @@ -607,7 +641,10 @@ unsafe fn init( } dpi_factor } else { - return Err(os_error!(io::Error::new(io::ErrorKind::NotFound, "No monitors were detected."))); + return Err(os_error!(io::Error::new( + io::ErrorKind::NotFound, + "No monitors were detected." + ))); }; dpi_factor.unwrap_or_else(|| { util::get_cursor_pos() @@ -631,7 +668,10 @@ unsafe fn init( let mut window_flags = WindowFlags::empty(); window_flags.set(WindowFlags::DECORATIONS, attributes.decorations); window_flags.set(WindowFlags::ALWAYS_ON_TOP, attributes.always_on_top); - window_flags.set(WindowFlags::NO_BACK_BUFFER, pl_attribs.no_redirection_bitmap); + window_flags.set( + WindowFlags::NO_BACK_BUFFER, + pl_attribs.no_redirection_bitmap, + ); window_flags.set(WindowFlags::TRANSPARENT, attributes.transparent); // WindowFlags::VISIBLE and MAXIMIZED are set down below after the window has been configured. window_flags.set(WindowFlags::RESIZABLE, attributes.resizable); @@ -646,8 +686,10 @@ unsafe fn init( class_name.as_ptr(), title.as_ptr() as LPCWSTR, style, - winuser::CW_USEDEFAULT, winuser::CW_USEDEFAULT, - winuser::CW_USEDEFAULT, winuser::CW_USEDEFAULT, + winuser::CW_USEDEFAULT, + winuser::CW_USEDEFAULT, + winuser::CW_USEDEFAULT, + winuser::CW_USEDEFAULT, pl_attribs.parent.unwrap_or(ptr::null_mut()), ptr::null_mut(), libloaderapi::GetModuleHandleW(ptr::null()), @@ -666,9 +708,9 @@ unsafe fn init( // Register for touch events if applicable { - let digitizer = winuser::GetSystemMetrics( winuser::SM_DIGITIZER ) as u32; + let digitizer = winuser::GetSystemMetrics(winuser::SM_DIGITIZER) as u32; if digitizer & winuser::NID_READY != 0 { - winuser::RegisterTouchWindow( real_window.0, winuser::TWF_WANTPALM ); + winuser::RegisterTouchWindow(real_window.0, winuser::TWF_WANTPALM); } } @@ -712,7 +754,12 @@ unsafe fn init( // The color key can be any value except for black (0x0). let color_key = 0x0030c100; - winuser::SetLayeredWindowAttributes(real_window.0, color_key, opacity, winuser::LWA_ALPHA); + winuser::SetLayeredWindowAttributes( + real_window.0, + color_key, + opacity, + winuser::LWA_ALPHA, + ); } } @@ -720,19 +767,11 @@ unsafe fn init( window_flags.set(WindowFlags::MAXIMIZED, attributes.maximized); let window_state = { - let window_state = WindowState::new( - &attributes, - window_icon, - taskbar_icon, - dpi_factor, - ); + let window_state = WindowState::new(&attributes, window_icon, taskbar_icon, dpi_factor); let window_state = Arc::new(Mutex::new(window_state)); - WindowState::set_window_flags( - window_state.lock(), - real_window.0, - None, - |f| *f = window_flags, - ); + WindowState::set_window_flags(window_state.lock(), real_window.0, None, |f| { + *f = window_flags + }); window_state }; @@ -803,7 +842,7 @@ impl Drop for ComInitialized { } } -thread_local!{ +thread_local! { static COM_INITIALIZED: ComInitialized = { unsafe { combaseapi::CoInitializeEx(ptr::null_mut(), COINIT_APARTMENTTHREADED); @@ -833,8 +872,7 @@ unsafe fn mark_fullscreen(handle: HWND, fullscreen: bool) { let mut task_bar_list = task_bar_list_ptr.get(); if task_bar_list == ptr::null_mut() { - use winapi::shared::winerror::S_OK; - use winapi::Interface; + use winapi::{shared::winerror::S_OK, Interface}; let hr = combaseapi::CoCreateInstance( &CLSID_TaskbarList, diff --git a/src/platform_impl/windows/window_state.rs b/src/platform_impl/windows/window_state.rs index 41dcb228..9d494508 100644 --- a/src/platform_impl/windows/window_state.rs +++ b/src/platform_impl/windows/window_state.rs @@ -1,13 +1,18 @@ -use monitor::MonitorHandle; -use window::{CursorIcon, WindowAttributes}; -use std::{io, ptr}; +use crate::{ + dpi::LogicalSize, + monitor::MonitorHandle, + platform_impl::platform::{event_loop, icon::WinIcon, util}, + window::{CursorIcon, WindowAttributes}, +}; use parking_lot::MutexGuard; -use dpi::LogicalSize; -use platform_impl::platform::{util, event_loop}; -use platform_impl::platform::icon::WinIcon; -use winapi::shared::windef::{RECT, HWND}; -use winapi::shared::minwindef::DWORD; -use winapi::um::winuser; +use std::{io, ptr}; +use winapi::{ + shared::{ + minwindef::DWORD, + windef::{HWND, RECT}, + }, + um::winuser, +}; /// Contains information about states and the window that the callback is going to use. #[derive(Clone)] @@ -25,6 +30,9 @@ pub struct WindowState { pub dpi_factor: f64, pub fullscreen: Option, + /// Used to supress duplicate redraw attempts when calling `request_redraw` multiple + /// times in `EventsCleared`. + pub queued_out_of_band_redraw: bool, window_flags: WindowFlags, } @@ -86,7 +94,7 @@ impl WindowState { attributes: &WindowAttributes, window_icon: Option, taskbar_icon: Option, - dpi_factor: f64 + dpi_factor: f64, ) -> WindowState { WindowState { mouse: MouseProperties { @@ -105,7 +113,8 @@ impl WindowState { dpi_factor, fullscreen: None, - window_flags: WindowFlags::empty() + queued_out_of_band_redraw: false, + window_flags: WindowFlags::empty(), } } @@ -113,26 +122,37 @@ impl WindowState { self.window_flags } - pub fn set_window_flags(mut this: MutexGuard, window: HWND, set_client_rect: Option, f: F) - where F: FnOnce(&mut WindowFlags) + pub fn set_window_flags( + mut this: MutexGuard<'_, Self>, + window: HWND, + set_client_rect: Option, + f: F, + ) where + F: FnOnce(&mut WindowFlags), { let old_flags = this.window_flags; f(&mut this.window_flags); let is_fullscreen = this.fullscreen.is_some(); - this.window_flags.set(WindowFlags::MARKER_FULLSCREEN, is_fullscreen); + this.window_flags + .set(WindowFlags::MARKER_FULLSCREEN, is_fullscreen); let new_flags = this.window_flags; drop(this); old_flags.apply_diff(window, new_flags, set_client_rect); } - pub fn refresh_window_state(this: MutexGuard, window: HWND, set_client_rect: Option) { + pub fn refresh_window_state( + this: MutexGuard<'_, Self>, + window: HWND, + set_client_rect: Option, + ) { Self::set_window_flags(this, window, set_client_rect, |_| ()); } pub fn set_window_flags_in_place(&mut self, f: F) - where F: FnOnce(&mut WindowFlags) + where + F: FnOnce(&mut WindowFlags), { f(&mut self.window_flags); } @@ -144,7 +164,8 @@ impl MouseProperties { } pub fn set_cursor_flags(&mut self, window: HWND, f: F) -> Result<(), io::Error> - where F: FnOnce(&mut CursorFlags) + where + F: FnOnce(&mut CursorFlags), { let old_flags = self.cursor_flags; f(&mut self.cursor_flags); @@ -198,9 +219,7 @@ impl WindowFlags { if self.contains(WindowFlags::NO_BACK_BUFFER) { style_ex |= WS_EX_NOREDIRECTIONBITMAP; } - if self.contains(WindowFlags::TRANSPARENT) { - // Is this necessary? The docs say that WS_EX_LAYERED requires a windows class without - // CS_OWNDC, and Winit windows have that flag set. + if self.contains(WindowFlags::TRANSPARENT) && self.contains(WindowFlags::DECORATIONS) { style_ex |= WS_EX_LAYERED; } if self.contains(WindowFlags::CHILD) { @@ -232,8 +251,8 @@ impl WindowFlags { window, match new.contains(WindowFlags::VISIBLE) { true => winuser::SW_SHOW, - false => winuser::SW_HIDE - } + false => winuser::SW_HIDE, + }, ); } } @@ -242,10 +261,13 @@ impl WindowFlags { winuser::SetWindowPos( window, match new.contains(WindowFlags::ALWAYS_ON_TOP) { - true => winuser::HWND_TOPMOST, + true => winuser::HWND_TOPMOST, false => winuser::HWND_NOTOPMOST, }, - 0, 0, 0, 0, + 0, + 0, + 0, + 0, winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOMOVE | winuser::SWP_NOSIZE, ); winuser::UpdateWindow(window); @@ -258,8 +280,8 @@ impl WindowFlags { window, match new.contains(WindowFlags::MAXIMIZED) { true => winuser::SW_MAXIMIZE, - false => winuser::SW_RESTORE - } + false => winuser::SW_RESTORE, + }, ); } } @@ -273,7 +295,9 @@ impl WindowFlags { winuser::SetWindowLongW(window, winuser::GWL_STYLE, style as _); winuser::SetWindowLongW(window, winuser::GWL_EXSTYLE, style_ex as _); - match set_client_rect.and_then(|r| util::adjust_window_rect_with_styles(window, style, style_ex, r)) { + match set_client_rect + .and_then(|r| util::adjust_window_rect_with_styles(window, style, style_ex, r)) + { Some(client_rect) => { let (x, y, w, h) = ( client_rect.left, @@ -284,21 +308,29 @@ impl WindowFlags { winuser::SetWindowPos( window, ptr::null_mut(), - x, y, w, h, + x, + y, + w, + h, winuser::SWP_NOZORDER - | winuser::SWP_FRAMECHANGED, + | winuser::SWP_FRAMECHANGED + | winuser::SWP_NOACTIVATE, ); - }, + } None => { // Refresh the window frame. winuser::SetWindowPos( window, ptr::null_mut(), - 0, 0, 0, 0, + 0, + 0, + 0, + 0, winuser::SWP_NOZORDER - | winuser::SWP_NOMOVE - | winuser::SWP_NOSIZE - | winuser::SWP_FRAMECHANGED, + | winuser::SWP_NOMOVE + | winuser::SWP_NOSIZE + | winuser::SWP_FRAMECHANGED + | winuser::SWP_NOACTIVATE, ); } } diff --git a/src/window.rs b/src/window.rs index 2567d94d..dfde6713 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,31 +1,36 @@ //! The `Window` struct and associated types. use std::fmt; -use platform_impl; -use error::{ExternalError, NotSupportedError, OsError}; -use event_loop::EventLoopWindowTarget; -use monitor::{AvailableMonitorsIter, MonitorHandle}; -use dpi::{LogicalPosition, LogicalSize}; +use crate::{ + dpi::{LogicalPosition, LogicalSize}, + error::{ExternalError, NotSupportedError, OsError}, + event_loop::EventLoopWindowTarget, + monitor::{AvailableMonitorsIter, MonitorHandle}, + platform_impl, +}; -pub use icon::*; +pub use crate::icon::*; /// Represents a window. /// /// # Example /// /// ```no_run -/// use winit::window::Window; -/// use winit::event::{Event, WindowEvent}; -/// use winit::event_loop::{EventLoop, ControlFlow}; +/// use winit::{ +/// event::{Event, WindowEvent}, +/// event_loop::{ControlFlow, EventLoop}, +/// window::Window, +/// }; /// /// let mut event_loop = EventLoop::new(); /// let window = Window::new(&event_loop).unwrap(); /// /// event_loop.run(move |event, _, control_flow| { /// match event { -/// Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { -/// *control_flow = ControlFlow::Exit -/// }, +/// Event::WindowEvent { +/// event: WindowEvent::CloseRequested, +/// .. +/// } => *control_flow = ControlFlow::Exit, /// _ => *control_flow = ControlFlow::Wait, /// } /// }); @@ -35,7 +40,7 @@ pub struct Window { } impl fmt::Debug for Window { - fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result { fmtr.pad("Window { .. }") } } @@ -66,12 +71,12 @@ pub struct WindowBuilder { /// The attributes to use to create the window. pub window: WindowAttributes, - // Platform-specific configuration. Private. + // Platform-specific configuration. pub(crate) platform_specific: platform_impl::PlatformSpecificWindowBuilderAttributes, } impl fmt::Debug for WindowBuilder { - fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result { fmtr.debug_struct("WindowBuilder") .field("window", &self.window) .finish() @@ -234,14 +239,14 @@ impl WindowBuilder { /// Sets whether the window will be initially hidden or visible. #[inline] - pub fn with_visibility(mut self, visible: bool) -> WindowBuilder { + pub fn with_visible(mut self, visible: bool) -> WindowBuilder { self.window.visible = visible; self } /// Sets whether the background of the window should be transparent. #[inline] - pub fn with_transparency(mut self, transparent: bool) -> WindowBuilder { + pub fn with_transparent(mut self, transparent: bool) -> WindowBuilder { self.window.transparent = transparent; self } @@ -280,26 +285,15 @@ impl WindowBuilder { /// Builds the window. /// - /// Error should be very rare and only occur in case of permission denied, incompatible system, - /// out of memory, etc. + /// Possible causes of error include denied permission, incompatible system, and lack of memory. #[inline] - pub fn build(mut self, window_target: &EventLoopWindowTarget) -> Result { - self.window.inner_size = Some(self.window.inner_size.unwrap_or_else(|| { - if let Some(ref monitor) = self.window.fullscreen { - // resizing the window to the dimensions of the monitor when fullscreen - LogicalSize::from_physical(monitor.dimensions(), 1.0) - } else { - // default dimensions - (1024, 768).into() - } - })); - + pub fn build( + self, + window_target: &EventLoopWindowTarget, + ) -> Result { // building - platform_impl::Window::new( - &window_target.p, - self.window, - self.platform_specific, - ).map(|window| Window { window }) + platform_impl::Window::new(&window_target.p, self.window, self.platform_specific) + .map(|window| Window { window }) } } @@ -325,7 +319,7 @@ impl Window { /// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa. /// - /// See the [`dpi`](dpi/index.html) module for more information. + /// See the [`dpi`](../dpi/index.html) module for more information. /// /// Note that this value can change depending on user action (for example if the window is /// moved to another screen); as such, tracking `WindowEvent::HiDpiFactorChanged` events is @@ -347,7 +341,7 @@ impl Window { /// Emits a `WindowEvent::RedrawRequested` event in the associated event loop after all OS /// events have been processed by the event loop. /// - /// This is the **strongly encouraged** method of redrawing windows, as it can integrates with + /// This is the **strongly encouraged** method of redrawing windows, as it can integrate with /// OS-requested redraws (e.g. when a window gets resized). /// /// This function can cause `RedrawRequested` events to be emitted after `Event::EventsCleared` @@ -638,7 +632,9 @@ impl Window { self.window.set_cursor_grab(grab) } - /// Hides the cursor, making it invisible but still usable. + /// Modifies the cursor's visibility. + /// + /// If `false`, this will hide the cursor. If `true`, this will show the cursor. /// /// ## Platform-specific /// @@ -676,7 +672,9 @@ impl Window { #[inline] pub fn available_monitors(&self) -> AvailableMonitorsIter { let data = self.window.available_monitors(); - AvailableMonitorsIter { data: data.into_iter() } + AvailableMonitorsIter { + data: data.into_iter(), + } } /// Returns the primary monitor of the system. @@ -688,7 +686,9 @@ impl Window { /// **iOS:** Can only be called on the main thread. #[inline] pub fn primary_monitor(&self) -> MonitorHandle { - MonitorHandle { inner: self.window.primary_monitor() } + MonitorHandle { + inner: self.window.primary_monitor(), + } } } diff --git a/tests/send_objects.rs b/tests/send_objects.rs index ad1f248a..9462d073 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -1,9 +1,9 @@ -extern crate winit; - -fn needs_send() {} +#[allow(dead_code)] +fn needs_send() {} #[test] fn event_loop_proxy_send() { + #[allow(dead_code)] fn is_send() { // ensures that `winit::EventLoopProxy` implements `Send` needs_send::>(); diff --git a/tests/serde_objects.rs b/tests/serde_objects.rs index 00f30b8f..df518988 100644 --- a/tests/serde_objects.rs +++ b/tests/serde_objects.rs @@ -1,16 +1,16 @@ #![cfg(feature = "serde")] -extern crate serde; -extern crate winit; - -use winit::window::{CursorIcon}; -use winit::event::{ - KeyboardInput, TouchPhase, ElementState, MouseButton, MouseScrollDelta, VirtualKeyCode, - ModifiersState +use serde::{Deserialize, Serialize}; +use winit::{ + dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}, + event::{ + ElementState, KeyboardInput, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase, + VirtualKeyCode, + }, + window::CursorIcon, }; -use winit::dpi::{LogicalPosition, PhysicalPosition, LogicalSize, PhysicalSize}; -use serde::{Serialize, Deserialize}; +#[allow(dead_code)] fn needs_serde>() {} #[test] diff --git a/tests/sync_object.rs b/tests/sync_object.rs index c59cc077..dad65202 100644 --- a/tests/sync_object.rs +++ b/tests/sync_object.rs @@ -1,6 +1,5 @@ -extern crate winit; - -fn needs_sync() {} +#[allow(dead_code)] +fn needs_sync() {} #[test] fn window_sync() {