mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Format everything and add rustfmt to travis (#951)
* Format everything and add rustfmt to travis * Remove extern crate winit from examples and add force_multiline_blocks * Format the code properly * Fix inconsistent period in PULL_REQUEST_TEMPLATE.md * Only run rustfmt on nightly * Travis fixings
This commit is contained in:
parent
b1b5aefc4b
commit
e2c84725de
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -1,4 +1,5 @@
|
||||||
- [ ] Tested on all platforms changed
|
- [ ] 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
|
- [ ] 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
|
- [ ] 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
|
- [ ] Created an example program if it would help users understand this functionality
|
||||||
|
|
|
@ -45,8 +45,11 @@ matrix:
|
||||||
install:
|
install:
|
||||||
- rustup self update
|
- rustup self update
|
||||||
- rustup target add $TARGET; true
|
- rustup target add $TARGET; true
|
||||||
|
- rustup install nightly
|
||||||
|
- rustup component add rustfmt --toolchain nightly
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
- cargo +nightly fmt --all -- --check
|
||||||
- cargo build --target $TARGET --verbose
|
- cargo build --target $TARGET --verbose
|
||||||
- cargo build --target $TARGET --features serde --verbose
|
- cargo build --target $TARGET --features serde --verbose
|
||||||
# Running iOS apps on OSX requires the simulator so we skip that for now
|
# Running iOS apps on OSX requires the simulator so we skip that for now
|
||||||
|
|
|
@ -31,10 +31,11 @@ show something on the window you need to use the platform-specific getters provi
|
||||||
another library.
|
another library.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate winit;
|
use winit::{
|
||||||
use winit::window::WindowBuilder;
|
event::{Event, WindowEvent},
|
||||||
use winit::event::{Event, WindowEvent};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
extern crate winit;
|
use winit::{
|
||||||
|
event::{ElementState, Event, KeyboardInput, WindowEvent},
|
||||||
use winit::window::{WindowBuilder, CursorIcon};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event::{Event, WindowEvent, ElementState, KeyboardInput};
|
window::{CursorIcon, WindowBuilder},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
@ -14,7 +14,18 @@ fn main() {
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => {
|
Event::WindowEvent {
|
||||||
|
event:
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
input:
|
||||||
|
KeyboardInput {
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} => {
|
||||||
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
|
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
|
||||||
window.set_cursor_icon(CURSORS[cursor_idx]);
|
window.set_cursor_icon(CURSORS[cursor_idx]);
|
||||||
if cursor_idx < CURSORS.len() - 1 {
|
if cursor_idx < CURSORS.len() - 1 {
|
||||||
|
@ -23,26 +34,52 @@ fn main() {
|
||||||
cursor_idx = 0;
|
cursor_idx = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const CURSORS: &[CursorIcon] = &[
|
const CURSORS: &[CursorIcon] = &[
|
||||||
CursorIcon::Default, CursorIcon::Crosshair, CursorIcon::Hand,
|
CursorIcon::Default,
|
||||||
CursorIcon::Arrow, CursorIcon::Move, CursorIcon::Text,
|
CursorIcon::Crosshair,
|
||||||
CursorIcon::Wait, CursorIcon::Help, CursorIcon::Progress,
|
CursorIcon::Hand,
|
||||||
CursorIcon::NotAllowed, CursorIcon::ContextMenu, CursorIcon::Cell,
|
CursorIcon::Arrow,
|
||||||
CursorIcon::VerticalText, CursorIcon::Alias, CursorIcon::Copy,
|
CursorIcon::Move,
|
||||||
CursorIcon::NoDrop, CursorIcon::Grab, CursorIcon::Grabbing,
|
CursorIcon::Text,
|
||||||
CursorIcon::AllScroll, CursorIcon::ZoomIn, CursorIcon::ZoomOut,
|
CursorIcon::Wait,
|
||||||
CursorIcon::EResize, CursorIcon::NResize, CursorIcon::NeResize,
|
CursorIcon::Help,
|
||||||
CursorIcon::NwResize, CursorIcon::SResize, CursorIcon::SeResize,
|
CursorIcon::Progress,
|
||||||
CursorIcon::SwResize, CursorIcon::WResize, CursorIcon::EwResize,
|
CursorIcon::NotAllowed,
|
||||||
CursorIcon::NsResize, CursorIcon::NeswResize, CursorIcon::NwseResize,
|
CursorIcon::ContextMenu,
|
||||||
CursorIcon::ColResize, CursorIcon::RowResize
|
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,
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
extern crate winit;
|
use winit::{
|
||||||
|
event::{ElementState, Event, KeyboardInput, WindowEvent},
|
||||||
use winit::window::WindowBuilder;
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event::{Event, WindowEvent, ElementState, KeyboardInput};
|
window::WindowBuilder,
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
@ -18,12 +18,13 @@ fn main() {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
WindowEvent::KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
input: KeyboardInput {
|
input:
|
||||||
state: ElementState::Released,
|
KeyboardInput {
|
||||||
virtual_keycode: Some(key),
|
state: ElementState::Released,
|
||||||
modifiers,
|
virtual_keycode: Some(key),
|
||||||
..
|
modifiers,
|
||||||
},
|
..
|
||||||
|
},
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
use winit::event::VirtualKeyCode::*;
|
use winit::event::VirtualKeyCode::*;
|
||||||
|
@ -33,7 +34,7 @@ fn main() {
|
||||||
H => window.set_cursor_visible(modifiers.shift),
|
H => window.set_cursor_visible(modifiers.shift),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
extern crate winit;
|
|
||||||
|
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use winit::monitor::MonitorHandle;
|
use winit::{
|
||||||
use winit::window::WindowBuilder;
|
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
|
||||||
use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInput};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
monitor::MonitorHandle,
|
||||||
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
@ -24,7 +24,7 @@ fn main() {
|
||||||
let num = num.trim().parse().ok().expect("Please enter a number");
|
let num = num.trim().parse().ok().expect("Please enter a number");
|
||||||
match num {
|
match num {
|
||||||
2 => macos_use_simple_fullscreen = true,
|
2 => macos_use_simple_fullscreen = true,
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prompt for monitor when using native fullscreen
|
// Prompt for monitor when using native fullscreen
|
||||||
|
@ -54,59 +54,69 @@ fn main() {
|
||||||
*control_flow = ControlFlow::Wait;
|
*control_flow = ControlFlow::Wait;
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event, .. } => match event {
|
Event::WindowEvent { event, .. } => {
|
||||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
match event {
|
||||||
WindowEvent::KeyboardInput {
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
input:
|
WindowEvent::KeyboardInput {
|
||||||
KeyboardInput {
|
input:
|
||||||
virtual_keycode: Some(virtual_code),
|
KeyboardInput {
|
||||||
state,
|
virtual_keycode: Some(virtual_code),
|
||||||
..
|
state,
|
||||||
},
|
..
|
||||||
..
|
},
|
||||||
} => match (virtual_code, state) {
|
..
|
||||||
(VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
|
} => {
|
||||||
(VirtualKeyCode::F, ElementState::Pressed) => {
|
match (virtual_code, state) {
|
||||||
#[cfg(target_os = "macos")]
|
(VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
|
||||||
{
|
(VirtualKeyCode::F, ElementState::Pressed) => {
|
||||||
if macos_use_simple_fullscreen {
|
#[cfg(target_os = "macos")]
|
||||||
use winit::platform::macos::WindowExtMacOS;
|
{
|
||||||
if WindowExtMacOS::set_simple_fullscreen(&window, !is_fullscreen) {
|
if macos_use_simple_fullscreen {
|
||||||
is_fullscreen = !is_fullscreen;
|
use winit::platform::macos::WindowExtMacOS;
|
||||||
|
if WindowExtMacOS::set_simple_fullscreen(
|
||||||
|
&window,
|
||||||
|
!is_fullscreen,
|
||||||
|
) {
|
||||||
|
is_fullscreen = !is_fullscreen;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is_fullscreen = !is_fullscreen;
|
is_fullscreen = !is_fullscreen;
|
||||||
if !is_fullscreen {
|
if !is_fullscreen {
|
||||||
window.set_fullscreen(None);
|
window.set_fullscreen(None);
|
||||||
} else {
|
} else {
|
||||||
window.set_fullscreen(Some(window.current_monitor()));
|
window.set_fullscreen(Some(window.current_monitor()));
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
(VirtualKeyCode::S, ElementState::Pressed) => {
|
(VirtualKeyCode::S, ElementState::Pressed) => {
|
||||||
println!("window.fullscreen {:?}", window.fullscreen());
|
println!("window.fullscreen {:?}", window.fullscreen());
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
use winit::platform::macos::WindowExtMacOS;
|
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) => {
|
||||||
|
is_maximized = !is_maximized;
|
||||||
|
window.set_maximized(is_maximized);
|
||||||
|
},
|
||||||
|
(VirtualKeyCode::D, ElementState::Pressed) => {
|
||||||
|
decorations = !decorations;
|
||||||
|
window.set_decorations(decorations);
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
(VirtualKeyCode::M, ElementState::Pressed) => {
|
|
||||||
is_maximized = !is_maximized;
|
|
||||||
window.set_maximized(is_maximized);
|
|
||||||
}
|
|
||||||
(VirtualKeyCode::D, ElementState::Pressed) => {
|
|
||||||
decorations = !decorations;
|
|
||||||
window.set_decorations(decorations);
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
}
|
||||||
_ => (),
|
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -123,7 +133,10 @@ fn prompt_for_monitor(event_loop: &EventLoop<()>) -> MonitorHandle {
|
||||||
let mut num = String::new();
|
let mut num = String::new();
|
||||||
io::stdin().read_line(&mut num).unwrap();
|
io::stdin().read_line(&mut num).unwrap();
|
||||||
let num = num.trim().parse().ok().expect("Please enter a number");
|
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());
|
println!("Using {:?}", monitor.name());
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
extern crate winit;
|
use winit::{
|
||||||
|
event::{Event, KeyboardInput, WindowEvent},
|
||||||
use winit::window::WindowBuilder;
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event::{Event, WindowEvent, KeyboardInput};
|
window::WindowBuilder,
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
@ -15,60 +15,66 @@ fn main() {
|
||||||
let mut close_requested = false;
|
let mut close_requested = false;
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
use winit::event::ElementState::Released;
|
use winit::event::{
|
||||||
use winit::event::VirtualKeyCode::{N, Y};
|
ElementState::Released,
|
||||||
|
VirtualKeyCode::{N, Y},
|
||||||
|
};
|
||||||
*control_flow = ControlFlow::Wait;
|
*control_flow = ControlFlow::Wait;
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event, .. } => match event {
|
Event::WindowEvent { event, .. } => {
|
||||||
WindowEvent::CloseRequested => {
|
match event {
|
||||||
// `CloseRequested` is sent when the close button on the window is pressed (or
|
WindowEvent::CloseRequested => {
|
||||||
// through whatever other mechanisms the window manager provides for closing a
|
// `CloseRequested` is sent when the close button on the window is pressed (or
|
||||||
// window). If you don't handle this event, the close button won't actually do
|
// through whatever other mechanisms the window manager provides for closing a
|
||||||
// anything.
|
// 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.
|
// 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
|
// 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.
|
// example, so here we'll just respond to the Y and N keys.
|
||||||
println!("Are you ready to bid your window farewell? [Y/N]");
|
println!("Are you ready to bid your window farewell? [Y/N]");
|
||||||
close_requested = true;
|
close_requested = true;
|
||||||
|
|
||||||
// In applications where you can safely close the window without further
|
// In applications where you can safely close the window without further
|
||||||
// action from the user, this is generally where you'd handle cleanup before
|
// 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
|
// closing the window. How to close the window is detailed in the handler for
|
||||||
// the Y key.
|
// the Y key.
|
||||||
}
|
},
|
||||||
WindowEvent::KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
input:
|
input:
|
||||||
KeyboardInput {
|
KeyboardInput {
|
||||||
virtual_keycode: Some(virtual_code),
|
virtual_keycode: Some(virtual_code),
|
||||||
state: Released,
|
state: Released,
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
..
|
..
|
||||||
} => match virtual_code {
|
} => {
|
||||||
Y => {
|
match virtual_code {
|
||||||
if close_requested {
|
Y => {
|
||||||
// This is where you'll want to do any cleanup you need.
|
if close_requested {
|
||||||
println!("Buh-bye!");
|
// 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
|
// 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
|
// 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
|
// 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
|
// drop the window. That closes it, and results in `Destroyed` being
|
||||||
// sent.
|
// sent.
|
||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
N => {
|
||||||
|
if close_requested {
|
||||||
|
println!("Your window will continue to stay by your side.");
|
||||||
|
close_requested = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
N => {
|
|
||||||
if close_requested {
|
|
||||||
println!("Your window will continue to stay by your side.");
|
|
||||||
close_requested = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
}
|
||||||
_ => (),
|
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
extern crate winit;
|
use winit::{
|
||||||
|
dpi::LogicalSize,
|
||||||
use winit::dpi::LogicalSize;
|
event::{Event, WindowEvent},
|
||||||
use winit::window::WindowBuilder;
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event::{Event, WindowEvent};
|
window::WindowBuilder,
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new()
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
.build(&event_loop)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
window.set_min_inner_size(Some(LogicalSize::new(400.0, 200.0)));
|
window.set_min_inner_size(Some(LogicalSize::new(400.0, 200.0)));
|
||||||
window.set_max_inner_size(Some(LogicalSize::new(800.0, 400.0)));
|
window.set_max_inner_size(Some(LogicalSize::new(800.0, 400.0)));
|
||||||
|
@ -19,8 +17,10 @@ fn main() {
|
||||||
println!("{:?}", event);
|
println!("{:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } =>
|
Event::WindowEvent {
|
||||||
*control_flow = ControlFlow::Exit,
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => *control_flow = ControlFlow::Exit,
|
||||||
_ => *control_flow = ControlFlow::Wait,
|
_ => *control_flow = ControlFlow::Wait,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
extern crate winit;
|
use winit::{event_loop::EventLoop, window::WindowBuilder};
|
||||||
use winit::event_loop::EventLoop;
|
|
||||||
use winit::window::WindowBuilder;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate winit;
|
|
||||||
|
|
||||||
use std::{collections::HashMap, sync::mpsc, thread, time::Duration};
|
use std::{collections::HashMap, sync::mpsc, thread, time::Duration};
|
||||||
|
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
|
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;
|
const WINDOW_COUNT: usize = 3;
|
||||||
|
@ -25,26 +24,34 @@ fn main() {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
while let Ok(event) = rx.recv() {
|
while let Ok(event) = rx.recv() {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::KeyboardInput { input: KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
state: ElementState::Released,
|
input:
|
||||||
virtual_keycode: Some(key),
|
KeyboardInput {
|
||||||
modifiers,
|
state: ElementState::Released,
|
||||||
|
virtual_keycode: Some(key),
|
||||||
|
modifiers,
|
||||||
|
..
|
||||||
|
},
|
||||||
..
|
..
|
||||||
}, .. } => {
|
} => {
|
||||||
window.set_title(&format!("{:?}", key));
|
window.set_title(&format!("{:?}", key));
|
||||||
let state = !modifiers.shift;
|
let state = !modifiers.shift;
|
||||||
use self::VirtualKeyCode::*;
|
use self::VirtualKeyCode::*;
|
||||||
match key {
|
match key {
|
||||||
A => window.set_always_on_top(state),
|
A => window.set_always_on_top(state),
|
||||||
C => window.set_cursor_icon(match state {
|
C => {
|
||||||
true => CursorIcon::Progress,
|
window.set_cursor_icon(match state {
|
||||||
false => CursorIcon::Default,
|
true => CursorIcon::Progress,
|
||||||
}),
|
false => CursorIcon::Default,
|
||||||
|
})
|
||||||
|
},
|
||||||
D => window.set_decorations(!state),
|
D => window.set_decorations(!state),
|
||||||
F => window.set_fullscreen(match state {
|
F => {
|
||||||
true => Some(window.current_monitor()),
|
window.set_fullscreen(match state {
|
||||||
false => None,
|
true => Some(window.current_monitor()),
|
||||||
}),
|
false => None,
|
||||||
|
})
|
||||||
|
},
|
||||||
G => window.set_cursor_grab(state).unwrap(),
|
G => window.set_cursor_grab(state).unwrap(),
|
||||||
H => window.set_cursor_visible(!state),
|
H => window.set_cursor_visible(!state),
|
||||||
I => {
|
I => {
|
||||||
|
@ -54,28 +61,40 @@ fn main() {
|
||||||
println!("-> outer_size : {:?}", window.outer_size());
|
println!("-> outer_size : {:?}", window.outer_size());
|
||||||
println!("-> inner_size : {:?}", window.inner_size());
|
println!("-> inner_size : {:?}", window.inner_size());
|
||||||
},
|
},
|
||||||
L => window.set_min_inner_size(match state {
|
L => {
|
||||||
true => Some(WINDOW_SIZE.into()),
|
window.set_min_inner_size(match state {
|
||||||
false => None,
|
true => Some(WINDOW_SIZE.into()),
|
||||||
}),
|
false => None,
|
||||||
|
})
|
||||||
|
},
|
||||||
M => window.set_maximized(state),
|
M => window.set_maximized(state),
|
||||||
P => window.set_outer_position({
|
P => {
|
||||||
let mut position = window.outer_position().unwrap();
|
window.set_outer_position({
|
||||||
let sign = if state { 1.0 } else { -1.0 };
|
let mut position = window.outer_position().unwrap();
|
||||||
position.x += 10.0 * sign;
|
let sign = if state { 1.0 } else { -1.0 };
|
||||||
position.y += 10.0 * sign;
|
position.x += 10.0 * sign;
|
||||||
position
|
position.y += 10.0 * sign;
|
||||||
}),
|
position
|
||||||
|
})
|
||||||
|
},
|
||||||
Q => window.request_redraw(),
|
Q => window.request_redraw(),
|
||||||
R => window.set_resizable(state),
|
R => window.set_resizable(state),
|
||||||
S => window.set_inner_size(match state {
|
S => {
|
||||||
true => (WINDOW_SIZE.0 + 100, WINDOW_SIZE.1 + 100),
|
window.set_inner_size(
|
||||||
false => WINDOW_SIZE,
|
match state {
|
||||||
}.into()),
|
true => (WINDOW_SIZE.0 + 100, WINDOW_SIZE.1 + 100),
|
||||||
W => window.set_cursor_position((
|
false => WINDOW_SIZE,
|
||||||
WINDOW_SIZE.0 as i32 / 2,
|
}
|
||||||
WINDOW_SIZE.1 as i32 / 2,
|
.into(),
|
||||||
).into()).unwrap(),
|
)
|
||||||
|
},
|
||||||
|
W => {
|
||||||
|
window
|
||||||
|
.set_cursor_position(
|
||||||
|
(WINDOW_SIZE.0 as i32 / 2, WINDOW_SIZE.1 as i32 / 2).into(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
},
|
||||||
Z => {
|
Z => {
|
||||||
window.set_visible(false);
|
window.set_visible(false);
|
||||||
thread::sleep(Duration::from_secs(1));
|
thread::sleep(Duration::from_secs(1));
|
||||||
|
@ -99,16 +118,23 @@ fn main() {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested
|
WindowEvent::CloseRequested
|
||||||
| WindowEvent::Destroyed
|
| WindowEvent::Destroyed
|
||||||
| WindowEvent::KeyboardInput { input: KeyboardInput {
|
| WindowEvent::KeyboardInput {
|
||||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
input:
|
||||||
.. }, .. } => {
|
KeyboardInput {
|
||||||
|
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} => {
|
||||||
window_senders.remove(&window_id);
|
window_senders.remove(&window_id);
|
||||||
},
|
},
|
||||||
_ => if let Some(tx) = window_senders.get(&window_id) {
|
_ => {
|
||||||
tx.send(event).unwrap();
|
if let Some(tx) = window_senders.get(&window_id) {
|
||||||
|
tx.send(event).unwrap();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
extern crate winit;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use winit::window::Window;
|
use winit::{
|
||||||
use winit::event::{Event, WindowEvent, ElementState, KeyboardInput};
|
event::{ElementState, Event, KeyboardInput, WindowEvent},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::Window,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
@ -29,13 +29,20 @@ fn main() {
|
||||||
*control_flow = ControlFlow::Exit;
|
*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();
|
let window = Window::new(&event_loop).unwrap();
|
||||||
windows.insert(window.id(), window);
|
windows.insert(window.id(), window);
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
extern crate winit;
|
use winit::{
|
||||||
use winit::window::WindowBuilder;
|
event::{Event, WindowEvent},
|
||||||
use winit::event::{Event, WindowEvent};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop: EventLoop<i32> = EventLoop::new_user_event();
|
let event_loop: EventLoop<i32> = EventLoop::new_user_event();
|
||||||
|
@ -26,8 +27,10 @@ fn main() {
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
println!("{:?}", event);
|
println!("{:?}", event);
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } =>
|
Event::WindowEvent {
|
||||||
*control_flow = ControlFlow::Exit,
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => *control_flow = ControlFlow::Exit,
|
||||||
_ => *control_flow = ControlFlow::Wait,
|
_ => *control_flow = ControlFlow::Wait,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
extern crate winit;
|
use std::time::{Duration, Instant};
|
||||||
use std::time::{Instant, Duration};
|
|
||||||
|
|
||||||
use winit::window::WindowBuilder;
|
use winit::{
|
||||||
use winit::event::{Event, WindowEvent};
|
event::{Event, WindowEvent},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
@ -25,7 +26,7 @@ fn main() {
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
*control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0))
|
*control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0))
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
extern crate winit;
|
use winit::{
|
||||||
use winit::window::WindowBuilder;
|
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
|
||||||
use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInput};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
@ -18,22 +19,24 @@ fn main() {
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
*control_flow = ControlFlow::Wait;
|
*control_flow = ControlFlow::Wait;
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event, .. } => match event {
|
Event::WindowEvent { event, .. } => {
|
||||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
match event {
|
||||||
WindowEvent::KeyboardInput {
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
input:
|
WindowEvent::KeyboardInput {
|
||||||
KeyboardInput {
|
input:
|
||||||
virtual_keycode: Some(VirtualKeyCode::Space),
|
KeyboardInput {
|
||||||
state: ElementState::Released,
|
virtual_keycode: Some(VirtualKeyCode::Space),
|
||||||
..
|
state: ElementState::Released,
|
||||||
},
|
..
|
||||||
..
|
},
|
||||||
} => {
|
..
|
||||||
resizable = !resizable;
|
} => {
|
||||||
println!("Resizable: {}", resizable);
|
resizable = !resizable;
|
||||||
window.set_resizable(resizable);
|
println!("Resizable: {}", resizable);
|
||||||
|
window.set_resizable(resizable);
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
extern crate winit;
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use winit::window::WindowBuilder;
|
use winit::{
|
||||||
use winit::event::{Event, WindowEvent, StartCause};
|
event::{Event, StartCause, WindowEvent},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
@ -18,9 +19,10 @@ fn main() {
|
||||||
println!("{:?}", event);
|
println!("{:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::NewEvents(StartCause::Init) =>
|
Event::NewEvents(StartCause::Init) => {
|
||||||
*control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length),
|
*control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length)
|
||||||
Event::NewEvents(StartCause::ResumeTimeReached{..}) => {
|
},
|
||||||
|
Event::NewEvents(StartCause::ResumeTimeReached { .. }) => {
|
||||||
*control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length);
|
*control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length);
|
||||||
println!("\nTimer\n");
|
println!("\nTimer\n");
|
||||||
},
|
},
|
||||||
|
@ -28,7 +30,7 @@ fn main() {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => *control_flow = ControlFlow::Exit,
|
} => *control_flow = ControlFlow::Exit,
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
extern crate winit;
|
use winit::{
|
||||||
use winit::window::WindowBuilder;
|
event::{Event, WindowEvent},
|
||||||
use winit::event::{Event, WindowEvent};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new().with_decorations(false)
|
let window = WindowBuilder::new()
|
||||||
.with_transparent(true)
|
.with_decorations(false)
|
||||||
.build(&event_loop).unwrap();
|
.with_transparent(true)
|
||||||
|
.build(&event_loop)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
window.set_title("A fantastic window!");
|
window.set_title("A fantastic window!");
|
||||||
|
|
||||||
|
@ -16,8 +19,10 @@ fn main() {
|
||||||
println!("{:?}", event);
|
println!("{:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } =>
|
Event::WindowEvent {
|
||||||
*control_flow = ControlFlow::Exit,
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => *control_flow = ControlFlow::Exit,
|
||||||
_ => *control_flow = ControlFlow::Wait,
|
_ => *control_flow = ControlFlow::Wait,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
extern crate winit;
|
|
||||||
|
|
||||||
use winit::event_loop::EventLoop;
|
use winit::event_loop::EventLoop;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
extern crate winit;
|
use winit::{
|
||||||
use winit::window::WindowBuilder;
|
event::{Event, WindowEvent},
|
||||||
use winit::event::{Event, WindowEvent};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
extern crate winit;
|
|
||||||
extern crate image;
|
extern crate image;
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use winit::window::{WindowBuilder, Icon};
|
use winit::{
|
||||||
use winit::event::Event;
|
event::Event,
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::{Icon, WindowBuilder},
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
// You'll have to choose an icon size at your own discretion. On X11, the desired size varies
|
// 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,
|
// 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
|
// since it seems to work well enough in most cases. Be careful about going too high, or
|
||||||
|
@ -43,8 +42,6 @@ fn main() {
|
||||||
match event {
|
match event {
|
||||||
CloseRequested => *control_flow = ControlFlow::Exit,
|
CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
DroppedFile(path) => {
|
DroppedFile(path) => {
|
||||||
|
|
||||||
|
|
||||||
window.set_window_icon(Some(load_icon(&path)));
|
window.set_window_icon(Some(load_icon(&path)));
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
extern crate winit;
|
use winit::{
|
||||||
|
event::{Event, WindowEvent},
|
||||||
use winit::window::WindowBuilder;
|
event_loop::{ControlFlow, EventLoop},
|
||||||
use winit::event::{Event, WindowEvent};
|
platform::desktop::EventLoopExtDesktop,
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
window::WindowBuilder,
|
||||||
use winit::platform::desktop::EventLoopExtDesktop;
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut event_loop = EventLoop::new();
|
let mut event_loop = EventLoop::new();
|
||||||
|
|
7
rustfmt.toml
Normal file
7
rustfmt.toml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
merge_imports=true
|
||||||
|
match_block_trailing_comma=true
|
||||||
|
force_explicit_abi=true
|
||||||
|
format_macro_matchers=true
|
||||||
|
use_field_init_shorthand=true
|
||||||
|
format_code_in_doc_comments=true
|
||||||
|
force_multiline_blocks=true
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
//! DPI is important, so read the docs for this module if you don't want to be confused.
|
//! 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
|
//! Originally, `winit` dealt entirely in physical pixels (excluding unintentional inconsistencies), but now all
|
||||||
|
|
20
src/error.rs
20
src/error.rs
|
@ -1,5 +1,4 @@
|
||||||
use std::fmt;
|
use std::{error, fmt};
|
||||||
use std::error;
|
|
||||||
|
|
||||||
use crate::platform_impl;
|
use crate::platform_impl;
|
||||||
|
|
||||||
|
@ -30,20 +29,14 @@ impl NotSupportedError {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn new() -> NotSupportedError {
|
pub(crate) fn new() -> NotSupportedError {
|
||||||
NotSupportedError {
|
NotSupportedError { _marker: () }
|
||||||
_marker: ()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OsError {
|
impl OsError {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn new(line: u32, file: &'static str, error: platform_impl::OsError) -> OsError {
|
pub(crate) fn new(line: u32, file: &'static str, error: platform_impl::OsError) -> OsError {
|
||||||
OsError {
|
OsError { line, file, error }
|
||||||
line,
|
|
||||||
file,
|
|
||||||
error,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,12 +44,15 @@ impl OsError {
|
||||||
macro_rules! os_error {
|
macro_rules! os_error {
|
||||||
($error:expr) => {{
|
($error:expr) => {{
|
||||||
crate::error::OsError::new(line!(), file!(), $error)
|
crate::error::OsError::new(line!(), file!(), $error)
|
||||||
}}
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for OsError {
|
impl fmt::Display for OsError {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
formatter.pad(&format!("os error at {}:{}: {}", self.file, self.line, self.error))
|
formatter.pad(&format!(
|
||||||
|
"os error at {}:{}: {}",
|
||||||
|
self.file, self.line, self.error
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
105
src/event.rs
105
src/event.rs
|
@ -4,12 +4,13 @@
|
||||||
//! processed and used to modify the program state. For more details, see the root-level documentation.
|
//! processed and used to modify the program state. For more details, see the root-level documentation.
|
||||||
//!
|
//!
|
||||||
//! [event_loop_run]: ../event_loop/struct.EventLoop.html#method.run
|
//! [event_loop_run]: ../event_loop/struct.EventLoop.html#method.run
|
||||||
use std::time::Instant;
|
use std::{path::PathBuf, time::Instant};
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use crate::dpi::{LogicalPosition, LogicalSize};
|
use crate::{
|
||||||
use crate::window::WindowId;
|
dpi::{LogicalPosition, LogicalSize},
|
||||||
use crate::platform_impl;
|
platform_impl,
|
||||||
|
window::WindowId,
|
||||||
|
};
|
||||||
|
|
||||||
/// Describes a generic event.
|
/// Describes a generic event.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -47,8 +48,8 @@ impl<T> Event<T> {
|
||||||
use self::Event::*;
|
use self::Event::*;
|
||||||
match self {
|
match self {
|
||||||
UserEvent(_) => Err(self),
|
UserEvent(_) => Err(self),
|
||||||
WindowEvent{window_id, event} => Ok(WindowEvent{window_id, event}),
|
WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }),
|
||||||
DeviceEvent{device_id, event} => Ok(DeviceEvent{device_id, event}),
|
DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }),
|
||||||
NewEvents(cause) => Ok(NewEvents(cause)),
|
NewEvents(cause) => Ok(NewEvents(cause)),
|
||||||
EventsCleared => Ok(EventsCleared),
|
EventsCleared => Ok(EventsCleared),
|
||||||
LoopDestroyed => Ok(LoopDestroyed),
|
LoopDestroyed => Ok(LoopDestroyed),
|
||||||
|
@ -65,14 +66,14 @@ pub enum StartCause {
|
||||||
/// guaranteed to be equal to or after the requested resume time.
|
/// guaranteed to be equal to or after the requested resume time.
|
||||||
ResumeTimeReached {
|
ResumeTimeReached {
|
||||||
start: Instant,
|
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
|
/// 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.
|
/// the moment the wait was requested and the resume time, if requested.
|
||||||
WaitCancelled {
|
WaitCancelled {
|
||||||
start: Instant,
|
start: Instant,
|
||||||
requested_resume: Option<Instant>
|
requested_resume: Option<Instant>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Sent if the event loop is being resumed after the loop's control flow was set to
|
/// Sent if the event loop is being resumed after the loop's control flow was set to
|
||||||
|
@ -80,7 +81,7 @@ pub enum StartCause {
|
||||||
Poll,
|
Poll,
|
||||||
|
|
||||||
/// Sent once, immediately after `run` is called. Indicates that the loop was just initialized.
|
/// Sent once, immediately after `run` is called. Indicates that the loop was just initialized.
|
||||||
Init
|
Init,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes an event from a `Window`.
|
/// Describes an event from a `Window`.
|
||||||
|
@ -125,7 +126,10 @@ pub enum WindowEvent {
|
||||||
Focused(bool),
|
Focused(bool),
|
||||||
|
|
||||||
/// An event from the keyboard has been received.
|
/// 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.
|
/// The cursor has moved on the window.
|
||||||
CursorMoved {
|
CursorMoved {
|
||||||
|
@ -135,7 +139,7 @@ pub enum WindowEvent {
|
||||||
/// limited by the display area and it may have been transformed by the OS to implement effects such as cursor
|
/// 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.
|
/// acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control.
|
||||||
position: LogicalPosition,
|
position: LogicalPosition,
|
||||||
modifiers: ModifiersState
|
modifiers: ModifiersState,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// The cursor has entered the window.
|
/// The cursor has entered the window.
|
||||||
|
@ -145,21 +149,38 @@ pub enum WindowEvent {
|
||||||
CursorLeft { device_id: DeviceId },
|
CursorLeft { device_id: DeviceId },
|
||||||
|
|
||||||
/// A mouse wheel movement or touchpad scroll occurred.
|
/// 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.
|
/// 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.
|
/// Touchpad pressure event.
|
||||||
///
|
///
|
||||||
/// At the moment, only supported on Apple forcetouch-capable macbooks.
|
/// 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
|
/// 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).
|
/// 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.
|
/// 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.
|
/// The OS or application has requested that the window be redrawn.
|
||||||
RedrawRequested,
|
RedrawRequested,
|
||||||
|
@ -229,11 +250,19 @@ pub enum DeviceEvent {
|
||||||
/// Motion on some analog axis. This event will be reported for all arbitrary input devices
|
/// 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
|
/// 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.
|
/// 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),
|
Key(KeyboardInput),
|
||||||
Text { codepoint: char },
|
Text {
|
||||||
|
codepoint: char,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes a keyboard input event.
|
/// Describes a keyboard input event.
|
||||||
|
@ -259,7 +288,7 @@ pub struct KeyboardInput {
|
||||||
///
|
///
|
||||||
/// This is tracked internally to avoid tracking errors arising from modifier key state changes when events from
|
/// 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.
|
/// 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.
|
/// Describes touch-screen input state.
|
||||||
|
@ -269,7 +298,7 @@ pub enum TouchPhase {
|
||||||
Started,
|
Started,
|
||||||
Moved,
|
Moved,
|
||||||
Ended,
|
Ended,
|
||||||
Cancelled
|
Cancelled,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents touch event
|
/// Represents touch event
|
||||||
|
@ -293,7 +322,7 @@ pub struct Touch {
|
||||||
pub phase: TouchPhase,
|
pub phase: TouchPhase,
|
||||||
pub location: LogicalPosition,
|
pub location: LogicalPosition,
|
||||||
/// unique identifier of a finger.
|
/// unique identifier of a finger.
|
||||||
pub id: u64
|
pub id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hardware-dependent keyboard scan code.
|
/// Hardware-dependent keyboard scan code.
|
||||||
|
@ -327,19 +356,19 @@ pub enum MouseButton {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub enum MouseScrollDelta {
|
pub enum MouseScrollDelta {
|
||||||
/// Amount in lines or rows to scroll in the horizontal
|
/// Amount in lines or rows to scroll in the horizontal
|
||||||
/// and vertical directions.
|
/// and vertical directions.
|
||||||
///
|
///
|
||||||
/// Positive values indicate movement forward
|
/// Positive values indicate movement forward
|
||||||
/// (away from the user) or rightwards.
|
/// (away from the user) or rightwards.
|
||||||
LineDelta(f32, f32),
|
LineDelta(f32, f32),
|
||||||
/// Amount in pixels to scroll in the horizontal and
|
/// Amount in pixels to scroll in the horizontal and
|
||||||
/// vertical direction.
|
/// vertical direction.
|
||||||
///
|
///
|
||||||
/// Scroll events are expressed as a PixelDelta if
|
/// Scroll events are expressed as a PixelDelta if
|
||||||
/// supported by the device (eg. a touchpad) and
|
/// supported by the device (eg. a touchpad) and
|
||||||
/// platform.
|
/// platform.
|
||||||
PixelDelta(LogicalPosition),
|
PixelDelta(LogicalPosition),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Symbolic name for a keyboard key.
|
/// Symbolic name for a keyboard key.
|
||||||
|
@ -499,7 +528,7 @@ pub enum VirtualKeyCode {
|
||||||
Multiply,
|
Multiply,
|
||||||
Mute,
|
Mute,
|
||||||
MyComputer,
|
MyComputer,
|
||||||
NavigateForward, // also called "Prior"
|
NavigateForward, // also called "Prior"
|
||||||
NavigateBackward, // also called "Next"
|
NavigateBackward, // also called "Next"
|
||||||
NextTrack,
|
NextTrack,
|
||||||
NoConvert,
|
NoConvert,
|
||||||
|
@ -557,5 +586,5 @@ pub struct ModifiersState {
|
||||||
/// The "logo" key
|
/// The "logo" key
|
||||||
///
|
///
|
||||||
/// This is the "windows" key on PC and "command" key on Mac.
|
/// This is the "windows" key on PC and "command" key on Mac.
|
||||||
pub logo: bool
|
pub logo: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
//! [create_proxy]: ./struct.EventLoop.html#method.create_proxy
|
//! [create_proxy]: ./struct.EventLoop.html#method.create_proxy
|
||||||
//! [event_loop_proxy]: ./struct.EventLoopProxy.html
|
//! [event_loop_proxy]: ./struct.EventLoopProxy.html
|
||||||
//! [send_event]: ./struct.EventLoopProxy.html#method.send_event
|
//! [send_event]: ./struct.EventLoopProxy.html#method.send_event
|
||||||
use std::{fmt, error};
|
use std::{error, fmt, ops::Deref, time::Instant};
|
||||||
use std::time::Instant;
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use crate::platform_impl;
|
use crate::{
|
||||||
use crate::event::Event;
|
event::Event,
|
||||||
use crate::monitor::{AvailableMonitorsIter, MonitorHandle};
|
monitor::{AvailableMonitorsIter, MonitorHandle},
|
||||||
|
platform_impl,
|
||||||
|
};
|
||||||
|
|
||||||
/// Provides a way to retrieve events from the system and from the windows that were registered to
|
/// Provides a way to retrieve events from the system and from the windows that were registered to
|
||||||
/// the events loop.
|
/// the events loop.
|
||||||
|
@ -32,7 +32,7 @@ use crate::monitor::{AvailableMonitorsIter, MonitorHandle};
|
||||||
/// `EventLoopProxy` allows you to wake up an `EventLoop` from an other thread.
|
/// `EventLoopProxy` allows you to wake up an `EventLoop` from an other thread.
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop<T: 'static> {
|
||||||
pub(crate) event_loop: platform_impl::EventLoop<T>,
|
pub(crate) event_loop: platform_impl::EventLoop<T>,
|
||||||
pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync
|
pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Target that associates windows with an `EventLoop`.
|
/// Target that associates windows with an `EventLoop`.
|
||||||
|
@ -42,7 +42,7 @@ pub struct EventLoop<T: 'static> {
|
||||||
/// take `&EventLoop`.
|
/// take `&EventLoop`.
|
||||||
pub struct EventLoopWindowTarget<T: 'static> {
|
pub struct EventLoopWindowTarget<T: 'static> {
|
||||||
pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
|
pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
|
||||||
pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync
|
pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for EventLoop<T> {
|
impl<T> fmt::Debug for EventLoop<T> {
|
||||||
|
@ -82,7 +82,7 @@ pub enum ControlFlow {
|
||||||
/// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
|
/// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
|
||||||
/// `control_flow` cannot be changed from `Exit`, and any future attempts to do so will result
|
/// `control_flow` cannot be changed from `Exit`, and any future attempts to do so will result
|
||||||
/// in the `control_flow` parameter being reset to `Exit`.
|
/// in the `control_flow` parameter being reset to `Exit`.
|
||||||
Exit
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ControlFlow {
|
impl Default for ControlFlow {
|
||||||
|
@ -133,7 +133,8 @@ impl<T> EventLoop<T> {
|
||||||
/// [`ControlFlow`]: ./enum.ControlFlow.html
|
/// [`ControlFlow`]: ./enum.ControlFlow.html
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn run<F>(self, event_handler: F) -> !
|
pub fn run<F>(self, event_handler: F) -> !
|
||||||
where F: 'static + FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow)
|
where
|
||||||
|
F: 'static + FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.event_loop.run(event_handler)
|
self.event_loop.run(event_handler)
|
||||||
}
|
}
|
||||||
|
@ -149,13 +150,17 @@ impl<T> EventLoop<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
||||||
let data = self.event_loop.available_monitors();
|
let data = self.event_loop.available_monitors();
|
||||||
AvailableMonitorsIter{ data: data.into_iter() }
|
AvailableMonitorsIter {
|
||||||
|
data: data.into_iter(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the primary monitor of the system.
|
/// Returns the primary monitor of the system.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn primary_monitor(&self) -> MonitorHandle {
|
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||||
MonitorHandle { inner: self.event_loop.primary_monitor() }
|
MonitorHandle {
|
||||||
|
inner: self.event_loop.primary_monitor(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,4 +210,3 @@ impl error::Error for EventLoopClosed {
|
||||||
"Tried to wake up a closed `EventLoop`"
|
"Tried to wake up a closed `EventLoop`"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
src/icon.rs
17
src/icon.rs
|
@ -1,5 +1,4 @@
|
||||||
use std::{fmt, mem};
|
use std::{error::Error, fmt, mem};
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -17,9 +16,7 @@ pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
|
||||||
pub enum BadIcon {
|
pub enum BadIcon {
|
||||||
/// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
|
/// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
|
||||||
/// safely interpreted as 32bpp RGBA pixels.
|
/// safely interpreted as 32bpp RGBA pixels.
|
||||||
ByteCountNotDivisibleBy4 {
|
ByteCountNotDivisibleBy4 { byte_count: usize },
|
||||||
byte_count: usize,
|
|
||||||
},
|
|
||||||
/// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
|
/// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
|
||||||
/// At least one of your arguments is incorrect.
|
/// At least one of your arguments is incorrect.
|
||||||
DimensionsVsPixelCount {
|
DimensionsVsPixelCount {
|
||||||
|
@ -76,7 +73,9 @@ impl Icon {
|
||||||
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
|
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
|
||||||
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
|
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
|
||||||
if rgba.len() % PIXEL_SIZE != 0 {
|
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;
|
let pixel_count = rgba.len() / PIXEL_SIZE;
|
||||||
if pixel_count != (width * height) as usize {
|
if pixel_count != (width * height) as usize {
|
||||||
|
@ -87,7 +86,11 @@ impl Icon {
|
||||||
pixel_count,
|
pixel_count,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Ok(Icon { rgba, width, height })
|
Ok(Icon {
|
||||||
|
rgba,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
src/lib.rs
13
src/lib.rs
|
@ -33,14 +33,19 @@
|
||||||
//! is emitted and the entire program terminates.
|
//! is emitted and the entire program terminates.
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use winit::event_loop::ControlFlow;
|
//! use winit::{
|
||||||
//! use winit::event::{Event, WindowEvent};
|
//! event::{Event, WindowEvent},
|
||||||
|
//! event_loop::ControlFlow,
|
||||||
|
//! };
|
||||||
//! # use winit::event_loop::EventLoop;
|
//! # use winit::event_loop::EventLoop;
|
||||||
//! # let event_loop = EventLoop::new();
|
//! # let event_loop = EventLoop::new();
|
||||||
//!
|
//!
|
||||||
//! event_loop.run(move |event, _, control_flow| {
|
//! event_loop.run(move |event, _, control_flow| {
|
||||||
//! match event {
|
//! match event {
|
||||||
//! Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
//! Event::WindowEvent {
|
||||||
|
//! event: WindowEvent::CloseRequested,
|
||||||
|
//! ..
|
||||||
|
//! } => {
|
||||||
//! println!("The close button was pressed; stopping");
|
//! println!("The close button was pressed; stopping");
|
||||||
//! *control_flow = ControlFlow::Exit
|
//! *control_flow = ControlFlow::Exit
|
||||||
//! },
|
//! },
|
||||||
|
@ -101,8 +106,8 @@ pub mod error;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod event_loop;
|
pub mod event_loop;
|
||||||
mod icon;
|
mod icon;
|
||||||
|
pub mod monitor;
|
||||||
mod platform_impl;
|
mod platform_impl;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
pub mod monitor;
|
|
||||||
|
|
||||||
pub mod platform;
|
pub mod platform;
|
||||||
|
|
|
@ -12,8 +12,10 @@
|
||||||
//! [window_get]: ../window/struct.Window.html#method.available_monitors
|
//! [window_get]: ../window/struct.Window.html#method.available_monitors
|
||||||
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
||||||
|
|
||||||
use crate::platform_impl;
|
use crate::{
|
||||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
dpi::{PhysicalPosition, PhysicalSize},
|
||||||
|
platform_impl,
|
||||||
|
};
|
||||||
|
|
||||||
/// An iterator over all available monitors.
|
/// An iterator over all available monitors.
|
||||||
///
|
///
|
||||||
|
@ -90,7 +92,7 @@ impl VideoMode {
|
||||||
/// [`Window`]: ../window/struct.Window.html
|
/// [`Window`]: ../window/struct.Window.html
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MonitorHandle {
|
pub struct MonitorHandle {
|
||||||
pub(crate) inner: platform_impl::MonitorHandle
|
pub(crate) inner: platform_impl::MonitorHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MonitorHandle {
|
impl MonitorHandle {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#![cfg(any(target_os = "android"))]
|
#![cfg(any(target_os = "android"))]
|
||||||
|
|
||||||
|
use crate::{EventLoop, Window, WindowBuilder};
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use crate::EventLoop;
|
|
||||||
use crate::Window;
|
|
||||||
use crate::WindowBuilder;
|
|
||||||
|
|
||||||
/// Additional methods on `EventLoop` that are specific to Android.
|
/// Additional methods on `EventLoop` that are specific to Android.
|
||||||
pub trait EventLoopExtAndroid {
|
pub trait EventLoopExtAndroid {
|
||||||
|
@ -30,9 +28,6 @@ impl WindowExtAndroid for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional methods on `WindowBuilder` that are specific to Android.
|
/// Additional methods on `WindowBuilder` that are specific to Android.
|
||||||
pub trait WindowBuilderExtAndroid {
|
pub trait WindowBuilderExtAndroid {}
|
||||||
|
|
||||||
}
|
impl WindowBuilderExtAndroid for WindowBuilder {}
|
||||||
|
|
||||||
impl WindowBuilderExtAndroid for WindowBuilder {
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"
|
target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"
|
||||||
))]
|
))]
|
||||||
|
|
||||||
use crate::event::Event;
|
use crate::{
|
||||||
use crate::event_loop::{EventLoop, EventLoopWindowTarget, ControlFlow};
|
event::Event,
|
||||||
|
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
|
||||||
|
};
|
||||||
|
|
||||||
/// Additional methods on `EventLoop` that are specific to desktop platforms.
|
/// Additional methods on `EventLoop` that are specific to desktop platforms.
|
||||||
pub trait EventLoopExtDesktop {
|
pub trait EventLoopExtDesktop {
|
||||||
|
@ -27,14 +29,16 @@ pub trait EventLoopExtDesktop {
|
||||||
///
|
///
|
||||||
/// You are strongly encouraged to use `run`, unless the use of this is absolutely necessary.
|
/// You are strongly encouraged to use `run`, unless the use of this is absolutely necessary.
|
||||||
fn run_return<F>(&mut self, event_handler: F)
|
fn run_return<F>(&mut self, event_handler: F)
|
||||||
where F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow);
|
where
|
||||||
|
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopExtDesktop for EventLoop<T> {
|
impl<T> EventLoopExtDesktop for EventLoop<T> {
|
||||||
type UserEvent = T;
|
type UserEvent = T;
|
||||||
|
|
||||||
fn run_return<F>(&mut self, event_handler: F)
|
fn run_return<F>(&mut self, event_handler: F)
|
||||||
where F: FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow)
|
where
|
||||||
|
F: FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.event_loop.run_return(event_handler)
|
self.event_loop.run_return(event_handler)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
use crate::event_loop::EventLoop;
|
use crate::{
|
||||||
use crate::monitor::MonitorHandle;
|
event_loop::EventLoop,
|
||||||
use crate::window::{Window, WindowBuilder};
|
monitor::MonitorHandle,
|
||||||
|
window::{Window, WindowBuilder},
|
||||||
|
};
|
||||||
|
|
||||||
/// Additional methods on `EventLoop` that are specific to iOS.
|
/// Additional methods on `EventLoop` that are specific to iOS.
|
||||||
pub trait EventLoopExtIOS {
|
pub trait EventLoopExtIOS {
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
use crate::dpi::LogicalSize;
|
use crate::{
|
||||||
use crate::monitor::MonitorHandle;
|
dpi::LogicalSize,
|
||||||
use crate::window::{Window, WindowBuilder};
|
monitor::MonitorHandle,
|
||||||
|
window::{Window, WindowBuilder},
|
||||||
|
};
|
||||||
|
|
||||||
/// Additional methods on `Window` that are specific to MacOS.
|
/// Additional methods on `Window` that are specific to MacOS.
|
||||||
pub trait WindowExtMacOS {
|
pub trait WindowExtMacOS {
|
||||||
|
@ -97,7 +99,8 @@ pub trait WindowBuilderExtMacOS {
|
||||||
/// Sets the activation policy for the window being built.
|
/// Sets the activation policy for the window being built.
|
||||||
fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder;
|
fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder;
|
||||||
/// Enables click-and-drag behavior for the entire window, not just the titlebar.
|
/// 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.
|
/// Makes the titlebar transparent and allows the content to appear behind it.
|
||||||
fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
|
fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
|
||||||
/// Hides the window title.
|
/// Hides the window title.
|
||||||
|
@ -120,7 +123,10 @@ impl WindowBuilderExtMacOS for WindowBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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.platform_specific.movable_by_window_background = movable_by_window_background;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,26 @@
|
||||||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||||
|
|
||||||
use std::os::raw;
|
use std::{os::raw, ptr, sync::Arc};
|
||||||
use std::ptr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use smithay_client_toolkit::window::{ButtonState, Theme};
|
use smithay_client_toolkit::window::{ButtonState, Theme};
|
||||||
|
|
||||||
use crate::dpi::LogicalSize;
|
use crate::{
|
||||||
use crate::event_loop::EventLoop;
|
dpi::LogicalSize,
|
||||||
use crate::monitor::MonitorHandle;
|
event_loop::EventLoop,
|
||||||
use crate::window::{Window, WindowBuilder};
|
monitor::MonitorHandle,
|
||||||
|
window::{Window, WindowBuilder},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::platform_impl::{
|
use crate::platform_impl::{
|
||||||
EventLoop as LinuxEventLoop,
|
x11::{ffi::XVisualInfo, XConnection},
|
||||||
Window as LinuxWindow,
|
EventLoop as LinuxEventLoop, Window as LinuxWindow,
|
||||||
};
|
};
|
||||||
use crate::platform_impl::x11::XConnection;
|
|
||||||
use crate::platform_impl::x11::ffi::XVisualInfo;
|
|
||||||
|
|
||||||
// TODO: stupid hack so that glutin can do its work
|
// TODO: stupid hack so that glutin can do its work
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::platform_impl::x11;
|
pub use crate::platform_impl::x11;
|
||||||
|
|
||||||
pub use crate::platform_impl::XNotSupported;
|
pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported};
|
||||||
pub use crate::platform_impl::x11::util::WindowType as XWindowType;
|
|
||||||
|
|
||||||
/// Theme for wayland client side decorations
|
/// Theme for wayland client side decorations
|
||||||
///
|
///
|
||||||
|
@ -97,11 +94,13 @@ impl Theme for WaylandThemeObject {
|
||||||
pub trait EventLoopExtUnix {
|
pub trait EventLoopExtUnix {
|
||||||
/// Builds a new `EventLoops` that is forced to use X11.
|
/// Builds a new `EventLoops` that is forced to use X11.
|
||||||
fn new_x11() -> Result<Self, XNotSupported>
|
fn new_x11() -> Result<Self, XNotSupported>
|
||||||
where Self: Sized;
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
/// Builds a new `EventLoop` that is forced to use Wayland.
|
/// Builds a new `EventLoop` that is forced to use Wayland.
|
||||||
fn new_wayland() -> Self
|
fn new_wayland() -> Self
|
||||||
where Self: Sized;
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
/// True if the `EventLoop` uses Wayland.
|
/// True if the `EventLoop` uses Wayland.
|
||||||
fn is_wayland(&self) -> bool;
|
fn is_wayland(&self) -> bool;
|
||||||
|
@ -123,12 +122,12 @@ pub trait EventLoopExtUnix {
|
||||||
impl<T> EventLoopExtUnix for EventLoop<T> {
|
impl<T> EventLoopExtUnix for EventLoop<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new_x11() -> Result<Self, XNotSupported> {
|
fn new_x11() -> Result<Self, XNotSupported> {
|
||||||
LinuxEventLoop::new_x11().map(|ev|
|
LinuxEventLoop::new_x11().map(|ev| {
|
||||||
EventLoop {
|
EventLoop {
|
||||||
event_loop: ev,
|
event_loop: ev,
|
||||||
_marker: ::std::marker::PhantomData,
|
_marker: ::std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -136,7 +135,7 @@ impl<T> EventLoopExtUnix for EventLoop<T> {
|
||||||
EventLoop {
|
EventLoop {
|
||||||
event_loop: match LinuxEventLoop::new_wayland() {
|
event_loop: match LinuxEventLoop::new_wayland() {
|
||||||
Ok(e) => e,
|
Ok(e) => e,
|
||||||
Err(_) => panic!() // TODO: propagate
|
Err(_) => panic!(), // TODO: propagate
|
||||||
},
|
},
|
||||||
_marker: ::std::marker::PhantomData,
|
_marker: ::std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
|
@ -157,7 +156,7 @@ impl<T> EventLoopExtUnix for EventLoop<T> {
|
||||||
fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
|
fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
|
||||||
match self.event_loop {
|
match self.event_loop {
|
||||||
LinuxEventLoop::X(ref e) => Some(e.x_connection().clone()),
|
LinuxEventLoop::X(ref e) => Some(e.x_connection().clone()),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +164,7 @@ impl<T> EventLoopExtUnix for EventLoop<T> {
|
||||||
fn wayland_display(&self) -> Option<*mut raw::c_void> {
|
fn wayland_display(&self) -> Option<*mut raw::c_void> {
|
||||||
match self.event_loop {
|
match self.event_loop {
|
||||||
LinuxEventLoop::Wayland(ref e) => Some(e.display().get_display_ptr() as *mut _),
|
LinuxEventLoop::Wayland(ref e) => Some(e.display().get_display_ptr() as *mut _),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,7 +230,7 @@ impl WindowExtUnix for Window {
|
||||||
fn xlib_window(&self) -> Option<raw::c_ulong> {
|
fn xlib_window(&self) -> Option<raw::c_ulong> {
|
||||||
match self.window {
|
match self.window {
|
||||||
LinuxWindow::X(ref w) => Some(w.xlib_window()),
|
LinuxWindow::X(ref w) => Some(w.xlib_window()),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +238,7 @@ impl WindowExtUnix for Window {
|
||||||
fn xlib_display(&self) -> Option<*mut raw::c_void> {
|
fn xlib_display(&self) -> Option<*mut raw::c_void> {
|
||||||
match self.window {
|
match self.window {
|
||||||
LinuxWindow::X(ref w) => Some(w.xlib_display()),
|
LinuxWindow::X(ref w) => Some(w.xlib_display()),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +246,7 @@ impl WindowExtUnix for Window {
|
||||||
fn xlib_screen_id(&self) -> Option<raw::c_int> {
|
fn xlib_screen_id(&self) -> Option<raw::c_int> {
|
||||||
match self.window {
|
match self.window {
|
||||||
LinuxWindow::X(ref w) => Some(w.xlib_screen_id()),
|
LinuxWindow::X(ref w) => Some(w.xlib_screen_id()),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +255,7 @@ impl WindowExtUnix for Window {
|
||||||
fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
|
fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
|
||||||
match self.window {
|
match self.window {
|
||||||
LinuxWindow::X(ref w) => Some(w.xlib_xconnection()),
|
LinuxWindow::X(ref w) => Some(w.xlib_xconnection()),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +263,7 @@ impl WindowExtUnix for Window {
|
||||||
fn xcb_connection(&self) -> Option<*mut raw::c_void> {
|
fn xcb_connection(&self) -> Option<*mut raw::c_void> {
|
||||||
match self.window {
|
match self.window {
|
||||||
LinuxWindow::X(ref w) => Some(w.xcb_connection()),
|
LinuxWindow::X(ref w) => Some(w.xcb_connection()),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +278,7 @@ impl WindowExtUnix for Window {
|
||||||
fn wayland_surface(&self) -> Option<*mut raw::c_void> {
|
fn wayland_surface(&self) -> Option<*mut raw::c_void> {
|
||||||
match self.window {
|
match self.window {
|
||||||
LinuxWindow::Wayland(ref w) => Some(w.surface().as_ref().c_ptr() as *mut _),
|
LinuxWindow::Wayland(ref w) => Some(w.surface().as_ref().c_ptr() as *mut _),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +286,7 @@ impl WindowExtUnix for Window {
|
||||||
fn wayland_display(&self) -> Option<*mut raw::c_void> {
|
fn wayland_display(&self) -> Option<*mut raw::c_void> {
|
||||||
match self.window {
|
match self.window {
|
||||||
LinuxWindow::Wayland(ref w) => Some(w.display().as_ref().c_ptr() as *mut _),
|
LinuxWindow::Wayland(ref w) => Some(w.display().as_ref().c_ptr() as *mut _),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +294,7 @@ impl WindowExtUnix for Window {
|
||||||
fn set_wayland_theme(&self, theme: WaylandTheme) {
|
fn set_wayland_theme(&self, theme: WaylandTheme) {
|
||||||
match self.window {
|
match self.window {
|
||||||
LinuxWindow::Wayland(ref w) => w.set_theme(WaylandThemeObject(theme)),
|
LinuxWindow::Wayland(ref w) => w.set_theme(WaylandThemeObject(theme)),
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,9 +333,8 @@ pub trait WindowBuilderExtUnix {
|
||||||
impl WindowBuilderExtUnix for WindowBuilder {
|
impl WindowBuilderExtUnix for WindowBuilder {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_x11_visual<T>(mut self, visual_infos: *const T) -> WindowBuilder {
|
fn with_x11_visual<T>(mut self, visual_infos: *const T) -> WindowBuilder {
|
||||||
self.platform_specific.visual_infos = Some(
|
self.platform_specific.visual_infos =
|
||||||
unsafe { ptr::read(visual_infos as *const XVisualInfo) }
|
Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) });
|
||||||
);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,17 +5,21 @@ use std::os::raw::c_void;
|
||||||
use libc;
|
use libc;
|
||||||
use winapi::shared::windef::HWND;
|
use winapi::shared::windef::HWND;
|
||||||
|
|
||||||
use crate::event::DeviceId;
|
use crate::{
|
||||||
use crate::monitor::MonitorHandle;
|
event::DeviceId,
|
||||||
use crate::event_loop::EventLoop;
|
event_loop::EventLoop,
|
||||||
use crate::window::{Icon, Window, WindowBuilder};
|
monitor::MonitorHandle,
|
||||||
use crate::platform_impl::EventLoop as WindowsEventLoop;
|
platform_impl::EventLoop as WindowsEventLoop,
|
||||||
|
window::{Icon, Window, WindowBuilder},
|
||||||
|
};
|
||||||
|
|
||||||
/// Additional methods on `EventLoop` that are specific to Windows.
|
/// Additional methods on `EventLoop` that are specific to Windows.
|
||||||
pub trait EventLoopExtWindows {
|
pub trait EventLoopExtWindows {
|
||||||
/// By default, winit on Windows will attempt to enable process-wide DPI awareness. If that's
|
/// 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.
|
/// 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<T> EventLoopExtWindows for EventLoop<T> {
|
impl<T> EventLoopExtWindows for EventLoop<T> {
|
||||||
|
|
|
@ -9,32 +9,32 @@ use std::os::raw;
|
||||||
#[link(name = "android")]
|
#[link(name = "android")]
|
||||||
#[link(name = "EGL")]
|
#[link(name = "EGL")]
|
||||||
#[link(name = "GLESv2")]
|
#[link(name = "GLESv2")]
|
||||||
extern {}
|
extern "C" {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* asset_manager.h
|
** asset_manager.h
|
||||||
*/
|
**/
|
||||||
pub type AAssetManager = raw::c_void;
|
pub type AAssetManager = raw::c_void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* native_window.h
|
** native_window.h
|
||||||
*/
|
**/
|
||||||
pub type ANativeWindow = raw::c_void;
|
pub type ANativeWindow = raw::c_void;
|
||||||
|
|
||||||
extern {
|
extern "C" {
|
||||||
pub fn ANativeWindow_getHeight(window: *const ANativeWindow) -> libc::int32_t;
|
pub fn ANativeWindow_getHeight(window: *const ANativeWindow) -> libc::int32_t;
|
||||||
pub fn ANativeWindow_getWidth(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 JavaVM = ();
|
||||||
pub type JNIEnv = ();
|
pub type JNIEnv = ();
|
||||||
pub type jobject = *const libc::c_void;
|
pub type jobject = *const libc::c_void;
|
||||||
|
|
||||||
pub type AInputQueue = (); // FIXME: wrong
|
pub type AInputQueue = (); // FIXME: wrong
|
||||||
pub type ARect = (); // FIXME: wrong
|
pub type ARect = (); // FIXME: wrong
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ANativeActivity {
|
pub struct ANativeActivity {
|
||||||
|
@ -52,43 +52,56 @@ pub struct ANativeActivity {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ANativeActivityCallbacks {
|
pub struct ANativeActivityCallbacks {
|
||||||
pub onStart: extern fn(*mut ANativeActivity),
|
pub onStart: extern "C" fn(*mut ANativeActivity),
|
||||||
pub onResume: extern fn(*mut ANativeActivity),
|
pub onResume: extern "C" fn(*mut ANativeActivity),
|
||||||
pub onSaveInstanceState: extern fn(*mut ANativeActivity, *mut libc::size_t),
|
pub onSaveInstanceState: extern "C" fn(*mut ANativeActivity, *mut libc::size_t),
|
||||||
pub onPause: extern fn(*mut ANativeActivity),
|
pub onPause: extern "C" fn(*mut ANativeActivity),
|
||||||
pub onStop: extern fn(*mut ANativeActivity),
|
pub onStop: extern "C" fn(*mut ANativeActivity),
|
||||||
pub onDestroy: extern fn(*mut ANativeActivity),
|
pub onDestroy: extern "C" fn(*mut ANativeActivity),
|
||||||
pub onWindowFocusChanged: extern fn(*mut ANativeActivity, libc::c_int),
|
pub onWindowFocusChanged: extern "C" fn(*mut ANativeActivity, libc::c_int),
|
||||||
pub onNativeWindowCreated: extern fn(*mut ANativeActivity, *const ANativeWindow),
|
pub onNativeWindowCreated: extern "C" fn(*mut ANativeActivity, *const ANativeWindow),
|
||||||
pub onNativeWindowResized: extern fn(*mut ANativeActivity, *const ANativeWindow),
|
pub onNativeWindowResized: extern "C" fn(*mut ANativeActivity, *const ANativeWindow),
|
||||||
pub onNativeWindowRedrawNeeded: extern fn(*mut ANativeActivity, *const ANativeWindow),
|
pub onNativeWindowRedrawNeeded: extern "C" fn(*mut ANativeActivity, *const ANativeWindow),
|
||||||
pub onNativeWindowDestroyed: extern fn(*mut ANativeActivity, *const ANativeWindow),
|
pub onNativeWindowDestroyed: extern "C" fn(*mut ANativeActivity, *const ANativeWindow),
|
||||||
pub onInputQueueCreated: extern fn(*mut ANativeActivity, *mut AInputQueue),
|
pub onInputQueueCreated: extern "C" fn(*mut ANativeActivity, *mut AInputQueue),
|
||||||
pub onInputQueueDestroyed: extern fn(*mut ANativeActivity, *mut AInputQueue),
|
pub onInputQueueDestroyed: extern "C" fn(*mut ANativeActivity, *mut AInputQueue),
|
||||||
pub onContentRectChanged: extern fn(*mut ANativeActivity, *const ARect),
|
pub onContentRectChanged: extern "C" fn(*mut ANativeActivity, *const ARect),
|
||||||
pub onConfigurationChanged: extern fn(*mut ANativeActivity),
|
pub onConfigurationChanged: extern "C" fn(*mut ANativeActivity),
|
||||||
pub onLowMemory: extern fn(*mut ANativeActivity),
|
pub onLowMemory: extern "C" fn(*mut ANativeActivity),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* looper.h
|
** looper.h
|
||||||
*/
|
**/
|
||||||
pub type ALooper = ();
|
pub type ALooper = ();
|
||||||
|
|
||||||
#[link(name = "android")]
|
#[link(name = "android")]
|
||||||
extern {
|
extern "C" {
|
||||||
pub fn ALooper_forThread() -> *const ALooper;
|
pub fn ALooper_forThread() -> *const ALooper;
|
||||||
pub fn ALooper_acquire(looper: *const ALooper);
|
pub fn ALooper_acquire(looper: *const ALooper);
|
||||||
pub fn ALooper_release(looper: *const ALooper);
|
pub fn ALooper_release(looper: *const ALooper);
|
||||||
pub fn ALooper_prepare(opts: libc::c_int) -> *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,
|
pub fn ALooper_pollOnce(
|
||||||
outEvents: *mut libc::c_int, outData: *mut *mut libc::c_void) -> libc::c_int;
|
timeoutMillis: libc::c_int,
|
||||||
pub fn ALooper_pollAll(timeoutMillis: libc::c_int, outFd: *mut libc::c_int,
|
outFd: *mut libc::c_int,
|
||||||
outEvents: *mut libc::c_int, outData: *mut *mut libc::c_void) -> 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_wake(looper: *const ALooper);
|
||||||
pub fn ALooper_addFd(looper: *const ALooper, fd: libc::c_int, ident: libc::c_int,
|
pub fn ALooper_addFd(
|
||||||
events: libc::c_int, callback: ALooper_callbackFunc, data: *mut libc::c_void)
|
looper: *const ALooper,
|
||||||
-> libc::c_int;
|
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;
|
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_HANGUP: libc::c_int = 1 << 3;
|
||||||
pub const ALOOPER_EVENT_INVALID: libc::c_int = 1 << 4;
|
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;
|
||||||
|
|
|
@ -4,28 +4,22 @@ extern crate android_glue;
|
||||||
|
|
||||||
mod ffi;
|
mod ffi;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::{
|
||||||
use std::collections::VecDeque;
|
cell::RefCell,
|
||||||
use std::fmt;
|
collections::VecDeque,
|
||||||
use std::os::raw::c_void;
|
fmt,
|
||||||
use std::sync::mpsc::{Receiver, channel};
|
os::raw::c_void,
|
||||||
|
sync::mpsc::{channel, Receiver},
|
||||||
|
};
|
||||||
|
|
||||||
use {
|
use crate::{
|
||||||
crate::CreationError,
|
error::{ExternalError, NotSupportedError},
|
||||||
crate::Event,
|
events::{Touch, TouchPhase},
|
||||||
crate::LogicalPosition,
|
window::MonitorHandle as RootMonitorHandle,
|
||||||
crate::LogicalSize,
|
CreationError, CursorIcon, Event, LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize,
|
||||||
crate::CursorIcon,
|
WindowAttributes, WindowEvent, WindowId as RootWindowId,
|
||||||
crate::PhysicalPosition,
|
|
||||||
crate::PhysicalSize,
|
|
||||||
crate::WindowAttributes,
|
|
||||||
crate::WindowEvent,
|
|
||||||
crate::WindowId as RootWindowId,
|
|
||||||
};
|
};
|
||||||
use CreationError::OsError;
|
use CreationError::OsError;
|
||||||
use crate::error::{ExternalError, NotSupportedError};
|
|
||||||
use crate::events::{Touch, TouchPhase};
|
|
||||||
use crate::window::MonitorHandle as RootMonitorHandle;
|
|
||||||
|
|
||||||
pub type OsError = std::io::Error;
|
pub type OsError = std::io::Error;
|
||||||
|
|
||||||
|
@ -60,10 +54,11 @@ impl EventLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_events<F>(&mut self, mut callback: F)
|
pub fn poll_events<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(::Event)
|
where
|
||||||
|
F: FnMut(::Event),
|
||||||
{
|
{
|
||||||
while let Ok(event) = self.event_rx.try_recv() {
|
while let Ok(event) = self.event_rx.try_recv() {
|
||||||
let e = match event{
|
let e = match event {
|
||||||
android_glue::Event::EventMotion(motion) => {
|
android_glue::Event::EventMotion(motion) => {
|
||||||
let dpi_factor = MonitorHandle.hidpi_factor();
|
let dpi_factor = MonitorHandle.hidpi_factor();
|
||||||
let location = LogicalPosition::from_physical(
|
let location = LogicalPosition::from_physical(
|
||||||
|
@ -99,8 +94,7 @@ impl EventLoop {
|
||||||
}
|
}
|
||||||
Some(Event::Suspended(true))
|
Some(Event::Suspended(true))
|
||||||
},
|
},
|
||||||
android_glue::Event::WindowResized |
|
android_glue::Event::WindowResized | android_glue::Event::ConfigChanged => {
|
||||||
android_glue::Event::ConfigChanged => {
|
|
||||||
// Activity Orientation changed or resized.
|
// Activity Orientation changed or resized.
|
||||||
let native_window = unsafe { android_glue::native_window() };
|
let native_window = unsafe { android_glue::native_window() };
|
||||||
if native_window.is_null() {
|
if native_window.is_null() {
|
||||||
|
@ -121,19 +115,15 @@ impl EventLoop {
|
||||||
window_id: RootWindowId(WindowId),
|
window_id: RootWindowId(WindowId),
|
||||||
event: WindowEvent::Redraw,
|
event: WindowEvent::Redraw,
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
android_glue::Event::Wake => {
|
android_glue::Event::Wake => Some(Event::Awakened),
|
||||||
Some(Event::Awakened)
|
_ => None,
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(event) = e {
|
if let Some(event) = e {
|
||||||
callback(event);
|
callback(event);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_suspend_callback(&self, cb: Option<Box<dyn Fn(bool) -> ()>>) {
|
pub fn set_suspend_callback(&self, cb: Option<Box<dyn Fn(bool) -> ()>>) {
|
||||||
|
@ -141,7 +131,8 @@ impl EventLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_forever<F>(&mut self, mut callback: F)
|
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(::Event) -> ::ControlFlow,
|
where
|
||||||
|
F: FnMut(::Event) -> ::ControlFlow,
|
||||||
{
|
{
|
||||||
// Yeah that's a very bad implementation.
|
// Yeah that's a very bad implementation.
|
||||||
loop {
|
loop {
|
||||||
|
@ -229,7 +220,8 @@ impl MonitorHandle {
|
||||||
(
|
(
|
||||||
ffi::ANativeWindow_getWidth(window) as f64,
|
ffi::ANativeWindow_getWidth(window) as f64,
|
||||||
ffi::ANativeWindow_getHeight(window) as f64,
|
ffi::ANativeWindow_getHeight(window) as f64,
|
||||||
).into()
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,10 +243,11 @@ pub struct PlatformSpecificWindowBuilderAttributes;
|
||||||
pub struct PlatformSpecificHeadlessBuilderAttributes;
|
pub struct PlatformSpecificHeadlessBuilderAttributes;
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(_: &EventLoop, win_attribs: WindowAttributes,
|
pub fn new(
|
||||||
_: PlatformSpecificWindowBuilderAttributes)
|
_: &EventLoop,
|
||||||
-> Result<Window, CreationError>
|
win_attribs: WindowAttributes,
|
||||||
{
|
_: PlatformSpecificWindowBuilderAttributes,
|
||||||
|
) -> Result<Window, CreationError> {
|
||||||
let native_window = unsafe { android_glue::native_window() };
|
let native_window = unsafe { android_glue::native_window() };
|
||||||
if native_window.is_null() {
|
if native_window.is_null() {
|
||||||
return Err(OsError(format!("Android's native window is null")));
|
return Err(OsError(format!("Android's native window is null")));
|
||||||
|
@ -406,7 +399,9 @@ impl Window {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_monitor(&self) -> RootMonitorHandle {
|
pub fn current_monitor(&self) -> RootMonitorHandle {
|
||||||
RootMonitorHandle { inner: MonitorHandle }
|
RootMonitorHandle {
|
||||||
|
inner: MonitorHandle,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#![allow(dead_code, non_camel_case_types, non_snake_case)]
|
#![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)]
|
#[cfg(test)]
|
||||||
use std::mem;
|
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_BOOL = c_int;
|
||||||
pub type EM_UTF8 = c_char;
|
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<unsafe extern "C" fn()>;
|
pub type em_callback_func = Option<unsafe extern "C" fn()>;
|
||||||
|
|
||||||
pub type em_key_callback_func = Option<unsafe extern "C" fn(
|
pub type em_key_callback_func = Option<
|
||||||
eventType: c_int,
|
unsafe extern "C" fn(
|
||||||
keyEvent: *const EmscriptenKeyboardEvent,
|
eventType: c_int,
|
||||||
userData: *mut c_void) -> EM_BOOL>;
|
keyEvent: *const EmscriptenKeyboardEvent,
|
||||||
|
userData: *mut c_void,
|
||||||
|
) -> EM_BOOL,
|
||||||
|
>;
|
||||||
|
|
||||||
pub type em_mouse_callback_func = Option<unsafe extern "C" fn(
|
pub type em_mouse_callback_func = Option<
|
||||||
eventType: c_int,
|
unsafe extern "C" fn(
|
||||||
mouseEvent: *const EmscriptenMouseEvent,
|
eventType: c_int,
|
||||||
userData: *mut c_void) -> EM_BOOL>;
|
mouseEvent: *const EmscriptenMouseEvent,
|
||||||
|
userData: *mut c_void,
|
||||||
|
) -> EM_BOOL,
|
||||||
|
>;
|
||||||
|
|
||||||
pub type em_pointerlockchange_callback_func = Option<unsafe extern "C" fn(
|
pub type em_pointerlockchange_callback_func = Option<
|
||||||
eventType: c_int,
|
unsafe extern "C" fn(
|
||||||
pointerlockChangeEvent: *const EmscriptenPointerlockChangeEvent,
|
eventType: c_int,
|
||||||
userData: *mut c_void) -> EM_BOOL>;
|
pointerlockChangeEvent: *const EmscriptenPointerlockChangeEvent,
|
||||||
|
userData: *mut c_void,
|
||||||
|
) -> EM_BOOL,
|
||||||
|
>;
|
||||||
|
|
||||||
pub type em_fullscreenchange_callback_func = Option<unsafe extern "C" fn(
|
pub type em_fullscreenchange_callback_func = Option<
|
||||||
eventType: c_int,
|
unsafe extern "C" fn(
|
||||||
fullscreenChangeEvent: *const EmscriptenFullscreenChangeEvent,
|
eventType: c_int,
|
||||||
userData: *mut c_void) -> EM_BOOL>;
|
fullscreenChangeEvent: *const EmscriptenFullscreenChangeEvent,
|
||||||
|
userData: *mut c_void,
|
||||||
|
) -> EM_BOOL,
|
||||||
|
>;
|
||||||
|
|
||||||
pub type em_touch_callback_func = Option<unsafe extern "C" fn(
|
pub type em_touch_callback_func = Option<
|
||||||
eventType: c_int,
|
unsafe extern "C" fn(
|
||||||
touchEvent: *const EmscriptenTouchEvent,
|
eventType: c_int,
|
||||||
userData: *mut c_void) -> EM_BOOL>;
|
touchEvent: *const EmscriptenTouchEvent,
|
||||||
|
userData: *mut c_void,
|
||||||
|
) -> EM_BOOL,
|
||||||
|
>;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct EmscriptenFullscreenChangeEvent {
|
pub struct EmscriptenFullscreenChangeEvent {
|
||||||
|
@ -136,7 +151,9 @@ fn bindgen_test_layout_EmscriptenKeyboardEvent() {
|
||||||
assert_eq!(mem::align_of::<EmscriptenKeyboardEvent>(), 8usize);
|
assert_eq!(mem::align_of::<EmscriptenKeyboardEvent>(), 8usize);
|
||||||
}
|
}
|
||||||
impl Clone for EmscriptenKeyboardEvent {
|
impl Clone for EmscriptenKeyboardEvent {
|
||||||
fn clone(&self) -> Self { *self }
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -219,96 +236,128 @@ fn bindgen_test_layout_EmscriptenPointerlockChangeEvent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn emscripten_set_canvas_size(
|
pub fn emscripten_set_canvas_size(width: c_int, height: c_int) -> EMSCRIPTEN_RESULT;
|
||||||
width: c_int, height: c_int)
|
|
||||||
-> EMSCRIPTEN_RESULT;
|
|
||||||
|
|
||||||
pub fn emscripten_get_canvas_size(
|
pub fn emscripten_get_canvas_size(
|
||||||
width: *mut c_int, height: *mut c_int,
|
width: *mut c_int,
|
||||||
is_fullscreen: *mut c_int)
|
height: *mut c_int,
|
||||||
-> EMSCRIPTEN_RESULT;
|
is_fullscreen: *mut c_int,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_element_css_size(
|
pub fn emscripten_set_element_css_size(
|
||||||
target: *const c_char, width: c_double,
|
target: *const c_char,
|
||||||
height: c_double) -> EMSCRIPTEN_RESULT;
|
width: c_double,
|
||||||
|
height: c_double,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_get_element_css_size(
|
pub fn emscripten_get_element_css_size(
|
||||||
target: *const c_char, width: *mut c_double,
|
target: *const c_char,
|
||||||
height: *mut c_double) -> EMSCRIPTEN_RESULT;
|
width: *mut c_double,
|
||||||
|
height: *mut c_double,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_request_pointerlock(
|
pub fn emscripten_request_pointerlock(
|
||||||
target: *const c_char, deferUntilInEventHandler: EM_BOOL)
|
target: *const c_char,
|
||||||
-> EMSCRIPTEN_RESULT;
|
deferUntilInEventHandler: EM_BOOL,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_exit_pointerlock() -> EMSCRIPTEN_RESULT;
|
pub fn emscripten_exit_pointerlock() -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_request_fullscreen(
|
pub fn emscripten_request_fullscreen(
|
||||||
target: *const c_char, deferUntilInEventHandler: EM_BOOL)
|
target: *const c_char,
|
||||||
-> EMSCRIPTEN_RESULT;
|
deferUntilInEventHandler: EM_BOOL,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_exit_fullscreen() -> EMSCRIPTEN_RESULT;
|
pub fn emscripten_exit_fullscreen() -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_keydown_callback(
|
pub fn emscripten_set_keydown_callback(
|
||||||
target: *const c_char, userData: *mut c_void,
|
target: *const c_char,
|
||||||
useCapture: EM_BOOL, callback: em_key_callback_func)
|
userData: *mut c_void,
|
||||||
-> EMSCRIPTEN_RESULT;
|
useCapture: EM_BOOL,
|
||||||
|
callback: em_key_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_keyup_callback(
|
pub fn emscripten_set_keyup_callback(
|
||||||
target: *const c_char, userData: *mut c_void,
|
target: *const c_char,
|
||||||
useCapture: EM_BOOL, callback: em_key_callback_func)
|
userData: *mut c_void,
|
||||||
-> EMSCRIPTEN_RESULT;
|
useCapture: EM_BOOL,
|
||||||
|
callback: em_key_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_mousemove_callback(
|
pub fn emscripten_set_mousemove_callback(
|
||||||
target: *const c_char, user_data: *mut c_void,
|
target: *const c_char,
|
||||||
use_capture: EM_BOOL, callback: em_mouse_callback_func)
|
user_data: *mut c_void,
|
||||||
-> EMSCRIPTEN_RESULT;
|
use_capture: EM_BOOL,
|
||||||
|
callback: em_mouse_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_mousedown_callback(
|
pub fn emscripten_set_mousedown_callback(
|
||||||
target: *const c_char, user_data: *mut c_void,
|
target: *const c_char,
|
||||||
use_capture: EM_BOOL, callback: em_mouse_callback_func)
|
user_data: *mut c_void,
|
||||||
-> EMSCRIPTEN_RESULT;
|
use_capture: EM_BOOL,
|
||||||
|
callback: em_mouse_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_mouseup_callback(
|
pub fn emscripten_set_mouseup_callback(
|
||||||
target: *const c_char, user_data: *mut c_void,
|
target: *const c_char,
|
||||||
use_capture: EM_BOOL, callback: em_mouse_callback_func)
|
user_data: *mut c_void,
|
||||||
-> EMSCRIPTEN_RESULT;
|
use_capture: EM_BOOL,
|
||||||
|
callback: em_mouse_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_hide_mouse();
|
pub fn emscripten_hide_mouse();
|
||||||
|
|
||||||
pub fn emscripten_get_device_pixel_ratio() -> f64;
|
pub fn emscripten_get_device_pixel_ratio() -> f64;
|
||||||
|
|
||||||
pub fn emscripten_set_pointerlockchange_callback(
|
pub fn emscripten_set_pointerlockchange_callback(
|
||||||
target: *const c_char, userData: *mut c_void, useCapture: EM_BOOL,
|
target: *const c_char,
|
||||||
callback: em_pointerlockchange_callback_func) -> EMSCRIPTEN_RESULT;
|
userData: *mut c_void,
|
||||||
|
useCapture: EM_BOOL,
|
||||||
|
callback: em_pointerlockchange_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_fullscreenchange_callback(
|
pub fn emscripten_set_fullscreenchange_callback(
|
||||||
target: *const c_char, userData: *mut c_void, useCapture: EM_BOOL,
|
target: *const c_char,
|
||||||
callback: em_fullscreenchange_callback_func) -> EMSCRIPTEN_RESULT;
|
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_asm_const(code: *const c_char);
|
||||||
|
|
||||||
pub fn emscripten_set_main_loop(
|
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_cancel_main_loop();
|
||||||
|
|
||||||
pub fn emscripten_set_touchstart_callback(
|
pub fn emscripten_set_touchstart_callback(
|
||||||
target: *const c_char, userData: *mut c_void,
|
target: *const c_char,
|
||||||
useCapture: c_int, callback: em_touch_callback_func)
|
userData: *mut c_void,
|
||||||
-> EMSCRIPTEN_RESULT;
|
useCapture: c_int,
|
||||||
|
callback: em_touch_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_touchend_callback(
|
pub fn emscripten_set_touchend_callback(
|
||||||
target: *const c_char, userData: *mut c_void,
|
target: *const c_char,
|
||||||
useCapture: c_int, callback: em_touch_callback_func)
|
userData: *mut c_void,
|
||||||
-> EMSCRIPTEN_RESULT;
|
useCapture: c_int,
|
||||||
|
callback: em_touch_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_touchmove_callback(
|
pub fn emscripten_set_touchmove_callback(
|
||||||
target: *const c_char, userData: *mut c_void,
|
target: *const c_char,
|
||||||
useCapture: c_int, callback: em_touch_callback_func)
|
userData: *mut c_void,
|
||||||
-> EMSCRIPTEN_RESULT;
|
useCapture: c_int,
|
||||||
|
callback: em_touch_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
|
|
||||||
pub fn emscripten_set_touchcancel_callback(
|
pub fn emscripten_set_touchcancel_callback(
|
||||||
target: *const c_char, userData: *mut c_void,
|
target: *const c_char,
|
||||||
useCapture: c_int, callback: em_touch_callback_func)
|
userData: *mut c_void,
|
||||||
-> EMSCRIPTEN_RESULT;
|
useCapture: c_int,
|
||||||
|
callback: em_touch_callback_func,
|
||||||
|
) -> EMSCRIPTEN_RESULT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,23 @@
|
||||||
|
|
||||||
mod ffi;
|
mod ffi;
|
||||||
|
|
||||||
use std::{mem, ptr, str};
|
use std::{
|
||||||
use std::cell::RefCell;
|
cell::RefCell,
|
||||||
use std::collections::VecDeque;
|
collections::VecDeque,
|
||||||
use std::os::raw::{c_char, c_void, c_double, c_ulong, c_int};
|
mem,
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
os::raw::{c_char, c_double, c_int, c_ulong, c_void},
|
||||||
use std::sync::{Mutex, Arc};
|
ptr, str,
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc, Mutex,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
use crate::{
|
||||||
use crate::error::{ExternalError, NotSupportedError};
|
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
|
||||||
use crate::window::MonitorHandle as RootMonitorHandle;
|
error::{ExternalError, NotSupportedError},
|
||||||
|
window::MonitorHandle as RootMonitorHandle,
|
||||||
|
};
|
||||||
|
|
||||||
const DOCUMENT_NAME: &'static str = "#document\0";
|
const DOCUMENT_NAME: &'static str = "#document\0";
|
||||||
|
|
||||||
|
@ -68,14 +75,22 @@ impl MonitorHandle {
|
||||||
thread_local!(static MAIN_LOOP_CALLBACK: RefCell<*mut c_void> = RefCell::new(ptr::null_mut()));
|
thread_local!(static MAIN_LOOP_CALLBACK: RefCell<*mut c_void> = RefCell::new(ptr::null_mut()));
|
||||||
|
|
||||||
// Used to assign a callback to emscripten main loop
|
// Used to assign a callback to emscripten main loop
|
||||||
pub fn set_main_loop_callback<F>(callback : F) where F : FnMut() {
|
pub fn set_main_loop_callback<F>(callback: F)
|
||||||
|
where
|
||||||
|
F: FnMut(),
|
||||||
|
{
|
||||||
MAIN_LOOP_CALLBACK.with(|log| {
|
MAIN_LOOP_CALLBACK.with(|log| {
|
||||||
*log.borrow_mut() = &callback as *const _ as *mut c_void;
|
*log.borrow_mut() = &callback as *const _ as *mut c_void;
|
||||||
});
|
});
|
||||||
|
|
||||||
unsafe { ffi::emscripten_set_main_loop(Some(wrapper::<F>), 0, 1); }
|
unsafe {
|
||||||
|
ffi::emscripten_set_main_loop(Some(wrapper::<F>), 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn wrapper<F>() where F : FnMut() {
|
unsafe extern "C" fn wrapper<F>()
|
||||||
|
where
|
||||||
|
F: FnMut(),
|
||||||
|
{
|
||||||
MAIN_LOOP_CALLBACK.with(|z| {
|
MAIN_LOOP_CALLBACK.with(|z| {
|
||||||
let closure = *z.borrow_mut() as *mut F;
|
let closure = *z.borrow_mut() as *mut F;
|
||||||
(*closure)();
|
(*closure)();
|
||||||
|
@ -128,7 +143,8 @@ impl EventLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_events<F>(&self, mut callback: F)
|
pub fn poll_events<F>(&self, mut callback: F)
|
||||||
where F: FnMut(::Event)
|
where
|
||||||
|
F: FnMut(::Event),
|
||||||
{
|
{
|
||||||
let ref mut window = *self.window.lock().unwrap();
|
let ref mut window = *self.window.lock().unwrap();
|
||||||
if let &mut Some(ref mut window) = window {
|
if let &mut Some(ref mut window) = window {
|
||||||
|
@ -139,17 +155,22 @@ impl EventLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_forever<F>(&self, mut callback: F)
|
pub fn run_forever<F>(&self, mut callback: F)
|
||||||
where F: FnMut(::Event) -> ::ControlFlow
|
where
|
||||||
|
F: FnMut(::Event) -> ::ControlFlow,
|
||||||
{
|
{
|
||||||
self.interrupted.store(false, Ordering::Relaxed);
|
self.interrupted.store(false, Ordering::Relaxed);
|
||||||
|
|
||||||
// TODO: handle control flow
|
// TODO: handle control flow
|
||||||
|
|
||||||
set_main_loop_callback(|| {
|
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));
|
::std::thread::sleep(::std::time::Duration::from_millis(5));
|
||||||
if self.interrupted.load(Ordering::Relaxed) {
|
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);
|
// styleSheet.insertRule('canvas.emscripten { border: none; cursor: auto; }', 0);
|
||||||
unsafe {
|
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(
|
extern "C" fn mouse_callback(
|
||||||
event_type: c_int,
|
event_type: c_int,
|
||||||
event: *const ffi::EmscriptenMouseEvent,
|
event: *const ffi::EmscriptenMouseEvent,
|
||||||
event_queue: *mut c_void) -> ffi::EM_BOOL
|
event_queue: *mut c_void,
|
||||||
{
|
) -> ffi::EM_BOOL {
|
||||||
unsafe {
|
unsafe {
|
||||||
let queue: &Mutex<VecDeque<::Event>> = mem::transmute(event_queue);
|
let queue: &Mutex<VecDeque<::Event>> = mem::transmute(event_queue);
|
||||||
|
|
||||||
|
@ -221,18 +242,18 @@ extern "C" fn mouse_callback(
|
||||||
event: ::WindowEvent::CursorMoved {
|
event: ::WindowEvent::CursorMoved {
|
||||||
device_id: ::DeviceId(DeviceId),
|
device_id: ::DeviceId(DeviceId),
|
||||||
position,
|
position,
|
||||||
modifiers: modifiers,
|
modifiers,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
queue.lock().unwrap().push_back(::Event::DeviceEvent {
|
queue.lock().unwrap().push_back(::Event::DeviceEvent {
|
||||||
device_id: ::DeviceId(DeviceId),
|
device_id: ::DeviceId(DeviceId),
|
||||||
event: ::DeviceEvent::MouseMotion {
|
event: ::DeviceEvent::MouseMotion {
|
||||||
delta: ((*event).movementX as f64, (*event).movementY as f64),
|
delta: ((*event).movementX as f64, (*event).movementY as f64),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEDOWN |
|
mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEDOWN
|
||||||
mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEUP => {
|
| mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEUP => {
|
||||||
let button = match (*event).button {
|
let button = match (*event).button {
|
||||||
0 => ::MouseButton::Left,
|
0 => ::MouseButton::Left,
|
||||||
1 => ::MouseButton::Middle,
|
1 => ::MouseButton::Middle,
|
||||||
|
@ -248,14 +269,13 @@ extern "C" fn mouse_callback(
|
||||||
window_id: ::WindowId(WindowId(0)),
|
window_id: ::WindowId(WindowId(0)),
|
||||||
event: ::WindowEvent::MouseInput {
|
event: ::WindowEvent::MouseInput {
|
||||||
device_id: ::DeviceId(DeviceId),
|
device_id: ::DeviceId(DeviceId),
|
||||||
state: state,
|
state,
|
||||||
button: button,
|
button,
|
||||||
modifiers: modifiers,
|
modifiers,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ffi::EM_FALSE
|
ffi::EM_FALSE
|
||||||
|
@ -264,8 +284,8 @@ extern "C" fn mouse_callback(
|
||||||
extern "C" fn keyboard_callback(
|
extern "C" fn keyboard_callback(
|
||||||
event_type: c_int,
|
event_type: c_int,
|
||||||
event: *const ffi::EmscriptenKeyboardEvent,
|
event: *const ffi::EmscriptenKeyboardEvent,
|
||||||
event_queue: *mut c_void) -> ffi::EM_BOOL
|
event_queue: *mut c_void,
|
||||||
{
|
) -> ffi::EM_BOOL {
|
||||||
unsafe {
|
unsafe {
|
||||||
let queue: &Mutex<VecDeque<::Event>> = mem::transmute(event_queue);
|
let queue: &Mutex<VecDeque<::Event>> = mem::transmute(event_queue);
|
||||||
|
|
||||||
|
@ -305,18 +325,17 @@ extern "C" fn keyboard_callback(
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ffi::EM_FALSE
|
ffi::EM_FALSE
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn touch_callback(
|
extern "C" fn touch_callback(
|
||||||
event_type: c_int,
|
event_type: c_int,
|
||||||
event: *const ffi::EmscriptenTouchEvent,
|
event: *const ffi::EmscriptenTouchEvent,
|
||||||
event_queue: *mut c_void) -> ffi::EM_BOOL
|
event_queue: *mut c_void,
|
||||||
{
|
) -> ffi::EM_BOOL {
|
||||||
unsafe {
|
unsafe {
|
||||||
let queue: &Mutex<VecDeque<::Event>> = mem::transmute(event_queue);
|
let queue: &Mutex<VecDeque<::Event>> = mem::transmute(event_queue);
|
||||||
|
|
||||||
|
@ -356,8 +375,8 @@ extern fn touch_callback(
|
||||||
unsafe extern "C" fn fullscreen_callback(
|
unsafe extern "C" fn fullscreen_callback(
|
||||||
_eventType: c_int,
|
_eventType: c_int,
|
||||||
_fullscreenChangeEvent: *const ffi::EmscriptenFullscreenChangeEvent,
|
_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::emscripten_request_fullscreen(ptr::null(), ffi::EM_TRUE);
|
||||||
ffi::EM_FALSE
|
ffi::EM_FALSE
|
||||||
}
|
}
|
||||||
|
@ -367,8 +386,8 @@ unsafe extern "C" fn fullscreen_callback(
|
||||||
unsafe extern "C" fn pointerlockchange_callback(
|
unsafe extern "C" fn pointerlockchange_callback(
|
||||||
_eventType: c_int,
|
_eventType: c_int,
|
||||||
_pointerlockChangeEvent: *const ffi::EmscriptenPointerlockChangeEvent,
|
_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::emscripten_request_pointerlock(ptr::null(), ffi::EM_TRUE);
|
||||||
ffi::EM_FALSE
|
ffi::EM_FALSE
|
||||||
}
|
}
|
||||||
|
@ -381,12 +400,15 @@ fn em_try(res: ffi::EMSCRIPTEN_RESULT) -> Result<(), String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(event_loop: &EventLoop, attribs: ::WindowAttributes,
|
pub fn new(
|
||||||
_pl_attribs: PlatformSpecificWindowBuilderAttributes)
|
event_loop: &EventLoop,
|
||||||
-> Result<Window, ::CreationError>
|
attribs: ::WindowAttributes,
|
||||||
{
|
_pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
|
) -> Result<Window, ::CreationError> {
|
||||||
if event_loop.window.lock().unwrap().is_some() {
|
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 {
|
let w = Window2 {
|
||||||
|
@ -400,35 +422,87 @@ impl Window {
|
||||||
window: Arc::new(w),
|
window: Arc::new(w),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// TODO: set up more event callbacks
|
// TODO: set up more event callbacks
|
||||||
unsafe {
|
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)))
|
em_try(ffi::emscripten_set_mousemove_callback(
|
||||||
.map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?;
|
DOCUMENT_NAME.as_ptr() as *const c_char,
|
||||||
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)))
|
mem::transmute(&*window.window.events),
|
||||||
.map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?;
|
ffi::EM_FALSE,
|
||||||
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)))
|
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)))?;
|
||||||
.map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?;
|
em_try(ffi::emscripten_set_mousedown_callback(
|
||||||
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)))
|
DOCUMENT_NAME.as_ptr() as *const c_char,
|
||||||
.map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?;
|
mem::transmute(&*window.window.events),
|
||||||
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)))
|
ffi::EM_FALSE,
|
||||||
.map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?;
|
Some(mouse_callback),
|
||||||
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)))?;
|
.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)))
|
em_try(ffi::emscripten_set_mouseup_callback(
|
||||||
.map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?;
|
DOCUMENT_NAME.as_ptr() as *const c_char,
|
||||||
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)))
|
mem::transmute(&*window.window.events),
|
||||||
.map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?;
|
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() {
|
if attribs.fullscreen.is_some() {
|
||||||
unsafe {
|
unsafe {
|
||||||
em_try(ffi::emscripten_request_fullscreen(ptr::null(), ffi::EM_TRUE))
|
em_try(ffi::emscripten_request_fullscreen(
|
||||||
.map_err(|e| ::CreationError::OsError(e))?;
|
ptr::null(),
|
||||||
em_try(ffi::emscripten_set_fullscreenchange_callback(ptr::null(), 0 as *mut c_void, ffi::EM_FALSE, Some(fullscreen_callback)))
|
ffi::EM_TRUE,
|
||||||
.map_err(|e| ::CreationError::OsError(e))?;
|
))
|
||||||
|
.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 {
|
} else if let Some(size) = attribs.inner_size {
|
||||||
window.set_inner_size(size);
|
window.set_inner_size(size);
|
||||||
|
@ -444,8 +518,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_title(&self, _title: &str) {
|
pub fn set_title(&self, _title: &str) {}
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_position(&self) -> Option<LogicalPosition> {
|
pub fn outer_position(&self) -> Option<LogicalPosition> {
|
||||||
|
@ -458,8 +531,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_outer_position(&self, _: LogicalPosition) {
|
pub fn set_outer_position(&self, _: LogicalPosition) {}
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inner_size(&self) -> Option<LogicalSize> {
|
pub fn inner_size(&self) -> Option<LogicalSize> {
|
||||||
|
@ -532,7 +604,9 @@ impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
|
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
|
||||||
let mut grabbed_lock = self.window.cursor_grabbed.lock().unwrap();
|
let mut grabbed_lock = self.window.cursor_grabbed.lock().unwrap();
|
||||||
if grab == *grabbed_lock { return Ok(()); }
|
if grab == *grabbed_lock {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
if grab {
|
if grab {
|
||||||
em_try(ffi::emscripten_set_pointerlockchange_callback(
|
em_try(ffi::emscripten_set_pointerlockchange_callback(
|
||||||
|
@ -541,7 +615,10 @@ impl Window {
|
||||||
ffi::EM_FALSE,
|
ffi::EM_FALSE,
|
||||||
Some(pointerlockchange_callback),
|
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 {
|
} else {
|
||||||
em_try(ffi::emscripten_set_pointerlockchange_callback(
|
em_try(ffi::emscripten_set_pointerlockchange_callback(
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
|
@ -559,7 +636,9 @@ impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_visible(&self, visible: bool) {
|
pub fn set_cursor_visible(&self, visible: bool) {
|
||||||
let mut visible_lock = self.window.cursor_visible.lock().unwrap();
|
let mut visible_lock = self.window.cursor_visible.lock().unwrap();
|
||||||
if visible == *visible_lock { return; }
|
if visible == *visible_lock {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if visible {
|
if visible {
|
||||||
show_mouse();
|
show_mouse();
|
||||||
} else {
|
} else {
|
||||||
|
@ -615,7 +694,9 @@ impl Window {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_monitor(&self) -> RootMonitorHandle {
|
pub fn current_monitor(&self) -> RootMonitorHandle {
|
||||||
RootMonitorHandle { inner: MonitorHandle }
|
RootMonitorHandle {
|
||||||
|
inner: MonitorHandle,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -646,21 +727,37 @@ impl Drop for Window {
|
||||||
|
|
||||||
// Exit fullscreen if on
|
// Exit fullscreen if on
|
||||||
if self.window.is_fullscreen {
|
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();
|
ffi::emscripten_exit_fullscreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete callbacks
|
// 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_keydown_callback(
|
||||||
ffi::emscripten_set_keyup_callback(DOCUMENT_NAME.as_ptr() as *const c_char, 0 as *mut c_void, ffi::EM_FALSE,None);
|
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 {
|
fn error_to_str(code: ffi::EMSCRIPTEN_RESULT) -> &'static str {
|
||||||
match code {
|
match code {
|
||||||
ffi::EMSCRIPTEN_RESULT_SUCCESS | ffi::EMSCRIPTEN_RESULT_DEFERRED
|
ffi::EMSCRIPTEN_RESULT_SUCCESS | ffi::EMSCRIPTEN_RESULT_DEFERRED => {
|
||||||
=> "Internal error in the library (success detected as failure)",
|
"Internal error in the library (success detected as failure)"
|
||||||
|
},
|
||||||
|
|
||||||
ffi::EMSCRIPTEN_RESULT_NOT_SUPPORTED => "Not supported",
|
ffi::EMSCRIPTEN_RESULT_NOT_SUPPORTED => "Not supported",
|
||||||
ffi::EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED => "Failed not deferred",
|
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_FAILED => "Failed",
|
||||||
ffi::EMSCRIPTEN_RESULT_NO_DATA => "No data",
|
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 maybe_key = unsafe { str::from_utf8(mem::transmute::<_, &[u8]>(slice)) };
|
||||||
let key = match maybe_key {
|
let key = match maybe_key {
|
||||||
Ok(key) => key,
|
Ok(key) => key,
|
||||||
Err(_) => { return 0; },
|
Err(_) => {
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
if key.chars().count() == 1 {
|
if key.chars().count() == 1 {
|
||||||
key.as_bytes()[0]
|
key.as_bytes()[0]
|
||||||
|
@ -688,28 +787,35 @@ 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],
|
fn key_translate_virt(
|
||||||
location: c_ulong) -> Option<::VirtualKeyCode>
|
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 slice = &input[0..input.iter().take_while(|x| **x != 0).count()];
|
||||||
let maybe_key = unsafe { str::from_utf8(mem::transmute::<_, &[u8]>(slice)) };
|
let maybe_key = unsafe { str::from_utf8(mem::transmute::<_, &[u8]>(slice)) };
|
||||||
let key = match maybe_key {
|
let key = match maybe_key {
|
||||||
Ok(key) => key,
|
Ok(key) => key,
|
||||||
Err(_) => { return None; },
|
Err(_) => {
|
||||||
|
return None;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use VirtualKeyCode::*;
|
use VirtualKeyCode::*;
|
||||||
match key {
|
match key {
|
||||||
"Alt" => match location {
|
"Alt" => {
|
||||||
ffi::DOM_KEY_LOCATION_LEFT => Some(LAlt),
|
match location {
|
||||||
ffi::DOM_KEY_LOCATION_RIGHT => Some(RAlt),
|
ffi::DOM_KEY_LOCATION_LEFT => Some(LAlt),
|
||||||
_ => None,
|
ffi::DOM_KEY_LOCATION_RIGHT => Some(RAlt),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"AltGraph" => None,
|
"AltGraph" => None,
|
||||||
"CapsLock" => None,
|
"CapsLock" => None,
|
||||||
"Control" => match location {
|
"Control" => {
|
||||||
ffi::DOM_KEY_LOCATION_LEFT => Some(LControl),
|
match location {
|
||||||
ffi::DOM_KEY_LOCATION_RIGHT => Some(RControl),
|
ffi::DOM_KEY_LOCATION_LEFT => Some(LControl),
|
||||||
_ => None,
|
ffi::DOM_KEY_LOCATION_RIGHT => Some(RControl),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Fn" => None,
|
"Fn" => None,
|
||||||
"FnLock" => None,
|
"FnLock" => None,
|
||||||
|
@ -717,18 +823,22 @@ fn key_translate_virt(input: [ffi::EM_UTF8; ffi::EM_HTML5_SHORT_STRING_LEN_BYTES
|
||||||
"Meta" => None,
|
"Meta" => None,
|
||||||
"NumLock" => Some(Numlock),
|
"NumLock" => Some(Numlock),
|
||||||
"ScrollLock" => Some(Scroll),
|
"ScrollLock" => Some(Scroll),
|
||||||
"Shift" => match location {
|
"Shift" => {
|
||||||
ffi::DOM_KEY_LOCATION_LEFT => Some(LShift),
|
match location {
|
||||||
ffi::DOM_KEY_LOCATION_RIGHT => Some(RShift),
|
ffi::DOM_KEY_LOCATION_LEFT => Some(LShift),
|
||||||
_ => None,
|
ffi::DOM_KEY_LOCATION_RIGHT => Some(RShift),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Super" => None,
|
"Super" => None,
|
||||||
"Symbol" => None,
|
"Symbol" => None,
|
||||||
"SymbolLock" => None,
|
"SymbolLock" => None,
|
||||||
|
|
||||||
"Enter" => match location {
|
"Enter" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadEnter),
|
match location {
|
||||||
_ => Some(Return),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadEnter),
|
||||||
|
_ => Some(Return),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Tab" => Some(Tab),
|
"Tab" => Some(Tab),
|
||||||
" " => Some(Space),
|
" " => Some(Space),
|
||||||
|
@ -1053,45 +1163,65 @@ fn key_translate_virt(input: [ffi::EM_UTF8; ffi::EM_HTML5_SHORT_STRING_LEN_BYTES
|
||||||
"Divide" => Some(Divide),
|
"Divide" => Some(Divide),
|
||||||
"Subtract" | "-" => Some(Subtract),
|
"Subtract" | "-" => Some(Subtract),
|
||||||
"Separator" => None,
|
"Separator" => None,
|
||||||
"0" => match location {
|
"0" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad0),
|
match location {
|
||||||
_ => Some(Key0),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad0),
|
||||||
|
_ => Some(Key0),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1" => match location {
|
"1" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad1),
|
match location {
|
||||||
_ => Some(Key1),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad1),
|
||||||
|
_ => Some(Key1),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"2" => match location {
|
"2" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad2),
|
match location {
|
||||||
_ => Some(Key2),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad2),
|
||||||
|
_ => Some(Key2),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"3" => match location {
|
"3" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad3),
|
match location {
|
||||||
_ => Some(Key3),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad3),
|
||||||
|
_ => Some(Key3),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"4" => match location {
|
"4" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad4),
|
match location {
|
||||||
_ => Some(Key4),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad4),
|
||||||
|
_ => Some(Key4),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"5" => match location {
|
"5" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad5),
|
match location {
|
||||||
_ => Some(Key5),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad5),
|
||||||
|
_ => Some(Key5),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"6" => match location {
|
"6" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad6),
|
match location {
|
||||||
_ => Some(Key6),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad6),
|
||||||
|
_ => Some(Key6),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"7" => match location {
|
"7" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad7),
|
match location {
|
||||||
_ => Some(Key7),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad7),
|
||||||
|
_ => Some(Key7),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"8" => match location {
|
"8" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad8),
|
match location {
|
||||||
_ => Some(Key8),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad8),
|
||||||
|
_ => Some(Key8),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"9" => match location {
|
"9" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad9),
|
match location {
|
||||||
_ => Some(Key9),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad9),
|
||||||
|
_ => Some(Key9),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"A" | "a" => Some(A),
|
"A" | "a" => Some(A),
|
||||||
|
@ -1124,13 +1254,17 @@ fn key_translate_virt(input: [ffi::EM_UTF8; ffi::EM_HTML5_SHORT_STRING_LEN_BYTES
|
||||||
"'" => Some(Apostrophe),
|
"'" => Some(Apostrophe),
|
||||||
"\\" => Some(Backslash),
|
"\\" => Some(Backslash),
|
||||||
":" => Some(Colon),
|
":" => Some(Colon),
|
||||||
"," => match location {
|
"," => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadComma),
|
match location {
|
||||||
_ => Some(Comma),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadComma),
|
||||||
|
_ => Some(Comma),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"=" => match location {
|
"=" => {
|
||||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadEquals),
|
match location {
|
||||||
_ => Some(Equals),
|
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadEquals),
|
||||||
|
_ => Some(Equals),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"{" => Some(LBracket),
|
"{" => Some(LBracket),
|
||||||
"." => Some(Period),
|
"." => Some(Period),
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
use std::{mem, ptr};
|
use std::{
|
||||||
use std::cell::{RefCell, RefMut};
|
cell::{RefCell, RefMut},
|
||||||
use std::mem::ManuallyDrop;
|
mem::{self, ManuallyDrop},
|
||||||
use std::os::raw::c_void;
|
os::raw::c_void,
|
||||||
use std::time::Instant;
|
ptr,
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::event::{Event, StartCause};
|
use crate::{
|
||||||
use crate::event_loop::ControlFlow;
|
event::{Event, StartCause},
|
||||||
|
event_loop::ControlFlow,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::platform_impl::platform::event_loop::{EventHandler, Never};
|
use crate::platform_impl::platform::{
|
||||||
use crate::platform_impl::platform::ffi::{
|
event_loop::{EventHandler, Never},
|
||||||
id,
|
ffi::{
|
||||||
CFAbsoluteTimeGetCurrent,
|
id, kCFRunLoopCommonModes, CFAbsoluteTimeGetCurrent, CFRelease, CFRunLoopAddTimer,
|
||||||
CFRelease,
|
CFRunLoopGetMain, CFRunLoopRef, CFRunLoopTimerCreate, CFRunLoopTimerInvalidate,
|
||||||
CFRunLoopAddTimer,
|
CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, NSUInteger,
|
||||||
CFRunLoopGetMain,
|
},
|
||||||
CFRunLoopRef,
|
|
||||||
CFRunLoopTimerCreate,
|
|
||||||
CFRunLoopTimerInvalidate,
|
|
||||||
CFRunLoopTimerRef,
|
|
||||||
CFRunLoopTimerSetNextFireDate,
|
|
||||||
kCFRunLoopCommonModes,
|
|
||||||
NSUInteger,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! bug {
|
macro_rules! bug {
|
||||||
|
@ -62,13 +59,19 @@ enum AppStateImpl {
|
||||||
impl Drop for AppStateImpl {
|
impl Drop for AppStateImpl {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
&mut AppStateImpl::NotLaunched { ref mut queued_windows, .. } |
|
&mut AppStateImpl::NotLaunched {
|
||||||
&mut AppStateImpl::Launching { ref mut queued_windows, .. } => unsafe {
|
ref mut queued_windows,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
| &mut AppStateImpl::Launching {
|
||||||
|
ref mut queued_windows,
|
||||||
|
..
|
||||||
|
} => unsafe {
|
||||||
for &mut window in queued_windows {
|
for &mut window in queued_windows {
|
||||||
let () = msg_send![window, release];
|
let () = msg_send![window, release];
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +91,9 @@ impl AppState {
|
||||||
static mut APP_STATE: RefCell<Option<AppState>> = RefCell::new(None);
|
static mut APP_STATE: RefCell<Option<AppState>> = RefCell::new(None);
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
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();
|
let mut guard = APP_STATE.borrow_mut();
|
||||||
|
@ -108,26 +113,31 @@ impl AppState {
|
||||||
}
|
}
|
||||||
init_guard(&mut guard)
|
init_guard(&mut guard)
|
||||||
}
|
}
|
||||||
RefMut::map(guard, |state| {
|
RefMut::map(guard, |state| state.as_mut().unwrap())
|
||||||
state.as_mut().unwrap()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// requires main thread and window is a UIWindow
|
// requires main thread and window is a UIWindow
|
||||||
// retains window
|
// retains window
|
||||||
pub unsafe fn set_key_window(window: id) {
|
pub unsafe fn set_key_window(window: id) {
|
||||||
let mut this = AppState::get_mut();
|
let mut this = AppState::get_mut();
|
||||||
match &mut this.app_state {
|
match &mut this.app_state {
|
||||||
&mut AppStateImpl::NotLaunched { ref mut queued_windows, .. } => {
|
&mut AppStateImpl::NotLaunched {
|
||||||
|
ref mut queued_windows,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
queued_windows.push(window);
|
queued_windows.push(window);
|
||||||
msg_send![window, retain];
|
msg_send![window, retain];
|
||||||
return;
|
return;
|
||||||
}
|
},
|
||||||
&mut AppStateImpl::ProcessingEvents { .. } => {},
|
&mut AppStateImpl::ProcessingEvents { .. } => {},
|
||||||
&mut AppStateImpl::InUserCallback { .. } => {},
|
&mut AppStateImpl::InUserCallback { .. } => {},
|
||||||
&mut AppStateImpl::Terminated => panic!("Attempt to create a `Window` \
|
&mut AppStateImpl::Terminated => {
|
||||||
after the app has terminated"),
|
panic!(
|
||||||
app_state => unreachable!("unexpected state: {:#?}", app_state), // all other cases should be impossible
|
"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);
|
drop(this);
|
||||||
msg_send![window, makeKeyAndVisible]
|
msg_send![window, makeKeyAndVisible]
|
||||||
|
@ -144,15 +154,22 @@ impl AppState {
|
||||||
let windows = ptr::read(queued_windows);
|
let windows = ptr::read(queued_windows);
|
||||||
let events = ptr::read(queued_events);
|
let events = ptr::read(queued_events);
|
||||||
(windows, 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 {
|
ptr::write(
|
||||||
queued_windows,
|
&mut this.app_state,
|
||||||
queued_events,
|
AppStateImpl::Launching {
|
||||||
queued_event_handler,
|
queued_windows,
|
||||||
});
|
queued_events,
|
||||||
|
queued_event_handler,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// requires main thread
|
// requires main thread
|
||||||
|
@ -163,10 +180,12 @@ impl AppState {
|
||||||
ref mut queued_windows,
|
ref mut queued_windows,
|
||||||
..
|
..
|
||||||
} => mem::replace(queued_windows, Vec::new()),
|
} => mem::replace(queued_windows, Vec::new()),
|
||||||
_ => panic!(
|
_ => {
|
||||||
"winit iOS expected the app to be in a `Launching` \
|
panic!(
|
||||||
state, but was not - please file an issue"
|
"winit iOS expected the app to be in a `Launching` \
|
||||||
),
|
state, but was not - please file an issue"
|
||||||
|
)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
// have to drop RefMut because the window setup code below can trigger new events
|
// have to drop RefMut because the window setup code below can trigger new events
|
||||||
drop(this);
|
drop(this);
|
||||||
|
@ -188,11 +207,11 @@ impl AppState {
|
||||||
let screen: id = msg_send![window, screen];
|
let screen: id = msg_send![window, screen];
|
||||||
let () = msg_send![screen, retain];
|
let () = msg_send![screen, retain];
|
||||||
let () = msg_send![window, setScreen:0 as id];
|
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 () = msg_send![screen, release];
|
||||||
let controller: id = msg_send![window, rootViewController];
|
let controller: id = msg_send![window, rootViewController];
|
||||||
let () = msg_send![window, setRootViewController:ptr::null::<()>()];
|
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, makeKeyAndVisible];
|
||||||
}
|
}
|
||||||
let () = msg_send![window, release];
|
let () = msg_send![window, release];
|
||||||
|
@ -209,16 +228,23 @@ impl AppState {
|
||||||
let events = ptr::read(queued_events);
|
let events = ptr::read(queued_events);
|
||||||
let event_handler = ptr::read(queued_event_handler);
|
let event_handler = ptr::read(queued_event_handler);
|
||||||
(windows, events, 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 {
|
ptr::write(
|
||||||
event_handler,
|
&mut this.app_state,
|
||||||
active_control_flow: ControlFlow::Poll,
|
AppStateImpl::ProcessingEvents {
|
||||||
});
|
event_handler,
|
||||||
|
active_control_flow: ControlFlow::Poll,
|
||||||
|
},
|
||||||
|
);
|
||||||
drop(this);
|
drop(this);
|
||||||
|
|
||||||
let events = std::iter::once(Event::NewEvents(StartCause::Init)).chain(events);
|
let events = std::iter::once(Event::NewEvents(StartCause::Init)).chain(events);
|
||||||
AppState::handle_nonuser_events(events);
|
AppState::handle_nonuser_events(events);
|
||||||
|
|
||||||
|
@ -238,69 +264,79 @@ impl AppState {
|
||||||
// AppState::did_finish_launching handles the special transition `Init`
|
// AppState::did_finish_launching handles the special transition `Init`
|
||||||
pub unsafe fn handle_wakeup_transition() {
|
pub unsafe fn handle_wakeup_transition() {
|
||||||
let mut this = AppState::get_mut();
|
let mut this = AppState::get_mut();
|
||||||
let event = match this.control_flow {
|
let event =
|
||||||
ControlFlow::Poll => {
|
match this.control_flow {
|
||||||
let event_handler = match &mut this.app_state {
|
ControlFlow::Poll => {
|
||||||
&mut AppStateImpl::NotLaunched { .. } |
|
let event_handler = match &mut this.app_state {
|
||||||
&mut AppStateImpl::Launching { .. } => return,
|
&mut AppStateImpl::NotLaunched { .. }
|
||||||
&mut AppStateImpl::PollFinished {
|
| &mut AppStateImpl::Launching { .. } => return,
|
||||||
ref mut waiting_event_handler,
|
&mut AppStateImpl::PollFinished {
|
||||||
} => ptr::read(waiting_event_handler),
|
ref mut waiting_event_handler,
|
||||||
_ => bug!("`EventHandler` unexpectedly started polling"),
|
} => ptr::read(waiting_event_handler),
|
||||||
};
|
_ => bug!("`EventHandler` unexpectedly started polling"),
|
||||||
ptr::write(&mut this.app_state, AppStateImpl::ProcessingEvents {
|
};
|
||||||
event_handler,
|
ptr::write(
|
||||||
active_control_flow: ControlFlow::Poll,
|
&mut this.app_state,
|
||||||
});
|
AppStateImpl::ProcessingEvents {
|
||||||
Event::NewEvents(StartCause::Poll)
|
event_handler,
|
||||||
}
|
active_control_flow: ControlFlow::Poll,
|
||||||
ControlFlow::Wait => {
|
},
|
||||||
let (event_handler, start) = match &mut this.app_state {
|
);
|
||||||
&mut AppStateImpl::NotLaunched { .. } |
|
Event::NewEvents(StartCause::Poll)
|
||||||
&mut AppStateImpl::Launching { .. } => return,
|
},
|
||||||
&mut AppStateImpl::Waiting {
|
ControlFlow::Wait => {
|
||||||
ref mut waiting_event_handler,
|
let (event_handler, start) = match &mut this.app_state {
|
||||||
ref mut start,
|
&mut AppStateImpl::NotLaunched { .. }
|
||||||
} => (ptr::read(waiting_event_handler), *start),
|
| &mut AppStateImpl::Launching { .. } => return,
|
||||||
_ => bug!("`EventHandler` unexpectedly woke up"),
|
&mut AppStateImpl::Waiting {
|
||||||
};
|
ref mut waiting_event_handler,
|
||||||
ptr::write(&mut this.app_state, AppStateImpl::ProcessingEvents {
|
ref mut start,
|
||||||
event_handler,
|
} => (ptr::read(waiting_event_handler), *start),
|
||||||
active_control_flow: ControlFlow::Wait,
|
_ => bug!("`EventHandler` unexpectedly woke up"),
|
||||||
});
|
};
|
||||||
Event::NewEvents(StartCause::WaitCancelled {
|
ptr::write(
|
||||||
start,
|
&mut this.app_state,
|
||||||
requested_resume: None,
|
AppStateImpl::ProcessingEvents {
|
||||||
})
|
event_handler,
|
||||||
}
|
active_control_flow: ControlFlow::Wait,
|
||||||
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 {
|
Event::NewEvents(StartCause::WaitCancelled {
|
||||||
start,
|
start,
|
||||||
requested_resume: Some(requested_resume),
|
requested_resume: None,
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
}
|
ControlFlow::WaitUntil(requested_resume) => {
|
||||||
ControlFlow::Exit => bug!("unexpected controlflow `Exit`"),
|
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);
|
drop(this);
|
||||||
AppState::handle_nonuser_event(event)
|
AppState::handle_nonuser_event(event)
|
||||||
}
|
}
|
||||||
|
@ -328,8 +364,8 @@ impl AppState {
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
queued_events.extend(events);
|
queued_events.extend(events);
|
||||||
return
|
return;
|
||||||
}
|
},
|
||||||
&mut AppStateImpl::ProcessingEvents {
|
&mut AppStateImpl::ProcessingEvents {
|
||||||
ref mut event_handler,
|
ref mut event_handler,
|
||||||
ref mut active_control_flow,
|
ref mut active_control_flow,
|
||||||
|
@ -338,9 +374,12 @@ impl AppState {
|
||||||
| &mut AppStateImpl::Waiting { .. }
|
| &mut AppStateImpl::Waiting { .. }
|
||||||
| &mut AppStateImpl::Terminated => bug!("unexpected attempted to process an event"),
|
| &mut AppStateImpl::Terminated => bug!("unexpected attempted to process an event"),
|
||||||
};
|
};
|
||||||
ptr::write(&mut this.app_state, AppStateImpl::InUserCallback {
|
ptr::write(
|
||||||
queued_events: Vec::new(),
|
&mut this.app_state,
|
||||||
});
|
AppStateImpl::InUserCallback {
|
||||||
|
queued_events: Vec::new(),
|
||||||
|
},
|
||||||
|
);
|
||||||
drop(this);
|
drop(this);
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
|
@ -360,7 +399,7 @@ impl AppState {
|
||||||
active_control_flow,
|
active_control_flow,
|
||||||
};
|
};
|
||||||
this.control_flow = control_flow;
|
this.control_flow = control_flow;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
drop(this);
|
drop(this);
|
||||||
for event in queued_events {
|
for event in queued_events {
|
||||||
|
@ -384,9 +423,12 @@ impl AppState {
|
||||||
| &mut AppStateImpl::Waiting { .. }
|
| &mut AppStateImpl::Waiting { .. }
|
||||||
| &mut AppStateImpl::Terminated => bug!("unexpected attempted to process an event"),
|
| &mut AppStateImpl::Terminated => bug!("unexpected attempted to process an event"),
|
||||||
};
|
};
|
||||||
ptr::write(&mut this.app_state, AppStateImpl::InUserCallback {
|
ptr::write(
|
||||||
queued_events: Vec::new(),
|
&mut this.app_state,
|
||||||
});
|
AppStateImpl::InUserCallback {
|
||||||
|
queued_events: Vec::new(),
|
||||||
|
},
|
||||||
|
);
|
||||||
drop(this);
|
drop(this);
|
||||||
|
|
||||||
event_handler.handle_user_events(&mut control_flow);
|
event_handler.handle_user_events(&mut control_flow);
|
||||||
|
@ -404,7 +446,7 @@ impl AppState {
|
||||||
active_control_flow,
|
active_control_flow,
|
||||||
};
|
};
|
||||||
this.control_flow = control_flow;
|
this.control_flow = control_flow;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
drop(this);
|
drop(this);
|
||||||
for event in queued_events {
|
for event in queued_events {
|
||||||
|
@ -419,7 +461,7 @@ impl AppState {
|
||||||
let mut this = AppState::get_mut();
|
let mut this = AppState::get_mut();
|
||||||
match &mut this.app_state {
|
match &mut this.app_state {
|
||||||
&mut AppStateImpl::NotLaunched { .. } | &mut AppStateImpl::Launching { .. } => return,
|
&mut AppStateImpl::NotLaunched { .. } | &mut AppStateImpl::Launching { .. } => return,
|
||||||
&mut AppStateImpl::ProcessingEvents { .. } => {}
|
&mut AppStateImpl::ProcessingEvents { .. } => {},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
drop(this);
|
drop(this);
|
||||||
|
@ -432,7 +474,12 @@ impl AppState {
|
||||||
&mut AppStateImpl::ProcessingEvents {
|
&mut AppStateImpl::ProcessingEvents {
|
||||||
ref mut event_handler,
|
ref mut event_handler,
|
||||||
ref mut active_control_flow,
|
ref mut active_control_flow,
|
||||||
} => (ManuallyDrop::new(ptr::read(event_handler)), *active_control_flow),
|
} => {
|
||||||
|
(
|
||||||
|
ManuallyDrop::new(ptr::read(event_handler)),
|
||||||
|
*active_control_flow,
|
||||||
|
)
|
||||||
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -457,7 +504,8 @@ impl AppState {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
(ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant))
|
(ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant))
|
||||||
if old_instant == new_instant => {
|
if old_instant == new_instant =>
|
||||||
|
{
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
ptr::write(
|
ptr::write(
|
||||||
&mut this.app_state,
|
&mut this.app_state,
|
||||||
|
@ -503,7 +551,7 @@ impl AppState {
|
||||||
// it is not possible to quit an iOS app gracefully and programatically
|
// it is not possible to quit an iOS app gracefully and programatically
|
||||||
warn!("`ControlFlow::Exit` ignored on iOS");
|
warn!("`ControlFlow::Exit` ignored on iOS");
|
||||||
this.control_flow = old
|
this.control_flow = old
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,7 +559,11 @@ impl AppState {
|
||||||
let mut this = unsafe { AppState::get_mut() };
|
let mut this = unsafe { AppState::get_mut() };
|
||||||
let mut old = mem::replace(&mut this.app_state, AppStateImpl::Terminated);
|
let mut old = mem::replace(&mut this.app_state, AppStateImpl::Terminated);
|
||||||
let mut control_flow = this.control_flow;
|
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);
|
drop(this);
|
||||||
event_handler.handle_nonuser_event(Event::LoopDestroyed, &mut control_flow)
|
event_handler.handle_nonuser_event(Event::LoopDestroyed, &mut control_flow)
|
||||||
} else {
|
} else {
|
||||||
|
@ -535,7 +587,7 @@ impl Drop for EventLoopWaker {
|
||||||
|
|
||||||
impl EventLoopWaker {
|
impl EventLoopWaker {
|
||||||
fn new(rl: CFRunLoopRef) -> 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 {
|
unsafe {
|
||||||
// create a timer with a 1microsec interval (1ns does not work) to mimic polling.
|
// 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
|
// it is initially setup with a first fire time really far into the
|
||||||
|
@ -577,4 +629,4 @@ impl EventLoopWaker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +1,33 @@
|
||||||
use std::{mem, ptr};
|
use std::{
|
||||||
use std::collections::VecDeque;
|
collections::VecDeque,
|
||||||
use std::ffi::c_void;
|
ffi::c_void,
|
||||||
use std::fmt::{self, Debug, Formatter};
|
fmt::{self, Debug, Formatter},
|
||||||
use std::marker::PhantomData;
|
marker::PhantomData,
|
||||||
use std::sync::mpsc::{self, Sender, Receiver};
|
mem, ptr,
|
||||||
|
sync::mpsc::{self, Receiver, Sender},
|
||||||
use crate::event::Event;
|
|
||||||
use crate::event_loop::{
|
|
||||||
ControlFlow,
|
|
||||||
EventLoopWindowTarget as RootEventLoopWindowTarget,
|
|
||||||
EventLoopClosed,
|
|
||||||
};
|
};
|
||||||
use crate::platform::ios::Idiom;
|
|
||||||
|
|
||||||
use crate::platform_impl::platform::app_state::AppState;
|
use crate::{
|
||||||
use crate::platform_impl::platform::ffi::{
|
event::Event,
|
||||||
id,
|
event_loop::{
|
||||||
nil,
|
ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget,
|
||||||
CFIndex,
|
},
|
||||||
CFRelease,
|
platform::ios::Idiom,
|
||||||
CFRunLoopActivity,
|
};
|
||||||
CFRunLoopAddObserver,
|
|
||||||
CFRunLoopAddSource,
|
use crate::platform_impl::platform::{
|
||||||
CFRunLoopGetMain,
|
app_state::AppState,
|
||||||
CFRunLoopObserverCreate,
|
ffi::{
|
||||||
CFRunLoopObserverRef,
|
id, kCFRunLoopAfterWaiting, kCFRunLoopBeforeWaiting, kCFRunLoopCommonModes,
|
||||||
CFRunLoopSourceContext,
|
kCFRunLoopDefaultMode, kCFRunLoopEntry, kCFRunLoopExit, nil, CFIndex, CFRelease,
|
||||||
CFRunLoopSourceCreate,
|
CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopAddSource, CFRunLoopGetMain,
|
||||||
CFRunLoopSourceInvalidate,
|
CFRunLoopObserverCreate, CFRunLoopObserverRef, CFRunLoopSourceContext,
|
||||||
CFRunLoopSourceRef,
|
CFRunLoopSourceCreate, CFRunLoopSourceInvalidate, CFRunLoopSourceRef,
|
||||||
CFRunLoopSourceSignal,
|
CFRunLoopSourceSignal, CFRunLoopWakeUp, NSOperatingSystemVersion, NSString,
|
||||||
CFRunLoopWakeUp,
|
UIApplicationMain, UIUserInterfaceIdiom,
|
||||||
kCFRunLoopCommonModes,
|
},
|
||||||
kCFRunLoopDefaultMode,
|
monitor, view, MonitorHandle,
|
||||||
kCFRunLoopEntry,
|
|
||||||
kCFRunLoopBeforeWaiting,
|
|
||||||
kCFRunLoopAfterWaiting,
|
|
||||||
kCFRunLoopExit,
|
|
||||||
NSOperatingSystemVersion,
|
|
||||||
NSString,
|
|
||||||
UIApplicationMain,
|
|
||||||
UIUserInterfaceIdiom,
|
|
||||||
};
|
};
|
||||||
use crate::platform_impl::platform::monitor;
|
|
||||||
use crate::platform_impl::platform::MonitorHandle;
|
|
||||||
use crate::platform_impl::platform::view;
|
|
||||||
|
|
||||||
pub struct EventLoopWindowTarget<T: 'static> {
|
pub struct EventLoopWindowTarget<T: 'static> {
|
||||||
receiver: Receiver<T>,
|
receiver: Receiver<T>,
|
||||||
|
@ -67,8 +50,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
static mut SINGLETON_INIT: bool = false;
|
static mut SINGLETON_INIT: bool = false;
|
||||||
unsafe {
|
unsafe {
|
||||||
assert_main_thread!("`EventLoop` can only be created on the main thread on iOS");
|
assert_main_thread!("`EventLoop` can only be created on the main thread on iOS");
|
||||||
assert!(!SINGLETON_INIT, "Only one `EventLoop` is supported on iOS. \
|
assert!(
|
||||||
`EventLoopProxy` might be helpful");
|
!SINGLETON_INIT,
|
||||||
|
"Only one `EventLoop` is supported on iOS. \
|
||||||
|
`EventLoopProxy` might be helpful"
|
||||||
|
);
|
||||||
SINGLETON_INIT = true;
|
SINGLETON_INIT = true;
|
||||||
view::create_delegate_class();
|
view::create_delegate_class();
|
||||||
}
|
}
|
||||||
|
@ -92,25 +78,34 @@ impl<T: 'static> EventLoop<T> {
|
||||||
capabilities,
|
capabilities,
|
||||||
},
|
},
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<F>(self, event_handler: F) -> !
|
pub fn run<F>(self, event_handler: F) -> !
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow)
|
F: 'static + FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let application: *mut c_void = msg_send![class!(UIApplication), sharedApplication];
|
let application: *mut c_void = msg_send![class!(UIApplication), sharedApplication];
|
||||||
assert_eq!(application, ptr::null_mut(), "\
|
assert_eq!(
|
||||||
`EventLoop` cannot be `run` after a call to `UIApplicationMain` on iOS\n\
|
application,
|
||||||
Note: `EventLoop::run` calls `UIApplicationMain` on iOS");
|
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 {
|
AppState::will_launch(Box::new(EventLoopHandler {
|
||||||
f: event_handler,
|
f: event_handler,
|
||||||
event_loop: self.window_target,
|
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!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,16 +116,12 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||||
// guaranteed to be on main thread
|
// guaranteed to be on main thread
|
||||||
unsafe {
|
unsafe { monitor::uiscreens() }
|
||||||
monitor::uiscreens()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary_monitor(&self) -> MonitorHandle {
|
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||||
// guaranteed to be on main thread
|
// guaranteed to be on main thread
|
||||||
unsafe {
|
unsafe { monitor::main_uiscreen() }
|
||||||
monitor::main_uiscreen()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_target(&self) -> &RootEventLoopWindowTarget<T> {
|
pub fn window_target(&self) -> &RootEventLoopWindowTarget<T> {
|
||||||
|
@ -142,9 +133,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl<T: 'static> EventLoop<T> {
|
||||||
pub fn idiom(&self) -> Idiom {
|
pub fn idiom(&self) -> Idiom {
|
||||||
// guaranteed to be on main thread
|
// guaranteed to be on main thread
|
||||||
unsafe {
|
unsafe { self::get_idiom() }
|
||||||
self::get_idiom()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,18 +172,12 @@ impl<T> EventLoopProxy<T> {
|
||||||
// we want all the members of context to be zero/null, except one
|
// we want all the members of context to be zero/null, except one
|
||||||
let mut context: CFRunLoopSourceContext = mem::zeroed();
|
let mut context: CFRunLoopSourceContext = mem::zeroed();
|
||||||
context.perform = event_loop_proxy_handler;
|
context.perform = event_loop_proxy_handler;
|
||||||
let source = CFRunLoopSourceCreate(
|
let source =
|
||||||
ptr::null_mut(),
|
CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context);
|
||||||
CFIndex::max_value() - 1,
|
|
||||||
&mut context,
|
|
||||||
);
|
|
||||||
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
||||||
CFRunLoopWakeUp(rl);
|
CFRunLoopWakeUp(rl);
|
||||||
|
|
||||||
EventLoopProxy {
|
EventLoopProxy { sender, source }
|
||||||
sender,
|
|
||||||
source,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +196,7 @@ impl<T> EventLoopProxy<T> {
|
||||||
fn setup_control_flow_observers() {
|
fn setup_control_flow_observers() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// begin is queued with the highest priority to ensure it is processed before other observers
|
// 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,
|
_: CFRunLoopObserverRef,
|
||||||
activity: CFRunLoopActivity,
|
activity: CFRunLoopActivity,
|
||||||
_: *mut c_void,
|
_: *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
|
// end is queued with the lowest priority to ensure it is processed after other observers
|
||||||
// without that, LoopDestroyed will get sent after EventsCleared
|
// without that, LoopDestroyed will get sent after EventsCleared
|
||||||
extern fn control_flow_end_handler(
|
extern "C" fn control_flow_end_handler(
|
||||||
_: CFRunLoopObserverRef,
|
_: CFRunLoopObserverRef,
|
||||||
activity: CFRunLoopActivity,
|
activity: CFRunLoopActivity,
|
||||||
_: *mut c_void,
|
_: *mut c_void,
|
||||||
|
@ -282,7 +265,8 @@ struct EventLoopHandler<F, T: 'static> {
|
||||||
|
|
||||||
impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
|
impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
formatter.debug_struct("EventLoopHandler")
|
formatter
|
||||||
|
.debug_struct("EventLoopHandler")
|
||||||
.field("event_loop", &self.event_loop)
|
.field("event_loop", &self.event_loop)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
@ -303,11 +287,7 @@ where
|
||||||
|
|
||||||
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
|
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
|
||||||
for event in self.event_loop.p.receiver.try_iter() {
|
for event in self.event_loop.p.receiver.try_iter() {
|
||||||
(self.f)(
|
(self.f)(Event::UserEvent(event), &self.event_loop, control_flow);
|
||||||
Event::UserEvent(event),
|
|
||||||
&self.event_loop,
|
|
||||||
control_flow,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,7 +305,10 @@ pub struct Capabilities {
|
||||||
|
|
||||||
impl From<NSOperatingSystemVersion> for Capabilities {
|
impl From<NSOperatingSystemVersion> for Capabilities {
|
||||||
fn from(os_version: NSOperatingSystemVersion) -> 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;
|
let supports_safe_area = os_version.major >= 11;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
|
#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::{ffi::CString, ops::BitOr, os::raw::*};
|
||||||
use std::ops::BitOr;
|
|
||||||
use std::os::raw::*;
|
|
||||||
|
|
||||||
use objc::{Encode, Encoding};
|
use objc::{runtime::Object, Encode, Encoding};
|
||||||
use objc::runtime::Object;
|
|
||||||
|
|
||||||
use crate::platform::ios::{Idiom, ValidOrientations};
|
use crate::platform::ios::{Idiom, ValidOrientations};
|
||||||
|
|
||||||
|
@ -87,7 +84,9 @@ pub struct UIEdgeInsets {
|
||||||
pub struct UIUserInterfaceIdiom(NSInteger);
|
pub struct UIUserInterfaceIdiom(NSInteger);
|
||||||
|
|
||||||
unsafe impl Encode for UIUserInterfaceIdiom {
|
unsafe impl Encode for UIUserInterfaceIdiom {
|
||||||
fn encode() -> Encoding { NSInteger::encode() }
|
fn encode() -> Encoding {
|
||||||
|
NSInteger::encode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIUserInterfaceIdiom {
|
impl UIUserInterfaceIdiom {
|
||||||
|
@ -128,7 +127,9 @@ impl Into<Idiom> for UIUserInterfaceIdiom {
|
||||||
pub struct UIInterfaceOrientationMask(NSUInteger);
|
pub struct UIInterfaceOrientationMask(NSUInteger);
|
||||||
|
|
||||||
unsafe impl Encode for UIInterfaceOrientationMask {
|
unsafe impl Encode for UIInterfaceOrientationMask {
|
||||||
fn encode() -> Encoding { NSUInteger::encode() }
|
fn encode() -> Encoding {
|
||||||
|
NSUInteger::encode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIInterfaceOrientationMask {
|
impl UIInterfaceOrientationMask {
|
||||||
|
@ -136,9 +137,12 @@ impl UIInterfaceOrientationMask {
|
||||||
pub const PortraitUpsideDown: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 2);
|
pub const PortraitUpsideDown: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 2);
|
||||||
pub const LandscapeLeft: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 4);
|
pub const LandscapeLeft: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 4);
|
||||||
pub const LandscapeRight: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 3);
|
pub const LandscapeRight: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 3);
|
||||||
pub const Landscape: UIInterfaceOrientationMask = UIInterfaceOrientationMask(Self::LandscapeLeft.0 | Self::LandscapeRight.0);
|
pub const Landscape: UIInterfaceOrientationMask =
|
||||||
pub const AllButUpsideDown: UIInterfaceOrientationMask = UIInterfaceOrientationMask(Self::Landscape.0 | Self::Portrait.0);
|
UIInterfaceOrientationMask(Self::LandscapeLeft.0 | Self::LandscapeRight.0);
|
||||||
pub const All: UIInterfaceOrientationMask = UIInterfaceOrientationMask(Self::AllButUpsideDown.0 | Self::PortraitUpsideDown.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 {
|
impl BitOr for UIInterfaceOrientationMask {
|
||||||
|
@ -155,18 +159,23 @@ impl UIInterfaceOrientationMask {
|
||||||
idiom: Idiom,
|
idiom: Idiom,
|
||||||
) -> UIInterfaceOrientationMask {
|
) -> UIInterfaceOrientationMask {
|
||||||
match (valid_orientations, idiom) {
|
match (valid_orientations, idiom) {
|
||||||
(ValidOrientations::LandscapeAndPortrait, Idiom::Phone) => UIInterfaceOrientationMask::AllButUpsideDown,
|
(ValidOrientations::LandscapeAndPortrait, Idiom::Phone) => {
|
||||||
|
UIInterfaceOrientationMask::AllButUpsideDown
|
||||||
|
},
|
||||||
(ValidOrientations::LandscapeAndPortrait, _) => UIInterfaceOrientationMask::All,
|
(ValidOrientations::LandscapeAndPortrait, _) => UIInterfaceOrientationMask::All,
|
||||||
(ValidOrientations::Landscape, _) => UIInterfaceOrientationMask::Landscape,
|
(ValidOrientations::Landscape, _) => UIInterfaceOrientationMask::Landscape,
|
||||||
(ValidOrientations::Portrait, Idiom::Phone) => UIInterfaceOrientationMask::Portrait,
|
(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 = "UIKit", kind = "framework")]
|
||||||
#[link(name = "CoreFoundation", kind = "framework")]
|
#[link(name = "CoreFoundation", kind = "framework")]
|
||||||
extern {
|
extern "C" {
|
||||||
pub static kCFRunLoopDefaultMode: CFRunLoopMode;
|
pub static kCFRunLoopDefaultMode: CFRunLoopMode;
|
||||||
pub static kCFRunLoopCommonModes: CFRunLoopMode;
|
pub static kCFRunLoopCommonModes: CFRunLoopMode;
|
||||||
|
|
||||||
|
@ -203,15 +212,8 @@ extern {
|
||||||
callout: CFRunLoopTimerCallBack,
|
callout: CFRunLoopTimerCallBack,
|
||||||
context: *mut CFRunLoopTimerContext,
|
context: *mut CFRunLoopTimerContext,
|
||||||
) -> CFRunLoopTimerRef;
|
) -> CFRunLoopTimerRef;
|
||||||
pub fn CFRunLoopAddTimer(
|
pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFRunLoopMode);
|
||||||
rl: CFRunLoopRef,
|
pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime);
|
||||||
timer: CFRunLoopTimerRef,
|
|
||||||
mode: CFRunLoopMode,
|
|
||||||
);
|
|
||||||
pub fn CFRunLoopTimerSetNextFireDate(
|
|
||||||
timer: CFRunLoopTimerRef,
|
|
||||||
fireDate: CFAbsoluteTime,
|
|
||||||
);
|
|
||||||
pub fn CFRunLoopTimerInvalidate(time: CFRunLoopTimerRef);
|
pub fn CFRunLoopTimerInvalidate(time: CFRunLoopTimerRef);
|
||||||
|
|
||||||
pub fn CFRunLoopSourceCreate(
|
pub fn CFRunLoopSourceCreate(
|
||||||
|
@ -219,11 +221,7 @@ extern {
|
||||||
order: CFIndex,
|
order: CFIndex,
|
||||||
context: *mut CFRunLoopSourceContext,
|
context: *mut CFRunLoopSourceContext,
|
||||||
) -> CFRunLoopSourceRef;
|
) -> CFRunLoopSourceRef;
|
||||||
pub fn CFRunLoopAddSource(
|
pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFRunLoopMode);
|
||||||
rl: CFRunLoopRef,
|
|
||||||
source: CFRunLoopSourceRef,
|
|
||||||
mode: CFRunLoopMode,
|
|
||||||
);
|
|
||||||
pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef);
|
pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef);
|
||||||
pub fn CFRunLoopSourceSignal(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 kCFRunLoopAfterWaiting: CFRunLoopActivity = 1 << 6;
|
||||||
pub const kCFRunLoopExit: CFRunLoopActivity = 1 << 7;
|
pub const kCFRunLoopExit: CFRunLoopActivity = 1 << 7;
|
||||||
|
|
||||||
pub type CFRunLoopObserverCallBack = extern "C" fn(
|
pub type CFRunLoopObserverCallBack =
|
||||||
observer: CFRunLoopObserverRef,
|
extern "C" fn(observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void);
|
||||||
activity: CFRunLoopActivity,
|
pub type CFRunLoopTimerCallBack = extern "C" fn(timer: CFRunLoopTimerRef, info: *mut c_void);
|
||||||
info: *mut c_void,
|
|
||||||
);
|
|
||||||
pub type CFRunLoopTimerCallBack = extern "C" fn(
|
|
||||||
timer: CFRunLoopTimerRef,
|
|
||||||
info: *mut c_void,
|
|
||||||
);
|
|
||||||
|
|
||||||
pub enum CFRunLoopObserverContext {}
|
pub enum CFRunLoopObserverContext {}
|
||||||
pub enum CFRunLoopTimerContext {}
|
pub enum CFRunLoopTimerContext {}
|
||||||
|
@ -299,11 +291,11 @@ pub trait NSString: Sized {
|
||||||
|
|
||||||
impl NSString for id {
|
impl NSString for id {
|
||||||
unsafe fn initWithUTF8String_(self, c_string: *const c_char) -> 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 {
|
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 {
|
unsafe fn init_str(self, string: &str) -> id {
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
//! fn start_inner() {
|
//! fn start_inner() {
|
||||||
//! ...
|
//! ...
|
||||||
//! }
|
//! }
|
||||||
//!
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Compile project and then drag resulting .a into Xcode project. Add winit.h to xcode.
|
//! Compile project and then drag resulting .a into Xcode project. Add winit.h to xcode.
|
||||||
|
@ -78,12 +77,10 @@ mod window;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
|
pub use self::{
|
||||||
pub use self::monitor::MonitorHandle;
|
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
|
||||||
pub use self::window::{
|
monitor::MonitorHandle,
|
||||||
PlatformSpecificWindowBuilderAttributes,
|
window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
|
||||||
Window,
|
|
||||||
WindowId,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -108,7 +105,7 @@ pub enum OsError {}
|
||||||
impl fmt::Display for OsError {
|
impl fmt::Display for OsError {
|
||||||
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,14 @@ use std::{
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
use crate::{
|
||||||
use crate::monitor::VideoMode;
|
dpi::{PhysicalPosition, PhysicalSize},
|
||||||
|
monitor::VideoMode,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::platform_impl::platform::ffi::{id, nil, CGFloat, CGRect, CGSize, NSInteger, NSUInteger};
|
use crate::platform_impl::platform::ffi::{
|
||||||
|
id, nil, CGFloat, CGRect, CGSize, NSInteger, NSUInteger,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Inner {
|
pub struct Inner {
|
||||||
uiscreen: id,
|
uiscreen: id,
|
||||||
|
@ -30,7 +34,9 @@ impl Deref for MonitorHandle {
|
||||||
|
|
||||||
fn deref(&self) -> &Inner {
|
fn deref(&self) -> &Inner {
|
||||||
unsafe {
|
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
|
&self.inner
|
||||||
}
|
}
|
||||||
|
@ -39,7 +45,9 @@ impl Deref for MonitorHandle {
|
||||||
impl DerefMut for MonitorHandle {
|
impl DerefMut for MonitorHandle {
|
||||||
fn deref_mut(&mut self) -> &mut Inner {
|
fn deref_mut(&mut self) -> &mut Inner {
|
||||||
unsafe {
|
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
|
&mut self.inner
|
||||||
}
|
}
|
||||||
|
@ -89,7 +97,9 @@ impl MonitorHandle {
|
||||||
assert_main_thread!("`MonitorHandle` can only be cloned on the main thread on iOS");
|
assert_main_thread!("`MonitorHandle` can only be cloned on the main thread on iOS");
|
||||||
let () = msg_send![uiscreen, retain];
|
let () = msg_send![uiscreen, retain];
|
||||||
}
|
}
|
||||||
MonitorHandle { inner: Inner { uiscreen } }
|
MonitorHandle {
|
||||||
|
inner: Inner { uiscreen },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +190,7 @@ pub unsafe fn uiscreens() -> VecDeque<MonitorHandle> {
|
||||||
loop {
|
loop {
|
||||||
let screen: id = msg_send![screens_enum, nextObject];
|
let screen: id = msg_send![screens_enum, nextObject];
|
||||||
if screen == nil {
|
if screen == nil {
|
||||||
break result
|
break result;
|
||||||
}
|
}
|
||||||
result.push_back(MonitorHandle::retained_new(screen));
|
result.push_back(MonitorHandle::retained_new(screen));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,23 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use objc::declare::ClassDecl;
|
use objc::{
|
||||||
use objc::runtime::{BOOL, Class, NO, Object, Sel, YES};
|
declare::ClassDecl,
|
||||||
|
runtime::{Class, Object, Sel, BOOL, NO, YES},
|
||||||
use crate::event::{
|
|
||||||
DeviceId as RootDeviceId,
|
|
||||||
Event,
|
|
||||||
Touch,
|
|
||||||
TouchPhase,
|
|
||||||
WindowEvent
|
|
||||||
};
|
};
|
||||||
use crate::platform::ios::MonitorHandleExtIOS;
|
|
||||||
use crate::window::{WindowAttributes, WindowId as RootWindowId};
|
|
||||||
|
|
||||||
use crate::platform_impl::platform::app_state::AppState;
|
use crate::{
|
||||||
use crate::platform_impl::platform::DeviceId;
|
event::{DeviceId as RootDeviceId, Event, Touch, TouchPhase, WindowEvent},
|
||||||
use crate::platform_impl::platform::event_loop;
|
platform::ios::MonitorHandleExtIOS,
|
||||||
use crate::platform_impl::platform::ffi::{
|
window::{WindowAttributes, WindowId as RootWindowId},
|
||||||
id,
|
};
|
||||||
nil,
|
|
||||||
CGFloat,
|
use crate::platform_impl::platform::{
|
||||||
CGPoint,
|
app_state::AppState,
|
||||||
CGRect,
|
event_loop,
|
||||||
UIInterfaceOrientationMask,
|
ffi::{id, nil, CGFloat, CGPoint, CGRect, UIInterfaceOrientationMask, UITouchPhase},
|
||||||
UITouchPhase,
|
window::PlatformSpecificWindowBuilderAttributes,
|
||||||
|
DeviceId,
|
||||||
};
|
};
|
||||||
use crate::platform_impl::platform::window::{PlatformSpecificWindowBuilderAttributes};
|
|
||||||
|
|
||||||
// requires main thread
|
// requires main thread
|
||||||
unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class {
|
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 || {
|
classes.entry(root_view_class).or_insert_with(move || {
|
||||||
let uiview_class = class!(UIView);
|
let uiview_class = class!(UIView);
|
||||||
let is_uiview: BOOL = msg_send![root_view_class, isSubclassOfClass:uiview_class];
|
let is_uiview: BOOL = msg_send![root_view_class, isSubclassOfClass: uiview_class];
|
||||||
assert_eq!(is_uiview, YES, "`root_view_class` must inherit from `UIView`");
|
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 {
|
unsafe {
|
||||||
let window: id = msg_send![object, window];
|
let window: id = msg_send![object, window];
|
||||||
AppState::handle_nonuser_event(Event::WindowEvent {
|
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 {
|
unsafe {
|
||||||
let window: id = msg_send![object, window];
|
let window: id = msg_send![object, window];
|
||||||
let bounds: CGRect = msg_send![window, bounds];
|
let bounds: CGRect = msg_send![window, bounds];
|
||||||
let screen: id = msg_send![window, screen];
|
let screen: id = msg_send![window, screen];
|
||||||
let screen_space: id = msg_send![screen, coordinateSpace];
|
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 {
|
let size = crate::dpi::LogicalSize {
|
||||||
width: screen_frame.size.width,
|
width: screen_frame.size.width,
|
||||||
height: screen_frame.size.height,
|
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)
|
let mut decl = ClassDecl::new(&format!("WinitUIView{}", ID), root_view_class)
|
||||||
.expect("Failed to declare class `WinitUIView`");
|
.expect("Failed to declare class `WinitUIView`");
|
||||||
ID += 1;
|
ID += 1;
|
||||||
decl.add_method(sel!(drawRect:),
|
decl.add_method(
|
||||||
draw_rect as extern fn(&Object, Sel, CGRect));
|
sel!(drawRect:),
|
||||||
decl.add_method(sel!(layoutSubviews),
|
draw_rect as extern "C" fn(&Object, Sel, CGRect),
|
||||||
layout_subviews as extern fn(&Object, Sel));
|
);
|
||||||
|
decl.add_method(
|
||||||
|
sel!(layoutSubviews),
|
||||||
|
layout_subviews as extern "C" fn(&Object, Sel),
|
||||||
|
);
|
||||||
decl.register()
|
decl.register()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -92,33 +92,39 @@ unsafe fn get_view_controller_class() -> &'static Class {
|
||||||
if CLASS.is_none() {
|
if CLASS.is_none() {
|
||||||
let uiviewcontroller_class = class!(UIViewController);
|
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 {
|
unsafe {
|
||||||
object.set_ivar::<BOOL>("_prefers_status_bar_hidden", hidden);
|
object.set_ivar::<BOOL>("_prefers_status_bar_hidden", hidden);
|
||||||
let () = msg_send![object, setNeedsStatusBarAppearanceUpdate];
|
let () = msg_send![object, setNeedsStatusBarAppearanceUpdate];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn prefers_status_bar_hidden(object: &Object, _: Sel) -> BOOL {
|
extern "C" fn prefers_status_bar_hidden(object: &Object, _: Sel) -> BOOL {
|
||||||
unsafe {
|
unsafe { *object.get_ivar::<BOOL>("_prefers_status_bar_hidden") }
|
||||||
*object.get_ivar::<BOOL>("_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 {
|
unsafe {
|
||||||
object.set_ivar::<UIInterfaceOrientationMask>("_supported_orientations", orientations);
|
object.set_ivar::<UIInterfaceOrientationMask>(
|
||||||
|
"_supported_orientations",
|
||||||
|
orientations,
|
||||||
|
);
|
||||||
let () = msg_send![class!(UIViewController), attemptRotationToDeviceOrientation];
|
let () = msg_send![class!(UIViewController), attemptRotationToDeviceOrientation];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn supported_orientations(object: &Object, _: Sel) -> UIInterfaceOrientationMask {
|
extern "C" fn supported_orientations(
|
||||||
unsafe {
|
object: &Object,
|
||||||
*object.get_ivar::<UIInterfaceOrientationMask>("_supported_orientations")
|
_: Sel,
|
||||||
}
|
) -> UIInterfaceOrientationMask {
|
||||||
|
unsafe { *object.get_ivar::<UIInterfaceOrientationMask>("_supported_orientations") }
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn should_autorotate(_: &Object, _: Sel) -> BOOL {
|
extern "C" fn should_autorotate(_: &Object, _: Sel) -> BOOL {
|
||||||
YES
|
YES
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,16 +132,27 @@ unsafe fn get_view_controller_class() -> &'static Class {
|
||||||
.expect("Failed to declare class `WinitUIViewController`");
|
.expect("Failed to declare class `WinitUIViewController`");
|
||||||
decl.add_ivar::<BOOL>("_prefers_status_bar_hidden");
|
decl.add_ivar::<BOOL>("_prefers_status_bar_hidden");
|
||||||
decl.add_ivar::<UIInterfaceOrientationMask>("_supported_orientations");
|
decl.add_ivar::<UIInterfaceOrientationMask>("_supported_orientations");
|
||||||
decl.add_method(sel!(setPrefersStatusBarHidden:),
|
decl.add_method(
|
||||||
set_prefers_status_bar_hidden as extern fn(&mut Object, Sel, BOOL));
|
sel!(setPrefersStatusBarHidden:),
|
||||||
decl.add_method(sel!(prefersStatusBarHidden),
|
set_prefers_status_bar_hidden as extern "C" fn(&mut Object, Sel, BOOL),
|
||||||
prefers_status_bar_hidden as extern fn(&Object, Sel) -> BOOL);
|
);
|
||||||
decl.add_method(sel!(setSupportedInterfaceOrientations:),
|
decl.add_method(
|
||||||
set_supported_orientations as extern fn(&mut Object, Sel, UIInterfaceOrientationMask));
|
sel!(prefersStatusBarHidden),
|
||||||
decl.add_method(sel!(supportedInterfaceOrientations),
|
prefers_status_bar_hidden as extern "C" fn(&Object, Sel) -> BOOL,
|
||||||
supported_orientations as extern fn(&Object, Sel) -> UIInterfaceOrientationMask);
|
);
|
||||||
decl.add_method(sel!(shouldAutorotate),
|
decl.add_method(
|
||||||
should_autorotate as extern fn(&Object, Sel) -> BOOL);
|
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 = Some(decl.register());
|
||||||
}
|
}
|
||||||
CLASS.unwrap()
|
CLASS.unwrap()
|
||||||
|
@ -147,7 +164,7 @@ unsafe fn get_window_class() -> &'static Class {
|
||||||
if CLASS.is_none() {
|
if CLASS.is_none() {
|
||||||
let uiwindow_class = class!(UIWindow);
|
let uiwindow_class = class!(UIWindow);
|
||||||
|
|
||||||
extern fn become_key_window(object: &Object, _: Sel) {
|
extern "C" fn become_key_window(object: &Object, _: Sel) {
|
||||||
unsafe {
|
unsafe {
|
||||||
AppState::handle_nonuser_event(Event::WindowEvent {
|
AppState::handle_nonuser_event(Event::WindowEvent {
|
||||||
window_id: RootWindowId(object.into()),
|
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 {
|
unsafe {
|
||||||
AppState::handle_nonuser_event(Event::WindowEvent {
|
AppState::handle_nonuser_event(Event::WindowEvent {
|
||||||
window_id: RootWindowId(object.into()),
|
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 {
|
unsafe {
|
||||||
let uiscreen = msg_send![object, screen];
|
let uiscreen = msg_send![object, screen];
|
||||||
let touches_enum: id = msg_send![touches, objectEnumerator];
|
let touches_enum: id = msg_send![touches, objectEnumerator];
|
||||||
|
@ -175,9 +192,9 @@ unsafe fn get_window_class() -> &'static Class {
|
||||||
loop {
|
loop {
|
||||||
let touch: id = msg_send![touches_enum, nextObject];
|
let touch: id = msg_send![touches_enum, nextObject];
|
||||||
if touch == nil {
|
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 touch_id = touch as u64;
|
||||||
let phase: UITouchPhase = msg_send![touch, phase];
|
let phase: UITouchPhase = msg_send![touch, phase];
|
||||||
let phase = match 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 {
|
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_controller: id = msg_send![object, rootViewController];
|
||||||
let view: id = msg_send![view_controller, view];
|
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 bounds: CGRect = msg_send![object, bounds];
|
||||||
let screen: id = msg_send![object, screen];
|
let screen: id = msg_send![object, screen];
|
||||||
let screen_space: id = msg_send![screen, coordinateSpace];
|
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 {
|
let size = crate::dpi::LogicalSize {
|
||||||
width: screen_frame.size.width,
|
width: screen_frame.size.width,
|
||||||
height: screen_frame.size.height,
|
height: screen_frame.size.height,
|
||||||
|
@ -221,32 +242,47 @@ unsafe fn get_window_class() -> &'static Class {
|
||||||
std::iter::once(Event::WindowEvent {
|
std::iter::once(Event::WindowEvent {
|
||||||
window_id: RootWindowId(object.into()),
|
window_id: RootWindowId(object.into()),
|
||||||
event: WindowEvent::HiDpiFactorChanged(hidpi_factor as _),
|
event: WindowEvent::HiDpiFactorChanged(hidpi_factor as _),
|
||||||
}).chain(std::iter::once(Event::WindowEvent {
|
})
|
||||||
|
.chain(std::iter::once(Event::WindowEvent {
|
||||||
window_id: RootWindowId(object.into()),
|
window_id: RootWindowId(object.into()),
|
||||||
event: WindowEvent::Resized(size),
|
event: WindowEvent::Resized(size),
|
||||||
}))
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut decl = ClassDecl::new("WinitUIWindow", uiwindow_class)
|
let mut decl = ClassDecl::new("WinitUIWindow", uiwindow_class)
|
||||||
.expect("Failed to declare class `WinitUIWindow`");
|
.expect("Failed to declare class `WinitUIWindow`");
|
||||||
decl.add_method(sel!(becomeKeyWindow),
|
decl.add_method(
|
||||||
become_key_window as extern fn(&Object, Sel));
|
sel!(becomeKeyWindow),
|
||||||
decl.add_method(sel!(resignKeyWindow),
|
become_key_window as extern "C" fn(&Object, Sel),
|
||||||
resign_key_window as extern fn(&Object, Sel));
|
);
|
||||||
|
decl.add_method(
|
||||||
|
sel!(resignKeyWindow),
|
||||||
|
resign_key_window as extern "C" fn(&Object, Sel),
|
||||||
|
);
|
||||||
|
|
||||||
decl.add_method(sel!(touchesBegan:withEvent:),
|
decl.add_method(
|
||||||
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
|
sel!(touchesBegan:withEvent:),
|
||||||
decl.add_method(sel!(touchesMoved:withEvent:),
|
handle_touches as extern "C" fn(this: &Object, _: Sel, _: id, _: id),
|
||||||
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
|
);
|
||||||
decl.add_method(sel!(touchesEnded:withEvent:),
|
decl.add_method(
|
||||||
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
|
sel!(touchesMoved:withEvent:),
|
||||||
decl.add_method(sel!(touchesCancelled:withEvent:),
|
handle_touches as extern "C" fn(this: &Object, _: Sel, _: id, _: id),
|
||||||
handle_touches as extern 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:),
|
decl.add_method(
|
||||||
set_content_scale_factor as extern fn(&mut Object, Sel, CGFloat));
|
sel!(setContentScaleFactor:),
|
||||||
|
set_content_scale_factor as extern "C" fn(&mut Object, Sel, CGFloat),
|
||||||
|
);
|
||||||
|
|
||||||
CLASS = Some(decl.register());
|
CLASS = Some(decl.register());
|
||||||
}
|
}
|
||||||
|
@ -263,9 +299,9 @@ pub unsafe fn create_view(
|
||||||
|
|
||||||
let view: id = msg_send![class, alloc];
|
let view: id = msg_send![class, alloc];
|
||||||
assert!(!view.is_null(), "Failed to create `UIView` instance");
|
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");
|
assert!(!view.is_null(), "Failed to initialize `UIView` instance");
|
||||||
let () = msg_send![view, setMultipleTouchEnabled:YES];
|
let () = msg_send![view, setMultipleTouchEnabled: YES];
|
||||||
|
|
||||||
view
|
view
|
||||||
}
|
}
|
||||||
|
@ -279,9 +315,15 @@ pub unsafe fn create_view_controller(
|
||||||
let class = get_view_controller_class();
|
let class = get_view_controller_class();
|
||||||
|
|
||||||
let view_controller: id = msg_send![class, alloc];
|
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];
|
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 {
|
let status_bar_hidden = if window_attributes.decorations {
|
||||||
NO
|
NO
|
||||||
} else {
|
} else {
|
||||||
|
@ -292,9 +334,15 @@ pub unsafe fn create_view_controller(
|
||||||
platform_attributes.valid_orientations,
|
platform_attributes.valid_orientations,
|
||||||
idiom,
|
idiom,
|
||||||
);
|
);
|
||||||
let () = msg_send![view_controller, setPrefersStatusBarHidden:status_bar_hidden];
|
let () = msg_send![
|
||||||
let () = msg_send![view_controller, setSupportedInterfaceOrientations:supported_orientations];
|
view_controller,
|
||||||
let () = msg_send![view_controller, setView:view];
|
setPrefersStatusBarHidden: status_bar_hidden
|
||||||
|
];
|
||||||
|
let () = msg_send![
|
||||||
|
view_controller,
|
||||||
|
setSupportedInterfaceOrientations: supported_orientations
|
||||||
|
];
|
||||||
|
let () = msg_send![view_controller, setView: view];
|
||||||
view_controller
|
view_controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,11 +357,14 @@ pub unsafe fn create_window(
|
||||||
|
|
||||||
let window: id = msg_send![class, alloc];
|
let window: id = msg_send![class, alloc];
|
||||||
assert!(!window.is_null(), "Failed to create `UIWindow` instance");
|
assert!(!window.is_null(), "Failed to create `UIWindow` instance");
|
||||||
let window: id = msg_send![window, initWithFrame:frame];
|
let window: id = msg_send![window, initWithFrame: frame];
|
||||||
assert!(!window.is_null(), "Failed to initialize `UIWindow` instance");
|
assert!(
|
||||||
let () = msg_send![window, setRootViewController:view_controller];
|
!window.is_null(),
|
||||||
|
"Failed to initialize `UIWindow` instance"
|
||||||
|
);
|
||||||
|
let () = msg_send![window, setRootViewController: view_controller];
|
||||||
if let Some(hidpi_factor) = platform_attributes.hidpi_factor {
|
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 {
|
if let &Some(ref monitor) = &window_attributes.fullscreen {
|
||||||
let () = msg_send![window, setScreen:monitor.ui_screen()];
|
let () = msg_send![window, setScreen:monitor.ui_screen()];
|
||||||
|
@ -323,29 +374,25 @@ pub unsafe fn create_window(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_delegate_class() {
|
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 {
|
unsafe {
|
||||||
AppState::did_finish_launching();
|
AppState::did_finish_launching();
|
||||||
}
|
}
|
||||||
YES
|
YES
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn did_become_active(_: &Object, _: Sel, _: id) {
|
extern "C" fn did_become_active(_: &Object, _: Sel, _: id) {
|
||||||
unsafe {
|
unsafe { AppState::handle_nonuser_event(Event::Suspended(false)) }
|
||||||
AppState::handle_nonuser_event(Event::Suspended(false))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn will_resign_active(_: &Object, _: Sel, _: id) {
|
extern "C" fn will_resign_active(_: &Object, _: Sel, _: id) {
|
||||||
unsafe {
|
unsafe { AppState::handle_nonuser_event(Event::Suspended(true)) }
|
||||||
AppState::handle_nonuser_event(Event::Suspended(true))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn will_enter_foreground(_: &Object, _: Sel, _: id) {}
|
extern "C" fn will_enter_foreground(_: &Object, _: Sel, _: id) {}
|
||||||
extern fn did_enter_background(_: &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 {
|
unsafe {
|
||||||
let app: id = msg_send![class!(UIApplication), sharedApplication];
|
let app: id = msg_send![class!(UIApplication), sharedApplication];
|
||||||
let windows: id = msg_send![app, windows];
|
let windows: id = msg_send![app, windows];
|
||||||
|
@ -354,9 +401,9 @@ pub fn create_delegate_class() {
|
||||||
loop {
|
loop {
|
||||||
let window: id = msg_send![windows_enum, nextObject];
|
let window: id = msg_send![windows_enum, nextObject];
|
||||||
if window == nil {
|
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 {
|
if is_winit_window == YES {
|
||||||
events.push(Event::WindowEvent {
|
events.push(Event::WindowEvent {
|
||||||
window_id: RootWindowId(window.into()),
|
window_id: RootWindowId(window.into()),
|
||||||
|
@ -370,23 +417,36 @@ pub fn create_delegate_class() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let ui_responder = class!(UIResponder);
|
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 {
|
unsafe {
|
||||||
decl.add_method(sel!(application:didFinishLaunchingWithOptions:),
|
decl.add_method(
|
||||||
did_finish_launching as extern fn(&mut Object, Sel, id, id) -> BOOL);
|
sel!(application:didFinishLaunchingWithOptions:),
|
||||||
|
did_finish_launching as extern "C" fn(&mut Object, Sel, id, id) -> BOOL,
|
||||||
|
);
|
||||||
|
|
||||||
decl.add_method(sel!(applicationDidBecomeActive:),
|
decl.add_method(
|
||||||
did_become_active as extern fn(&Object, Sel, id));
|
sel!(applicationDidBecomeActive:),
|
||||||
decl.add_method(sel!(applicationWillResignActive:),
|
did_become_active as extern "C" fn(&Object, Sel, id),
|
||||||
will_resign_active as extern fn(&Object, Sel, id));
|
);
|
||||||
decl.add_method(sel!(applicationWillEnterForeground:),
|
decl.add_method(
|
||||||
will_enter_foreground as extern fn(&Object, Sel, id));
|
sel!(applicationWillResignActive:),
|
||||||
decl.add_method(sel!(applicationDidEnterBackground:),
|
will_resign_active as extern "C" fn(&Object, Sel, id),
|
||||||
did_enter_background as extern 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:),
|
decl.add_method(
|
||||||
will_terminate as extern fn(&Object, Sel, id));
|
sel!(applicationWillTerminate:),
|
||||||
|
will_terminate as extern "C" fn(&Object, Sel, id),
|
||||||
|
);
|
||||||
|
|
||||||
decl.register();
|
decl.register();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,35 +3,21 @@ use std::{
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
use objc::runtime::{Class, NO, Object, YES};
|
use objc::runtime::{Class, Object, NO, YES};
|
||||||
|
|
||||||
use crate::dpi::{self, LogicalPosition, LogicalSize};
|
use crate::{
|
||||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
dpi::{self, LogicalPosition, LogicalSize},
|
||||||
use crate::icon::Icon;
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
icon::Icon,
|
||||||
use crate::platform::ios::{MonitorHandleExtIOS, ValidOrientations};
|
monitor::MonitorHandle as RootMonitorHandle,
|
||||||
use crate::window::{
|
platform::ios::{MonitorHandleExtIOS, ValidOrientations},
|
||||||
CursorIcon,
|
platform_impl::platform::{
|
||||||
WindowAttributes,
|
|
||||||
};
|
|
||||||
use crate::platform_impl::{
|
|
||||||
platform::{
|
|
||||||
app_state::AppState,
|
app_state::AppState,
|
||||||
event_loop,
|
event_loop,
|
||||||
ffi::{
|
ffi::{id, CGFloat, CGPoint, CGRect, CGSize, UIEdgeInsets, UIInterfaceOrientationMask},
|
||||||
id,
|
monitor, view, EventLoopWindowTarget, MonitorHandle,
|
||||||
CGFloat,
|
|
||||||
CGPoint,
|
|
||||||
CGRect,
|
|
||||||
CGSize,
|
|
||||||
UIEdgeInsets,
|
|
||||||
UIInterfaceOrientationMask,
|
|
||||||
},
|
|
||||||
monitor,
|
|
||||||
view,
|
|
||||||
EventLoopWindowTarget,
|
|
||||||
MonitorHandle
|
|
||||||
},
|
},
|
||||||
|
window::{CursorIcon, WindowAttributes},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Inner {
|
pub struct Inner {
|
||||||
|
@ -59,10 +45,10 @@ impl Inner {
|
||||||
pub fn set_visible(&self, visible: bool) {
|
pub fn set_visible(&self, visible: bool) {
|
||||||
match visible {
|
match visible {
|
||||||
true => unsafe {
|
true => unsafe {
|
||||||
let () = msg_send![self.window, setHidden:NO];
|
let () = msg_send![self.window, setHidden: NO];
|
||||||
},
|
},
|
||||||
false => unsafe {
|
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,
|
size: screen_frame.size,
|
||||||
};
|
};
|
||||||
let bounds = self.from_screen_space(new_screen_frame);
|
let bounds = self.from_screen_space(new_screen_frame);
|
||||||
let () = msg_send![self.window, setBounds:bounds];
|
let () = msg_send![self.window, setBounds: bounds];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,10 +167,10 @@ impl Inner {
|
||||||
|
|
||||||
// this is pretty slow on iOS, so avoid doing it if we can
|
// this is pretty slow on iOS, so avoid doing it if we can
|
||||||
if uiscreen != current {
|
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"),
|
None => warn!("`Window::set_fullscreen(None)` ignored on iOS"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +199,10 @@ impl Inner {
|
||||||
pub fn set_decorations(&self, decorations: bool) {
|
pub fn set_decorations(&self, decorations: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let status_bar_hidden = if decorations { NO } else { YES };
|
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 {
|
pub fn current_monitor(&self) -> RootMonitorHandle {
|
||||||
unsafe {
|
unsafe {
|
||||||
let uiscreen: id = msg_send![self.window, screen];
|
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<MonitorHandle> {
|
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||||
unsafe {
|
unsafe { monitor::uiscreens() }
|
||||||
monitor::uiscreens()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary_monitor(&self) -> MonitorHandle {
|
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||||
unsafe {
|
unsafe { monitor::main_uiscreen() }
|
||||||
monitor::main_uiscreen()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> WindowId {
|
pub fn id(&self) -> WindowId {
|
||||||
|
@ -306,23 +293,35 @@ impl Window {
|
||||||
// TODO: transparency, visible
|
// TODO: transparency, visible
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let screen = window_attributes.fullscreen
|
let screen = window_attributes
|
||||||
|
.fullscreen
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|screen| screen.ui_screen() as _)
|
.map(|screen| screen.ui_screen() as _)
|
||||||
.unwrap_or_else(|| monitor::main_uiscreen().ui_screen());
|
.unwrap_or_else(|| monitor::main_uiscreen().ui_screen());
|
||||||
let screen_bounds: CGRect = msg_send![screen, bounds];
|
let screen_bounds: CGRect = msg_send![screen, bounds];
|
||||||
|
|
||||||
let frame = match window_attributes.inner_size {
|
let frame = match window_attributes.inner_size {
|
||||||
Some(dim) => CGRect {
|
Some(dim) => {
|
||||||
origin: screen_bounds.origin,
|
CGRect {
|
||||||
size: CGSize { width: dim.width, height: dim.height },
|
origin: screen_bounds.origin,
|
||||||
|
size: CGSize {
|
||||||
|
width: dim.width,
|
||||||
|
height: dim.height,
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => screen_bounds,
|
None => screen_bounds,
|
||||||
};
|
};
|
||||||
|
|
||||||
let view = view::create_view(&window_attributes, &platform_attributes, frame.clone());
|
let view = view::create_view(&window_attributes, &platform_attributes, frame.clone());
|
||||||
let view_controller = view::create_view_controller(&window_attributes, &platform_attributes, view);
|
let view_controller =
|
||||||
let window = view::create_window(&window_attributes, &platform_attributes, frame, 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;
|
let supports_safe_area = event_loop.capabilities().supports_safe_area;
|
||||||
|
|
||||||
|
@ -342,23 +341,38 @@ impl Window {
|
||||||
|
|
||||||
// WindowExtIOS
|
// WindowExtIOS
|
||||||
impl Inner {
|
impl Inner {
|
||||||
pub fn ui_window(&self) -> id { self.window }
|
pub fn ui_window(&self) -> id {
|
||||||
pub fn ui_view_controller(&self) -> id { self.view_controller }
|
self.window
|
||||||
pub fn ui_view(&self) -> id { self.view }
|
}
|
||||||
|
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) {
|
pub fn set_hidpi_factor(&self, hidpi_factor: f64) {
|
||||||
unsafe {
|
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 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) {
|
pub fn set_valid_orientations(&self, valid_orientations: ValidOrientations) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let idiom = event_loop::get_idiom();
|
let idiom = event_loop::get_idiom();
|
||||||
let supported_orientations = UIInterfaceOrientationMask::from_valid_orientations_idiom(valid_orientations, idiom);
|
let supported_orientations = UIInterfaceOrientationMask::from_valid_orientations_idiom(
|
||||||
msg_send![self.view_controller, setSupportedInterfaceOrientations:supported_orientations];
|
valid_orientations,
|
||||||
|
idiom,
|
||||||
|
);
|
||||||
|
msg_send![
|
||||||
|
self.view_controller,
|
||||||
|
setSupportedInterfaceOrientations: supported_orientations
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,14 +425,18 @@ impl Inner {
|
||||||
let screen_frame = self.to_screen_space(bounds);
|
let screen_frame = self.to_screen_space(bounds);
|
||||||
let status_bar_frame: CGRect = {
|
let status_bar_frame: CGRect = {
|
||||||
let app: id = msg_send![class!(UIApplication), sharedApplication];
|
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]
|
msg_send![app, statusBarFrame]
|
||||||
};
|
};
|
||||||
let (y, height) = if screen_frame.origin.y > status_bar_frame.size.height {
|
let (y, height) = if screen_frame.origin.y > status_bar_frame.size.height {
|
||||||
(screen_frame.origin.y, screen_frame.size.height)
|
(screen_frame.origin.y, screen_frame.size.height)
|
||||||
} else {
|
} else {
|
||||||
let y = status_bar_frame.size.height;
|
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)
|
(y, height)
|
||||||
};
|
};
|
||||||
CGRect {
|
CGRect {
|
||||||
|
@ -429,7 +447,7 @@ impl Inner {
|
||||||
size: CGSize {
|
size: CGSize {
|
||||||
width: screen_frame.size.width,
|
width: screen_frame.size.width,
|
||||||
height,
|
height,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,13 +471,17 @@ unsafe impl Sync for WindowId {}
|
||||||
|
|
||||||
impl From<&Object> for WindowId {
|
impl From<&Object> for WindowId {
|
||||||
fn from(window: &Object) -> WindowId {
|
fn from(window: &Object) -> WindowId {
|
||||||
WindowId { window: window as *const _ as _ }
|
WindowId {
|
||||||
|
window: window as *const _ as _,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&mut Object> for WindowId {
|
impl From<&mut Object> for WindowId {
|
||||||
fn from(window: &mut Object) -> WindowId {
|
fn from(window: &mut Object) -> WindowId {
|
||||||
WindowId { window: window as _ }
|
WindowId {
|
||||||
|
window: window as _,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||||
#![allow(dead_code)]
|
#![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_LAZY: c_int = 0x001;
|
||||||
pub const RTLD_NOW: c_int = 0x002;
|
pub const RTLD_NOW: c_int = 0x002;
|
||||||
|
|
||||||
#[link(name ="dl")]
|
#[link(name = "dl")]
|
||||||
extern {
|
extern "C" {
|
||||||
pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
|
pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
|
||||||
pub fn dlerror() -> *mut c_char;
|
pub fn dlerror() -> *mut c_char;
|
||||||
pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
|
pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
|
||||||
|
|
|
@ -1,24 +1,21 @@
|
||||||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::{collections::VecDeque, env, ffi::CStr, fmt, mem, os::raw::*, sync::Arc};
|
||||||
use std::{env, mem, fmt};
|
|
||||||
use std::ffi::CStr;
|
|
||||||
use std::os::raw::*;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smithay_client_toolkit::reexports::client::ConnectError;
|
use smithay_client_toolkit::reexports::client::ConnectError;
|
||||||
|
|
||||||
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
|
||||||
use crate::icon::Icon;
|
|
||||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
|
||||||
use crate::event::Event;
|
|
||||||
use crate::event_loop::{EventLoopClosed, ControlFlow, EventLoopWindowTarget as RootELW};
|
|
||||||
use crate::monitor::{MonitorHandle as RootMonitorHandle, VideoMode};
|
|
||||||
use crate::window::{WindowAttributes, CursorIcon};
|
|
||||||
use self::x11::{XConnection, XError};
|
|
||||||
use self::x11::ffi::XVisualInfo;
|
|
||||||
pub use self::x11::XNotSupported;
|
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;
|
mod dlopen;
|
||||||
pub mod wayland;
|
pub mod wayland;
|
||||||
|
@ -43,14 +40,13 @@ pub struct PlatformSpecificWindowBuilderAttributes {
|
||||||
pub override_redirect: bool,
|
pub override_redirect: bool,
|
||||||
pub x11_window_type: x11::util::WindowType,
|
pub x11_window_type: x11::util::WindowType,
|
||||||
pub gtk_theme_variant: Option<String>,
|
pub gtk_theme_variant: Option<String>,
|
||||||
pub app_id: Option<String>
|
pub app_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static!(
|
lazy_static! {
|
||||||
pub static ref X11_BACKEND: Mutex<Result<Arc<XConnection>, XNotSupported>> = {
|
pub static ref X11_BACKEND: Mutex<Result<Arc<XConnection>, XNotSupported>> =
|
||||||
Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new))
|
{ Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)) };
|
||||||
};
|
}
|
||||||
);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum OsError {
|
pub enum OsError {
|
||||||
|
@ -269,7 +265,7 @@ impl Window {
|
||||||
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.set_cursor_icon(cursor),
|
&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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +287,7 @@ impl Window {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn hidpi_factor(&self) -> f64 {
|
pub fn hidpi_factor(&self) -> f64 {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.hidpi_factor(),
|
&Window::X(ref w) => w.hidpi_factor(),
|
||||||
&Window::Wayland(ref w) => w.hidpi_factor() as f64,
|
&Window::Wayland(ref w) => w.hidpi_factor() as f64,
|
||||||
}
|
}
|
||||||
|
@ -317,8 +313,13 @@ impl Window {
|
||||||
pub fn fullscreen(&self) -> Option<RootMonitorHandle> {
|
pub fn fullscreen(&self) -> Option<RootMonitorHandle> {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.fullscreen(),
|
&Window::X(ref w) => w.fullscreen(),
|
||||||
&Window::Wayland(ref w) => w.fullscreen()
|
&Window::Wayland(ref w) => {
|
||||||
.map(|monitor_id| RootMonitorHandle { inner: MonitorHandle::Wayland(monitor_id) })
|
w.fullscreen().map(|monitor_id| {
|
||||||
|
RootMonitorHandle {
|
||||||
|
inner: MonitorHandle::Wayland(monitor_id),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +327,7 @@ impl Window {
|
||||||
pub fn set_fullscreen(&self, monitor: Option<RootMonitorHandle>) {
|
pub fn set_fullscreen(&self, monitor: Option<RootMonitorHandle>) {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.set_fullscreen(monitor),
|
&Window::X(ref w) => w.set_fullscreen(monitor),
|
||||||
&Window::Wayland(ref w) => w.set_fullscreen(monitor)
|
&Window::Wayland(ref w) => w.set_fullscreen(monitor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +335,7 @@ impl Window {
|
||||||
pub fn set_decorations(&self, decorations: bool) {
|
pub fn set_decorations(&self, decorations: bool) {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.set_decorations(decorations),
|
&Window::X(ref w) => w.set_decorations(decorations),
|
||||||
&Window::Wayland(ref w) => w.set_decorations(decorations)
|
&Window::Wayland(ref w) => w.set_decorations(decorations),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,22 +374,36 @@ impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_monitor(&self) -> RootMonitorHandle {
|
pub fn current_monitor(&self) -> RootMonitorHandle {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref window) => RootMonitorHandle { inner: MonitorHandle::X(window.current_monitor()) },
|
&Window::X(ref window) => {
|
||||||
&Window::Wayland(ref window) => RootMonitorHandle { inner: MonitorHandle::Wayland(window.current_monitor()) },
|
RootMonitorHandle {
|
||||||
|
inner: MonitorHandle::X(window.current_monitor()),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&Window::Wayland(ref window) => {
|
||||||
|
RootMonitorHandle {
|
||||||
|
inner: MonitorHandle::Wayland(window.current_monitor()),
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref window) => window.available_monitors()
|
&Window::X(ref window) => {
|
||||||
.into_iter()
|
window
|
||||||
.map(MonitorHandle::X)
|
.available_monitors()
|
||||||
.collect(),
|
.into_iter()
|
||||||
&Window::Wayland(ref window) => window.available_monitors()
|
.map(MonitorHandle::X)
|
||||||
.into_iter()
|
.collect()
|
||||||
.map(MonitorHandle::Wayland)
|
},
|
||||||
.collect(),
|
&Window::Wayland(ref window) => {
|
||||||
|
window
|
||||||
|
.available_monitors()
|
||||||
|
.into_iter()
|
||||||
|
.map(MonitorHandle::Wayland)
|
||||||
|
.collect()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +416,6 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsafe extern "C" fn x_error_callback(
|
unsafe extern "C" fn x_error_callback(
|
||||||
display: *mut x11::ffi::Display,
|
display: *mut x11::ffi::Display,
|
||||||
event: *mut x11::ffi::XErrorEvent,
|
event: *mut x11::ffi::XErrorEvent,
|
||||||
|
@ -432,10 +446,9 @@ unsafe extern "C" fn x_error_callback(
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub enum EventLoop<T: 'static> {
|
pub enum EventLoop<T: 'static> {
|
||||||
Wayland(wayland::EventLoop<T>),
|
Wayland(wayland::EventLoop<T>),
|
||||||
X(x11::EventLoop<T>)
|
X(x11::EventLoop<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -444,7 +457,7 @@ pub enum EventLoopProxy<T: 'static> {
|
||||||
Wayland(wayland::EventLoopProxy<T>),
|
Wayland(wayland::EventLoopProxy<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:'static> EventLoop<T> {
|
impl<T: 'static> EventLoop<T> {
|
||||||
pub fn new() -> EventLoop<T> {
|
pub fn new() -> EventLoop<T> {
|
||||||
if let Ok(env_var) = env::var(BACKEND_PREFERENCE_ENV_VAR) {
|
if let Ok(env_var) = env::var(BACKEND_PREFERENCE_ENV_VAR) {
|
||||||
match env_var.as_str() {
|
match env_var.as_str() {
|
||||||
|
@ -453,13 +466,14 @@ impl<T:'static> EventLoop<T> {
|
||||||
return EventLoop::new_x11().expect("Failed to initialize X11 backend");
|
return EventLoop::new_x11().expect("Failed to initialize X11 backend");
|
||||||
},
|
},
|
||||||
"wayland" => {
|
"wayland" => {
|
||||||
return EventLoop::new_wayland()
|
return EventLoop::new_wayland().expect("Failed to initialize Wayland backend");
|
||||||
.expect("Failed to initialize Wayland backend");
|
},
|
||||||
|
_ => {
|
||||||
|
panic!(
|
||||||
|
"Unknown environment variable value for {}, try one of `x11`,`wayland`",
|
||||||
|
BACKEND_PREFERENCE_ENV_VAR,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
_ => panic!(
|
|
||||||
"Unknown environment variable value for {}, try one of `x11`,`wayland`",
|
|
||||||
BACKEND_PREFERENCE_ENV_VAR,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,15 +489,13 @@ impl<T:'static> EventLoop<T> {
|
||||||
|
|
||||||
let err_string = format!(
|
let err_string = format!(
|
||||||
"Failed to initialize any backend! Wayland status: {:?} X11 status: {:?}",
|
"Failed to initialize any backend! Wayland status: {:?} X11 status: {:?}",
|
||||||
wayland_err,
|
wayland_err, x11_err,
|
||||||
x11_err,
|
|
||||||
);
|
);
|
||||||
panic!(err_string);
|
panic!(err_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_wayland() -> Result<EventLoop<T>, ConnectError> {
|
pub fn new_wayland() -> Result<EventLoop<T>, ConnectError> {
|
||||||
wayland::EventLoop::new()
|
wayland::EventLoop::new().map(EventLoop::Wayland)
|
||||||
.map(EventLoop::Wayland)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_x11() -> Result<EventLoop<T>, XNotSupported> {
|
pub fn new_x11() -> Result<EventLoop<T>, XNotSupported> {
|
||||||
|
@ -499,17 +511,19 @@ impl<T:'static> EventLoop<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||||
match *self {
|
match *self {
|
||||||
EventLoop::Wayland(ref evlp) => evlp
|
EventLoop::Wayland(ref evlp) => {
|
||||||
.available_monitors()
|
evlp.available_monitors()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(MonitorHandle::Wayland)
|
.map(MonitorHandle::Wayland)
|
||||||
.collect(),
|
.collect()
|
||||||
EventLoop::X(ref evlp) => evlp
|
},
|
||||||
.x_connection()
|
EventLoop::X(ref evlp) => {
|
||||||
.available_monitors()
|
evlp.x_connection()
|
||||||
.into_iter()
|
.available_monitors()
|
||||||
.map(MonitorHandle::X)
|
.into_iter()
|
||||||
.collect(),
|
.map(MonitorHandle::X)
|
||||||
|
.collect()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,20 +543,22 @@ impl<T:'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, callback: F)
|
pub fn run_return<F>(&mut self, callback: F)
|
||||||
where F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow)
|
where
|
||||||
|
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
EventLoop::Wayland(ref mut evlp) => evlp.run_return(callback),
|
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<F>(self, callback: F) -> !
|
pub fn run<F>(self, callback: F) -> !
|
||||||
where F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow)
|
where
|
||||||
|
F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
EventLoop::Wayland(evlp) => evlp.run(callback),
|
EventLoop::Wayland(evlp) => evlp.run(callback),
|
||||||
EventLoop::X(evlp) => evlp.run(callback)
|
EventLoop::X(evlp) => evlp.run(callback),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +573,7 @@ impl<T:'static> EventLoop<T> {
|
||||||
pub fn window_target(&self) -> &crate::event_loop::EventLoopWindowTarget<T> {
|
pub fn window_target(&self) -> &crate::event_loop::EventLoopWindowTarget<T> {
|
||||||
match *self {
|
match *self {
|
||||||
EventLoop::Wayland(ref evl) => evl.window_target(),
|
EventLoop::Wayland(ref evl) => evl.window_target(),
|
||||||
EventLoop::X(ref evl) => evl.window_target()
|
EventLoop::X(ref evl) => evl.window_target(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -573,12 +589,16 @@ impl<T: 'static> EventLoopProxy<T> {
|
||||||
|
|
||||||
pub enum EventLoopWindowTarget<T> {
|
pub enum EventLoopWindowTarget<T> {
|
||||||
Wayland(wayland::EventLoopWindowTarget<T>),
|
Wayland(wayland::EventLoopWindowTarget<T>),
|
||||||
X(x11::EventLoopWindowTarget<T>)
|
X(x11::EventLoopWindowTarget<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sticky_exit_callback<T, F>(
|
fn sticky_exit_callback<T, F>(
|
||||||
evt: Event<T>, target: &RootELW<T>, control_flow: &mut ControlFlow, callback: &mut F
|
evt: Event<T>,
|
||||||
) where F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow)
|
target: &RootELW<T>,
|
||||||
|
control_flow: &mut ControlFlow,
|
||||||
|
callback: &mut F,
|
||||||
|
) where
|
||||||
|
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
// make ControlFlow::Exit sticky by providing a dummy
|
// make ControlFlow::Exit sticky by providing a dummy
|
||||||
// control flow reference if it is already Exit.
|
// control flow reference if it is already Exit.
|
||||||
|
|
|
@ -1,25 +1,30 @@
|
||||||
use std::cell::RefCell;
|
use std::{
|
||||||
use std::collections::VecDeque;
|
cell::RefCell,
|
||||||
use std::fmt;
|
collections::VecDeque,
|
||||||
use std::rc::Rc;
|
fmt,
|
||||||
use std::sync::{Arc, Mutex};
|
rc::Rc,
|
||||||
use std::time::Instant;
|
sync::{Arc, Mutex},
|
||||||
|
time::Instant,
|
||||||
use crate::event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW};
|
};
|
||||||
use crate::event::ModifiersState;
|
|
||||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
use crate::{
|
||||||
use crate::platform_impl::platform::sticky_exit_callback;
|
dpi::{PhysicalPosition, PhysicalSize},
|
||||||
use crate::monitor::VideoMode;
|
event::ModifiersState,
|
||||||
|
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||||
use super::window::WindowStore;
|
monitor::VideoMode,
|
||||||
use super::WindowId;
|
platform_impl::platform::sticky_exit_callback,
|
||||||
|
};
|
||||||
use smithay_client_toolkit::output::OutputMgr;
|
|
||||||
use smithay_client_toolkit::reexports::client::protocol::{
|
use super::{window::WindowStore, WindowId};
|
||||||
wl_keyboard, wl_output, wl_pointer, wl_registry, wl_seat, wl_touch,
|
|
||||||
|
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,
|
||||||
};
|
};
|
||||||
use smithay_client_toolkit::reexports::client::{ConnectError, Display, EventQueue, GlobalEvent};
|
|
||||||
use smithay_client_toolkit::Environment;
|
|
||||||
|
|
||||||
pub struct WindowEventsSink {
|
pub struct WindowEventsSink {
|
||||||
buffer: VecDeque<(crate::event::WindowEvent, crate::window::WindowId)>,
|
buffer: VecDeque<(crate::event::WindowEvent, crate::window::WindowId)>,
|
||||||
|
@ -33,7 +38,10 @@ impl WindowEventsSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) {
|
pub fn send_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) {
|
||||||
self.buffer.push_back((evt, crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid))));
|
self.buffer.push_back((
|
||||||
|
evt,
|
||||||
|
crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid)),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty_with<F, T>(&mut self, mut callback: F)
|
fn empty_with<F, T>(&mut self, mut callback: F)
|
||||||
|
@ -41,7 +49,10 @@ impl WindowEventsSink {
|
||||||
F: FnMut(crate::event::Event<T>),
|
F: FnMut(crate::event::Event<T>),
|
||||||
{
|
{
|
||||||
for (evt, wid) in self.buffer.drain(..) {
|
for (evt, wid) in self.buffer.drain(..) {
|
||||||
callback(crate::event::Event::WindowEvent { event: evt, window_id: wid})
|
callback(crate::event::Event::WindowEvent {
|
||||||
|
event: evt,
|
||||||
|
window_id: wid,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,8 +69,10 @@ pub struct EventLoop<T: 'static> {
|
||||||
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
||||||
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
|
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
|
||||||
user_sender: ::calloop::channel::Sender<T>,
|
user_sender: ::calloop::channel::Sender<T>,
|
||||||
_kbd_source: ::calloop::Source<::calloop::channel::Channel<(crate::event::WindowEvent, super::WindowId)>>,
|
_kbd_source: ::calloop::Source<
|
||||||
window_target: RootELW<T>
|
::calloop::channel::Channel<(crate::event::WindowEvent, super::WindowId)>,
|
||||||
|
>,
|
||||||
|
window_target: RootELW<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A handle that can be sent across threads and used to wake up the `EventLoop`.
|
// A handle that can be sent across threads and used to wake up the `EventLoop`.
|
||||||
|
@ -67,7 +80,7 @@ pub struct EventLoop<T: 'static> {
|
||||||
// We should only try and wake up the `EventLoop` if it still exists, so we hold Weak ptrs.
|
// We should only try and wake up the `EventLoop` if it still exists, so we hold Weak ptrs.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
pub struct EventLoopProxy<T: 'static> {
|
||||||
user_sender: ::calloop::channel::Sender<T>
|
user_sender: ::calloop::channel::Sender<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoopWindowTarget<T> {
|
pub struct EventLoopWindowTarget<T> {
|
||||||
|
@ -83,7 +96,7 @@ pub struct EventLoopWindowTarget<T> {
|
||||||
pub display: Arc<Display>,
|
pub display: Arc<Display>,
|
||||||
// The list of seats
|
// The list of seats
|
||||||
pub seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
pub seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
||||||
_marker: ::std::marker::PhantomData<T>
|
_marker: ::std::marker::PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl<T: 'static> EventLoopProxy<T> {
|
||||||
|
@ -105,11 +118,14 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
let (kbd_sender, kbd_channel) = ::calloop::channel::channel();
|
let (kbd_sender, kbd_channel) = ::calloop::channel::channel();
|
||||||
let kbd_sink = sink.clone();
|
let kbd_sink = sink.clone();
|
||||||
let kbd_source = inner_loop.handle().insert_source(kbd_channel, move |evt, &mut()| {
|
let kbd_source = inner_loop
|
||||||
if let ::calloop::channel::Event::Msg((evt, wid)) = evt {
|
.handle()
|
||||||
kbd_sink.lock().unwrap().send_event(evt, wid);
|
.insert_source(kbd_channel, move |evt, &mut ()| {
|
||||||
}
|
if let ::calloop::channel::Event::Msg((evt, wid)) = evt {
|
||||||
}).unwrap();
|
kbd_sink.lock().unwrap().send_event(evt, wid);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut seat_manager = SeatManager {
|
let mut seat_manager = SeatManager {
|
||||||
sink: sink.clone(),
|
sink: sink.clone(),
|
||||||
|
@ -123,7 +139,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
&mut event_queue,
|
&mut event_queue,
|
||||||
move |event, registry| {
|
move |event, registry| {
|
||||||
match event {
|
match event {
|
||||||
GlobalEvent::New { id, ref interface, version } => {
|
GlobalEvent::New {
|
||||||
|
id,
|
||||||
|
ref interface,
|
||||||
|
version,
|
||||||
|
} => {
|
||||||
if interface == "wl_seat" {
|
if interface == "wl_seat" {
|
||||||
seat_manager.add_seat(id, version, registry)
|
seat_manager.add_seat(id, version, registry)
|
||||||
}
|
}
|
||||||
|
@ -135,20 +155,27 @@ impl<T: 'static> EventLoop<T> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
).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_events = Rc::new(RefCell::new(VecDeque::new()));
|
||||||
let pending_user_events2 = pending_user_events.clone();
|
let pending_user_events2 = pending_user_events.clone();
|
||||||
|
|
||||||
let (user_sender, user_channel) = ::calloop::channel::channel();
|
let (user_sender, user_channel) = ::calloop::channel::channel();
|
||||||
|
|
||||||
let user_source = inner_loop.handle().insert_source(user_channel, move |evt, &mut()| {
|
let user_source = inner_loop
|
||||||
if let ::calloop::channel::Event::Msg(msg) = evt {
|
.handle()
|
||||||
pending_user_events2.borrow_mut().push_back(msg);
|
.insert_source(user_channel, move |evt, &mut ()| {
|
||||||
}
|
if let ::calloop::channel::Event::Msg(msg) = evt {
|
||||||
}).unwrap();
|
pending_user_events2.borrow_mut().push_back(msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
Ok(EventLoop {
|
Ok(EventLoop {
|
||||||
inner_loop,
|
inner_loop,
|
||||||
|
@ -167,28 +194,30 @@ impl<T: 'static> EventLoop<T> {
|
||||||
cleanup_needed: Arc::new(Mutex::new(false)),
|
cleanup_needed: Arc::new(Mutex::new(false)),
|
||||||
seats,
|
seats,
|
||||||
display,
|
display,
|
||||||
_marker: ::std::marker::PhantomData
|
_marker: ::std::marker::PhantomData,
|
||||||
}),
|
}),
|
||||||
_marker: ::std::marker::PhantomData
|
_marker: ::std::marker::PhantomData,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||||
EventLoopProxy {
|
EventLoopProxy {
|
||||||
user_sender: self.user_sender.clone()
|
user_sender: self.user_sender.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<F>(mut self, callback: F) -> !
|
pub fn run<F>(mut self, callback: F) -> !
|
||||||
where F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow)
|
where
|
||||||
|
F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.run_return(callback);
|
self.run_return(callback);
|
||||||
::std::process::exit(0);
|
::std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, mut callback: F)
|
pub fn run_return<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow)
|
where
|
||||||
|
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
// send pending events to the server
|
// send pending events to the server
|
||||||
self.display.flush().expect("Wayland connection lost.");
|
self.display.flush().expect("Wayland connection lost.");
|
||||||
|
@ -198,7 +227,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let sink = self.sink.clone();
|
let sink = self.sink.clone();
|
||||||
let user_events = self.pending_user_events.clone();
|
let user_events = self.pending_user_events.clone();
|
||||||
|
|
||||||
callback(crate::event::Event::NewEvents(crate::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 {
|
loop {
|
||||||
self.post_dispatch_triggers();
|
self.post_dispatch_triggers();
|
||||||
|
@ -207,7 +240,12 @@ impl<T: 'static> EventLoop<T> {
|
||||||
{
|
{
|
||||||
let mut guard = sink.lock().unwrap();
|
let mut guard = sink.lock().unwrap();
|
||||||
guard.empty_with(|evt| {
|
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
|
// empty user events
|
||||||
|
@ -218,7 +256,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
crate::event::Event::UserEvent(evt),
|
crate::event::Event::UserEvent(evt),
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
&mut callback
|
&mut callback,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,7 +266,12 @@ impl<T: 'static> EventLoop<T> {
|
||||||
{
|
{
|
||||||
let mut guard = sink.lock().unwrap();
|
let mut guard = sink.lock().unwrap();
|
||||||
guard.empty_with(|evt| {
|
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
|
// send Events cleared
|
||||||
|
@ -237,7 +280,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
crate::event::Event::EventsCleared,
|
crate::event::Event::EventsCleared,
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
&mut callback
|
&mut callback,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,18 +291,24 @@ impl<T: 'static> EventLoop<T> {
|
||||||
ControlFlow::Exit => break,
|
ControlFlow::Exit => break,
|
||||||
ControlFlow::Poll => {
|
ControlFlow::Poll => {
|
||||||
// non-blocking dispatch
|
// non-blocking dispatch
|
||||||
self.inner_loop.dispatch(Some(::std::time::Duration::from_millis(0)), &mut ()).unwrap();
|
self.inner_loop
|
||||||
callback(crate::event::Event::NewEvents(crate::event::StartCause::Poll), &self.window_target, &mut control_flow);
|
.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 => {
|
ControlFlow::Wait => {
|
||||||
self.inner_loop.dispatch(None, &mut ()).unwrap();
|
self.inner_loop.dispatch(None, &mut ()).unwrap();
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
||||||
start: Instant::now(),
|
start: Instant::now(),
|
||||||
requested_resume: None
|
requested_resume: None,
|
||||||
}),
|
}),
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
ControlFlow::WaitUntil(deadline) => {
|
ControlFlow::WaitUntil(deadline) => {
|
||||||
|
@ -274,28 +323,36 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now < deadline {
|
if now < deadline {
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
crate::event::Event::NewEvents(
|
||||||
start,
|
crate::event::StartCause::WaitCancelled {
|
||||||
requested_resume: Some(deadline)
|
start,
|
||||||
}),
|
requested_resume: Some(deadline),
|
||||||
|
},
|
||||||
|
),
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::ResumeTimeReached {
|
crate::event::Event::NewEvents(
|
||||||
start,
|
crate::event::StartCause::ResumeTimeReached {
|
||||||
requested_resume: deadline
|
start,
|
||||||
}),
|
requested_resume: deadline,
|
||||||
|
},
|
||||||
|
),
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(crate::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 {
|
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||||
|
@ -324,7 +381,7 @@ impl<T> EventLoop<T> {
|
||||||
let mut sink = self.sink.lock().unwrap();
|
let mut sink = self.sink.lock().unwrap();
|
||||||
let window_target = match self.window_target.p {
|
let window_target = match self.window_target.p {
|
||||||
crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt,
|
crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt,
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
// prune possible dead windows
|
// prune possible dead windows
|
||||||
{
|
{
|
||||||
|
@ -355,7 +412,10 @@ impl<T> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(dpi) = new_dpi {
|
if let Some(dpi) = new_dpi {
|
||||||
sink.send_event(crate::event::WindowEvent::HiDpiFactorChanged(dpi as f64), wid);
|
sink.send_event(
|
||||||
|
crate::event::WindowEvent::HiDpiFactorChanged(dpi as f64),
|
||||||
|
wid,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if refresh {
|
if refresh {
|
||||||
sink.send_event(crate::event::WindowEvent::RedrawRequested, wid);
|
sink.send_event(crate::event::WindowEvent::RedrawRequested, wid);
|
||||||
|
@ -376,7 +436,7 @@ struct SeatManager {
|
||||||
sink: Arc<Mutex<WindowEventsSink>>,
|
sink: Arc<Mutex<WindowEventsSink>>,
|
||||||
store: Arc<Mutex<WindowStore>>,
|
store: Arc<Mutex<WindowStore>>,
|
||||||
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
||||||
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>
|
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SeatManager {
|
impl SeatManager {
|
||||||
|
@ -394,9 +454,7 @@ impl SeatManager {
|
||||||
};
|
};
|
||||||
let seat = registry
|
let seat = registry
|
||||||
.bind(min(version, 5), id, move |seat| {
|
.bind(min(version, 5), id, move |seat| {
|
||||||
seat.implement_closure(move |event, seat| {
|
seat.implement_closure(move |event, seat| seat_data.receive(event, seat), ())
|
||||||
seat_data.receive(event, seat)
|
|
||||||
}, ())
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.store.lock().unwrap().new_seat(&seat);
|
self.store.lock().unwrap().new_seat(&seat);
|
||||||
|
@ -479,7 +537,7 @@ impl SeatData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -566,7 +624,8 @@ impl MonitorHandle {
|
||||||
}) {
|
}) {
|
||||||
Some(Some((w, h))) => (w as u32, h as u32),
|
Some(Some((w, h))) => (w as u32, h as u32),
|
||||||
_ => (0, 0),
|
_ => (0, 0),
|
||||||
}.into()
|
}
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn position(&self) -> PhysicalPosition {
|
pub fn position(&self) -> PhysicalPosition {
|
||||||
|
@ -584,16 +643,17 @@ impl MonitorHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode>
|
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||||
{
|
|
||||||
self.mgr
|
self.mgr
|
||||||
.with_info(&self.proxy, |_, info| info.modes.clone())
|
.with_info(&self.proxy, |_, info| info.modes.clone())
|
||||||
.unwrap_or(vec![])
|
.unwrap_or(vec![])
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| VideoMode {
|
.map(|x| {
|
||||||
size: (x.dimensions.0 as u32, x.dimensions.1 as u32),
|
VideoMode {
|
||||||
refresh_rate: (x.refresh_rate as f32 / 1000.0).round() as u16,
|
size: (x.dimensions.0 as u32, x.dimensions.1 as u32),
|
||||||
bit_depth: 32
|
refresh_rate: (x.refresh_rate as f32 / 1000.0).round() as u16,
|
||||||
|
bit_depth: 32,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -614,9 +674,11 @@ pub fn primary_monitor(outputs: &OutputMgr) -> MonitorHandle {
|
||||||
pub fn available_monitors(outputs: &OutputMgr) -> VecDeque<MonitorHandle> {
|
pub fn available_monitors(outputs: &OutputMgr) -> VecDeque<MonitorHandle> {
|
||||||
outputs.with_all(|list| {
|
outputs.with_all(|list| {
|
||||||
list.iter()
|
list.iter()
|
||||||
.map(|&(_, ref proxy, _)| MonitorHandle {
|
.map(|&(_, ref proxy, _)| {
|
||||||
proxy: proxy.clone(),
|
MonitorHandle {
|
||||||
mgr: outputs.clone(),
|
proxy: proxy.clone(),
|
||||||
|
mgr: outputs.clone(),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use super::{make_wid, DeviceId};
|
use super::{make_wid, DeviceId};
|
||||||
use smithay_client_toolkit::keyboard::{
|
use smithay_client_toolkit::{
|
||||||
self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind,
|
keyboard::{
|
||||||
|
self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind,
|
||||||
|
},
|
||||||
|
reexports::client::protocol::{wl_keyboard, wl_seat},
|
||||||
};
|
};
|
||||||
use smithay_client_toolkit::reexports::client::protocol::{wl_keyboard, wl_seat};
|
|
||||||
|
|
||||||
use crate::event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent};
|
use crate::event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent};
|
||||||
|
|
||||||
|
@ -23,78 +25,92 @@ pub fn init_keyboard(
|
||||||
let ret = map_keyboard_auto_with_repeat(
|
let ret = map_keyboard_auto_with_repeat(
|
||||||
seat,
|
seat,
|
||||||
KeyRepeatKind::System,
|
KeyRepeatKind::System,
|
||||||
move |evt: KbEvent<'_>, _| match evt {
|
move |evt: KbEvent<'_>, _| {
|
||||||
KbEvent::Enter { surface, .. } => {
|
match evt {
|
||||||
let wid = make_wid(&surface);
|
KbEvent::Enter { surface, .. } => {
|
||||||
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
let wid = make_wid(&surface);
|
||||||
*target.lock().unwrap() = Some(wid);
|
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
||||||
}
|
*target.lock().unwrap() = Some(wid);
|
||||||
KbEvent::Leave { surface, .. } => {
|
},
|
||||||
let wid = make_wid(&surface);
|
KbEvent::Leave { surface, .. } => {
|
||||||
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
let wid = make_wid(&surface);
|
||||||
*target.lock().unwrap() = None;
|
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
||||||
}
|
*target.lock().unwrap() = None;
|
||||||
KbEvent::Key {
|
},
|
||||||
rawkey,
|
KbEvent::Key {
|
||||||
keysym,
|
rawkey,
|
||||||
state,
|
keysym,
|
||||||
utf8,
|
state,
|
||||||
..
|
utf8,
|
||||||
} => {
|
..
|
||||||
if let Some(wid) = *target.lock().unwrap() {
|
} => {
|
||||||
let state = match state {
|
if let Some(wid) = *target.lock().unwrap() {
|
||||||
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
let state = match state {
|
||||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||||
_ => unreachable!(),
|
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||||
};
|
_ => unreachable!(),
|
||||||
let vkcode = key_to_vkey(rawkey, keysym);
|
};
|
||||||
my_sink.send(
|
let vkcode = key_to_vkey(rawkey, keysym);
|
||||||
(WindowEvent::KeyboardInput {
|
my_sink
|
||||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
.send((
|
||||||
input: KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
state: state,
|
device_id: crate::event::DeviceId(
|
||||||
scancode: rawkey,
|
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||||
virtual_keycode: vkcode,
|
),
|
||||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
input: KeyboardInput {
|
||||||
},
|
state,
|
||||||
},
|
scancode: rawkey,
|
||||||
wid)
|
virtual_keycode: vkcode,
|
||||||
).unwrap();
|
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||||
// send char event only on key press, not release
|
},
|
||||||
if let ElementState::Released = state {
|
},
|
||||||
return;
|
wid,
|
||||||
}
|
))
|
||||||
if let Some(txt) = utf8 {
|
.unwrap();
|
||||||
for chr in txt.chars() {
|
// send char event only on key press, not release
|
||||||
my_sink.send((WindowEvent::ReceivedCharacter(chr), wid)).unwrap();
|
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, _| {
|
move |repeat_event: KeyRepeatEvent, _| {
|
||||||
if let Some(wid) = *repeat_target.lock().unwrap() {
|
if let Some(wid) = *repeat_target.lock().unwrap() {
|
||||||
let state = ElementState::Pressed;
|
let state = ElementState::Pressed;
|
||||||
let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym);
|
let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym);
|
||||||
repeat_sink.send((
|
repeat_sink
|
||||||
WindowEvent::KeyboardInput {
|
.send((
|
||||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
WindowEvent::KeyboardInput {
|
||||||
input: KeyboardInput {
|
device_id: crate::event::DeviceId(
|
||||||
state: state,
|
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||||
scancode: repeat_event.rawkey,
|
),
|
||||||
virtual_keycode: vkcode,
|
input: KeyboardInput {
|
||||||
modifiers: my_modifiers.lock().unwrap().clone(),
|
state,
|
||||||
|
scancode: repeat_event.rawkey,
|
||||||
|
virtual_keycode: vkcode,
|
||||||
|
modifiers: my_modifiers.lock().unwrap().clone(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
wid,
|
||||||
wid)
|
))
|
||||||
).unwrap();
|
.unwrap();
|
||||||
if let Some(txt) = repeat_event.utf8 {
|
if let Some(txt) = repeat_event.utf8 {
|
||||||
for chr in txt.chars() {
|
for chr in txt.chars() {
|
||||||
repeat_sink.send((WindowEvent::ReceivedCharacter(chr), wid)).unwrap();
|
repeat_sink
|
||||||
|
.send((WindowEvent::ReceivedCharacter(chr), wid))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,42 +132,54 @@ pub fn init_keyboard(
|
||||||
let my_sink = sink;
|
let my_sink = sink;
|
||||||
// }
|
// }
|
||||||
seat.get_keyboard(|keyboard| {
|
seat.get_keyboard(|keyboard| {
|
||||||
keyboard.implement_closure(move |evt, _| match evt {
|
keyboard.implement_closure(
|
||||||
wl_keyboard::Event::Enter { surface, .. } => {
|
move |evt, _| {
|
||||||
let wid = make_wid(&surface);
|
match evt {
|
||||||
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
wl_keyboard::Event::Enter { surface, .. } => {
|
||||||
target = Some(wid);
|
let wid = make_wid(&surface);
|
||||||
}
|
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
||||||
wl_keyboard::Event::Leave { surface, .. } => {
|
target = Some(wid);
|
||||||
let wid = make_wid(&surface);
|
},
|
||||||
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
wl_keyboard::Event::Leave { surface, .. } => {
|
||||||
target = None;
|
let wid = make_wid(&surface);
|
||||||
}
|
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
||||||
wl_keyboard::Event::Key { key, state, .. } => {
|
target = None;
|
||||||
if let Some(wid) = target {
|
},
|
||||||
let state = match state {
|
wl_keyboard::Event::Key { key, state, .. } => {
|
||||||
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
if let Some(wid) = target {
|
||||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
let state = match state {
|
||||||
_ => unreachable!()
|
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||||
};
|
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||||
my_sink.send((
|
_ => unreachable!(),
|
||||||
WindowEvent::KeyboardInput {
|
};
|
||||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
my_sink
|
||||||
input: KeyboardInput {
|
.send((
|
||||||
state: state,
|
WindowEvent::KeyboardInput {
|
||||||
scancode: key,
|
device_id: crate::event::DeviceId(
|
||||||
virtual_keycode: None,
|
crate::platform_impl::DeviceId::Wayland(
|
||||||
modifiers: ModifiersState::default(),
|
DeviceId,
|
||||||
},
|
),
|
||||||
},
|
),
|
||||||
wid,
|
input: KeyboardInput {
|
||||||
)).unwrap();
|
state,
|
||||||
|
scancode: key,
|
||||||
|
virtual_keycode: None,
|
||||||
|
modifiers: ModifiersState::default(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wid,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => (),
|
(),
|
||||||
}, ())
|
)
|
||||||
}).unwrap()
|
})
|
||||||
}
|
.unwrap()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd",
|
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd",
|
||||||
target_os = "netbsd", target_os = "openbsd"))]
|
target_os = "netbsd", target_os = "openbsd"))]
|
||||||
|
|
||||||
pub use self::window::Window;
|
pub use self::{
|
||||||
pub use self::event_loop::{EventLoop, EventLoopWindowTarget, EventLoopProxy, WindowEventsSink, MonitorHandle};
|
event_loop::{
|
||||||
|
EventLoop, EventLoopProxy, EventLoopWindowTarget, MonitorHandle, WindowEventsSink,
|
||||||
|
},
|
||||||
|
window::Window,
|
||||||
|
};
|
||||||
|
|
||||||
use smithay_client_toolkit::reexports::client::protocol::wl_surface;
|
use smithay_client_toolkit::reexports::client::protocol::wl_surface;
|
||||||
|
|
||||||
mod event_loop;
|
mod event_loop;
|
||||||
|
mod keyboard;
|
||||||
mod pointer;
|
mod pointer;
|
||||||
mod touch;
|
mod touch;
|
||||||
mod keyboard;
|
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent, ModifiersState};
|
use crate::event::{
|
||||||
|
ElementState, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent,
|
||||||
|
};
|
||||||
|
|
||||||
use super::DeviceId;
|
use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId};
|
||||||
use super::event_loop::WindowEventsSink;
|
|
||||||
use super::window::WindowStore;
|
|
||||||
|
|
||||||
use smithay_client_toolkit::reexports::client::protocol::wl_pointer::{self, Event as PtrEvent, WlPointer};
|
use smithay_client_toolkit::reexports::client::protocol::{
|
||||||
use smithay_client_toolkit::reexports::client::protocol::wl_seat;
|
wl_pointer::{self, Event as PtrEvent, WlPointer},
|
||||||
|
wl_seat,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn implement_pointer(
|
pub fn implement_pointer(
|
||||||
seat: &wl_seat::WlSeat,
|
seat: &wl_seat::WlSeat,
|
||||||
|
@ -21,171 +23,195 @@ pub fn implement_pointer(
|
||||||
let mut axis_state = TouchPhase::Ended;
|
let mut axis_state = TouchPhase::Ended;
|
||||||
|
|
||||||
seat.get_pointer(|pointer| {
|
seat.get_pointer(|pointer| {
|
||||||
pointer.implement_closure(move |evt, pointer| {
|
pointer.implement_closure(
|
||||||
let mut sink = sink.lock().unwrap();
|
move |evt, pointer| {
|
||||||
let store = store.lock().unwrap();
|
let mut sink = sink.lock().unwrap();
|
||||||
match evt {
|
let store = store.lock().unwrap();
|
||||||
PtrEvent::Enter {
|
match evt {
|
||||||
surface,
|
PtrEvent::Enter {
|
||||||
surface_x,
|
surface,
|
||||||
surface_y,
|
surface_x,
|
||||||
..
|
surface_y,
|
||||||
} => {
|
..
|
||||||
let wid = store.find_wid(&surface);
|
} => {
|
||||||
if let Some(wid) = wid {
|
let wid = store.find_wid(&surface);
|
||||||
mouse_focus = Some(wid);
|
if let Some(wid) = wid {
|
||||||
sink.send_event(
|
mouse_focus = Some(wid);
|
||||||
WindowEvent::CursorEntered {
|
|
||||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
|
||||||
},
|
|
||||||
wid,
|
|
||||||
);
|
|
||||||
sink.send_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::Leave { surface, .. } => {
|
|
||||||
mouse_focus = None;
|
|
||||||
let wid = store.find_wid(&surface);
|
|
||||||
if let Some(wid) = wid {
|
|
||||||
sink.send_event(
|
|
||||||
WindowEvent::CursorLeft {
|
|
||||||
device_id: crate::event::DeviceId(crate::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: crate::event::DeviceId(crate::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: crate::event::DeviceId(crate::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(
|
sink.send_event(
|
||||||
WindowEvent::MouseWheel {
|
WindowEvent::CursorEntered {
|
||||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
device_id: crate::event::DeviceId(
|
||||||
delta: MouseScrollDelta::PixelDelta((x as f64, y as f64).into()),
|
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||||
phase: TouchPhase::Moved,
|
),
|
||||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
|
||||||
},
|
},
|
||||||
wid,
|
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(
|
sink.send_event(
|
||||||
WindowEvent::MouseWheel {
|
WindowEvent::CursorMoved {
|
||||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
device_id: crate::event::DeviceId(
|
||||||
delta: MouseScrollDelta::LineDelta(x as f32, y as f32),
|
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||||
phase: axis_state,
|
),
|
||||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
position: (surface_x, surface_y).into(),
|
||||||
},
|
|
||||||
wid,
|
|
||||||
);
|
|
||||||
} else if let Some((x, y)) = axis_buffer {
|
|
||||||
sink.send_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(),
|
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||||
},
|
},
|
||||||
wid,
|
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: crate::event::DeviceId(
|
||||||
|
crate::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: crate::event::DeviceId(
|
||||||
|
crate::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: 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_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_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_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!(),
|
||||||
}
|
}
|
||||||
PtrEvent::AxisSource { .. } => (),
|
},
|
||||||
PtrEvent::AxisStop { .. } => {
|
(),
|
||||||
axis_state = TouchPhase::Ended;
|
)
|
||||||
}
|
})
|
||||||
PtrEvent::AxisDiscrete { axis, discrete } => {
|
.unwrap()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::event::{TouchPhase, WindowEvent};
|
use crate::event::{TouchPhase, WindowEvent};
|
||||||
|
|
||||||
use super::{DeviceId, WindowId};
|
use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId, WindowId};
|
||||||
use super::event_loop::WindowEventsSink;
|
|
||||||
use super::window::WindowStore;
|
|
||||||
|
|
||||||
use smithay_client_toolkit::reexports::client::protocol::wl_touch::{Event as TouchEvent, WlTouch};
|
use smithay_client_toolkit::reexports::client::protocol::{
|
||||||
use smithay_client_toolkit::reexports::client::protocol::wl_seat;
|
wl_seat,
|
||||||
|
wl_touch::{Event as TouchEvent, WlTouch},
|
||||||
|
};
|
||||||
|
|
||||||
struct TouchPoint {
|
struct TouchPoint {
|
||||||
wid: WindowId,
|
wid: WindowId,
|
||||||
|
@ -22,75 +22,89 @@ pub(crate) fn implement_touch(
|
||||||
) -> WlTouch {
|
) -> WlTouch {
|
||||||
let mut pending_ids = Vec::new();
|
let mut pending_ids = Vec::new();
|
||||||
seat.get_touch(|touch| {
|
seat.get_touch(|touch| {
|
||||||
touch.implement_closure(move |evt, _| {
|
touch.implement_closure(
|
||||||
let mut sink = sink.lock().unwrap();
|
move |evt, _| {
|
||||||
let store = store.lock().unwrap();
|
let mut sink = sink.lock().unwrap();
|
||||||
match evt {
|
let store = store.lock().unwrap();
|
||||||
TouchEvent::Down {
|
match evt {
|
||||||
surface, id, x, y, ..
|
TouchEvent::Down {
|
||||||
} => {
|
surface, id, x, y, ..
|
||||||
let wid = store.find_wid(&surface);
|
} => {
|
||||||
if let Some(wid) = wid {
|
let wid = store.find_wid(&surface);
|
||||||
sink.send_event(
|
if let Some(wid) = wid {
|
||||||
WindowEvent::Touch(crate::event::Touch {
|
sink.send_event(
|
||||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
WindowEvent::Touch(crate::event::Touch {
|
||||||
phase: TouchPhase::Started,
|
device_id: crate::event::DeviceId(
|
||||||
location: (x, y).into(),
|
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||||
id: id as u64,
|
),
|
||||||
}),
|
phase: TouchPhase::Started,
|
||||||
wid,
|
location: (x, y).into(),
|
||||||
);
|
id: id as u64,
|
||||||
pending_ids.push(TouchPoint {
|
}),
|
||||||
wid: wid,
|
wid,
|
||||||
location: (x, y),
|
);
|
||||||
id: id,
|
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(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(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_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::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(
|
.unwrap()
|
||||||
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(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_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!()
|
|
||||||
}
|
|
||||||
}, ())
|
|
||||||
}).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,29 @@
|
||||||
use std::collections::VecDeque;
|
use std::{
|
||||||
use std::io::{Seek, SeekFrom, Write};
|
collections::VecDeque,
|
||||||
use std::sync::{Arc, Mutex, Weak};
|
io::{Seek, SeekFrom, Write},
|
||||||
|
sync::{Arc, Mutex, Weak},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::dpi::{LogicalPosition, LogicalSize};
|
use crate::{
|
||||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
dpi::{LogicalPosition, LogicalSize},
|
||||||
use crate::platform_impl::{MonitorHandle as PlatformMonitorHandle, PlatformSpecificWindowBuilderAttributes as PlAttributes};
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
monitor::MonitorHandle as RootMonitorHandle,
|
||||||
use crate::window::{WindowAttributes, CursorIcon};
|
platform_impl::{
|
||||||
|
MonitorHandle as PlatformMonitorHandle,
|
||||||
|
PlatformSpecificWindowBuilderAttributes as PlAttributes,
|
||||||
|
},
|
||||||
|
window::{CursorIcon, WindowAttributes},
|
||||||
|
};
|
||||||
|
|
||||||
use smithay_client_toolkit::surface::{get_dpi_factor, get_outputs};
|
use smithay_client_toolkit::{
|
||||||
use smithay_client_toolkit::window::{ConceptFrame, Event as WEvent, State as WState, Window as SWindow, Theme};
|
output::OutputMgr,
|
||||||
use smithay_client_toolkit::reexports::client::{Display, NewProxy};
|
reexports::client::{
|
||||||
use smithay_client_toolkit::reexports::client::protocol::{wl_seat, wl_surface, wl_subsurface, wl_shm};
|
protocol::{wl_seat, wl_shm, wl_subsurface, wl_surface},
|
||||||
use smithay_client_toolkit::output::OutputMgr;
|
Display, NewProxy,
|
||||||
|
},
|
||||||
|
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 super::{make_wid, EventLoopWindowTarget, MonitorHandle, WindowId};
|
||||||
use crate::platform_impl::platform::wayland::event_loop::{available_monitors, primary_monitor};
|
use crate::platform_impl::platform::wayland::event_loop::{available_monitors, primary_monitor};
|
||||||
|
@ -32,7 +43,11 @@ pub struct Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new<T>(evlp: &EventLoopWindowTarget<T>, attributes: WindowAttributes, pl_attribs: PlAttributes) -> Result<Window, RootOsError> {
|
pub fn new<T>(
|
||||||
|
evlp: &EventLoopWindowTarget<T>,
|
||||||
|
attributes: WindowAttributes,
|
||||||
|
pl_attribs: PlAttributes,
|
||||||
|
) -> Result<Window, RootOsError> {
|
||||||
let (width, height) = attributes.inner_size.map(Into::into).unwrap_or((800, 600));
|
let (width, height) = attributes.inner_size.map(Into::into).unwrap_or((800, 600));
|
||||||
// Create the window
|
// Create the window
|
||||||
let size = Arc::new(Mutex::new((width, height)));
|
let size = Arc::new(Mutex::new((width, height)));
|
||||||
|
@ -71,47 +86,50 @@ impl Window {
|
||||||
&evlp.env,
|
&evlp.env,
|
||||||
bg_surface.clone(),
|
bg_surface.clone(),
|
||||||
(width, height),
|
(width, height),
|
||||||
move |event| match event {
|
move |event| {
|
||||||
WEvent::Configure { new_size, states } => {
|
match event {
|
||||||
let mut store = window_store.lock().unwrap();
|
WEvent::Configure { new_size, states } => {
|
||||||
let is_fullscreen = states.contains(&WState::Fullscreen);
|
let mut store = window_store.lock().unwrap();
|
||||||
|
let is_fullscreen = states.contains(&WState::Fullscreen);
|
||||||
|
|
||||||
for window in &mut store.windows {
|
for window in &mut store.windows {
|
||||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||||
window.newsize = new_size;
|
window.newsize = new_size;
|
||||||
*(window.need_refresh.lock().unwrap()) = true;
|
*(window.need_refresh.lock().unwrap()) = true;
|
||||||
*(window.fullscreen.lock().unwrap()) = is_fullscreen;
|
*(window.fullscreen.lock().unwrap()) = is_fullscreen;
|
||||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||||
if !window.configured {
|
if !window.configured {
|
||||||
// this is our first configure event, display ourselves !
|
// this is our first configure event, display ourselves !
|
||||||
window.configured = true;
|
window.configured = true;
|
||||||
my_bg_surface.attach(Some(&buffer), 0, 0);
|
my_bg_surface.attach(Some(&buffer), 0, 0);
|
||||||
my_bg_surface.commit();
|
my_bg_surface.commit();
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
WEvent::Refresh => {
|
||||||
WEvent::Refresh => {
|
let store = window_store.lock().unwrap();
|
||||||
let store = window_store.lock().unwrap();
|
for window in &store.windows {
|
||||||
for window in &store.windows {
|
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
WEvent::Close => {
|
||||||
WEvent::Close => {
|
let mut store = window_store.lock().unwrap();
|
||||||
let mut store = window_store.lock().unwrap();
|
for window in &mut store.windows {
|
||||||
for window in &mut store.windows {
|
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
window.closed = true;
|
||||||
window.closed = true;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
if let Some(app_id) = pl_attribs.app_id {
|
if let Some(app_id) = pl_attribs.app_id {
|
||||||
frame.set_app_id(app_id);
|
frame.set_app_id(app_id);
|
||||||
|
@ -166,11 +184,11 @@ impl Window {
|
||||||
Ok(Window {
|
Ok(Window {
|
||||||
display: evlp.display.clone(),
|
display: evlp.display.clone(),
|
||||||
_bg_surface: bg_surface,
|
_bg_surface: bg_surface,
|
||||||
user_surface: user_surface,
|
user_surface,
|
||||||
_user_subsurface: user_subsurface,
|
_user_subsurface: user_subsurface,
|
||||||
frame: frame,
|
frame,
|
||||||
outputs: evlp.env.outputs.clone(),
|
outputs: evlp.env.outputs.clone(),
|
||||||
size: size,
|
size,
|
||||||
kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
|
kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
|
||||||
need_frame_refresh,
|
need_frame_refresh,
|
||||||
need_refresh,
|
need_refresh,
|
||||||
|
@ -231,12 +249,18 @@ impl Window {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_min_inner_size(&self, dimensions: Option<LogicalSize>) {
|
pub fn set_min_inner_size(&self, dimensions: Option<LogicalSize>) {
|
||||||
self.frame.lock().unwrap().set_min_size(dimensions.map(Into::into));
|
self.frame
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_min_size(dimensions.map(Into::into));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_max_inner_size(&self, dimensions: Option<LogicalSize>) {
|
pub fn set_max_inner_size(&self, dimensions: Option<LogicalSize>) {
|
||||||
self.frame.lock().unwrap().set_max_size(dimensions.map(Into::into));
|
self.frame
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_max_size(dimensions.map(Into::into));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -412,7 +436,16 @@ impl WindowStore {
|
||||||
|
|
||||||
pub fn for_each<F>(&mut self, mut f: F)
|
pub fn for_each<F>(&mut self, mut f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(Option<(u32, u32)>, &mut (u32, u32), Option<i32>, bool, bool, bool, WindowId, Option<&mut SWindow<ConceptFrame>>),
|
F: FnMut(
|
||||||
|
Option<(u32, u32)>,
|
||||||
|
&mut (u32, u32),
|
||||||
|
Option<i32>,
|
||||||
|
bool,
|
||||||
|
bool,
|
||||||
|
bool,
|
||||||
|
WindowId,
|
||||||
|
Option<&mut SWindow<ConceptFrame>>,
|
||||||
|
),
|
||||||
{
|
{
|
||||||
for window in &mut self.windows {
|
for window in &mut self.windows {
|
||||||
let opt_arc = window.frame.upgrade();
|
let opt_arc = window.frame.upgrade();
|
||||||
|
@ -435,4 +468,3 @@ impl WindowStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use std::io;
|
use std::{
|
||||||
use std::sync::Arc;
|
io,
|
||||||
use std::path::{Path, PathBuf};
|
os::raw::*,
|
||||||
use std::str::Utf8Error;
|
path::{Path, PathBuf},
|
||||||
use std::os::raw::*;
|
str::Utf8Error,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use percent_encoding::percent_decode;
|
use percent_encoding::percent_decode;
|
||||||
|
|
||||||
|
@ -127,13 +129,15 @@ impl Dnd {
|
||||||
DndState::Accepted => (1, self.atoms.action_private as c_long),
|
DndState::Accepted => (1, self.atoms.action_private as c_long),
|
||||||
DndState::Rejected => (0, self.atoms.none as c_long),
|
DndState::Rejected => (0, self.atoms.none as c_long),
|
||||||
};
|
};
|
||||||
self.xconn.send_client_msg(
|
self.xconn
|
||||||
target_window,
|
.send_client_msg(
|
||||||
target_window,
|
target_window,
|
||||||
self.atoms.status,
|
target_window,
|
||||||
None,
|
self.atoms.status,
|
||||||
[this_window as c_long, accepted, 0, 0, action],
|
None,
|
||||||
).flush()
|
[this_window as c_long, accepted, 0, 0, action],
|
||||||
|
)
|
||||||
|
.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn send_finished(
|
pub unsafe fn send_finished(
|
||||||
|
@ -146,24 +150,23 @@ impl Dnd {
|
||||||
DndState::Accepted => (1, self.atoms.action_private as c_long),
|
DndState::Accepted => (1, self.atoms.action_private as c_long),
|
||||||
DndState::Rejected => (0, self.atoms.none as c_long),
|
DndState::Rejected => (0, self.atoms.none as c_long),
|
||||||
};
|
};
|
||||||
self.xconn.send_client_msg(
|
self.xconn
|
||||||
target_window,
|
.send_client_msg(
|
||||||
target_window,
|
target_window,
|
||||||
self.atoms.finished,
|
target_window,
|
||||||
None,
|
self.atoms.finished,
|
||||||
[this_window as c_long, accepted, action, 0, 0],
|
None,
|
||||||
).flush()
|
[this_window as c_long, accepted, action, 0, 0],
|
||||||
|
)
|
||||||
|
.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn get_type_list(
|
pub unsafe fn get_type_list(
|
||||||
&self,
|
&self,
|
||||||
source_window: c_ulong,
|
source_window: c_ulong,
|
||||||
) -> Result<Vec<ffi::Atom>, util::GetPropertyError> {
|
) -> Result<Vec<ffi::Atom>, util::GetPropertyError> {
|
||||||
self.xconn.get_property(
|
self.xconn
|
||||||
source_window,
|
.get_property(source_window, self.atoms.type_list, ffi::XA_ATOM)
|
||||||
self.atoms.type_list,
|
|
||||||
ffi::XA_ATOM,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn convert_selection(&self, window: c_ulong, time: c_ulong) {
|
pub unsafe fn convert_selection(&self, window: c_ulong, time: c_ulong) {
|
||||||
|
@ -181,11 +184,8 @@ impl Dnd {
|
||||||
&self,
|
&self,
|
||||||
window: c_ulong,
|
window: c_ulong,
|
||||||
) -> Result<Vec<c_uchar>, util::GetPropertyError> {
|
) -> Result<Vec<c_uchar>, util::GetPropertyError> {
|
||||||
self.xconn.get_property(
|
self.xconn
|
||||||
window,
|
.get_property(window, self.atoms.selection, self.atoms.uri_list)
|
||||||
self.atoms.selection,
|
|
||||||
self.atoms.uri_list,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_data(&self, data: &mut Vec<c_uchar>) -> Result<Vec<PathBuf>, DndDataParseError> {
|
pub fn parse_data(&self, data: &mut Vec<c_uchar>) -> Result<Vec<PathBuf>, DndDataParseError> {
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
use std::cell::RefCell;
|
use std::{cell::RefCell, collections::HashMap, ptr, rc::Rc, slice};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ptr;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::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::{
|
use super::{
|
||||||
mkdid, mkwid, get_xtarget, DeviceId, WindowId, Device, ImeReceiver, XExtension,
|
events, ffi, get_xtarget, mkdid, mkwid, monitor, util, Device, DeviceId, DeviceInfo, Dnd,
|
||||||
monitor, ffi, UnownedWindow, ScrollOrientation, GenericEventCookie,
|
DndState, GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
|
||||||
events, util, DndState, Dnd, DeviceInfo
|
XExtension,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::event_loop::EventLoopWindowTarget as RootELW;
|
use crate::{
|
||||||
use crate::event::{DeviceEvent, Event, KeyboardInput, ModifiersState, WindowEvent};
|
dpi::{LogicalPosition, LogicalSize},
|
||||||
use crate::dpi::{LogicalPosition,LogicalSize};
|
event::{DeviceEvent, Event, KeyboardInput, ModifiersState, WindowEvent},
|
||||||
|
event_loop::EventLoopWindowTarget as RootELW,
|
||||||
|
};
|
||||||
|
|
||||||
pub(super) struct EventProcessor<T: 'static> {
|
pub(super) struct EventProcessor<T: 'static> {
|
||||||
pub(super) dnd: Dnd,
|
pub(super) dnd: Dnd,
|
||||||
|
@ -22,7 +20,7 @@ pub(super) struct EventProcessor<T: 'static> {
|
||||||
pub(super) randr_event_offset: c_int,
|
pub(super) randr_event_offset: c_int,
|
||||||
pub(super) devices: RefCell<HashMap<DeviceId, Device>>,
|
pub(super) devices: RefCell<HashMap<DeviceId, Device>>,
|
||||||
pub(super) xi2ext: XExtension,
|
pub(super) xi2ext: XExtension,
|
||||||
pub(super) target: Rc<RootELW<T>>
|
pub(super) target: Rc<RootELW<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventProcessor<T> {
|
impl<T: 'static> EventProcessor<T> {
|
||||||
|
@ -37,12 +35,14 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_window<F, Ret>(&self, window_id: ffi::Window, callback: F) -> Option<Ret>
|
fn with_window<F, Ret>(&self, window_id: ffi::Window, callback: F) -> Option<Ret>
|
||||||
where F: Fn(&UnownedWindow) -> Ret
|
where
|
||||||
|
F: Fn(&UnownedWindow) -> Ret,
|
||||||
{
|
{
|
||||||
let mut deleted = false;
|
let mut deleted = false;
|
||||||
let window_id = WindowId(window_id);
|
let window_id = WindowId(window_id);
|
||||||
let wt = get_xtarget(&self.target);
|
let wt = get_xtarget(&self.target);
|
||||||
let result = wt.windows
|
let result = wt
|
||||||
|
.windows
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&window_id)
|
.get(&window_id)
|
||||||
.and_then(|window| {
|
.and_then(|window| {
|
||||||
|
@ -62,7 +62,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
self.with_window(window_id, |_| ()).is_some()
|
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);
|
let wt = get_xtarget(&self.target);
|
||||||
// This function is used to poll and remove a single event
|
// This function is used to poll and remove a single event
|
||||||
// from the Xlib event queue in a non-blocking, atomic way.
|
// from the Xlib event queue in a non-blocking, atomic way.
|
||||||
|
@ -73,7 +73,8 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
unsafe extern "C" fn predicate(
|
unsafe extern "C" fn predicate(
|
||||||
_display: *mut ffi::Display,
|
_display: *mut ffi::Display,
|
||||||
_event: *mut ffi::XEvent,
|
_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
|
// This predicate always returns "true" (1) to accept all events
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
@ -82,32 +83,42 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
wt.xconn.display,
|
wt.xconn.display,
|
||||||
event_ptr,
|
event_ptr,
|
||||||
Some(predicate),
|
Some(predicate),
|
||||||
std::ptr::null_mut());
|
std::ptr::null_mut(),
|
||||||
|
);
|
||||||
|
|
||||||
result != 0
|
result != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F)
|
pub(super) fn process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F)
|
||||||
where F: FnMut(Event<T>)
|
where
|
||||||
|
F: FnMut(Event<T>),
|
||||||
{
|
{
|
||||||
let wt = get_xtarget(&self.target);
|
let wt = get_xtarget(&self.target);
|
||||||
// XFilterEvent tells us when an event has been discarded by the input method.
|
// 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,
|
// 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
|
// along with an extra copy of the KeyRelease events. This also prevents backspace and
|
||||||
// arrow keys from being detected twice.
|
// arrow keys from being detected twice.
|
||||||
if ffi::True == unsafe { (wt.xconn.xlib.XFilterEvent)(
|
if ffi::True
|
||||||
xev,
|
== unsafe {
|
||||||
{ let xev: &ffi::XAnyEvent = xev.as_ref(); xev.window }
|
(wt.xconn.xlib.XFilterEvent)(xev, {
|
||||||
) } {
|
let xev: &ffi::XAnyEvent = xev.as_ref();
|
||||||
|
xev.window
|
||||||
|
})
|
||||||
|
}
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let event_type = xev.get_type();
|
let event_type = xev.get_type();
|
||||||
match event_type {
|
match event_type {
|
||||||
ffi::MappingNotify => {
|
ffi::MappingNotify => {
|
||||||
unsafe { (wt.xconn.xlib.XRefreshKeyboardMapping)(xev.as_mut()); }
|
unsafe {
|
||||||
wt.xconn.check_errors().expect("Failed to call XRefreshKeyboardMapping");
|
(wt.xconn.xlib.XRefreshKeyboardMapping)(xev.as_mut());
|
||||||
}
|
}
|
||||||
|
wt.xconn
|
||||||
|
.check_errors()
|
||||||
|
.expect("Failed to call XRefreshKeyboardMapping");
|
||||||
|
},
|
||||||
|
|
||||||
ffi::ClientMessage => {
|
ffi::ClientMessage => {
|
||||||
let client_msg: &ffi::XClientMessageEvent = xev.as_ref();
|
let client_msg: &ffi::XClientMessageEvent = xev.as_ref();
|
||||||
|
@ -116,7 +127,10 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
let window_id = mkwid(window);
|
let window_id = mkwid(window);
|
||||||
|
|
||||||
if client_msg.data.get_long(0) as ffi::Atom == wt.wm_delete_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.message_type == self.dnd.atoms.enter {
|
} else if client_msg.message_type == self.dnd.atoms.enter {
|
||||||
let source_window = client_msg.data.get_long(0) as c_ulong;
|
let source_window = client_msg.data.get_long(0) as c_ulong;
|
||||||
let flags = client_msg.data.get_long(1);
|
let flags = client_msg.data.get_long(1);
|
||||||
|
@ -127,10 +141,11 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
let type_list = vec![
|
let type_list = vec![
|
||||||
client_msg.data.get_long(2) as c_ulong,
|
client_msg.data.get_long(2) as c_ulong,
|
||||||
client_msg.data.get_long(3) 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);
|
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);
|
self.dnd.type_list = Some(more_types);
|
||||||
}
|
}
|
||||||
} else if client_msg.message_type == self.dnd.atoms.position {
|
} else if client_msg.message_type == self.dnd.atoms.position {
|
||||||
|
@ -178,18 +193,21 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
// This results in the `SelectionNotify` event below
|
// This results in the `SelectionNotify` event below
|
||||||
self.dnd.convert_selection(window, time);
|
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.");
|
.expect("Failed to send `XdndStatus` message.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
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.");
|
.expect("Failed to send `XdndStatus` message.");
|
||||||
}
|
}
|
||||||
self.dnd.reset();
|
self.dnd.reset();
|
||||||
}
|
}
|
||||||
} else if client_msg.message_type == self.dnd.atoms.drop {
|
} 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 {
|
if let Some(Ok(ref path_list)) = self.dnd.result {
|
||||||
for path in path_list {
|
for path in path_list {
|
||||||
callback(Event::WindowEvent {
|
callback(Event::WindowEvent {
|
||||||
|
@ -206,7 +224,8 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
(source_window, DndState::Rejected)
|
(source_window, DndState::Rejected)
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
self.dnd.send_finished(window, source_window, state)
|
self.dnd
|
||||||
|
.send_finished(window, source_window, state)
|
||||||
.expect("Failed to send `XdndFinished` message.");
|
.expect("Failed to send `XdndFinished` message.");
|
||||||
}
|
}
|
||||||
self.dnd.reset();
|
self.dnd.reset();
|
||||||
|
@ -217,7 +236,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
event: WindowEvent::HoveredFileCancelled,
|
event: WindowEvent::HoveredFileCancelled,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::SelectionNotify => {
|
ffi::SelectionNotify => {
|
||||||
let xsel: &ffi::XSelectionEvent = xev.as_ref();
|
let xsel: &ffi::XSelectionEvent = xev.as_ref();
|
||||||
|
@ -244,7 +263,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
|
|
||||||
self.dnd.result = result;
|
self.dnd.result = result;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::ConfigureNotify => {
|
ffi::ConfigureNotify => {
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -274,15 +293,22 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
let mut shared_state_lock = window.shared_state.lock();
|
let mut shared_state_lock = window.shared_state.lock();
|
||||||
|
|
||||||
let (mut resized, moved) = {
|
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 {
|
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 {
|
} else {
|
||||||
// Detect when frame extents change.
|
// Detect when frame extents change.
|
||||||
// Since this isn't synthetic, as per the notes above, this position is relative to the
|
// Since this isn't synthetic, as per the notes above, this position is relative to the
|
||||||
// parent window.
|
// parent window.
|
||||||
let rel_parent = new_inner_position;
|
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`.
|
// This ensures we process the next `Moved`.
|
||||||
shared_state_lock.inner_position = None;
|
shared_state_lock.inner_position = None;
|
||||||
// Extra insurance against stale frame extents.
|
// Extra insurance against stale frame extents.
|
||||||
|
@ -297,18 +323,22 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
|
|
||||||
let new_outer_position = if moved || shared_state_lock.position.is_none() {
|
let new_outer_position = if moved || shared_state_lock.position.is_none() {
|
||||||
// We need to convert client area position to window position.
|
// 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()
|
.as_ref()
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| {
|
.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());
|
shared_state_lock.frame_extents = Some(frame_extents.clone());
|
||||||
frame_extents
|
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);
|
shared_state_lock.position = Some(outer);
|
||||||
if moved {
|
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));
|
events.moved = Some(WindowEvent::Moved(logical_position));
|
||||||
}
|
}
|
||||||
outer
|
outer
|
||||||
|
@ -319,12 +349,13 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
if is_synthetic {
|
if is_synthetic {
|
||||||
// If we don't use the existing adjusted value when available, then the user can screw up the
|
// 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.
|
// 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));
|
.unwrap_or_else(|| (xev.width as f64, xev.height as f64));
|
||||||
let last_hidpi_factor = shared_state_lock.guessed_dpi
|
let last_hidpi_factor =
|
||||||
.take()
|
shared_state_lock.guessed_dpi.take().unwrap_or_else(|| {
|
||||||
.unwrap_or_else(|| {
|
shared_state_lock
|
||||||
shared_state_lock.last_monitor
|
.last_monitor
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|last_monitor| last_monitor.hidpi_factor)
|
.map(|last_monitor| last_monitor.hidpi_factor)
|
||||||
.unwrap_or(1.0)
|
.unwrap_or(1.0)
|
||||||
|
@ -337,7 +368,8 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
new_hidpi_factor
|
new_hidpi_factor
|
||||||
};
|
};
|
||||||
if last_hidpi_factor != 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(
|
let (new_width, new_height, flusher) = window.adjust_for_dpi(
|
||||||
last_hidpi_factor,
|
last_hidpi_factor,
|
||||||
new_hidpi_factor,
|
new_hidpi_factor,
|
||||||
|
@ -357,7 +389,10 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
// WMs constrain the window size, making the resize fail. This would cause an endless stream of
|
// 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.
|
// XResizeWindow requests, making Xorg, the winit client, and the WM consume 100% of CPU.
|
||||||
if let Some(adjusted_size) = shared_state_lock.dpi_adjusted {
|
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"]) {
|
if new_inner_size == rounded_size || !util::wm_name_is_one_of(&["Xfwm4"]) {
|
||||||
// When this finally happens, the event will not be synthetic.
|
// When this finally happens, the event will not be synthetic.
|
||||||
shared_state_lock.dpi_adjusted = None;
|
shared_state_lock.dpi_adjusted = None;
|
||||||
|
@ -374,7 +409,8 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if resized {
|
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));
|
events.resized = Some(WindowEvent::Resized(logical_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +429,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
callback(Event::WindowEvent { window_id, event });
|
callback(Event::WindowEvent { window_id, event });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::ReparentNotify => {
|
ffi::ReparentNotify => {
|
||||||
let xev: &ffi::XReparentEvent = xev.as_ref();
|
let xev: &ffi::XReparentEvent = xev.as_ref();
|
||||||
|
@ -408,7 +444,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
self.with_window(xev.window, |window| {
|
self.with_window(xev.window, |window| {
|
||||||
window.invalidate_cached_frame_extents();
|
window.invalidate_cached_frame_extents();
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::DestroyNotify => {
|
ffi::DestroyNotify => {
|
||||||
let xev: &ffi::XDestroyWindowEvent = xev.as_ref();
|
let xev: &ffi::XDestroyWindowEvent = xev.as_ref();
|
||||||
|
@ -427,8 +463,11 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
.remove_context(window)
|
.remove_context(window)
|
||||||
.expect("Failed to destroy input context");
|
.expect("Failed to destroy input context");
|
||||||
|
|
||||||
callback(Event::WindowEvent { window_id, event: WindowEvent::Destroyed });
|
callback(Event::WindowEvent {
|
||||||
}
|
window_id,
|
||||||
|
event: WindowEvent::Destroyed,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
ffi::Expose => {
|
ffi::Expose => {
|
||||||
let xev: &ffi::XExposeEvent = xev.as_ref();
|
let xev: &ffi::XExposeEvent = xev.as_ref();
|
||||||
|
@ -436,8 +475,11 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
let window = xev.window;
|
let window = xev.window;
|
||||||
let window_id = mkwid(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 => {
|
ffi::KeyPress | ffi::KeyRelease => {
|
||||||
use crate::event::ElementState::{Pressed, Released};
|
use crate::event::ElementState::{Pressed, Released};
|
||||||
|
@ -493,7 +535,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
virtual_keycode,
|
virtual_keycode,
|
||||||
modifiers,
|
modifiers,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,20 +554,29 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
callback(event);
|
callback(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::GenericEvent => {
|
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;
|
let xev = &guard.cookie;
|
||||||
if self.xi2ext.opcode != xev.extension {
|
if self.xi2ext.opcode != xev.extension {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::event::WindowEvent::{Focused, CursorEntered, MouseInput, CursorLeft, CursorMoved, MouseWheel, AxisMotion};
|
use crate::event::{
|
||||||
use crate::event::ElementState::{Pressed, Released};
|
ElementState::{Pressed, Released},
|
||||||
use crate::event::MouseButton::{Left, Right, Middle, Other};
|
MouseButton::{Left, Middle, Other, Right},
|
||||||
use crate::event::MouseScrollDelta::LineDelta;
|
MouseScrollDelta::LineDelta,
|
||||||
use crate::event::{Touch, TouchPhase};
|
Touch, TouchPhase,
|
||||||
|
WindowEvent::{
|
||||||
|
AxisMotion, CursorEntered, CursorLeft, CursorMoved, Focused, MouseInput,
|
||||||
|
MouseWheel,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
match xev.evtype {
|
match xev.evtype {
|
||||||
ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
|
ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
|
||||||
|
@ -545,66 +596,76 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
Released
|
Released
|
||||||
};
|
};
|
||||||
match xev.detail as u32 {
|
match xev.detail as u32 {
|
||||||
ffi::Button1 => callback(Event::WindowEvent {
|
ffi::Button1 => {
|
||||||
window_id,
|
callback(Event::WindowEvent {
|
||||||
event: MouseInput {
|
window_id,
|
||||||
device_id,
|
event: MouseInput {
|
||||||
state,
|
device_id,
|
||||||
button: Left,
|
state,
|
||||||
modifiers,
|
button: Left,
|
||||||
},
|
modifiers,
|
||||||
}),
|
},
|
||||||
ffi::Button2 => callback(Event::WindowEvent {
|
})
|
||||||
window_id,
|
},
|
||||||
event: MouseInput {
|
ffi::Button2 => {
|
||||||
device_id,
|
callback(Event::WindowEvent {
|
||||||
state,
|
window_id,
|
||||||
button: Middle,
|
event: MouseInput {
|
||||||
modifiers,
|
device_id,
|
||||||
},
|
state,
|
||||||
}),
|
button: Middle,
|
||||||
ffi::Button3 => callback(Event::WindowEvent {
|
modifiers,
|
||||||
window_id,
|
},
|
||||||
event: MouseInput {
|
})
|
||||||
device_id,
|
},
|
||||||
state,
|
ffi::Button3 => {
|
||||||
button: Right,
|
callback(Event::WindowEvent {
|
||||||
modifiers,
|
window_id,
|
||||||
},
|
event: MouseInput {
|
||||||
}),
|
device_id,
|
||||||
|
state,
|
||||||
|
button: Right,
|
||||||
|
modifiers,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
// Suppress emulated scroll wheel clicks, since we handle the real motion events for those.
|
// 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
|
// 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.
|
// turn) as axis motion, so we don't otherwise special-case these button presses.
|
||||||
4 | 5 | 6 | 7 => if xev.flags & ffi::XIPointerEmulated == 0 {
|
4 | 5 | 6 | 7 => {
|
||||||
callback(Event::WindowEvent {
|
if xev.flags & ffi::XIPointerEmulated == 0 {
|
||||||
window_id,
|
callback(Event::WindowEvent {
|
||||||
event: MouseWheel {
|
window_id,
|
||||||
device_id,
|
event: MouseWheel {
|
||||||
delta: match xev.detail {
|
device_id,
|
||||||
4 => LineDelta(0.0, 1.0),
|
delta: match xev.detail {
|
||||||
5 => LineDelta(0.0, -1.0),
|
4 => LineDelta(0.0, 1.0),
|
||||||
6 => LineDelta(-1.0, 0.0),
|
5 => LineDelta(0.0, -1.0),
|
||||||
7 => LineDelta(1.0, 0.0),
|
6 => LineDelta(-1.0, 0.0),
|
||||||
_ => unreachable!(),
|
7 => LineDelta(1.0, 0.0),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
phase: TouchPhase::Moved,
|
||||||
|
modifiers,
|
||||||
},
|
},
|
||||||
phase: TouchPhase::Moved,
|
});
|
||||||
modifiers,
|
}
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
x => callback(Event::WindowEvent {
|
x => {
|
||||||
window_id,
|
callback(Event::WindowEvent {
|
||||||
event: MouseInput {
|
window_id,
|
||||||
device_id,
|
event: MouseInput {
|
||||||
state,
|
device_id,
|
||||||
button: Other(x as u8),
|
state,
|
||||||
modifiers,
|
button: Other(x as u8),
|
||||||
},
|
modifiers,
|
||||||
}),
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
ffi::XI_Motion => {
|
ffi::XI_Motion => {
|
||||||
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
||||||
let device_id = mkdid(xev.deviceid);
|
let device_id = mkdid(xev.deviceid);
|
||||||
|
@ -618,9 +679,8 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos)
|
util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos)
|
||||||
});
|
});
|
||||||
if cursor_moved == Some(true) {
|
if cursor_moved == Some(true) {
|
||||||
let dpi_factor = self.with_window(xev.event, |window| {
|
let dpi_factor =
|
||||||
window.hidpi_factor()
|
self.with_window(xev.event, |window| window.hidpi_factor());
|
||||||
});
|
|
||||||
if let Some(dpi_factor) = dpi_factor {
|
if let Some(dpi_factor) = dpi_factor {
|
||||||
let position = LogicalPosition::from_physical(
|
let position = LogicalPosition::from_physical(
|
||||||
(xev.event_x as f64, xev.event_y as f64),
|
(xev.event_x as f64, xev.event_y as f64),
|
||||||
|
@ -644,7 +704,12 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
// More gymnastics, for self.devices
|
// More gymnastics, for self.devices
|
||||||
let mut events = Vec::new();
|
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 mut devices = self.devices.borrow_mut();
|
||||||
let physical_device = match devices.get_mut(&DeviceId(xev.sourceid)) {
|
let physical_device = match devices.get_mut(&DeviceId(xev.sourceid)) {
|
||||||
Some(device) => device,
|
Some(device) => device,
|
||||||
|
@ -652,10 +717,14 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut value = xev.valuators.values;
|
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) {
|
if ffi::XIMaskIsSet(mask, i) {
|
||||||
let x = unsafe { *value };
|
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;
|
let delta = (x - info.position) / info.increment;
|
||||||
info.position = x;
|
info.position = x;
|
||||||
events.push(Event::WindowEvent {
|
events.push(Event::WindowEvent {
|
||||||
|
@ -663,9 +732,13 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
event: MouseWheel {
|
event: MouseWheel {
|
||||||
device_id,
|
device_id,
|
||||||
delta: match info.orientation {
|
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
|
// 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,
|
phase: TouchPhase::Moved,
|
||||||
modifiers,
|
modifiers,
|
||||||
|
@ -688,7 +761,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
for event in events {
|
for event in events {
|
||||||
callback(event);
|
callback(event);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::XI_Enter => {
|
ffi::XI_Enter => {
|
||||||
let xev: &ffi::XIEnterEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIEnterEvent = unsafe { &*(xev.data as *const _) };
|
||||||
|
@ -704,7 +777,8 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
// presumably some other WMs. On those, `XI_Enter` doesn't include
|
// presumably some other WMs. On those, `XI_Enter` doesn't include
|
||||||
// the physical device ID, so both `sourceid` and `deviceid` are
|
// the physical device ID, so both `sourceid` and `deviceid` are
|
||||||
// the virtual device.
|
// the virtual device.
|
||||||
|| device_info.attachment == xev.sourceid {
|
|| device_info.attachment == xev.sourceid
|
||||||
|
{
|
||||||
let device_id = DeviceId(device_info.deviceid);
|
let device_id = DeviceId(device_info.deviceid);
|
||||||
if let Some(device) = devices.get_mut(&device_id) {
|
if let Some(device) = devices.get_mut(&device_id) {
|
||||||
device.reset_scroll_position(device_info);
|
device.reset_scroll_position(device_info);
|
||||||
|
@ -717,9 +791,9 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
event: CursorEntered { device_id },
|
event: CursorEntered { device_id },
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(dpi_factor) = self.with_window(xev.event, |window| {
|
if let Some(dpi_factor) =
|
||||||
window.hidpi_factor()
|
self.with_window(xev.event, |window| window.hidpi_factor())
|
||||||
}) {
|
{
|
||||||
let position = LogicalPosition::from_physical(
|
let position = LogicalPosition::from_physical(
|
||||||
(xev.event_x as f64, xev.event_y as f64),
|
(xev.event_x as f64, xev.event_y as f64),
|
||||||
dpi_factor,
|
dpi_factor,
|
||||||
|
@ -732,7 +806,8 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
// This needs to only be done after confirming the window still exists,
|
// This needs to only be done after confirming the window still exists,
|
||||||
// since otherwise we risk getting a `BadWindow` error if the window was
|
// since otherwise we risk getting a `BadWindow` error if the window was
|
||||||
// dropped with queued events.
|
// dropped with queued events.
|
||||||
let modifiers = wt.xconn
|
let modifiers = wt
|
||||||
|
.xconn
|
||||||
.query_pointer(xev.event, xev.deviceid)
|
.query_pointer(xev.event, xev.deviceid)
|
||||||
.expect("Failed to query pointer device")
|
.expect("Failed to query pointer device")
|
||||||
.get_modifier_state();
|
.get_modifier_state();
|
||||||
|
@ -746,7 +821,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
ffi::XI_Leave => {
|
ffi::XI_Leave => {
|
||||||
let xev: &ffi::XILeaveEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XILeaveEvent = unsafe { &*(xev.data as *const _) };
|
||||||
|
|
||||||
|
@ -756,19 +831,20 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
if !window_closed {
|
if !window_closed {
|
||||||
callback(Event::WindowEvent {
|
callback(Event::WindowEvent {
|
||||||
window_id: mkwid(xev.event),
|
window_id: mkwid(xev.event),
|
||||||
event: CursorLeft { device_id: mkdid(xev.deviceid) },
|
event: CursorLeft {
|
||||||
|
device_id: mkdid(xev.deviceid),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
ffi::XI_FocusIn => {
|
ffi::XI_FocusIn => {
|
||||||
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
|
||||||
|
|
||||||
let dpi_factor = match self.with_window(xev.event, |window| {
|
let dpi_factor =
|
||||||
window.hidpi_factor()
|
match self.with_window(xev.event, |window| window.hidpi_factor()) {
|
||||||
}) {
|
Some(dpi_factor) => dpi_factor,
|
||||||
Some(dpi_factor) => dpi_factor,
|
None => return,
|
||||||
None => return,
|
};
|
||||||
};
|
|
||||||
let window_id = mkwid(xev.event);
|
let window_id = mkwid(xev.event);
|
||||||
|
|
||||||
wt.ime
|
wt.ime
|
||||||
|
@ -776,11 +852,15 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
.focus(xev.event)
|
.focus(xev.event)
|
||||||
.expect("Failed to focus input context");
|
.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,
|
// The deviceid for this event is for a keyboard instead of a pointer,
|
||||||
// so we have to do a little extra work.
|
// so we have to do a little extra work.
|
||||||
let pointer_id = self.devices
|
let pointer_id = self
|
||||||
|
.devices
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&DeviceId(xev.deviceid))
|
.get(&DeviceId(xev.deviceid))
|
||||||
.map(|device| device.attachment)
|
.map(|device| device.attachment)
|
||||||
|
@ -796,12 +876,14 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
device_id: mkdid(pointer_id),
|
device_id: mkdid(pointer_id),
|
||||||
position,
|
position,
|
||||||
modifiers: ModifiersState::from(xev.mods),
|
modifiers: ModifiersState::from(xev.mods),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
ffi::XI_FocusOut => {
|
ffi::XI_FocusOut => {
|
||||||
let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) };
|
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
|
wt.ime
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.unfocus(xev.event)
|
.unfocus(xev.event)
|
||||||
|
@ -810,7 +892,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
window_id: mkwid(xev.event),
|
window_id: mkwid(xev.event),
|
||||||
event: Focused(false),
|
event: Focused(false),
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::XI_TouchBegin | ffi::XI_TouchUpdate | ffi::XI_TouchEnd => {
|
ffi::XI_TouchBegin | ffi::XI_TouchUpdate | ffi::XI_TouchEnd => {
|
||||||
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
||||||
|
@ -819,11 +901,10 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
ffi::XI_TouchBegin => TouchPhase::Started,
|
ffi::XI_TouchBegin => TouchPhase::Started,
|
||||||
ffi::XI_TouchUpdate => TouchPhase::Moved,
|
ffi::XI_TouchUpdate => TouchPhase::Moved,
|
||||||
ffi::XI_TouchEnd => TouchPhase::Ended,
|
ffi::XI_TouchEnd => TouchPhase::Ended,
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let dpi_factor = self.with_window(xev.event, |window| {
|
let dpi_factor =
|
||||||
window.hidpi_factor()
|
self.with_window(xev.event, |window| window.hidpi_factor());
|
||||||
});
|
|
||||||
if let Some(dpi_factor) = dpi_factor {
|
if let Some(dpi_factor) = dpi_factor {
|
||||||
let location = LogicalPosition::from_physical(
|
let location = LogicalPosition::from_physical(
|
||||||
(xev.event_x as f64, xev.event_y as f64),
|
(xev.event_x as f64, xev.event_y as f64),
|
||||||
|
@ -839,31 +920,39 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::XI_RawButtonPress | ffi::XI_RawButtonRelease => {
|
ffi::XI_RawButtonPress | ffi::XI_RawButtonRelease => {
|
||||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||||
if xev.flags & ffi::XIPointerEmulated == 0 {
|
if xev.flags & ffi::XIPointerEmulated == 0 {
|
||||||
callback(Event::DeviceEvent { device_id: mkdid(xev.deviceid), event: DeviceEvent::Button {
|
callback(Event::DeviceEvent {
|
||||||
button: xev.detail as u32,
|
device_id: mkdid(xev.deviceid),
|
||||||
state: match xev.evtype {
|
event: DeviceEvent::Button {
|
||||||
ffi::XI_RawButtonPress => Pressed,
|
button: xev.detail as u32,
|
||||||
ffi::XI_RawButtonRelease => Released,
|
state: match xev.evtype {
|
||||||
_ => unreachable!(),
|
ffi::XI_RawButtonPress => Pressed,
|
||||||
|
ffi::XI_RawButtonRelease => Released,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::XI_RawMotion => {
|
ffi::XI_RawMotion => {
|
||||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||||
let did = mkdid(xev.deviceid);
|
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 value = xev.raw_values;
|
||||||
let mut mouse_delta = (0.0, 0.0);
|
let mut mouse_delta = (0.0, 0.0);
|
||||||
let mut scroll_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) {
|
if ffi::XIMaskIsSet(mask, i) {
|
||||||
let x = unsafe { *value };
|
let x = unsafe { *value };
|
||||||
// We assume that every XInput2 device with analog axes is a pointing device emitting
|
// We assume that every XInput2 device with analog axes is a pointing device emitting
|
||||||
|
@ -875,24 +964,31 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
3 => scroll_delta.1 = x as f32,
|
3 => scroll_delta.1 = x as f32,
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::Motion {
|
callback(Event::DeviceEvent {
|
||||||
axis: i as u32,
|
device_id: did,
|
||||||
value: x,
|
event: DeviceEvent::Motion {
|
||||||
}});
|
axis: i as u32,
|
||||||
|
value: x,
|
||||||
|
},
|
||||||
|
});
|
||||||
value = unsafe { value.offset(1) };
|
value = unsafe { value.offset(1) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mouse_delta != (0.0, 0.0) {
|
if mouse_delta != (0.0, 0.0) {
|
||||||
callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::MouseMotion {
|
callback(Event::DeviceEvent {
|
||||||
delta: mouse_delta,
|
device_id: did,
|
||||||
}});
|
event: DeviceEvent::MouseMotion { delta: mouse_delta },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if scroll_delta != (0.0, 0.0) {
|
if scroll_delta != (0.0, 0.0) {
|
||||||
callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::MouseWheel {
|
callback(Event::DeviceEvent {
|
||||||
delta: LineDelta(scroll_delta.0, scroll_delta.1),
|
device_id: did,
|
||||||
}});
|
event: DeviceEvent::MouseWheel {
|
||||||
|
delta: LineDelta(scroll_delta.0, scroll_delta.1),
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => {
|
ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => {
|
||||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||||
|
@ -905,7 +1001,9 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
|
|
||||||
let device_id = xev.sourceid;
|
let device_id = xev.sourceid;
|
||||||
let keycode = xev.detail;
|
let keycode = xev.detail;
|
||||||
if keycode < 8 { return; }
|
if keycode < 8 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let scancode = (keycode - 8) as u32;
|
let scancode = (keycode - 8) as u32;
|
||||||
|
|
||||||
let keysym = unsafe {
|
let keysym = unsafe {
|
||||||
|
@ -915,7 +1013,9 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
0,
|
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);
|
let virtual_keycode = events::keysym_to_element(keysym as c_uint);
|
||||||
|
|
||||||
|
@ -933,23 +1033,32 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
ffi::XI_HierarchyChanged => {
|
ffi::XI_HierarchyChanged => {
|
||||||
let xev: &ffi::XIHierarchyEvent = unsafe { &*(xev.data as *const _) };
|
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) {
|
if 0 != info.flags & (ffi::XISlaveAdded | ffi::XIMasterAdded) {
|
||||||
self.init_device(info.deviceid);
|
self.init_device(info.deviceid);
|
||||||
callback(Event::DeviceEvent { device_id: mkdid(info.deviceid), event: DeviceEvent::Added });
|
callback(Event::DeviceEvent {
|
||||||
} else if 0 != info.flags & (ffi::XISlaveRemoved | ffi::XIMasterRemoved) {
|
device_id: mkdid(info.deviceid),
|
||||||
callback(Event::DeviceEvent { device_id: mkdid(info.deviceid), event: DeviceEvent::Removed });
|
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();
|
let mut devices = self.devices.borrow_mut();
|
||||||
devices.remove(&DeviceId(info.deviceid));
|
devices.remove(&DeviceId(info.deviceid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -972,10 +1081,11 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
callback(Event::WindowEvent {
|
callback(Event::WindowEvent {
|
||||||
window_id: mkwid(window_id.0),
|
window_id: mkwid(window_id.0),
|
||||||
event: WindowEvent::HiDpiFactorChanged(
|
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(
|
let (_, _, flusher) = window.adjust_for_dpi(
|
||||||
prev_monitor.hidpi_factor,
|
prev_monitor.hidpi_factor,
|
||||||
new_monitor.hidpi_factor,
|
new_monitor.hidpi_factor,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use libc;
|
|
||||||
use super::ffi;
|
use super::ffi;
|
||||||
use crate::event::VirtualKeyCode;
|
use crate::event::VirtualKeyCode;
|
||||||
|
use libc;
|
||||||
|
|
||||||
pub fn keysym_to_element(keysym: libc::c_uint) -> Option<VirtualKeyCode> {
|
pub fn keysym_to_element(keysym: libc::c_uint) -> Option<VirtualKeyCode> {
|
||||||
Some(match keysym {
|
Some(match keysym {
|
||||||
|
@ -1003,6 +1003,6 @@ pub fn keysym_to_element(keysym: libc::c_uint) -> Option<VirtualKeyCode> {
|
||||||
ffi::XF86XK_Copy => VirtualKeyCode::Copy,
|
ffi::XF86XK_Copy => VirtualKeyCode::Copy,
|
||||||
ffi::XF86XK_Paste => VirtualKeyCode::Paste,
|
ffi::XF86XK_Paste => VirtualKeyCode::Paste,
|
||||||
ffi::XF86XK_Cut => VirtualKeyCode::Cut,
|
ffi::XF86XK_Cut => VirtualKeyCode::Cut,
|
||||||
_ => return None
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
pub use x11_dl::keysym::*;
|
pub use x11_dl::{
|
||||||
pub use x11_dl::xcursor::*;
|
error::OpenError, keysym::*, xcursor::*, xinput::*, xinput2::*, xlib::*, xlib_xcb::*,
|
||||||
pub use x11_dl::xlib::*;
|
xrandr::*, xrender::*,
|
||||||
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::*;
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
use std::ptr;
|
use std::{collections::HashMap, os::raw::c_char, ptr, sync::Arc};
|
||||||
use std::sync::Arc;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
|
|
||||||
use super::{ffi, XConnection, XError};
|
use super::{ffi, XConnection, XError};
|
||||||
|
|
||||||
use super::inner::{close_im, ImeInner};
|
use super::{
|
||||||
use super::input_method::PotentialInputMethods;
|
context::{ImeContext, ImeContextCreationError},
|
||||||
use super::context::{ImeContextCreationError, ImeContext};
|
inner::{close_im, ImeInner},
|
||||||
|
input_method::PotentialInputMethods,
|
||||||
|
};
|
||||||
|
|
||||||
pub unsafe fn xim_set_callback(
|
pub unsafe fn xim_set_callback(
|
||||||
xconn: &Arc<XConnection>,
|
xconn: &Arc<XConnection>,
|
||||||
|
@ -17,12 +16,7 @@ pub unsafe fn xim_set_callback(
|
||||||
) -> Result<(), XError> {
|
) -> Result<(), XError> {
|
||||||
// It's advisable to wrap variadic FFI functions in our own functions, as we want to minimize
|
// It's advisable to wrap variadic FFI functions in our own functions, as we want to minimize
|
||||||
// access that isn't type-checked.
|
// access that isn't type-checked.
|
||||||
(xconn.xlib.XSetIMValues)(
|
(xconn.xlib.XSetIMValues)(xim, field, callback, ptr::null_mut::<()>());
|
||||||
xim,
|
|
||||||
field,
|
|
||||||
callback,
|
|
||||||
ptr::null_mut::<()>(),
|
|
||||||
);
|
|
||||||
xconn.check_errors()
|
xconn.check_errors()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,18 +101,14 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> {
|
||||||
let _ = close_im(xconn, new_im.im);
|
let _ = close_im(xconn, new_im.im);
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}.map_err(ReplaceImError::SetDestroyCallbackFailed)?;
|
}
|
||||||
|
.map_err(ReplaceImError::SetDestroyCallbackFailed)?;
|
||||||
|
|
||||||
let mut new_contexts = HashMap::new();
|
let mut new_contexts = HashMap::new();
|
||||||
for (window, old_context) in (*inner).contexts.iter() {
|
for (window, old_context) in (*inner).contexts.iter() {
|
||||||
let spot = old_context.as_ref().map(|old_context| old_context.ic_spot);
|
let spot = old_context.as_ref().map(|old_context| old_context.ic_spot);
|
||||||
let new_context = {
|
let new_context = {
|
||||||
let result = ImeContext::new(
|
let result = ImeContext::new(xconn, new_im.im, *window, spot);
|
||||||
xconn,
|
|
||||||
new_im.im,
|
|
||||||
*window,
|
|
||||||
spot,
|
|
||||||
);
|
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
let _ = close_im(xconn, new_im.im);
|
let _ = close_im(xconn, new_im.im);
|
||||||
}
|
}
|
||||||
|
@ -137,7 +127,7 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern fn xim_instantiate_callback(
|
pub unsafe extern "C" fn xim_instantiate_callback(
|
||||||
_display: *mut ffi::Display,
|
_display: *mut ffi::Display,
|
||||||
client_data: ffi::XPointer,
|
client_data: ffi::XPointer,
|
||||||
// This field is unsupplied.
|
// 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
|
// 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
|
// 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).
|
// 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,
|
_xim: ffi::XIM,
|
||||||
client_data: ffi::XPointer,
|
client_data: ffi::XPointer,
|
||||||
// This field is unsupplied.
|
// This field is unsupplied.
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::ptr;
|
use std::{
|
||||||
use std::sync::Arc;
|
os::raw::{c_short, c_void},
|
||||||
use std::os::raw::{c_short, c_void};
|
ptr,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{ffi, util, XConnection, XError};
|
use super::{ffi, util, XConnection, XError};
|
||||||
|
|
||||||
|
@ -22,7 +24,8 @@ unsafe fn create_pre_edit_attr<'a>(
|
||||||
ic_spot,
|
ic_spot,
|
||||||
ptr::null_mut::<()>(),
|
ptr::null_mut::<()>(),
|
||||||
),
|
),
|
||||||
).expect("XVaCreateNestedList returned NULL")
|
)
|
||||||
|
.expect("XVaCreateNestedList returned NULL")
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNING: this struct doesn't destroy its XIC resource when dropped.
|
// WARNING: this struct doesn't destroy its XIC resource when dropped.
|
||||||
|
@ -49,7 +52,9 @@ impl ImeContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
let ic = ic.ok_or(ImeContextCreationError::Null)?;
|
let ic = ic.ok_or(ImeContextCreationError::Null)?;
|
||||||
xconn.check_errors().map_err(ImeContextCreationError::XError)?;
|
xconn
|
||||||
|
.check_errors()
|
||||||
|
.map_err(ImeContextCreationError::XError)?;
|
||||||
|
|
||||||
Ok(ImeContext {
|
Ok(ImeContext {
|
||||||
ic,
|
ic,
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
use std::mem;
|
use std::{collections::HashMap, mem, ptr, sync::Arc};
|
||||||
use std::ptr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use super::{ffi, XConnection, XError};
|
use super::{ffi, XConnection, XError};
|
||||||
|
|
||||||
use super::input_method::PotentialInputMethods;
|
use super::{context::ImeContext, input_method::PotentialInputMethods};
|
||||||
use super::context::ImeContext;
|
|
||||||
|
|
||||||
pub unsafe fn close_im(xconn: &Arc<XConnection>, im: ffi::XIM) -> Result<(), XError> {
|
pub unsafe fn close_im(xconn: &Arc<XConnection>, im: ffi::XIM) -> Result<(), XError> {
|
||||||
(xconn.xlib.XCloseIM)(im);
|
(xconn.xlib.XCloseIM)(im);
|
||||||
|
@ -33,10 +29,7 @@ pub struct ImeInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImeInner {
|
impl ImeInner {
|
||||||
pub fn new(
|
pub fn new(xconn: Arc<XConnection>, potential_input_methods: PotentialInputMethods) -> Self {
|
||||||
xconn: Arc<XConnection>,
|
|
||||||
potential_input_methods: PotentialInputMethods,
|
|
||||||
) -> Self {
|
|
||||||
ImeInner {
|
ImeInner {
|
||||||
xconn,
|
xconn,
|
||||||
im: ptr::null_mut(),
|
im: ptr::null_mut(),
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use std::env;
|
use std::{
|
||||||
use std::fmt;
|
env,
|
||||||
use std::ptr;
|
ffi::{CStr, CString, IntoStringError},
|
||||||
use std::sync::Arc;
|
fmt,
|
||||||
use std::os::raw::c_char;
|
os::raw::c_char,
|
||||||
use std::ffi::{CStr, CString, IntoStringError};
|
ptr,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
@ -13,10 +15,7 @@ lazy_static! {
|
||||||
static ref GLOBAL_LOCK: Mutex<()> = Default::default();
|
static ref GLOBAL_LOCK: Mutex<()> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn open_im(
|
unsafe fn open_im(xconn: &Arc<XConnection>, locale_modifiers: &CStr) -> Option<ffi::XIM> {
|
||||||
xconn: &Arc<XConnection>,
|
|
||||||
locale_modifiers: &CStr,
|
|
||||||
) -> Option<ffi::XIM> {
|
|
||||||
let _lock = GLOBAL_LOCK.lock();
|
let _lock = GLOBAL_LOCK.lock();
|
||||||
|
|
||||||
// XSetLocaleModifiers returns...
|
// XSetLocaleModifiers returns...
|
||||||
|
@ -97,11 +96,9 @@ unsafe fn get_xim_servers(xconn: &Arc<XConnection>) -> Result<Vec<String>, GetXi
|
||||||
|
|
||||||
let root = (xconn.xlib.XDefaultRootWindow)(xconn.display);
|
let root = (xconn.xlib.XDefaultRootWindow)(xconn.display);
|
||||||
|
|
||||||
let mut atoms: Vec<ffi::Atom> = xconn.get_property(
|
let mut atoms: Vec<ffi::Atom> = xconn
|
||||||
root,
|
.get_property(root, servers_atom, ffi::XA_ATOM)
|
||||||
servers_atom,
|
.map_err(GetXimServersError::GetPropertyError)?;
|
||||||
ffi::XA_ATOM,
|
|
||||||
).map_err(GetXimServersError::GetPropertyError)?;
|
|
||||||
|
|
||||||
let mut names: Vec<*const c_char> = Vec::with_capacity(atoms.len());
|
let mut names: Vec<*const c_char> = Vec::with_capacity(atoms.len());
|
||||||
(xconn.xlib.XGetAtomNames)(
|
(xconn.xlib.XGetAtomNames)(
|
||||||
|
@ -135,15 +132,12 @@ impl InputMethodName {
|
||||||
pub fn from_string(string: String) -> Self {
|
pub fn from_string(string: String) -> Self {
|
||||||
let c_string = CString::new(string.clone())
|
let c_string = CString::new(string.clone())
|
||||||
.expect("String used to construct CString contained null byte");
|
.expect("String used to construct CString contained null byte");
|
||||||
InputMethodName {
|
InputMethodName { c_string, string }
|
||||||
c_string,
|
|
||||||
string,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_str(string: &str) -> Self {
|
pub fn from_str(string: &str) -> Self {
|
||||||
let c_string = CString::new(string)
|
let c_string =
|
||||||
.expect("String used to construct CString contained null byte");
|
CString::new(string).expect("String used to construct CString contained null byte");
|
||||||
InputMethodName {
|
InputMethodName {
|
||||||
c_string,
|
c_string,
|
||||||
string: string.to_owned(),
|
string: string.to_owned(),
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
// Important: all XIM calls need to happen from the same thread!
|
// Important: all XIM calls need to happen from the same thread!
|
||||||
|
|
||||||
|
mod callbacks;
|
||||||
|
mod context;
|
||||||
mod inner;
|
mod inner;
|
||||||
mod input_method;
|
mod input_method;
|
||||||
mod context;
|
|
||||||
mod callbacks;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::{
|
||||||
use std::sync::mpsc::{Receiver, Sender};
|
mpsc::{Receiver, Sender},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{ffi, util, XConnection, XError};
|
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;
|
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 ImeReceiver = Receiver<(ffi::Window, i16, i16)>;
|
||||||
pub type ImeSender = Sender<(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 potential_input_methods = PotentialInputMethods::new(&xconn);
|
||||||
|
|
||||||
let (mut inner, client_data) = {
|
let (mut inner, client_data) = {
|
||||||
let mut inner = Box::new(ImeInner::new(
|
let mut inner = Box::new(ImeInner::new(xconn, potential_input_methods));
|
||||||
xconn,
|
|
||||||
potential_input_methods,
|
|
||||||
));
|
|
||||||
let inner_ptr = Box::into_raw(inner);
|
let inner_ptr = Box::into_raw(inner);
|
||||||
let client_data = inner_ptr as _;
|
let client_data = inner_ptr as _;
|
||||||
let destroy_callback = ffi::XIMCallback {
|
let destroy_callback = ffi::XIMCallback {
|
||||||
|
@ -54,9 +55,12 @@ impl Ime {
|
||||||
|
|
||||||
let xconn = Arc::clone(&inner.xconn);
|
let xconn = Arc::clone(&inner.xconn);
|
||||||
|
|
||||||
let input_method = inner.potential_input_methods.open_im(&xconn, Some(&|| {
|
let input_method = inner.potential_input_methods.open_im(
|
||||||
let _ = unsafe { set_instantiate_callback(&xconn, client_data) };
|
&xconn,
|
||||||
}));
|
Some(&|| {
|
||||||
|
let _ = unsafe { set_instantiate_callback(&xconn, client_data) };
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
let is_fallback = input_method.is_fallback();
|
let is_fallback = input_method.is_fallback();
|
||||||
if let Some(input_method) = input_method.ok() {
|
if let Some(input_method) = input_method.ok() {
|
||||||
|
@ -84,19 +88,12 @@ impl Ime {
|
||||||
// Ok(_) indicates that nothing went wrong internally
|
// Ok(_) indicates that nothing went wrong internally
|
||||||
// Ok(true) indicates that the action was actually performed
|
// Ok(true) indicates that the action was actually performed
|
||||||
// Ok(false) indicates that the action is not presently applicable
|
// Ok(false) indicates that the action is not presently applicable
|
||||||
pub fn create_context(&mut self, window: ffi::Window)
|
pub fn create_context(&mut self, window: ffi::Window) -> Result<bool, ImeContextCreationError> {
|
||||||
-> Result<bool, ImeContextCreationError>
|
|
||||||
{
|
|
||||||
let context = if self.is_destroyed() {
|
let context = if self.is_destroyed() {
|
||||||
// Create empty entry in map, so that when IME is rebuilt, this window has a context.
|
// Create empty entry in map, so that when IME is rebuilt, this window has a context.
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(unsafe { ImeContext::new(
|
Some(unsafe { ImeContext::new(&self.inner.xconn, self.inner.im, window, None) }?)
|
||||||
&self.inner.xconn,
|
|
||||||
self.inner.im,
|
|
||||||
window,
|
|
||||||
None,
|
|
||||||
) }?)
|
|
||||||
};
|
};
|
||||||
self.inner.contexts.insert(window, context);
|
self.inner.contexts.insert(window, context);
|
||||||
Ok(!self.is_destroyed())
|
Ok(!self.is_destroyed())
|
||||||
|
|
|
@ -1,39 +1,47 @@
|
||||||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
#![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;
|
mod events;
|
||||||
|
pub mod ffi;
|
||||||
|
mod ime;
|
||||||
mod monitor;
|
mod monitor;
|
||||||
|
pub mod util;
|
||||||
mod window;
|
mod window;
|
||||||
mod xdisplay;
|
mod xdisplay;
|
||||||
mod dnd;
|
|
||||||
mod ime;
|
|
||||||
pub mod util;
|
|
||||||
mod event_processor;
|
|
||||||
|
|
||||||
pub use self::monitor::MonitorHandle;
|
pub use self::{
|
||||||
pub use self::window::UnownedWindow;
|
monitor::MonitorHandle,
|
||||||
pub use self::xdisplay::{XConnection, XNotSupported, XError};
|
window::UnownedWindow,
|
||||||
|
xdisplay::{XConnection, XError, XNotSupported},
|
||||||
|
};
|
||||||
|
|
||||||
use std::{mem, slice};
|
use std::{
|
||||||
use std::cell::RefCell;
|
cell::RefCell,
|
||||||
use std::collections::{VecDeque, HashMap, HashSet};
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
use std::ffi::CStr;
|
ffi::CStr,
|
||||||
use std::ops::Deref;
|
mem,
|
||||||
use std::os::raw::*;
|
ops::Deref,
|
||||||
use std::rc::Rc;
|
os::raw::*,
|
||||||
use std::sync::{Arc, mpsc, Weak, Mutex};
|
rc::Rc,
|
||||||
|
slice,
|
||||||
|
sync::{mpsc, Arc, Mutex, Weak},
|
||||||
|
};
|
||||||
|
|
||||||
use libc::{self, setlocale, LC_CTYPE};
|
use libc::{self, setlocale, LC_CTYPE};
|
||||||
|
|
||||||
use crate::error::OsError as RootOsError;
|
use self::{
|
||||||
use crate::event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW};
|
dnd::{Dnd, DndState},
|
||||||
use crate::event::{WindowEvent, Event};
|
event_processor::EventProcessor,
|
||||||
use crate::platform_impl::PlatformSpecificWindowBuilderAttributes;
|
ime::{Ime, ImeCreationError, ImeReceiver, ImeSender},
|
||||||
use crate::platform_impl::platform::sticky_exit_callback;
|
};
|
||||||
use crate::window::{WindowAttributes};
|
use crate::{
|
||||||
use self::dnd::{Dnd, DndState};
|
error::OsError as RootOsError,
|
||||||
use self::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime};
|
event::{Event, WindowEvent},
|
||||||
use self::event_processor::EventProcessor;
|
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||||
|
platform_impl::{platform::sticky_exit_callback, PlatformSpecificWindowBuilderAttributes},
|
||||||
|
window::WindowAttributes,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct EventLoopWindowTarget<T> {
|
pub struct EventLoopWindowTarget<T> {
|
||||||
xconn: Arc<XConnection>,
|
xconn: Arc<XConnection>,
|
||||||
|
@ -43,7 +51,7 @@ pub struct EventLoopWindowTarget<T> {
|
||||||
ime: RefCell<Ime>,
|
ime: RefCell<Ime>,
|
||||||
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
|
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
|
||||||
pending_redraws: Arc<Mutex<HashSet<WindowId>>>,
|
pending_redraws: Arc<Mutex<HashSet<WindowId>>>,
|
||||||
_marker: ::std::marker::PhantomData<T>
|
_marker: ::std::marker::PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop<T: 'static> {
|
||||||
|
@ -53,7 +61,7 @@ pub struct EventLoop<T: 'static> {
|
||||||
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
||||||
user_sender: ::calloop::channel::Sender<T>,
|
user_sender: ::calloop::channel::Sender<T>,
|
||||||
pending_events: Rc<RefCell<VecDeque<Event<T>>>>,
|
pending_events: Rc<RefCell<VecDeque<Event<T>>>>,
|
||||||
target: Rc<RootELW<T>>
|
target: Rc<RootELW<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -73,7 +81,9 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let (ime_sender, ime_receiver) = mpsc::channel();
|
let (ime_sender, ime_receiver) = mpsc::channel();
|
||||||
// Input methods will open successfully without setting the locale, but it won't be
|
// Input methods will open successfully without setting the locale, but it won't be
|
||||||
// possible to actually commit pre-edit sequences.
|
// 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 ime = RefCell::new({
|
||||||
let result = Ime::new(Arc::clone(&xconn));
|
let result = Ime::new(Arc::clone(&xconn));
|
||||||
if let Err(ImeCreationError::OpenFailure(ref state)) = result {
|
if let Err(ImeCreationError::OpenFailure(ref state)) = result {
|
||||||
|
@ -82,7 +92,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
result.expect("Failed to set input method destruction callback")
|
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");
|
.expect("Failed to query XRandR extension");
|
||||||
|
|
||||||
let xi2ext = unsafe {
|
let xi2ext = unsafe {
|
||||||
|
@ -96,7 +107,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
b"XInputExtension\0".as_ptr() as *const c_char,
|
b"XInputExtension\0".as_ptr() as *const c_char,
|
||||||
&mut result.opcode as *mut c_int,
|
&mut result.opcode as *mut c_int,
|
||||||
&mut result.first_event_id 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 {
|
if res == ffi::False {
|
||||||
panic!("X server missing XInput extension");
|
panic!("X server missing XInput extension");
|
||||||
}
|
}
|
||||||
|
@ -110,18 +122,18 @@ impl<T: 'static> EventLoop<T> {
|
||||||
xconn.display,
|
xconn.display,
|
||||||
&mut xinput_major_ver,
|
&mut xinput_major_ver,
|
||||||
&mut xinput_minor_ver,
|
&mut xinput_minor_ver,
|
||||||
) != ffi::Success as libc::c_int {
|
) != ffi::Success as libc::c_int
|
||||||
|
{
|
||||||
panic!(
|
panic!(
|
||||||
"X server has XInput extension {}.{} but does not support XInput2",
|
"X server has XInput extension {}.{} but does not support XInput2",
|
||||||
xinput_major_ver,
|
xinput_major_ver, xinput_minor_ver,
|
||||||
xinput_minor_ver,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xconn.update_cached_wm_info(root);
|
xconn.update_cached_wm_info(root);
|
||||||
|
|
||||||
let target = Rc::new(RootELW{
|
let target = Rc::new(RootELW {
|
||||||
p: super::EventLoopWindowTarget::X(EventLoopWindowTarget {
|
p: super::EventLoopWindowTarget::X(EventLoopWindowTarget {
|
||||||
ime,
|
ime,
|
||||||
root,
|
root,
|
||||||
|
@ -132,7 +144,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
wm_delete_window,
|
wm_delete_window,
|
||||||
pending_redraws: Default::default(),
|
pending_redraws: Default::default(),
|
||||||
}),
|
}),
|
||||||
_marker: ::std::marker::PhantomData
|
_marker: ::std::marker::PhantomData,
|
||||||
});
|
});
|
||||||
|
|
||||||
// A calloop event loop to drive us
|
// A calloop event loop to drive us
|
||||||
|
@ -144,11 +156,14 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
let (user_sender, user_channel) = ::calloop::channel::channel();
|
let (user_sender, user_channel) = ::calloop::channel::channel();
|
||||||
|
|
||||||
let _user_source = inner_loop.handle().insert_source(user_channel, move |evt, &mut()| {
|
let _user_source = inner_loop
|
||||||
if let ::calloop::channel::Event::Msg(msg) = evt {
|
.handle()
|
||||||
pending_user_events2.borrow_mut().push_back(msg);
|
.insert_source(user_channel, move |evt, &mut ()| {
|
||||||
}
|
if let ::calloop::channel::Event::Msg(msg) = evt {
|
||||||
}).unwrap();
|
pending_user_events2.borrow_mut().push_back(msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Handle X11 events
|
// Handle X11 events
|
||||||
let pending_events: Rc<RefCell<VecDeque<_>>> = Default::default();
|
let pending_events: Rc<RefCell<VecDeque<_>>> = Default::default();
|
||||||
|
@ -164,20 +179,20 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
// Register for device hotplug events
|
// Register for device hotplug events
|
||||||
// (The request buffer is flushed during `init_device`)
|
// (The request buffer is flushed during `init_device`)
|
||||||
get_xtarget(&target).xconn.select_xinput_events(
|
get_xtarget(&target)
|
||||||
root,
|
.xconn
|
||||||
ffi::XIAllDevices,
|
.select_xinput_events(root, ffi::XIAllDevices, ffi::XI_HierarchyChangedMask)
|
||||||
ffi::XI_HierarchyChangedMask,
|
.queue();
|
||||||
).queue();
|
|
||||||
|
|
||||||
processor.init_device(ffi::XIAllDevices);
|
processor.init_device(ffi::XIAllDevices);
|
||||||
|
|
||||||
// Setup the X11 event source
|
// 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());
|
x11_events.set_interest(::calloop::mio::Ready::readable());
|
||||||
let _x11_source = inner_loop.handle().insert_source(
|
let _x11_source = inner_loop
|
||||||
x11_events,
|
.handle()
|
||||||
{
|
.insert_source(x11_events, {
|
||||||
let pending_events = pending_events.clone();
|
let pending_events = pending_events.clone();
|
||||||
let mut callback = move |event| {
|
let mut callback = move |event| {
|
||||||
pending_events.borrow_mut().push_back(event);
|
pending_events.borrow_mut().push_back(event);
|
||||||
|
@ -191,8 +206,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
).unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = EventLoop {
|
let result = EventLoop {
|
||||||
inner_loop,
|
inner_loop,
|
||||||
|
@ -201,7 +216,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
_user_source,
|
_user_source,
|
||||||
user_sender,
|
user_sender,
|
||||||
pending_user_events,
|
pending_user_events,
|
||||||
target
|
target,
|
||||||
};
|
};
|
||||||
|
|
||||||
result
|
result
|
||||||
|
@ -224,7 +239,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, mut callback: F)
|
pub fn run_return<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow)
|
where
|
||||||
|
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
let mut control_flow = ControlFlow::default();
|
let mut control_flow = ControlFlow::default();
|
||||||
let wt = get_xtarget(&self.target);
|
let wt = get_xtarget(&self.target);
|
||||||
|
@ -246,7 +262,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
crate::event::Event::UserEvent(evt),
|
crate::event::Event::UserEvent(evt),
|
||||||
&self.target,
|
&self.target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
&mut callback
|
&mut callback,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,11 +273,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
sticky_exit_callback(
|
sticky_exit_callback(
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
window_id: crate::window::WindowId(super::WindowId::X(wid)),
|
window_id: crate::window::WindowId(super::WindowId::X(wid)),
|
||||||
event: WindowEvent::RedrawRequested
|
event: WindowEvent::RedrawRequested,
|
||||||
},
|
},
|
||||||
&self.target,
|
&self.target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
&mut callback
|
&mut callback,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,29 +287,37 @@ impl<T: 'static> EventLoop<T> {
|
||||||
crate::event::Event::EventsCleared,
|
crate::event::Event::EventsCleared,
|
||||||
&self.target,
|
&self.target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
&mut callback
|
&mut callback,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush the X11 connection
|
// flush the X11 connection
|
||||||
unsafe { (wt.xconn.xlib.XFlush)(wt.xconn.display); }
|
unsafe {
|
||||||
|
(wt.xconn.xlib.XFlush)(wt.xconn.display);
|
||||||
|
}
|
||||||
|
|
||||||
match control_flow {
|
match control_flow {
|
||||||
ControlFlow::Exit => break,
|
ControlFlow::Exit => break,
|
||||||
ControlFlow::Poll => {
|
ControlFlow::Poll => {
|
||||||
// non-blocking dispatch
|
// non-blocking dispatch
|
||||||
self.inner_loop.dispatch(Some(::std::time::Duration::from_millis(0)), &mut ()).unwrap();
|
self.inner_loop
|
||||||
callback(crate::event::Event::NewEvents(crate::event::StartCause::Poll), &self.target, &mut control_flow);
|
.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 => {
|
ControlFlow::Wait => {
|
||||||
self.inner_loop.dispatch(None, &mut ()).unwrap();
|
self.inner_loop.dispatch(None, &mut ()).unwrap();
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
||||||
start: ::std::time::Instant::now(),
|
start: ::std::time::Instant::now(),
|
||||||
requested_resume: None
|
requested_resume: None,
|
||||||
}),
|
}),
|
||||||
&self.target,
|
&self.target,
|
||||||
&mut control_flow
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
ControlFlow::WaitUntil(deadline) => {
|
ControlFlow::WaitUntil(deadline) => {
|
||||||
|
@ -308,32 +332,41 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let now = std::time::Instant::now();
|
let now = std::time::Instant::now();
|
||||||
if now < deadline {
|
if now < deadline {
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
crate::event::Event::NewEvents(
|
||||||
start,
|
crate::event::StartCause::WaitCancelled {
|
||||||
requested_resume: Some(deadline)
|
start,
|
||||||
}),
|
requested_resume: Some(deadline),
|
||||||
|
},
|
||||||
|
),
|
||||||
&self.target,
|
&self.target,
|
||||||
&mut control_flow
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::ResumeTimeReached {
|
crate::event::Event::NewEvents(
|
||||||
start,
|
crate::event::StartCause::ResumeTimeReached {
|
||||||
requested_resume: deadline
|
start,
|
||||||
}),
|
requested_resume: deadline,
|
||||||
|
},
|
||||||
|
),
|
||||||
&self.target,
|
&self.target,
|
||||||
&mut control_flow
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(crate::event::Event::LoopDestroyed, &self.target, &mut control_flow);
|
callback(
|
||||||
|
crate::event::Event::LoopDestroyed,
|
||||||
|
&self.target,
|
||||||
|
&mut control_flow,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<F>(mut self, callback: F) -> !
|
pub fn run<F>(mut self, callback: F) -> !
|
||||||
where F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow)
|
where
|
||||||
|
F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.run_return(callback);
|
self.run_return(callback);
|
||||||
::std::process::exit(0);
|
::std::process::exit(0);
|
||||||
|
@ -342,10 +375,10 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
fn get_xtarget<T>(rt: &RootELW<T>) -> &EventLoopWindowTarget<T> {
|
fn get_xtarget<T>(rt: &RootELW<T>) -> &EventLoopWindowTarget<T> {
|
||||||
if let super::EventLoopWindowTarget::X(ref target) = rt.p {
|
if let super::EventLoopWindowTarget::X(ref target) = rt.p {
|
||||||
target
|
target
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl<T: 'static> EventLoopProxy<T> {
|
||||||
|
@ -365,19 +398,17 @@ impl<'a> DeviceInfo<'a> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut count = mem::uninitialized();
|
let mut count = mem::uninitialized();
|
||||||
let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
|
let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
|
||||||
xconn.check_errors()
|
xconn.check_errors().ok().and_then(|_| {
|
||||||
.ok()
|
if info.is_null() || count == 0 {
|
||||||
.and_then(|_| {
|
None
|
||||||
if info.is_null() || count == 0 {
|
} else {
|
||||||
None
|
Some(DeviceInfo {
|
||||||
} else {
|
xconn,
|
||||||
Some(DeviceInfo {
|
info,
|
||||||
xconn,
|
count: count as usize,
|
||||||
info,
|
})
|
||||||
count: count as usize,
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,10 +459,11 @@ impl Window {
|
||||||
pub fn new<T>(
|
pub fn new<T>(
|
||||||
event_loop: &EventLoopWindowTarget<T>,
|
event_loop: &EventLoopWindowTarget<T>,
|
||||||
attribs: WindowAttributes,
|
attribs: WindowAttributes,
|
||||||
pl_attribs: PlatformSpecificWindowBuilderAttributes
|
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
) -> Result<Self, RootOsError> {
|
) -> Result<Self, RootOsError> {
|
||||||
let window = Arc::new(UnownedWindow::new(&event_loop, attribs, pl_attribs)?);
|
let window = Arc::new(UnownedWindow::new(&event_loop, attribs, pl_attribs)?);
|
||||||
event_loop.windows
|
event_loop
|
||||||
|
.windows
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(window.id(), Arc::downgrade(&window));
|
.insert(window.id(), Arc::downgrade(&window));
|
||||||
Ok(Window(window))
|
Ok(Window(window))
|
||||||
|
@ -454,11 +486,14 @@ impl Drop for Window {
|
||||||
/// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed
|
/// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed
|
||||||
struct GenericEventCookie<'a> {
|
struct GenericEventCookie<'a> {
|
||||||
xconn: &'a XConnection,
|
xconn: &'a XConnection,
|
||||||
cookie: ffi::XGenericEventCookie
|
cookie: ffi::XGenericEventCookie,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GenericEventCookie<'a> {
|
impl<'a> GenericEventCookie<'a> {
|
||||||
fn from_event<'b>(xconn: &'b XConnection, event: ffi::XEvent) -> Option<GenericEventCookie<'b>> {
|
fn from_event<'b>(
|
||||||
|
xconn: &'b XConnection,
|
||||||
|
event: ffi::XEvent,
|
||||||
|
) -> Option<GenericEventCookie<'b>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut cookie: ffi::XGenericEventCookie = From::from(event);
|
let mut cookie: ffi::XGenericEventCookie = From::from(event);
|
||||||
if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == ffi::True {
|
if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == ffi::True {
|
||||||
|
@ -485,8 +520,12 @@ struct XExtension {
|
||||||
first_error_id: c_int,
|
first_error_id: c_int,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mkwid(w: ffi::Window) -> crate::window::WindowId { crate::window::WindowId(crate::platform_impl::WindowId::X(WindowId(w))) }
|
fn mkwid(w: ffi::Window) -> crate::window::WindowId {
|
||||||
fn mkdid(w: c_int) -> crate::event::DeviceId { crate::event::DeviceId(crate::platform_impl::DeviceId::X(DeviceId(w))) }
|
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)]
|
#[derive(Debug)]
|
||||||
struct Device {
|
struct Device {
|
||||||
|
@ -525,32 +564,39 @@ impl Device {
|
||||||
| ffi::XI_RawKeyPressMask
|
| ffi::XI_RawKeyPressMask
|
||||||
| ffi::XI_RawKeyReleaseMask;
|
| ffi::XI_RawKeyReleaseMask;
|
||||||
// The request buffer is flushed when we poll for events
|
// 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
|
// Identify scroll axes
|
||||||
for class_ptr in Device::classes(info) {
|
for class_ptr in Device::classes(info) {
|
||||||
let class = unsafe { &**class_ptr };
|
let class = unsafe { &**class_ptr };
|
||||||
match class._type {
|
match class._type {
|
||||||
ffi::XIScrollClass => {
|
ffi::XIScrollClass => {
|
||||||
let info = unsafe { mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIScrollClassInfo>(class) };
|
let info = unsafe {
|
||||||
scroll_axes.push((info.number, ScrollAxis {
|
mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIScrollClassInfo>(class)
|
||||||
increment: info.increment,
|
};
|
||||||
orientation: match info.scroll_type {
|
scroll_axes.push((
|
||||||
ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
|
info.number,
|
||||||
ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
|
ScrollAxis {
|
||||||
_ => { unreachable!() }
|
increment: info.increment,
|
||||||
|
orientation: match info.scroll_type {
|
||||||
|
ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
|
||||||
|
ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
position: 0.0,
|
||||||
},
|
},
|
||||||
position: 0.0,
|
));
|
||||||
}));
|
},
|
||||||
}
|
_ => {},
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut device = Device {
|
let mut device = Device {
|
||||||
name: name.into_owned(),
|
name: name.into_owned(),
|
||||||
scroll_axes: scroll_axes,
|
scroll_axes,
|
||||||
attachment: info.attachment,
|
attachment: info.attachment,
|
||||||
};
|
};
|
||||||
device.reset_scroll_position(info);
|
device.reset_scroll_position(info);
|
||||||
|
@ -563,12 +609,18 @@ impl Device {
|
||||||
let class = unsafe { &**class_ptr };
|
let class = unsafe { &**class_ptr };
|
||||||
match class._type {
|
match class._type {
|
||||||
ffi::XIValuatorClass => {
|
ffi::XIValuatorClass => {
|
||||||
let info = unsafe { mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIValuatorClassInfo>(class) };
|
let info = unsafe {
|
||||||
if let Some(&mut (_, ref mut axis)) = self.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == info.number) {
|
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;
|
axis.position = info.value;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -576,11 +628,18 @@ impl Device {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn physical_device(info: &ffi::XIDeviceInfo) -> bool {
|
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]
|
#[inline]
|
||||||
fn classes(info: &ffi::XIDeviceInfo) -> &[*const ffi::XIAnyClassInfo] {
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ use std::os::raw::*;
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
use super::{
|
||||||
use crate::monitor::VideoMode;
|
ffi::{
|
||||||
use super::{util, XConnection, XError};
|
RRCrtcChangeNotifyMask, RROutputPropertyNotifyMask, RRScreenChangeNotifyMask, True, Window,
|
||||||
use super::ffi::{
|
XRRScreenResources,
|
||||||
RRCrtcChangeNotifyMask,
|
},
|
||||||
RROutputPropertyNotifyMask,
|
util, XConnection, XError,
|
||||||
RRScreenChangeNotifyMask,
|
};
|
||||||
True,
|
use crate::{
|
||||||
Window,
|
dpi::{PhysicalPosition, PhysicalSize},
|
||||||
XRRScreenResources,
|
monitor::VideoMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used to test XRandR < 1.5 code path. This should always be committed as false.
|
// Used to test XRandR < 1.5 code path. This should always be committed as false.
|
||||||
|
@ -160,7 +160,8 @@ impl XConnection {
|
||||||
// videowalls.
|
// videowalls.
|
||||||
let xrandr_1_5 = self.xrandr_1_5.as_ref().unwrap();
|
let xrandr_1_5 = self.xrandr_1_5.as_ref().unwrap();
|
||||||
let mut monitor_count = 0;
|
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);
|
assert!(monitor_count >= 0);
|
||||||
available = Vec::with_capacity(monitor_count as usize);
|
available = Vec::with_capacity(monitor_count as usize);
|
||||||
for monitor_index in 0..monitor_count {
|
for monitor_index in 0..monitor_count {
|
||||||
|
@ -173,7 +174,8 @@ impl XConnection {
|
||||||
monitor_index as u32,
|
monitor_index as u32,
|
||||||
monitor.into(),
|
monitor.into(),
|
||||||
is_primary,
|
is_primary,
|
||||||
).map(|monitor_id| available.push(monitor_id));
|
)
|
||||||
|
.map(|monitor_id| available.push(monitor_id));
|
||||||
}
|
}
|
||||||
(xrandr_1_5.XRRFreeMonitors)(monitors);
|
(xrandr_1_5.XRRFreeMonitors)(monitors);
|
||||||
} else {
|
} else {
|
||||||
|
@ -190,13 +192,8 @@ impl XConnection {
|
||||||
let crtc = util::MonitorRepr::from(crtc);
|
let crtc = util::MonitorRepr::from(crtc);
|
||||||
let is_primary = crtc.get_output() == primary;
|
let is_primary = crtc.get_output() == primary;
|
||||||
has_primary |= is_primary;
|
has_primary |= is_primary;
|
||||||
MonitorHandle::from_repr(
|
MonitorHandle::from_repr(self, resources, crtc_id as u32, crtc, is_primary)
|
||||||
self,
|
.map(|monitor_id| available.push(monitor_id));
|
||||||
resources,
|
|
||||||
crtc_id as u32,
|
|
||||||
crtc,
|
|
||||||
is_primary,
|
|
||||||
).map(|monitor_id| available.push(monitor_id));
|
|
||||||
}
|
}
|
||||||
(self.xrandr.XRRFreeCrtcInfo)(crtc);
|
(self.xrandr.XRRFreeCrtcInfo)(crtc);
|
||||||
}
|
}
|
||||||
|
@ -244,13 +241,8 @@ impl XConnection {
|
||||||
if version_lock.is_none() {
|
if version_lock.is_none() {
|
||||||
let mut major = 0;
|
let mut major = 0;
|
||||||
let mut minor = 0;
|
let mut minor = 0;
|
||||||
let has_extension = unsafe {
|
let has_extension =
|
||||||
(self.xrandr.XRRQueryVersion)(
|
unsafe { (self.xrandr.XRRQueryVersion)(self.display, &mut major, &mut minor) };
|
||||||
self.display,
|
|
||||||
&mut major,
|
|
||||||
&mut minor,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
if has_extension != True {
|
if has_extension != True {
|
||||||
panic!("[winit] XRandR extension not available.");
|
panic!("[winit] XRandR extension not available.");
|
||||||
}
|
}
|
||||||
|
@ -261,11 +253,7 @@ impl XConnection {
|
||||||
let mut event_offset = 0;
|
let mut event_offset = 0;
|
||||||
let mut error_offset = 0;
|
let mut error_offset = 0;
|
||||||
let status = unsafe {
|
let status = unsafe {
|
||||||
(self.xrandr.XRRQueryExtension)(
|
(self.xrandr.XRRQueryExtension)(self.display, &mut event_offset, &mut error_offset)
|
||||||
self.display,
|
|
||||||
&mut event_offset,
|
|
||||||
&mut error_offset,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if status != True {
|
if status != True {
|
||||||
|
@ -273,9 +261,7 @@ impl XConnection {
|
||||||
unreachable!("[winit] `XRRQueryExtension` failed but no error was received.");
|
unreachable!("[winit] `XRRQueryExtension` failed but no error was received.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mask = RRCrtcChangeNotifyMask
|
let mask = RRCrtcChangeNotifyMask | RROutputPropertyNotifyMask | RRScreenChangeNotifyMask;
|
||||||
| RROutputPropertyNotifyMask
|
|
||||||
| RRScreenChangeNotifyMask;
|
|
||||||
unsafe { (self.xrandr.XRRSelectInput)(self.display, root, mask) };
|
unsafe { (self.xrandr.XRRSelectInput)(self.display, root, mask) };
|
||||||
|
|
||||||
Ok(event_offset)
|
Ok(event_offset)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use std::collections::HashMap;
|
use std::{
|
||||||
use std::ffi::{CStr, CString};
|
collections::HashMap,
|
||||||
use std::fmt::Debug;
|
ffi::{CStr, CString},
|
||||||
use std::os::raw::*;
|
fmt::Debug,
|
||||||
|
os::raw::*,
|
||||||
|
};
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
@ -21,11 +23,9 @@ impl XConnection {
|
||||||
if let Some(atom) = cached_atom {
|
if let Some(atom) = cached_atom {
|
||||||
atom
|
atom
|
||||||
} else {
|
} else {
|
||||||
let atom = unsafe { (self.xlib.XInternAtom)(
|
let atom = unsafe {
|
||||||
self.display,
|
(self.xlib.XInternAtom)(self.display, name.as_ptr() as *const c_char, ffi::False)
|
||||||
name.as_ptr() as *const c_char,
|
};
|
||||||
ffi::False,
|
|
||||||
) };
|
|
||||||
if atom == 0 {
|
if atom == 0 {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"`XInternAtom` failed, which really shouldn't happen. Atom: {:?}, Error: {:#?}",
|
"`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.
|
// 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.
|
// 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<Vec<ffi::Atom>, XError> {
|
pub unsafe fn get_atoms(&self, names: &[*mut c_char]) -> Result<Vec<ffi::Atom>, XError> {
|
||||||
let mut atoms = Vec::with_capacity(names.len());
|
let mut atoms = Vec::with_capacity(names.len());
|
||||||
(self.xlib.XInternAtoms)(
|
(self.xlib.XInternAtoms)(
|
||||||
self.display,
|
self.display,
|
||||||
|
|
|
@ -24,7 +24,7 @@ impl XConnection {
|
||||||
|
|
||||||
pub fn send_client_msg(
|
pub fn send_client_msg(
|
||||||
&self,
|
&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
|
target_window: c_ulong, // The window we're sending to
|
||||||
message_type: ffi::Atom,
|
message_type: ffi::Atom,
|
||||||
event_mask: Option<c_long>,
|
event_mask: Option<c_long>,
|
||||||
|
@ -45,7 +45,7 @@ impl XConnection {
|
||||||
// to send more than one message worth of data.
|
// to send more than one message worth of data.
|
||||||
pub fn send_client_msg_multi<T: Formattable>(
|
pub fn send_client_msg_multi<T: Formattable>(
|
||||||
&self,
|
&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
|
target_window: c_ulong, // The window we're sending to
|
||||||
message_type: ffi::Atom,
|
message_type: ffi::Atom,
|
||||||
event_mask: Option<c_long>,
|
event_mask: Option<c_long>,
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use std::fmt::Debug;
|
use std::{fmt::Debug, mem, os::raw::*};
|
||||||
use std::mem;
|
|
||||||
use std::os::raw::*;
|
|
||||||
|
|
||||||
// This isn't actually the number of the bits in the format.
|
// 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.
|
// 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.
|
// 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_schar {
|
||||||
impl Formattable for c_uchar { const FORMAT: Format = Format::Char; }
|
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_uchar {
|
||||||
impl Formattable for c_long { const FORMAT: Format = Format::Long; }
|
const FORMAT: Format = Format::Char;
|
||||||
impl Formattable for c_ulong { const FORMAT: Format = Format::Long; }
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,12 @@ impl AaRect {
|
||||||
pub fn new((x, y): (i32, i32), (width, height): (u32, u32)) -> Self {
|
pub fn new((x, y): (i32, i32), (width, height): (u32, u32)) -> Self {
|
||||||
let (x, y) = (x as i64, y as i64);
|
let (x, y) = (x as i64, y as i64);
|
||||||
let (width, height) = (width as i64, height 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 {
|
pub fn contains_point(&self, x: i64, y: i64) -> bool {
|
||||||
|
@ -73,7 +78,12 @@ pub struct FrameExtents {
|
||||||
|
|
||||||
impl FrameExtents {
|
impl FrameExtents {
|
||||||
pub fn new(left: c_ulong, right: c_ulong, top: c_ulong, bottom: c_ulong) -> Self {
|
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 {
|
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) {
|
pub fn inner_pos_to_outer(&self, x: i32, y: i32) -> (i32, i32) {
|
||||||
use self::FrameExtentsHeuristicPath::*;
|
use self::FrameExtentsHeuristicPath::*;
|
||||||
if self.heuristic_path != UnsupportedBordered {
|
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 {
|
} else {
|
||||||
(x, y)
|
(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::*;
|
use self::FrameExtentsHeuristicPath::*;
|
||||||
if self.heuristic_path != UnsupportedBordered {
|
if self.heuristic_path != UnsupportedBordered {
|
||||||
let frame_extents = self.frame_extents.as_logical(factor);
|
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) {
|
pub fn inner_size_to_outer(&self, width: u32, height: u32) -> (u32, u32) {
|
||||||
(
|
(
|
||||||
width.saturating_add(
|
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(
|
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);
|
let frame_extents = self.frame_extents.as_logical(factor);
|
||||||
logical.width += frame_extents.left + frame_extents.right;
|
logical.width += frame_extents.left + frame_extents.right;
|
||||||
logical.height += frame_extents.top + frame_extents.bottom;
|
logical.height += frame_extents.top + frame_extents.bottom;
|
||||||
|
@ -153,7 +178,11 @@ impl FrameExtentsHeuristic {
|
||||||
|
|
||||||
impl XConnection {
|
impl XConnection {
|
||||||
// This is adequate for inner_position
|
// This is adequate for inner_position
|
||||||
pub fn translate_coords(&self, window: ffi::Window, root: ffi::Window) -> Result<TranslatedCoords, XError> {
|
pub fn translate_coords(
|
||||||
|
&self,
|
||||||
|
window: ffi::Window,
|
||||||
|
root: ffi::Window,
|
||||||
|
) -> Result<TranslatedCoords, XError> {
|
||||||
let mut translated_coords: TranslatedCoords = unsafe { mem::uninitialized() };
|
let mut translated_coords: TranslatedCoords = unsafe { mem::uninitialized() };
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.xlib.XTranslateCoordinates)(
|
(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
|
// 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
|
// support this. As this is part of EWMH (Extended Window Manager Hints), it's likely to
|
||||||
// be unsupported by many smaller WMs.
|
// be unsupported by many smaller WMs.
|
||||||
let extents: Option<Vec<c_ulong>> = self.get_property(
|
let extents: Option<Vec<c_ulong>> = self
|
||||||
window,
|
.get_property(window, extents_atom, ffi::XA_CARDINAL)
|
||||||
extents_atom,
|
.ok();
|
||||||
ffi::XA_CARDINAL,
|
|
||||||
).ok();
|
|
||||||
|
|
||||||
extents.and_then(|extents| {
|
extents.and_then(|extents| {
|
||||||
if extents.len() >= 4 {
|
if extents.len() >= 4 {
|
||||||
|
@ -228,11 +255,9 @@ impl XConnection {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let client_list: Option<Vec<ffi::Window>> = self.get_property(
|
let client_list: Option<Vec<ffi::Window>> = self
|
||||||
root,
|
.get_property(root, client_list_atom, ffi::XA_WINDOW)
|
||||||
client_list_atom,
|
.ok();
|
||||||
ffi::XA_WINDOW,
|
|
||||||
).ok();
|
|
||||||
|
|
||||||
client_list.map(|client_list| client_list.contains(&window))
|
client_list.map(|client_list| client_list.contains(&window))
|
||||||
}
|
}
|
||||||
|
@ -264,7 +289,11 @@ impl XConnection {
|
||||||
self.check_errors().map(|_| parent)
|
self.check_errors().map(|_| parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn climb_hierarchy(&self, window: ffi::Window, root: ffi::Window) -> Result<ffi::Window, XError> {
|
fn climb_hierarchy(
|
||||||
|
&self,
|
||||||
|
window: ffi::Window,
|
||||||
|
root: ffi::Window,
|
||||||
|
) -> Result<ffi::Window, XError> {
|
||||||
let mut outer_window = window;
|
let mut outer_window = window;
|
||||||
loop {
|
loop {
|
||||||
let candidate = self.get_parent_window(outer_window)?;
|
let candidate = self.get_parent_window(outer_window)?;
|
||||||
|
@ -276,7 +305,11 @@ impl XConnection {
|
||||||
Ok(outer_window)
|
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::*;
|
use self::FrameExtentsHeuristicPath::*;
|
||||||
|
|
||||||
// Position relative to root window.
|
// 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
|
// isn't nested are outlined in the comments throghout this function, but in addition to
|
||||||
// that, fullscreen windows often aren't nested.
|
// that, fullscreen windows often aren't nested.
|
||||||
let (inner_y_rel_root, child) = {
|
let (inner_y_rel_root, child) = {
|
||||||
let coords = self.translate_coords(window, root).expect("Failed to translate window coordinates");
|
let coords = self
|
||||||
(
|
.translate_coords(window, root)
|
||||||
coords.y_rel_root,
|
.expect("Failed to translate window coordinates");
|
||||||
coords.child,
|
(coords.y_rel_root, coords.child)
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (width, height, border) = {
|
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.width,
|
||||||
inner_geometry.height,
|
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
|
// 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
|
// just climb up the hierarchy and get the geometry of the outermost window we're
|
||||||
// nested in.
|
// 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_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.y_rel_parent,
|
||||||
outer_geometry.width,
|
outer_geometry.width,
|
||||||
|
@ -364,12 +402,8 @@ impl XConnection {
|
||||||
let top = offset_y;
|
let top = offset_y;
|
||||||
let bottom = diff_y.saturating_sub(offset_y);
|
let bottom = diff_y.saturating_sub(offset_y);
|
||||||
|
|
||||||
let frame_extents = FrameExtents::new(
|
let frame_extents =
|
||||||
left.into(),
|
FrameExtents::new(left.into(), right.into(), top.into(), bottom.into());
|
||||||
right.into(),
|
|
||||||
top.into(),
|
|
||||||
bottom.into(),
|
|
||||||
);
|
|
||||||
FrameExtentsHeuristic {
|
FrameExtentsHeuristic {
|
||||||
frame_extents,
|
frame_extents,
|
||||||
heuristic_path: UnsupportedNested,
|
heuristic_path: UnsupportedNested,
|
||||||
|
|
|
@ -99,7 +99,9 @@ pub struct NormalHints<'a> {
|
||||||
|
|
||||||
impl<'a> NormalHints<'a> {
|
impl<'a> NormalHints<'a> {
|
||||||
pub fn new(xconn: &'a XConnection) -> Self {
|
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 {
|
pub fn has_flag(&self, flag: c_long) -> bool {
|
||||||
|
@ -130,7 +132,11 @@ impl<'a> NormalHints<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_max_size(&self) -> Option<(u32, u32)> {
|
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)>) {
|
pub fn set_max_size(&mut self, max_size: Option<(u32, u32)>) {
|
||||||
|
@ -144,7 +150,11 @@ impl<'a> NormalHints<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_min_size(&self) -> Option<(u32, u32)> {
|
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)>) {
|
pub fn set_min_size(&mut self, min_size: Option<(u32, u32)>) {
|
||||||
|
@ -158,7 +168,11 @@ impl<'a> NormalHints<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_resize_increments(&self) -> Option<(u32, u32)> {
|
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)>) {
|
pub fn set_resize_increments(&mut self, resize_increments: Option<(u32, u32)>) {
|
||||||
|
@ -172,7 +186,11 @@ impl<'a> NormalHints<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_base_size(&self) -> Option<(u32, u32)> {
|
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)>) {
|
pub fn set_base_size(&mut self, base_size: Option<(u32, u32)>) {
|
||||||
|
@ -187,7 +205,10 @@ impl<'a> NormalHints<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XConnection {
|
impl XConnection {
|
||||||
pub fn get_wm_hints(&self, window: ffi::Window) -> Result<XSmartPointer<'_, ffi::XWMHints>, XError> {
|
pub fn get_wm_hints(
|
||||||
|
&self,
|
||||||
|
window: ffi::Window,
|
||||||
|
) -> Result<XSmartPointer<'_, ffi::XWMHints>, XError> {
|
||||||
let wm_hints = unsafe { (self.xlib.XGetWMHints)(self.display, window) };
|
let wm_hints = unsafe { (self.xlib.XGetWMHints)(self.display, window) };
|
||||||
self.check_errors()?;
|
self.check_errors()?;
|
||||||
let wm_hints = if wm_hints.is_null() {
|
let wm_hints = if wm_hints.is_null() {
|
||||||
|
@ -198,13 +219,13 @@ impl XConnection {
|
||||||
Ok(wm_hints)
|
Ok(wm_hints)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_wm_hints(&self, window: ffi::Window, wm_hints: XSmartPointer<'_, ffi::XWMHints>) -> Flusher<'_> {
|
pub fn set_wm_hints(
|
||||||
|
&self,
|
||||||
|
window: ffi::Window,
|
||||||
|
wm_hints: XSmartPointer<'_, ffi::XWMHints>,
|
||||||
|
) -> Flusher<'_> {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.xlib.XSetWMHints)(
|
(self.xlib.XSetWMHints)(self.display, window, wm_hints.ptr);
|
||||||
self.display,
|
|
||||||
window,
|
|
||||||
wm_hints.ptr,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Flusher::new(self)
|
Flusher::new(self)
|
||||||
}
|
}
|
||||||
|
@ -223,13 +244,13 @@ impl XConnection {
|
||||||
self.check_errors().map(|_| NormalHints { size_hints })
|
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 {
|
unsafe {
|
||||||
(self.xlib.XSetWMNormalHints)(
|
(self.xlib.XSetWMNormalHints)(self.display, window, normal_hints.size_hints.ptr);
|
||||||
self.display,
|
|
||||||
window,
|
|
||||||
normal_hints.size_hints.ptr,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Flusher::new(self)
|
Flusher::new(self)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::window::{Icon, Pixel, PIXEL_SIZE};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::window::{Icon, Pixel, PIXEL_SIZE};
|
||||||
|
|
||||||
impl Pixel {
|
impl Pixel {
|
||||||
pub fn to_packed_argb(&self) -> Cardinal {
|
pub fn to_packed_argb(&self) -> Cardinal {
|
||||||
|
|
|
@ -55,7 +55,12 @@ impl<'a> Drop for PointerState<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XConnection {
|
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 {
|
let mut event_mask = ffi::XIEventMask {
|
||||||
deviceid: device_id,
|
deviceid: device_id,
|
||||||
mask: &mask as *const _ as *mut c_uchar,
|
mask: &mask as *const _ as *mut c_uchar,
|
||||||
|
@ -74,14 +79,7 @@ impl XConnection {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn select_xkb_events(&self, device_id: c_uint, mask: c_ulong) -> Option<Flusher<'_>> {
|
pub fn select_xkb_events(&self, device_id: c_uint, mask: c_ulong) -> Option<Flusher<'_>> {
|
||||||
let status = unsafe {
|
let status = unsafe { (self.xlib.XkbSelectEvents)(self.display, device_id, mask, mask) };
|
||||||
(self.xlib.XkbSelectEvents)(
|
|
||||||
self.display,
|
|
||||||
device_id,
|
|
||||||
mask,
|
|
||||||
mask,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
if status == ffi::True {
|
if status == ffi::True {
|
||||||
Some(Flusher::new(self))
|
Some(Flusher::new(self))
|
||||||
} else {
|
} else {
|
||||||
|
@ -89,7 +87,11 @@ impl XConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_pointer(&self, window: ffi::Window, device_id: c_int) -> Result<PointerState<'_>, XError> {
|
pub fn query_pointer(
|
||||||
|
&self,
|
||||||
|
window: ffi::Window,
|
||||||
|
device_id: c_int,
|
||||||
|
) -> Result<PointerState<'_>, XError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut pointer_state: PointerState<'_> = mem::uninitialized();
|
let mut pointer_state: PointerState<'_> = mem::uninitialized();
|
||||||
pointer_state.xconn = self;
|
pointer_state.xconn = self;
|
||||||
|
|
|
@ -12,10 +12,7 @@ impl<'a, T> XSmartPointer<'a, T> {
|
||||||
// Returns None if ptr is null.
|
// Returns None if ptr is null.
|
||||||
pub fn new(xconn: &'a XConnection, ptr: *mut T) -> Option<Self> {
|
pub fn new(xconn: &'a XConnection, ptr: *mut T) -> Option<Self> {
|
||||||
if !ptr.is_null() {
|
if !ptr.is_null() {
|
||||||
Some(XSmartPointer {
|
Some(XSmartPointer { xconn, ptr })
|
||||||
xconn,
|
|
||||||
ptr,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,22 +13,12 @@ mod randr;
|
||||||
mod window_property;
|
mod window_property;
|
||||||
mod wm;
|
mod wm;
|
||||||
|
|
||||||
pub use self::atom::*;
|
pub use self::{
|
||||||
pub use self::client_msg::*;
|
atom::*, client_msg::*, format::*, geometry::*, hint::*, icon::*, input::*, memory::*,
|
||||||
pub use self::format::*;
|
randr::*, window_property::*, wm::*,
|
||||||
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::*;
|
|
||||||
|
|
||||||
use std::mem;
|
use std::{mem, ops::BitAnd, os::raw::*, ptr};
|
||||||
use std::ptr;
|
|
||||||
use std::ops::BitAnd;
|
|
||||||
use std::os::raw::*;
|
|
||||||
|
|
||||||
use super::{ffi, XConnection, XError};
|
use super::{ffi, XConnection, XError};
|
||||||
|
|
||||||
|
@ -48,8 +38,8 @@ pub fn maybe_change<T: PartialEq>(field: &mut Option<T>, value: T) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
||||||
where T:
|
where
|
||||||
Copy + PartialEq + BitAnd<T, Output = T>
|
T: Copy + PartialEq + BitAnd<T, Output = T>,
|
||||||
{
|
{
|
||||||
bitset & flag == flag
|
bitset & flag == flag
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use std::{env, slice};
|
use std::{env, slice, str::FromStr};
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use crate::monitor::VideoMode;
|
|
||||||
use crate::dpi::validate_hidpi_factor;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::{dpi::validate_hidpi_factor, monitor::VideoMode};
|
||||||
|
|
||||||
pub fn calc_dpi_factor(
|
pub fn calc_dpi_factor(
|
||||||
(width_px, height_px): (u32, u32),
|
(width_px, height_px): (u32, u32),
|
||||||
|
@ -29,9 +27,7 @@ pub fn calc_dpi_factor(
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ppmm = (
|
let ppmm = ((width_px as f64 * height_px as f64) / (width_mm as f64 * height_mm as f64)).sqrt();
|
||||||
(width_px as f64 * height_px as f64) / (width_mm as f64 * height_mm as f64)
|
|
||||||
).sqrt();
|
|
||||||
// Quantize 1/12 step size
|
// Quantize 1/12 step size
|
||||||
let dpi_factor = ((ppmm * (12.0 * 25.4 / 96.0)).round() / 12.0).max(1.0);
|
let dpi_factor = ((ppmm * (12.0 * 25.4 / 96.0)).round() / 12.0).max(1.0);
|
||||||
assert!(validate_hidpi_factor(dpi_factor));
|
assert!(validate_hidpi_factor(dpi_factor));
|
||||||
|
@ -88,7 +84,7 @@ impl XConnection {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if let Ok(res) = ::std::ffi::CStr::from_ptr(resource_manager_str).to_str() {
|
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") {
|
for pair in res.split("\n") {
|
||||||
if pair.starts_with(&name) {
|
if pair.starts_with(&name) {
|
||||||
let res = &pair[name.len()..];
|
let res = &pair[name.len()..];
|
||||||
|
@ -103,11 +99,8 @@ impl XConnection {
|
||||||
resources: *mut ffi::XRRScreenResources,
|
resources: *mut ffi::XRRScreenResources,
|
||||||
repr: &MonitorRepr,
|
repr: &MonitorRepr,
|
||||||
) -> Option<(String, f64, Vec<VideoMode>)> {
|
) -> Option<(String, f64, Vec<VideoMode>)> {
|
||||||
let output_info = (self.xrandr.XRRGetOutputInfo)(
|
let output_info =
|
||||||
self.display,
|
(self.xrandr.XRRGetOutputInfo)(self.display, resources, repr.get_output());
|
||||||
resources,
|
|
||||||
repr.get_output(),
|
|
||||||
);
|
|
||||||
if output_info.is_null() {
|
if output_info.is_null() {
|
||||||
// When calling `XRRGetOutputInfo` on a virtual monitor (versus a physical display)
|
// When calling `XRRGetOutputInfo` on a virtual monitor (versus a physical display)
|
||||||
// it's possible for it to return null.
|
// it's possible for it to return null.
|
||||||
|
@ -152,7 +145,10 @@ impl XConnection {
|
||||||
} else {
|
} else {
|
||||||
calc_dpi_factor(
|
calc_dpi_factor(
|
||||||
repr.size(),
|
repr.size(),
|
||||||
((*output_info).mm_width as u64, (*output_info).mm_height as u64),
|
(
|
||||||
|
(*output_info).mm_width as u64,
|
||||||
|
(*output_info).mm_height as u64,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,8 @@ impl XConnection {
|
||||||
|
|
||||||
if !buf.is_null() {
|
if !buf.is_null() {
|
||||||
offset += PROPERTY_BUFFER_SIZE;
|
offset += PROPERTY_BUFFER_SIZE;
|
||||||
let new_data = std::slice::from_raw_parts(
|
let new_data =
|
||||||
buf as *mut T,
|
std::slice::from_raw_parts(buf as *mut T, quantity_returned as usize);
|
||||||
quantity_returned as usize,
|
|
||||||
);
|
|
||||||
/*println!(
|
/*println!(
|
||||||
"XGetWindowProperty prop:{:?} fmt:{:02} len:{:02} off:{:02} out:{:02}, buf:{:?}",
|
"XGetWindowProperty prop:{:?} fmt:{:02} len:{:02} off:{:02} out:{:02}, buf:{:?}",
|
||||||
property,
|
property,
|
||||||
|
|
|
@ -28,11 +28,8 @@ impl XConnection {
|
||||||
|
|
||||||
fn get_supported_hints(&self, root: ffi::Window) -> Vec<ffi::Atom> {
|
fn get_supported_hints(&self, root: ffi::Window) -> Vec<ffi::Atom> {
|
||||||
let supported_atom = unsafe { self.get_atom_unchecked(b"_NET_SUPPORTED\0") };
|
let supported_atom = unsafe { self.get_atom_unchecked(b"_NET_SUPPORTED\0") };
|
||||||
self.get_property(
|
self.get_property(root, supported_atom, ffi::XA_ATOM)
|
||||||
root,
|
.unwrap_or_else(|_| Vec::with_capacity(0))
|
||||||
supported_atom,
|
|
||||||
ffi::XA_ATOM,
|
|
||||||
).unwrap_or_else(|_| Vec::with_capacity(0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_wm_name(&self, root: ffi::Window) -> Option<String> {
|
fn get_wm_name(&self, root: ffi::Window) -> Option<String> {
|
||||||
|
@ -61,15 +58,9 @@ impl XConnection {
|
||||||
// Querying this property on the root window will give us the ID of a child window created by
|
// Querying this property on the root window will give us the ID of a child window created by
|
||||||
// the WM.
|
// the WM.
|
||||||
let root_window_wm_check = {
|
let root_window_wm_check = {
|
||||||
let result = self.get_property(
|
let result = self.get_property(root, check_atom, ffi::XA_WINDOW);
|
||||||
root,
|
|
||||||
check_atom,
|
|
||||||
ffi::XA_WINDOW,
|
|
||||||
);
|
|
||||||
|
|
||||||
let wm_check = result
|
let wm_check = result.ok().and_then(|wm_check| wm_check.get(0).cloned());
|
||||||
.ok()
|
|
||||||
.and_then(|wm_check| wm_check.get(0).cloned());
|
|
||||||
|
|
||||||
if let Some(wm_check) = wm_check {
|
if let Some(wm_check) = 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
|
// Querying the same property on the child window we were given, we should get this child
|
||||||
// window's ID again.
|
// window's ID again.
|
||||||
let child_window_wm_check = {
|
let child_window_wm_check = {
|
||||||
let result = self.get_property(
|
let result = self.get_property(root_window_wm_check, check_atom, ffi::XA_WINDOW);
|
||||||
root_window_wm_check,
|
|
||||||
check_atom,
|
|
||||||
ffi::XA_WINDOW,
|
|
||||||
);
|
|
||||||
|
|
||||||
let wm_check = result
|
let wm_check = result.ok().and_then(|wm_check| wm_check.get(0).cloned());
|
||||||
.ok()
|
|
||||||
.and_then(|wm_check| wm_check.get(0).cloned());
|
|
||||||
|
|
||||||
if let Some(wm_check) = wm_check {
|
if let Some(wm_check) = wm_check {
|
||||||
wm_check
|
wm_check
|
||||||
|
@ -107,11 +92,7 @@ impl XConnection {
|
||||||
let wm_name = {
|
let wm_name = {
|
||||||
let utf8_string_atom = unsafe { self.get_atom_unchecked(b"UTF8_STRING\0") };
|
let utf8_string_atom = unsafe { self.get_atom_unchecked(b"UTF8_STRING\0") };
|
||||||
|
|
||||||
let result = self.get_property(
|
let result = self.get_property(root_window_wm_check, wm_name_atom, utf8_string_atom);
|
||||||
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
|
// 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
|
// string. For more fun trivia, IceWM is also unique in including version and uname
|
||||||
|
@ -126,15 +107,12 @@ impl XConnection {
|
||||||
};
|
};
|
||||||
|
|
||||||
if no_utf8 {
|
if no_utf8 {
|
||||||
self.get_property(
|
self.get_property(root_window_wm_check, wm_name_atom, ffi::XA_STRING)
|
||||||
root_window_wm_check,
|
|
||||||
wm_name_atom,
|
|
||||||
ffi::XA_STRING,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}.ok();
|
}
|
||||||
|
.ok();
|
||||||
|
|
||||||
wm_name.and_then(|wm_name| String::from_utf8(wm_name).ok())
|
wm_name.and_then(|wm_name| String::from_utf8(wm_name).ok())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
use std::{cmp, env, mem};
|
use std::{cmp, collections::HashSet, env, ffi::CString, mem, os::raw::*, path::Path, sync::Arc};
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::os::raw::*;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
use crate::{
|
||||||
use crate::window::{Icon, CursorIcon, WindowAttributes};
|
dpi::{LogicalPosition, LogicalSize},
|
||||||
use crate::dpi::{LogicalPosition, LogicalSize};
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
use crate::platform_impl::MonitorHandle as PlatformMonitorHandle;
|
monitor::MonitorHandle as RootMonitorHandle,
|
||||||
use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes};
|
platform_impl::{
|
||||||
use crate::platform_impl::x11::ime::ImeContextCreationError;
|
x11::{ime::ImeContextCreationError, MonitorHandle as X11MonitorHandle},
|
||||||
use crate::platform_impl::x11::MonitorHandle as X11MonitorHandle;
|
MonitorHandle as PlatformMonitorHandle, OsError, PlatformSpecificWindowBuilderAttributes,
|
||||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
},
|
||||||
|
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(
|
unsafe extern "C" fn visibility_predicate(
|
||||||
_display: *mut ffi::Display,
|
_display: *mut ffi::Display,
|
||||||
|
@ -60,9 +57,9 @@ unsafe impl Sync for UnownedWindow {}
|
||||||
|
|
||||||
pub struct UnownedWindow {
|
pub struct UnownedWindow {
|
||||||
pub xconn: Arc<XConnection>, // never changes
|
pub xconn: Arc<XConnection>, // never changes
|
||||||
xwindow: ffi::Window, // never changes
|
xwindow: ffi::Window, // never changes
|
||||||
root: ffi::Window, // never changes
|
root: ffi::Window, // never changes
|
||||||
screen_id: i32, // never changes
|
screen_id: i32, // never changes
|
||||||
cursor: Mutex<CursorIcon>,
|
cursor: Mutex<CursorIcon>,
|
||||||
cursor_grabbed: Mutex<bool>,
|
cursor_grabbed: Mutex<bool>,
|
||||||
cursor_visible: Mutex<bool>,
|
cursor_visible: Mutex<bool>,
|
||||||
|
@ -89,7 +86,8 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dpi_factor.unwrap_or_else(|| {
|
dpi_factor.unwrap_or_else(|| {
|
||||||
xconn.query_pointer(root, util::VIRTUAL_CORE_POINTER)
|
xconn
|
||||||
|
.query_pointer(root, util::VIRTUAL_CORE_POINTER)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|pointer_state| {
|
.and_then(|pointer_state| {
|
||||||
let (x, y) = (pointer_state.root_x as i64, pointer_state.root_y as i64);
|
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);
|
info!("Guessed window DPI factor: {}", dpi_factor);
|
||||||
|
|
||||||
let max_inner_size: Option<(u32, u32)> = window_attrs.max_inner_size.map(|size| {
|
let max_inner_size: Option<(u32, u32)> = window_attrs
|
||||||
size.to_physical(dpi_factor).into()
|
.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| {
|
let min_inner_size: Option<(u32, u32)> = window_attrs
|
||||||
size.to_physical(dpi_factor).into()
|
.min_inner_size
|
||||||
});
|
.map(|size| size.to_physical(dpi_factor).into());
|
||||||
|
|
||||||
let dimensions = {
|
let dimensions = {
|
||||||
// x11 only applies constraints when the window is actively resized
|
// x11 only applies constraints when the window is actively resized
|
||||||
// by the user, so we have to manually apply the initial constraints
|
// 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()))
|
.or_else(|| Some((800, 600).into()))
|
||||||
.map(|size| size.to_physical(dpi_factor))
|
.map(|size| size.to_physical(dpi_factor))
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
|
@ -133,7 +132,10 @@ impl UnownedWindow {
|
||||||
dimensions.0 = cmp::max(dimensions.0, min.0);
|
dimensions.0 = cmp::max(dimensions.0, min.0);
|
||||||
dimensions.1 = cmp::max(dimensions.1, min.1);
|
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
|
dimensions
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,7 +152,9 @@ impl UnownedWindow {
|
||||||
let visual = vi.visual;
|
let visual = vi.visual;
|
||||||
(xconn.xlib.XCreateColormap)(xconn.display, root, visual, ffi::AllocNone)
|
(xconn.xlib.XCreateColormap)(xconn.display, root, visual, ffi::AllocNone)
|
||||||
}
|
}
|
||||||
} else { 0 };
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
swa.event_mask = ffi::ExposureMask
|
swa.event_mask = ffi::ExposureMask
|
||||||
| ffi::StructureNotifyMask
|
| ffi::StructureNotifyMask
|
||||||
| ffi::VisibilityChangeMask
|
| ffi::VisibilityChangeMask
|
||||||
|
@ -220,7 +224,9 @@ impl UnownedWindow {
|
||||||
// title to determine placement/etc., so doing this after mapping would cause the WM to
|
// title to determine placement/etc., so doing this after mapping would cause the WM to
|
||||||
// act on the wrong title state.
|
// act on the wrong title state.
|
||||||
window.set_title_inner(&window_attrs.title).queue();
|
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)
|
// Enable drag and drop (TODO: extend API to make this toggleable)
|
||||||
|
@ -234,15 +240,16 @@ impl UnownedWindow {
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
version,
|
version,
|
||||||
)
|
)
|
||||||
}.queue();
|
}
|
||||||
|
.queue();
|
||||||
|
|
||||||
// WM_CLASS must be set *before* mapping the window, as per ICCCM!
|
// WM_CLASS must be set *before* mapping the window, as per ICCCM!
|
||||||
{
|
{
|
||||||
let (class, instance) = if let Some((instance, class)) = pl_attribs.class {
|
let (class, instance) = if let Some((instance, class)) = pl_attribs.class {
|
||||||
let instance = CString::new(instance.as_str())
|
let instance = CString::new(instance.as_str())
|
||||||
.expect("`WM_CLASS` instance contained null byte");
|
.expect("`WM_CLASS` instance contained null byte");
|
||||||
let class = CString::new(class.as_str())
|
let class =
|
||||||
.expect("`WM_CLASS` class contained null byte");
|
CString::new(class.as_str()).expect("`WM_CLASS` class contained null byte");
|
||||||
(instance, class)
|
(instance, class)
|
||||||
} else {
|
} else {
|
||||||
let class = env::args()
|
let class = env::args()
|
||||||
|
@ -269,12 +276,8 @@ impl UnownedWindow {
|
||||||
(*class_hint).res_class = instance.as_ptr() as *mut c_char;
|
(*class_hint).res_class = instance.as_ptr() as *mut c_char;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(xconn.xlib.XSetClassHint)(
|
(xconn.xlib.XSetClassHint)(xconn.display, window.xwindow, class_hint.ptr);
|
||||||
xconn.display,
|
} //.queue();
|
||||||
window.xwindow,
|
|
||||||
class_hint.ptr,
|
|
||||||
);
|
|
||||||
}//.queue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.set_pid().map(|flusher| flusher.queue());
|
window.set_pid().map(|flusher| flusher.queue());
|
||||||
|
@ -289,9 +292,11 @@ impl UnownedWindow {
|
||||||
|
|
||||||
// set size hints
|
// 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));
|
.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));
|
.map(|size| size.to_physical(dpi_factor));
|
||||||
if !window_attrs.resizable {
|
if !window_attrs.resizable {
|
||||||
if util::wm_name_is_one_of(&["Xfwm4"]) {
|
if util::wm_name_is_one_of(&["Xfwm4"]) {
|
||||||
|
@ -328,13 +333,13 @@ impl UnownedWindow {
|
||||||
&event_loop.wm_delete_window as *const ffi::Atom as *mut ffi::Atom,
|
&event_loop.wm_delete_window as *const ffi::Atom as *mut ffi::Atom,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
}//.queue();
|
} //.queue();
|
||||||
|
|
||||||
// Set visibility (map window)
|
// Set visibility (map window)
|
||||||
if window_attrs.visible {
|
if window_attrs.visible {
|
||||||
unsafe {
|
unsafe {
|
||||||
(xconn.xlib.XMapRaised)(xconn.display, window.xwindow);
|
(xconn.xlib.XMapRaised)(xconn.display, window.xwindow);
|
||||||
}//.queue();
|
} //.queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to make keyboard input repeat detectable
|
// Attempt to make keyboard input repeat detectable
|
||||||
|
@ -346,7 +351,9 @@ impl UnownedWindow {
|
||||||
&mut supported_ptr,
|
&mut supported_ptr,
|
||||||
);
|
);
|
||||||
if supported_ptr == ffi::False {
|
if supported_ptr == ffi::False {
|
||||||
return Err(os_error!(OsError::XMisc("`XkbSetDetectableAutoRepeat` failed")));
|
return Err(os_error!(OsError::XMisc(
|
||||||
|
"`XkbSetDetectableAutoRepeat` failed"
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,16 +373,18 @@ impl UnownedWindow {
|
||||||
| ffi::XI_TouchEndMask;
|
| ffi::XI_TouchEndMask;
|
||||||
mask
|
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
|
let result = event_loop.ime.borrow_mut().create_context(window.xwindow);
|
||||||
.borrow_mut()
|
|
||||||
.create_context(window.xwindow);
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
let e = match err {
|
let e = match err {
|
||||||
ImeContextCreationError::XError(err) => OsError::XError(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));
|
return Err(os_error!(e));
|
||||||
}
|
}
|
||||||
|
@ -386,10 +395,14 @@ impl UnownedWindow {
|
||||||
window.set_maximized_inner(window_attrs.maximized).queue();
|
window.set_maximized_inner(window_attrs.maximized).queue();
|
||||||
}
|
}
|
||||||
if window_attrs.fullscreen.is_some() {
|
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 {
|
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 {
|
if window_attrs.visible {
|
||||||
|
@ -397,7 +410,8 @@ impl UnownedWindow {
|
||||||
// XSetInputFocus generates an error if the window is not visible, so we wait
|
// XSetInputFocus generates an error if the window is not visible, so we wait
|
||||||
// until we receive VisibilityNotify.
|
// until we receive VisibilityNotify.
|
||||||
let mut event = mem::uninitialized();
|
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,
|
xconn.display,
|
||||||
&mut event as *mut ffi::XEvent,
|
&mut event as *mut ffi::XEvent,
|
||||||
Some(visibility_predicate),
|
Some(visibility_predicate),
|
||||||
|
@ -414,7 +428,8 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We never want to give the user a broken window, since by then, it's too late to handle.
|
// 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(|_| window)
|
||||||
.map_err(|x_err| os_error!(OsError::XError(x_err)))
|
.map_err(|x_err| os_error!(OsError::XError(x_err)))
|
||||||
}
|
}
|
||||||
|
@ -439,18 +454,22 @@ impl UnownedWindow {
|
||||||
const MAXHOSTNAMELEN: usize = 256;
|
const MAXHOSTNAMELEN: usize = 256;
|
||||||
let mut hostname: [c_char; MAXHOSTNAMELEN] = mem::uninitialized();
|
let mut hostname: [c_char; MAXHOSTNAMELEN] = mem::uninitialized();
|
||||||
let status = libc::gethostname(hostname.as_mut_ptr(), hostname.len());
|
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
|
hostname[MAXHOSTNAMELEN - 1] = '\0' as c_char; // a little extra safety
|
||||||
let hostname_length = libc::strlen(hostname.as_ptr());
|
let hostname_length = libc::strlen(hostname.as_ptr());
|
||||||
(hostname, hostname_length as usize)
|
(hostname, hostname_length as usize)
|
||||||
};
|
};
|
||||||
self.xconn.change_property(
|
self.xconn
|
||||||
self.xwindow,
|
.change_property(
|
||||||
pid_atom,
|
self.xwindow,
|
||||||
ffi::XA_CARDINAL,
|
pid_atom,
|
||||||
util::PropMode::Replace,
|
ffi::XA_CARDINAL,
|
||||||
&[libc::getpid() as util::Cardinal],
|
util::PropMode::Replace,
|
||||||
).queue();
|
&[libc::getpid() as util::Cardinal],
|
||||||
|
)
|
||||||
|
.queue();
|
||||||
let flusher = self.xconn.change_property(
|
let flusher = self.xconn.change_property(
|
||||||
self.xwindow,
|
self.xwindow,
|
||||||
client_machine_atom,
|
client_machine_atom,
|
||||||
|
@ -489,13 +508,19 @@ impl UnownedWindow {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_urgent(&self, is_urgent: bool) {
|
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 {
|
if is_urgent {
|
||||||
(*wm_hints).flags |= ffi::XUrgencyHint;
|
(*wm_hints).flags |= ffi::XUrgencyHint;
|
||||||
} else {
|
} else {
|
||||||
(*wm_hints).flags &= !ffi::XUrgencyHint;
|
(*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(
|
fn set_netwm(
|
||||||
|
@ -520,7 +545,8 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_fullscreen_hint(&self, fullscreen: bool) -> util::Flusher<'_> {
|
fn set_fullscreen_hint(&self, fullscreen: bool) -> util::Flusher<'_> {
|
||||||
let fullscreen_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_FULLSCREEN\0") };
|
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))
|
self.set_netwm(fullscreen.into(), (fullscreen_atom as c_long, 0, 0, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,13 +559,16 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
flusher
|
flusher
|
||||||
},
|
},
|
||||||
Some(RootMonitorHandle { inner: PlatformMonitorHandle::X(monitor) }) => {
|
Some(RootMonitorHandle {
|
||||||
|
inner: PlatformMonitorHandle::X(monitor),
|
||||||
|
}) => {
|
||||||
let window_position = self.outer_position_physical();
|
let window_position = self.outer_position_physical();
|
||||||
self.shared_state.lock().restore_position = Some(window_position);
|
self.shared_state.lock().restore_position = Some(window_position);
|
||||||
let monitor_origin: (i32, i32) = monitor.position().into();
|
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)
|
self.set_fullscreen_hint(true)
|
||||||
}
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -567,17 +596,15 @@ impl UnownedWindow {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_monitor(&self) -> X11MonitorHandle {
|
pub fn current_monitor(&self) -> X11MonitorHandle {
|
||||||
let monitor = self.shared_state
|
let monitor = self.shared_state.lock().last_monitor.as_ref().cloned();
|
||||||
.lock()
|
monitor.unwrap_or_else(|| {
|
||||||
.last_monitor
|
let monitor = self
|
||||||
.as_ref()
|
.xconn
|
||||||
.cloned();
|
.get_monitor_for_window(Some(self.get_rect()))
|
||||||
monitor
|
.to_owned();
|
||||||
.unwrap_or_else(|| {
|
self.shared_state.lock().last_monitor = Some(monitor.clone());
|
||||||
let monitor = self.xconn.get_monitor_for_window(Some(self.get_rect())).to_owned();
|
monitor
|
||||||
self.shared_state.lock().last_monitor = Some(monitor.clone());
|
})
|
||||||
monitor
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn available_monitors(&self) -> Vec<X11MonitorHandle> {
|
pub fn available_monitors(&self) -> Vec<X11MonitorHandle> {
|
||||||
|
@ -589,9 +616,18 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_maximized_inner(&self, maximized: bool) -> util::Flusher<'_> {
|
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 horz_atom = unsafe {
|
||||||
let vert_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_VERT\0") };
|
self.xconn
|
||||||
self.set_netwm(maximized.into(), (horz_atom as c_long, vert_atom as c_long, 0, 0))
|
.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]
|
#[inline]
|
||||||
|
@ -638,10 +674,10 @@ impl UnownedWindow {
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
&[
|
&[
|
||||||
util::MWM_HINTS_DECORATIONS, // flags
|
util::MWM_HINTS_DECORATIONS, // flags
|
||||||
0, // functions
|
0, // functions
|
||||||
decorations as c_ulong, // decorations
|
decorations as c_ulong, // decorations
|
||||||
0, // input mode
|
0, // input mode
|
||||||
0, // status
|
0, // status
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -695,7 +731,9 @@ impl UnownedWindow {
|
||||||
match icon {
|
match icon {
|
||||||
Some(icon) => self.set_icon_inner(icon),
|
Some(icon) => self.set_icon_inner(icon),
|
||||||
None => self.unset_icon_inner(),
|
None => self.unset_icon_inner(),
|
||||||
}.flush().expect("Failed to set icons");
|
}
|
||||||
|
.flush()
|
||||||
|
.expect("Failed to set icons");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -703,19 +741,23 @@ impl UnownedWindow {
|
||||||
match visible {
|
match visible {
|
||||||
true => unsafe {
|
true => unsafe {
|
||||||
(self.xconn.xlib.XMapRaised)(self.xconn.display, self.xwindow);
|
(self.xconn.xlib.XMapRaised)(self.xconn.display, self.xwindow);
|
||||||
self.xconn.flush_requests()
|
self.xconn
|
||||||
|
.flush_requests()
|
||||||
.expect("Failed to call XMapRaised");
|
.expect("Failed to call XMapRaised");
|
||||||
},
|
},
|
||||||
false => unsafe {
|
false => unsafe {
|
||||||
(self.xconn.xlib.XUnmapWindow)(self.xconn.display, self.xwindow);
|
(self.xconn.xlib.XUnmapWindow)(self.xconn.display, self.xwindow);
|
||||||
self.xconn.flush_requests()
|
self.xconn
|
||||||
|
.flush_requests()
|
||||||
.expect("Failed to call XUnmapWindow");
|
.expect("Failed to call XUnmapWindow");
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_cached_frame_extents(&self) {
|
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);
|
(*self.shared_state.lock()).frame_extents = Some(extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,7 +791,8 @@ impl UnownedWindow {
|
||||||
pub(crate) fn inner_position_physical(&self) -> (i32, i32) {
|
pub(crate) fn inner_position_physical(&self) -> (i32, i32) {
|
||||||
// This should be okay to unwrap since the only error XTranslateCoordinates can return
|
// 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.
|
// 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))
|
.map(|coords| (coords.x_rel_root, coords.y_rel_root))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
@ -773,12 +816,7 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.xconn.xlib.XMoveWindow)(
|
(self.xconn.xlib.XMoveWindow)(self.xconn.display, self.xwindow, x as c_int, y as c_int);
|
||||||
self.xconn.display,
|
|
||||||
self.xwindow,
|
|
||||||
x as c_int,
|
|
||||||
y as c_int,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
util::Flusher::new(&self.xconn)
|
util::Flusher::new(&self.xconn)
|
||||||
}
|
}
|
||||||
|
@ -798,7 +836,8 @@ impl UnownedWindow {
|
||||||
pub(crate) fn inner_size_physical(&self) -> (u32, u32) {
|
pub(crate) fn inner_size_physical(&self) -> (u32, u32) {
|
||||||
// This should be okay to unwrap since the only error XGetGeometry can return
|
// 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.
|
// 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))
|
.map(|geo| (geo.width, geo.height))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
@ -840,7 +879,8 @@ impl UnownedWindow {
|
||||||
height as c_uint,
|
height as c_uint,
|
||||||
);
|
);
|
||||||
self.xconn.flush_requests()
|
self.xconn.flush_requests()
|
||||||
}.expect("Failed to call `XResizeWindow`");
|
}
|
||||||
|
.expect("Failed to call `XResizeWindow`");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -851,11 +891,14 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_normal_hints<F>(&self, callback: F) -> Result<(), XError>
|
fn update_normal_hints<F>(&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)?;
|
let mut normal_hints = self.xconn.get_normal_hints(self.xwindow)?;
|
||||||
callback(&mut normal_hints);
|
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)>) {
|
pub(crate) fn set_min_inner_size_physical(&self, dimensions: Option<(u32, u32)>) {
|
||||||
|
@ -866,9 +909,8 @@ impl UnownedWindow {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_min_inner_size(&self, logical_dimensions: Option<LogicalSize>) {
|
pub fn set_min_inner_size(&self, logical_dimensions: Option<LogicalSize>) {
|
||||||
self.shared_state.lock().min_inner_size = logical_dimensions;
|
self.shared_state.lock().min_inner_size = logical_dimensions;
|
||||||
let physical_dimensions = logical_dimensions.map(|logical_dimensions| {
|
let physical_dimensions = logical_dimensions
|
||||||
logical_dimensions.to_physical(self.hidpi_factor()).into()
|
.map(|logical_dimensions| logical_dimensions.to_physical(self.hidpi_factor()).into());
|
||||||
});
|
|
||||||
self.set_min_inner_size_physical(physical_dimensions);
|
self.set_min_inner_size_physical(physical_dimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,9 +922,8 @@ impl UnownedWindow {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_max_inner_size(&self, logical_dimensions: Option<LogicalSize>) {
|
pub fn set_max_inner_size(&self, logical_dimensions: Option<LogicalSize>) {
|
||||||
self.shared_state.lock().max_inner_size = logical_dimensions;
|
self.shared_state.lock().max_inner_size = logical_dimensions;
|
||||||
let physical_dimensions = logical_dimensions.map(|logical_dimensions| {
|
let physical_dimensions = logical_dimensions
|
||||||
logical_dimensions.to_physical(self.hidpi_factor()).into()
|
.map(|logical_dimensions| logical_dimensions.to_physical(self.hidpi_factor()).into());
|
||||||
});
|
|
||||||
self.set_max_inner_size_physical(physical_dimensions);
|
self.set_max_inner_size_physical(physical_dimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -910,7 +951,8 @@ impl UnownedWindow {
|
||||||
normal_hints.set_min_size(min_size);
|
normal_hints.set_min_size(min_size);
|
||||||
normal_hints.set_resize_increments(resize_increments);
|
normal_hints.set_resize_increments(resize_increments);
|
||||||
normal_hints.set_base_size(base_size);
|
normal_hints.set_base_size(base_size);
|
||||||
}).expect("Failed to update normal hints");
|
})
|
||||||
|
.expect("Failed to update normal hints");
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.xconn.xlib.XResizeWindow)(
|
(self.xconn.xlib.XResizeWindow)(
|
||||||
self.xconn.display,
|
self.xconn.display,
|
||||||
|
@ -933,7 +975,10 @@ impl UnownedWindow {
|
||||||
|
|
||||||
let (logical_min, logical_max) = if resizable {
|
let (logical_min, logical_max) = if resizable {
|
||||||
let shared_state_lock = self.shared_state.lock();
|
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 {
|
} else {
|
||||||
let window_size = Some(self.inner_size());
|
let window_size = Some(self.inner_size());
|
||||||
(window_size.clone(), window_size)
|
(window_size.clone(), window_size)
|
||||||
|
@ -949,7 +994,8 @@ impl UnownedWindow {
|
||||||
self.update_normal_hints(|normal_hints| {
|
self.update_normal_hints(|normal_hints| {
|
||||||
normal_hints.set_min_size(min_inner_size);
|
normal_hints.set_min_size(min_inner_size);
|
||||||
normal_hints.set_max_size(max_inner_size);
|
normal_hints.set_max_size(max_inner_size);
|
||||||
}).expect("Failed to call `XSetWMNormalHints`");
|
})
|
||||||
|
.expect("Failed to call `XSetWMNormalHints`");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -974,9 +1020,7 @@ impl UnownedWindow {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn xcb_connection(&self) -> *mut c_void {
|
pub fn xcb_connection(&self) -> *mut c_void {
|
||||||
unsafe {
|
unsafe { (self.xconn.xlib_xcb.XGetXCBConnection)(self.xconn.display) as *mut _ }
|
||||||
(self.xconn.xlib_xcb.XGetXCBConnection)(self.xconn.display) as *mut _
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_cursor(&self, name: &[u8]) -> ffi::Cursor {
|
fn load_cursor(&self, name: &[u8]) -> ffi::Cursor {
|
||||||
|
@ -999,13 +1043,9 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_cursor(&self, cursor: CursorIcon) -> ffi::Cursor {
|
fn get_cursor(&self, cursor: CursorIcon) -> ffi::Cursor {
|
||||||
let load = |name: &[u8]| {
|
let load = |name: &[u8]| self.load_cursor(name);
|
||||||
self.load_cursor(name)
|
|
||||||
};
|
|
||||||
|
|
||||||
let loadn = |names: &[&[u8]]| {
|
let loadn = |names: &[&[u8]]| self.load_first_existing_cursor(names);
|
||||||
self.load_first_existing_cursor(names)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Try multiple names in some cases where the name
|
// Try multiple names in some cases where the name
|
||||||
// differs on the desktop environments or themes.
|
// differs on the desktop environments or themes.
|
||||||
|
@ -1030,7 +1070,6 @@ impl UnownedWindow {
|
||||||
CursorIcon::NoDrop => loadn(&[b"no-drop\0", b"circle\0"]),
|
CursorIcon::NoDrop => loadn(&[b"no-drop\0", b"circle\0"]),
|
||||||
CursorIcon::NotAllowed => load(b"crossed_circle\0"),
|
CursorIcon::NotAllowed => load(b"crossed_circle\0"),
|
||||||
|
|
||||||
|
|
||||||
// Resize cursors
|
// Resize cursors
|
||||||
CursorIcon::EResize => load(b"right_side\0"),
|
CursorIcon::EResize => load(b"right_side\0"),
|
||||||
CursorIcon::NResize => load(b"top_side\0"),
|
CursorIcon::NResize => load(b"top_side\0"),
|
||||||
|
@ -1063,7 +1102,9 @@ impl UnownedWindow {
|
||||||
if cursor != 0 {
|
if cursor != 0 {
|
||||||
(self.xconn.xlib.XFreeCursor)(self.xconn.display, cursor);
|
(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 +1122,7 @@ impl UnownedWindow {
|
||||||
fn create_empty_cursor(&self) -> Option<ffi::Cursor> {
|
fn create_empty_cursor(&self) -> Option<ffi::Cursor> {
|
||||||
let data = 0;
|
let data = 0;
|
||||||
let pixmap = unsafe {
|
let pixmap = unsafe {
|
||||||
(self.xconn.xlib.XCreateBitmapFromData)(
|
(self.xconn.xlib.XCreateBitmapFromData)(self.xconn.display, self.xwindow, &data, 1, 1)
|
||||||
self.xconn.display,
|
|
||||||
self.xwindow,
|
|
||||||
&data,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
if pixmap == 0 {
|
if pixmap == 0 {
|
||||||
// Failed to allocate
|
// Failed to allocate
|
||||||
|
@ -1116,7 +1151,9 @@ impl UnownedWindow {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
|
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
|
||||||
let mut grabbed_lock = self.cursor_grabbed.lock();
|
let mut grabbed_lock = self.cursor_grabbed.lock();
|
||||||
if grab == *grabbed_lock { return Ok(()); }
|
if grab == *grabbed_lock {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
// We ungrab before grabbing to prevent passive grabs from causing `AlreadyGrabbed`.
|
// We ungrab before grabbing to prevent passive grabs from causing `AlreadyGrabbed`.
|
||||||
// Therefore, this is common to both codepaths.
|
// Therefore, this is common to both codepaths.
|
||||||
|
@ -1128,8 +1165,7 @@ impl UnownedWindow {
|
||||||
self.xconn.display,
|
self.xconn.display,
|
||||||
self.xwindow,
|
self.xwindow,
|
||||||
ffi::True,
|
ffi::True,
|
||||||
(
|
(ffi::ButtonPressMask
|
||||||
ffi::ButtonPressMask
|
|
||||||
| ffi::ButtonReleaseMask
|
| ffi::ButtonReleaseMask
|
||||||
| ffi::EnterWindowMask
|
| ffi::EnterWindowMask
|
||||||
| ffi::LeaveWindowMask
|
| ffi::LeaveWindowMask
|
||||||
|
@ -1141,8 +1177,7 @@ impl UnownedWindow {
|
||||||
| ffi::Button4MotionMask
|
| ffi::Button4MotionMask
|
||||||
| ffi::Button5MotionMask
|
| ffi::Button5MotionMask
|
||||||
| ffi::ButtonMotionMask
|
| ffi::ButtonMotionMask
|
||||||
| ffi::KeymapStateMask
|
| ffi::KeymapStateMask) as c_uint,
|
||||||
) as c_uint,
|
|
||||||
ffi::GrabModeAsync,
|
ffi::GrabModeAsync,
|
||||||
ffi::GrabModeAsync,
|
ffi::GrabModeAsync,
|
||||||
self.xwindow,
|
self.xwindow,
|
||||||
|
@ -1153,14 +1188,20 @@ impl UnownedWindow {
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
ffi::GrabSuccess => Ok(()),
|
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::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"),
|
ffi::GrabFrozen => Err("Cursor could not be grabbed: frozen by another client"),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}.map_err(|err| ExternalError::Os(os_error!(OsError::XMisc(err))))
|
}
|
||||||
|
.map_err(|err| ExternalError::Os(os_error!(OsError::XMisc(err))))
|
||||||
} else {
|
} else {
|
||||||
self.xconn.flush_requests()
|
self.xconn
|
||||||
|
.flush_requests()
|
||||||
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err))))
|
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err))))
|
||||||
};
|
};
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
|
@ -1172,11 +1213,14 @@ impl UnownedWindow {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_visible(&self, visible: bool) {
|
pub fn set_cursor_visible(&self, visible: bool) {
|
||||||
let mut visible_lock = self.cursor_visible.lock();
|
let mut visible_lock = self.cursor_visible.lock();
|
||||||
if visible == *visible_lock {return; }
|
if visible == *visible_lock {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let cursor = if visible {
|
let cursor = if visible {
|
||||||
self.get_cursor(*self.cursor.lock())
|
self.get_cursor(*self.cursor.lock())
|
||||||
} else {
|
} else {
|
||||||
self.create_empty_cursor().expect("Failed to create empty cursor")
|
self.create_empty_cursor()
|
||||||
|
.expect("Failed to create empty cursor")
|
||||||
};
|
};
|
||||||
*visible_lock = visible;
|
*visible_lock = visible;
|
||||||
drop(visible_lock);
|
drop(visible_lock);
|
||||||
|
@ -1190,29 +1234,25 @@ impl UnownedWindow {
|
||||||
|
|
||||||
pub fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), ExternalError> {
|
pub fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), ExternalError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.xconn.xlib.XWarpPointer)(
|
(self.xconn.xlib.XWarpPointer)(self.xconn.display, 0, self.xwindow, 0, 0, 0, 0, x, y);
|
||||||
self.xconn.display,
|
self.xconn
|
||||||
0,
|
.flush_requests()
|
||||||
self.xwindow,
|
.map_err(|e| ExternalError::Os(os_error!(OsError::XError(e))))
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
);
|
|
||||||
self.xconn.flush_requests().map_err(|e| ExternalError::Os(os_error!(OsError::XError(e))))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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();
|
let (x, y) = logical_position.to_physical(self.hidpi_factor()).into();
|
||||||
self.set_cursor_position_physical(x, y)
|
self.set_cursor_position_physical(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_ime_position_physical(&self, x: i32, y: i32) {
|
pub(crate) fn set_ime_position_physical(&self, x: i32, y: i32) {
|
||||||
let _ = self.ime_sender
|
let _ = self
|
||||||
|
.ime_sender
|
||||||
.lock()
|
.lock()
|
||||||
.send((self.xwindow, x as i16, y as i16));
|
.send((self.xwindow, x as i16, y as i16));
|
||||||
}
|
}
|
||||||
|
@ -1224,10 +1264,15 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn id(&self) -> WindowId { WindowId(self.xwindow) }
|
pub fn id(&self) -> WindowId {
|
||||||
|
WindowId(self.xwindow)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn request_redraw(&self) {
|
pub fn request_redraw(&self) {
|
||||||
self.pending_redraws.lock().unwrap().insert(WindowId(self.xwindow));
|
self.pending_redraws
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.insert(WindowId(self.xwindow));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
use std::ptr;
|
use std::{error::Error, fmt, os::raw::c_int, ptr};
|
||||||
use std::fmt;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::os::raw::c_int;
|
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
@ -27,7 +24,8 @@ pub struct XConnection {
|
||||||
unsafe impl Send for XConnection {}
|
unsafe impl Send for XConnection {}
|
||||||
unsafe impl Sync for XConnection {}
|
unsafe impl Sync for XConnection {}
|
||||||
|
|
||||||
pub type XErrorHandler = Option<unsafe extern fn(*mut ffi::Display, *mut ffi::XErrorEvent) -> libc::c_int>;
|
pub type XErrorHandler =
|
||||||
|
Option<unsafe extern "C" fn(*mut ffi::Display, *mut ffi::XErrorEvent) -> libc::c_int>;
|
||||||
|
|
||||||
impl XConnection {
|
impl XConnection {
|
||||||
pub fn new(error_handler: XErrorHandler) -> Result<XConnection, XNotSupported> {
|
pub fn new(error_handler: XErrorHandler) -> Result<XConnection, XNotSupported> {
|
||||||
|
@ -53,9 +51,7 @@ impl XConnection {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get X11 socket file descriptor
|
// Get X11 socket file descriptor
|
||||||
let fd = unsafe {
|
let fd = unsafe { (xlib.XConnectionNumber)(display) };
|
||||||
(xlib.XConnectionNumber)(display)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(XConnection {
|
Ok(XConnection {
|
||||||
xlib,
|
xlib,
|
||||||
|
@ -120,8 +116,11 @@ impl Error for XError {
|
||||||
|
|
||||||
impl fmt::Display for XError {
|
impl fmt::Display for XError {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
write!(formatter, "X error: {} (code: {}, request code: {}, minor code: {})",
|
write!(
|
||||||
self.description, self.error_code, self.request_code, self.minor_code)
|
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.
|
/// Failed to load one or several shared libraries.
|
||||||
LibraryOpenError(ffi::OpenError),
|
LibraryOpenError(ffi::OpenError),
|
||||||
/// Connecting to the X server with `XOpenDisplay` failed.
|
/// Connecting to the X server with `XOpenDisplay` failed.
|
||||||
XOpenDisplayFailed, // TODO: add better message
|
XOpenDisplayFailed, // TODO: add better message
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ffi::OpenError> for XNotSupported {
|
impl From<ffi::OpenError> for XNotSupported {
|
||||||
|
@ -154,7 +153,7 @@ impl Error for XNotSupported {
|
||||||
fn cause(&self) -> Option<&dyn Error> {
|
fn cause(&self) -> Option<&dyn Error> {
|
||||||
match *self {
|
match *self {
|
||||||
XNotSupported::LibraryOpenError(ref err) => Some(err),
|
XNotSupported::LibraryOpenError(ref err) => Some(err),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use cocoa::{appkit::{self, NSEvent}, base::id};
|
use cocoa::{
|
||||||
use objc::{declare::ClassDecl, runtime::{Class, Object, Sel}};
|
appkit::{self, NSEvent},
|
||||||
|
base::id,
|
||||||
|
};
|
||||||
|
use objc::{
|
||||||
|
declare::ClassDecl,
|
||||||
|
runtime::{Class, Object, Sel},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::event::{DeviceEvent, Event};
|
use crate::{
|
||||||
use crate::platform_impl::platform::{app_state::AppState, DEVICE_ID, util};
|
event::{DeviceEvent, Event},
|
||||||
|
platform_impl::platform::{app_state::AppState, util, DEVICE_ID},
|
||||||
|
};
|
||||||
|
|
||||||
pub struct AppClass(pub *const Class);
|
pub struct AppClass(pub *const Class);
|
||||||
unsafe impl Send for AppClass {}
|
unsafe impl Send for AppClass {}
|
||||||
|
@ -17,7 +25,7 @@ lazy_static! {
|
||||||
|
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(sendEvent:),
|
sel!(sendEvent:),
|
||||||
send_event as extern fn(&Object, Sel, id),
|
send_event as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
|
|
||||||
AppClass(decl.register())
|
AppClass(decl.register())
|
||||||
|
@ -27,23 +35,25 @@ lazy_static! {
|
||||||
// Normally, holding Cmd + any key never sends us a `keyUp` event for that key.
|
// 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)
|
// 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)
|
// 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 {
|
unsafe {
|
||||||
// For posterity, there are some undocumented event types
|
// For posterity, there are some undocumented event types
|
||||||
// (https://github.com/servo/cocoa-rs/issues/155)
|
// (https://github.com/servo/cocoa-rs/issues/155)
|
||||||
// but that doesn't really matter here.
|
// but that doesn't really matter here.
|
||||||
let event_type = event.eventType();
|
let event_type = event.eventType();
|
||||||
let modifier_flags = event.modifierFlags();
|
let modifier_flags = event.modifierFlags();
|
||||||
if event_type == appkit::NSKeyUp && util::has_flag(
|
if event_type == appkit::NSKeyUp
|
||||||
modifier_flags,
|
&& util::has_flag(
|
||||||
appkit::NSEventModifierFlags::NSCommandKeyMask,
|
modifier_flags,
|
||||||
) {
|
appkit::NSEventModifierFlags::NSCommandKeyMask,
|
||||||
|
)
|
||||||
|
{
|
||||||
let key_window: id = msg_send![this, keyWindow];
|
let key_window: id = msg_send![this, keyWindow];
|
||||||
let _: () = msg_send![key_window, sendEvent:event];
|
let _: () = msg_send![key_window, sendEvent: event];
|
||||||
} else {
|
} else {
|
||||||
maybe_dispatch_device_event(event);
|
maybe_dispatch_device_event(event);
|
||||||
let superclass = util::superclass(this);
|
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) {
|
unsafe fn maybe_dispatch_device_event(event: id) {
|
||||||
let event_type = event.eventType();
|
let event_type = event.eventType();
|
||||||
match event_type {
|
match event_type {
|
||||||
appkit::NSMouseMoved |
|
appkit::NSMouseMoved
|
||||||
appkit::NSLeftMouseDragged |
|
| appkit::NSLeftMouseDragged
|
||||||
appkit::NSOtherMouseDragged |
|
| appkit::NSOtherMouseDragged
|
||||||
appkit::NSRightMouseDragged => {
|
| appkit::NSRightMouseDragged => {
|
||||||
let mut events = VecDeque::with_capacity(3);
|
let mut events = VecDeque::with_capacity(3);
|
||||||
|
|
||||||
let delta_x = event.deltaX() as f64;
|
let delta_x = event.deltaX() as f64;
|
||||||
|
@ -63,21 +73,29 @@ unsafe fn maybe_dispatch_device_event(event: id) {
|
||||||
if delta_x != 0.0 {
|
if delta_x != 0.0 {
|
||||||
events.push_back(Event::DeviceEvent {
|
events.push_back(Event::DeviceEvent {
|
||||||
device_id: DEVICE_ID,
|
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 {
|
if delta_y != 0.0 {
|
||||||
events.push_back(Event::DeviceEvent {
|
events.push_back(Event::DeviceEvent {
|
||||||
device_id: DEVICE_ID,
|
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 {
|
if delta_x != 0.0 || delta_y != 0.0 {
|
||||||
events.push_back(Event::DeviceEvent {
|
events.push_back(Event::DeviceEvent {
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
event: DeviceEvent::MouseMotion { delta: (delta_x, delta_y) },
|
event: DeviceEvent::MouseMotion {
|
||||||
|
delta: (delta_x, delta_y),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use cocoa::base::id;
|
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 crate::platform_impl::platform::app_state::AppState;
|
use crate::platform_impl::platform::app_state::AppState;
|
||||||
|
|
||||||
|
@ -14,41 +17,41 @@ lazy_static! {
|
||||||
|
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(applicationDidFinishLaunching:),
|
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(
|
decl.add_method(
|
||||||
sel!(applicationDidBecomeActive:),
|
sel!(applicationDidBecomeActive:),
|
||||||
did_become_active as extern fn(&Object, Sel, id),
|
did_become_active as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(applicationWillResignActive:),
|
sel!(applicationWillResignActive:),
|
||||||
will_resign_active as extern fn(&Object, Sel, id),
|
will_resign_active as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(applicationWillEnterForeground:),
|
sel!(applicationWillEnterForeground:),
|
||||||
will_enter_foreground as extern fn(&Object, Sel, id),
|
will_enter_foreground as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(applicationDidEnterBackground:),
|
sel!(applicationDidEnterBackground:),
|
||||||
did_enter_background as extern fn(&Object, Sel, id),
|
did_enter_background as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(applicationWillTerminate:),
|
sel!(applicationWillTerminate:),
|
||||||
will_terminate as extern fn(&Object, Sel, id),
|
will_terminate as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
|
|
||||||
AppDelegateClass(decl.register())
|
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`");
|
trace!("Triggered `didFinishLaunching`");
|
||||||
AppState::launched();
|
AppState::launched();
|
||||||
trace!("Completed `didFinishLaunching`");
|
trace!("Completed `didFinishLaunching`");
|
||||||
YES
|
YES
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn did_become_active(_: &Object, _: Sel, _: id) {
|
extern "C" fn did_become_active(_: &Object, _: Sel, _: id) {
|
||||||
trace!("Triggered `didBecomeActive`");
|
trace!("Triggered `didBecomeActive`");
|
||||||
/*unsafe {
|
/*unsafe {
|
||||||
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(false))
|
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(false))
|
||||||
|
@ -56,7 +59,7 @@ extern fn did_become_active(_: &Object, _: Sel, _: id) {
|
||||||
trace!("Completed `didBecomeActive`");
|
trace!("Completed `didBecomeActive`");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn will_resign_active(_: &Object, _: Sel, _: id) {
|
extern "C" fn will_resign_active(_: &Object, _: Sel, _: id) {
|
||||||
trace!("Triggered `willResignActive`");
|
trace!("Triggered `willResignActive`");
|
||||||
/*unsafe {
|
/*unsafe {
|
||||||
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(true))
|
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(true))
|
||||||
|
@ -64,17 +67,17 @@ extern fn will_resign_active(_: &Object, _: Sel, _: id) {
|
||||||
trace!("Completed `willResignActive`");
|
trace!("Completed `willResignActive`");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn will_enter_foreground(_: &Object, _: Sel, _: id) {
|
extern "C" fn will_enter_foreground(_: &Object, _: Sel, _: id) {
|
||||||
trace!("Triggered `willEnterForeground`");
|
trace!("Triggered `willEnterForeground`");
|
||||||
trace!("Completed `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!("Triggered `didEnterBackground`");
|
||||||
trace!("Completed `didEnterBackground`");
|
trace!("Completed `didEnterBackground`");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn will_terminate(_: &Object, _: Sel, _: id) {
|
extern "C" fn will_terminate(_: &Object, _: Sel, _: id) {
|
||||||
trace!("Triggered `willTerminate`");
|
trace!("Triggered `willTerminate`");
|
||||||
/*unsafe {
|
/*unsafe {
|
||||||
let app: id = msg_send![class!(UIApplication), sharedApplication];
|
let app: id = msg_send![class!(UIApplication), sharedApplication];
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque, fmt::{self, Debug},
|
collections::VecDeque,
|
||||||
hint::unreachable_unchecked, mem,
|
fmt::{self, Debug},
|
||||||
sync::{atomic::{AtomicBool, Ordering}, Mutex, MutexGuard}, time::Instant,
|
hint::unreachable_unchecked,
|
||||||
|
mem,
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Mutex, MutexGuard,
|
||||||
|
},
|
||||||
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
use cocoa::{appkit::NSApp, base::nil};
|
use cocoa::{appkit::NSApp, base::nil};
|
||||||
|
@ -9,9 +15,9 @@ use cocoa::{appkit::NSApp, base::nil};
|
||||||
use crate::{
|
use crate::{
|
||||||
event::{Event, StartCause, WindowEvent},
|
event::{Event, StartCause, WindowEvent},
|
||||||
event_loop::{ControlFlow, EventLoopWindowTarget as RootWindowTarget},
|
event_loop::{ControlFlow, EventLoopWindowTarget as RootWindowTarget},
|
||||||
|
platform_impl::platform::{observer::EventLoopWaker, util::Never},
|
||||||
window::WindowId,
|
window::WindowId,
|
||||||
};
|
};
|
||||||
use crate::platform_impl::platform::{observer::EventLoopWaker, util::Never};
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref HANDLER: Handler = Default::default();
|
static ref HANDLER: Handler = Default::default();
|
||||||
|
@ -39,7 +45,8 @@ struct EventLoopHandler<F, T: 'static> {
|
||||||
|
|
||||||
impl<F, T> Debug for EventLoopHandler<F, T> {
|
impl<F, T> Debug for EventLoopHandler<F, T> {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
formatter.debug_struct("EventLoopHandler")
|
formatter
|
||||||
|
.debug_struct("EventLoopHandler")
|
||||||
.field("window_target", &self.window_target)
|
.field("window_target", &self.window_target)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
@ -51,11 +58,7 @@ where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
{
|
{
|
||||||
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow) {
|
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow) {
|
||||||
(self.callback)(
|
(self.callback)(event.userify(), &self.window_target, control_flow);
|
||||||
event.userify(),
|
|
||||||
&self.window_target,
|
|
||||||
control_flow,
|
|
||||||
);
|
|
||||||
self.will_exit |= *control_flow == ControlFlow::Exit;
|
self.will_exit |= *control_flow == ControlFlow::Exit;
|
||||||
if self.will_exit {
|
if self.will_exit {
|
||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
|
@ -65,11 +68,7 @@ where
|
||||||
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
|
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
|
||||||
let mut will_exit = self.will_exit;
|
let mut will_exit = self.will_exit;
|
||||||
for event in self.window_target.p.receiver.try_iter() {
|
for event in self.window_target.p.receiver.try_iter() {
|
||||||
(self.callback)(
|
(self.callback)(Event::UserEvent(event), &self.window_target, control_flow);
|
||||||
Event::UserEvent(event),
|
|
||||||
&self.window_target,
|
|
||||||
control_flow,
|
|
||||||
);
|
|
||||||
will_exit |= *control_flow == ControlFlow::Exit;
|
will_exit |= *control_flow == ControlFlow::Exit;
|
||||||
if will_exit {
|
if will_exit {
|
||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
|
@ -167,18 +166,13 @@ impl Handler {
|
||||||
|
|
||||||
fn handle_nonuser_event(&self, event: Event<Never>) {
|
fn handle_nonuser_event(&self, event: Event<Never>) {
|
||||||
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
|
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
|
||||||
callback.handle_nonuser_event(
|
callback.handle_nonuser_event(event, &mut *self.control_flow.lock().unwrap());
|
||||||
event,
|
|
||||||
&mut *self.control_flow.lock().unwrap(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_user_events(&self) {
|
fn handle_user_events(&self) {
|
||||||
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
|
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
|
||||||
callback.handle_user_events(
|
callback.handle_user_events(&mut *self.control_flow.lock().unwrap());
|
||||||
&mut *self.control_flow.lock().unwrap(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,13 +207,17 @@ impl AppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wakeup() {
|
pub fn wakeup() {
|
||||||
if !HANDLER.is_ready() { return }
|
if !HANDLER.is_ready() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let start = HANDLER.get_start_time().unwrap();
|
let start = HANDLER.get_start_time().unwrap();
|
||||||
let cause = match HANDLER.get_control_flow_and_update_prev() {
|
let cause = match HANDLER.get_control_flow_and_update_prev() {
|
||||||
ControlFlow::Poll => StartCause::Poll,
|
ControlFlow::Poll => StartCause::Poll,
|
||||||
ControlFlow::Wait => StartCause::WaitCancelled {
|
ControlFlow::Wait => {
|
||||||
start,
|
StartCause::WaitCancelled {
|
||||||
requested_resume: None,
|
start,
|
||||||
|
requested_resume: None,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ControlFlow::WaitUntil(requested_resume) => {
|
ControlFlow::WaitUntil(requested_resume) => {
|
||||||
if Instant::now() >= requested_resume {
|
if Instant::now() >= requested_resume {
|
||||||
|
@ -234,7 +232,7 @@ impl AppState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ControlFlow::Exit => StartCause::Poll,//panic!("unexpected `ControlFlow::Exit`"),
|
ControlFlow::Exit => StartCause::Poll, //panic!("unexpected `ControlFlow::Exit`"),
|
||||||
};
|
};
|
||||||
HANDLER.set_in_callback(true);
|
HANDLER.set_in_callback(true);
|
||||||
HANDLER.handle_nonuser_event(Event::NewEvents(cause));
|
HANDLER.handle_nonuser_event(Event::NewEvents(cause));
|
||||||
|
@ -278,7 +276,9 @@ impl AppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cleared() {
|
pub fn cleared() {
|
||||||
if !HANDLER.is_ready() { return }
|
if !HANDLER.is_ready() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if !HANDLER.get_in_callback() {
|
if !HANDLER.get_in_callback() {
|
||||||
HANDLER.set_in_callback(true);
|
HANDLER.set_in_callback(true);
|
||||||
HANDLER.handle_user_events();
|
HANDLER.handle_user_events();
|
||||||
|
@ -295,8 +295,8 @@ impl AppState {
|
||||||
HANDLER.set_in_callback(false);
|
HANDLER.set_in_callback(false);
|
||||||
}
|
}
|
||||||
if HANDLER.should_exit() {
|
if HANDLER.should_exit() {
|
||||||
let _: () = unsafe { msg_send![NSApp(), stop:nil] };
|
let _: () = unsafe { msg_send![NSApp(), stop: nil] };
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
HANDLER.update_start_time();
|
HANDLER.update_start_time();
|
||||||
match HANDLER.get_old_and_new_control_flow() {
|
match HANDLER.get_old_and_new_control_flow() {
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use std::os::raw::c_ushort;
|
use std::os::raw::c_ushort;
|
||||||
|
|
||||||
use cocoa::{appkit::{NSEvent, NSEventModifierFlags}, base::id};
|
use cocoa::{
|
||||||
|
appkit::{NSEvent, NSEventModifierFlags},
|
||||||
use crate::event::{
|
base::id,
|
||||||
ElementState, KeyboardInput,
|
};
|
||||||
ModifiersState, VirtualKeyCode, WindowEvent,
|
|
||||||
|
use crate::{
|
||||||
|
event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent},
|
||||||
|
platform_impl::platform::DEVICE_ID,
|
||||||
};
|
};
|
||||||
use crate::platform_impl::platform::DEVICE_ID;
|
|
||||||
|
|
||||||
pub fn char_to_keycode(c: char) -> Option<VirtualKeyCode> {
|
pub fn char_to_keycode(c: char) -> Option<VirtualKeyCode> {
|
||||||
// We only translate keys that are affected by keyboard layout.
|
// We only translate keys that are affected by keyboard layout.
|
||||||
|
@ -57,9 +59,9 @@ pub fn char_to_keycode(c: char) -> Option<VirtualKeyCode> {
|
||||||
'-' | '_' => VirtualKeyCode::Minus,
|
'-' | '_' => VirtualKeyCode::Minus,
|
||||||
']' | '}' => VirtualKeyCode::RBracket,
|
']' | '}' => VirtualKeyCode::RBracket,
|
||||||
'[' | '{' => VirtualKeyCode::LBracket,
|
'[' | '{' => VirtualKeyCode::LBracket,
|
||||||
'\''| '"' => VirtualKeyCode::Apostrophe,
|
'\'' | '"' => VirtualKeyCode::Apostrophe,
|
||||||
';' | ':' => VirtualKeyCode::Semicolon,
|
';' | ':' => VirtualKeyCode::Semicolon,
|
||||||
'\\'| '|' => VirtualKeyCode::Backslash,
|
'\\' | '|' => VirtualKeyCode::Backslash,
|
||||||
',' | '<' => VirtualKeyCode::Comma,
|
',' | '<' => VirtualKeyCode::Comma,
|
||||||
'/' | '?' => VirtualKeyCode::Slash,
|
'/' | '?' => VirtualKeyCode::Slash,
|
||||||
'.' | '>' => VirtualKeyCode::Period,
|
'.' | '>' => VirtualKeyCode::Period,
|
||||||
|
@ -198,7 +200,6 @@ pub fn scancode_to_keycode(scancode: c_ushort) -> Option<VirtualKeyCode> {
|
||||||
0x7d => VirtualKeyCode::Down,
|
0x7d => VirtualKeyCode::Down,
|
||||||
0x7e => VirtualKeyCode::Up,
|
0x7e => VirtualKeyCode::Up,
|
||||||
//0x7f => unkown,
|
//0x7f => unkown,
|
||||||
|
|
||||||
0xa => VirtualKeyCode::Caret,
|
0xa => VirtualKeyCode::Caret,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
|
@ -215,16 +216,14 @@ pub fn check_function_keys(string: &String) -> Option<VirtualKeyCode> {
|
||||||
0xf71a => VirtualKeyCode::F23,
|
0xf71a => VirtualKeyCode::F23,
|
||||||
0xf71b => VirtualKeyCode::F24,
|
0xf71b => VirtualKeyCode::F24,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event_mods(event: id) -> ModifiersState {
|
pub fn event_mods(event: id) -> ModifiersState {
|
||||||
let flags = unsafe {
|
let flags = unsafe { NSEvent::modifierFlags(event) };
|
||||||
NSEvent::modifierFlags(event)
|
|
||||||
};
|
|
||||||
ModifiersState {
|
ModifiersState {
|
||||||
shift: flags.contains(NSEventModifierFlags::NSShiftKeyMask),
|
shift: flags.contains(NSEventModifierFlags::NSShiftKeyMask),
|
||||||
ctrl: flags.contains(NSEventModifierFlags::NSControlKeyMask),
|
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.
|
// 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
|
// In winit, we use keycode to refer to the key's character, and so this function aligns
|
||||||
// AppKit's terminology with ours.
|
// AppKit's terminology with ours.
|
||||||
unsafe {
|
unsafe { msg_send![event, keyCode] }
|
||||||
msg_send![event, keyCode]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn modifier_event(
|
pub unsafe fn modifier_event(
|
||||||
|
@ -249,7 +246,8 @@ pub unsafe fn modifier_event(
|
||||||
was_key_pressed: bool,
|
was_key_pressed: bool,
|
||||||
) -> Option<WindowEvent> {
|
) -> Option<WindowEvent> {
|
||||||
if !was_key_pressed && NSEvent::modifierFlags(ns_event).contains(keymask)
|
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 {
|
let state = if was_key_pressed {
|
||||||
ElementState::Released
|
ElementState::Released
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
use std::{
|
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 crate::{
|
use crate::{
|
||||||
event::Event,
|
event::Event,
|
||||||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootWindowTarget},
|
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootWindowTarget},
|
||||||
};
|
platform_impl::platform::{
|
||||||
use crate::platform_impl::platform::{
|
app::APP_CLASS,
|
||||||
app::APP_CLASS, app_delegate::APP_DELEGATE_CLASS,
|
app_delegate::APP_DELEGATE_CLASS,
|
||||||
app_state::AppState, monitor::{self, MonitorHandle},
|
app_state::AppState,
|
||||||
observer::*, util::IdRef,
|
monitor::{self, MonitorHandle},
|
||||||
|
observer::*,
|
||||||
|
util::IdRef,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct EventLoopWindowTarget<T: 'static> {
|
pub struct EventLoopWindowTarget<T: 'static> {
|
||||||
|
@ -75,7 +82,8 @@ impl<T> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<F>(self, callback: F) -> !
|
pub fn run<F>(self, callback: F) -> !
|
||||||
where F: 'static + FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
|
where
|
||||||
|
F: 'static + FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let _pool = NSAutoreleasePool::new(nil);
|
let _pool = NSAutoreleasePool::new(nil);
|
||||||
|
@ -89,7 +97,8 @@ impl<T> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, _callback: F)
|
pub fn run_return<F>(&mut self, _callback: F)
|
||||||
where F: FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
|
where
|
||||||
|
F: FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
@ -119,11 +128,8 @@ impl<T> Proxy<T> {
|
||||||
let rl = CFRunLoopGetMain();
|
let rl = CFRunLoopGetMain();
|
||||||
let mut context: CFRunLoopSourceContext = mem::zeroed();
|
let mut context: CFRunLoopSourceContext = mem::zeroed();
|
||||||
context.perform = event_loop_proxy_handler;
|
context.perform = event_loop_proxy_handler;
|
||||||
let source = CFRunLoopSourceCreate(
|
let source =
|
||||||
ptr::null_mut(),
|
CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context);
|
||||||
CFIndex::max_value() - 1,
|
|
||||||
&mut context,
|
|
||||||
);
|
|
||||||
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
||||||
CFRunLoopWakeUp(rl);
|
CFRunLoopWakeUp(rl);
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
#![allow(dead_code, non_snake_case, non_upper_case_globals)]
|
#![allow(dead_code, non_snake_case, non_upper_case_globals)]
|
||||||
|
|
||||||
use cocoa::base::id;
|
use cocoa::{
|
||||||
use cocoa::foundation::{NSInteger, NSUInteger};
|
base::id,
|
||||||
|
foundation::{NSInteger, NSUInteger},
|
||||||
|
};
|
||||||
use objc;
|
use objc;
|
||||||
|
|
||||||
pub const NSNotFound: NSInteger = NSInteger::max_value();
|
pub const NSNotFound: NSInteger = NSInteger::max_value();
|
||||||
|
@ -53,11 +55,11 @@ impl NSMutableAttributedString for id {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn initWithString(self, string: id) -> 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 {
|
unsafe fn initWithAttributedString(self, string: id) -> id {
|
||||||
msg_send![self, initWithAttributedString:string]
|
msg_send![self, initWithAttributedString: string]
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn string(self) -> id {
|
unsafe fn string(self) -> id {
|
||||||
|
|
|
@ -15,16 +15,13 @@ mod window_delegate;
|
||||||
|
|
||||||
use std::{fmt, ops::Deref, sync::Arc};
|
use std::{fmt, ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
|
||||||
event::DeviceId as RootDeviceId, window::WindowAttributes,
|
|
||||||
error::OsError as RootOsError,
|
|
||||||
};
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
event_loop::{EventLoop, EventLoopWindowTarget, Proxy as EventLoopProxy},
|
event_loop::{EventLoop, EventLoopWindowTarget, Proxy as EventLoopProxy},
|
||||||
monitor::MonitorHandle,
|
monitor::MonitorHandle,
|
||||||
window::{
|
window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, UnownedWindow},
|
||||||
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)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -48,7 +45,7 @@ pub struct Window {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum OsError {
|
pub enum OsError {
|
||||||
CGError(core_graphics::base::CGError),
|
CGError(core_graphics::base::CGError),
|
||||||
CreationError(&'static str)
|
CreationError(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Window {}
|
unsafe impl Send for Window {}
|
||||||
|
|
|
@ -11,9 +11,11 @@ use core_video_sys::{
|
||||||
CVDisplayLinkGetNominalOutputVideoRefreshPeriod, CVDisplayLinkRelease,
|
CVDisplayLinkGetNominalOutputVideoRefreshPeriod, CVDisplayLinkRelease,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
use crate::{
|
||||||
use crate::monitor::VideoMode;
|
dpi::{PhysicalPosition, PhysicalSize},
|
||||||
use crate::platform_impl::platform::util::IdRef;
|
monitor::VideoMode,
|
||||||
|
platform_impl::platform::util::IdRef,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct MonitorHandle(CGDirectDisplayID);
|
pub struct MonitorHandle(CGDirectDisplayID);
|
||||||
|
@ -79,10 +81,7 @@ impl MonitorHandle {
|
||||||
let display = CGDisplay::new(display_id);
|
let display = CGDisplay::new(display_id);
|
||||||
let height = display.pixels_high();
|
let height = display.pixels_high();
|
||||||
let width = display.pixels_wide();
|
let width = display.pixels_wide();
|
||||||
PhysicalSize::from_logical(
|
PhysicalSize::from_logical((width as f64, height as f64), self.hidpi_factor())
|
||||||
(width as f64, height as f64),
|
|
||||||
self.hidpi_factor(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use std::{self, ptr, os::raw::*, time::Instant};
|
use std::{self, os::raw::*, ptr, time::Instant};
|
||||||
|
|
||||||
use crate::platform_impl::platform::app_state::AppState;
|
use crate::platform_impl::platform::app_state::AppState;
|
||||||
|
|
||||||
#[link(name = "CoreFoundation", kind = "framework")]
|
#[link(name = "CoreFoundation", kind = "framework")]
|
||||||
extern {
|
extern "C" {
|
||||||
pub static kCFRunLoopDefaultMode: CFRunLoopMode;
|
pub static kCFRunLoopDefaultMode: CFRunLoopMode;
|
||||||
pub static kCFRunLoopCommonModes: CFRunLoopMode;
|
pub static kCFRunLoopCommonModes: CFRunLoopMode;
|
||||||
|
|
||||||
|
@ -33,15 +33,8 @@ extern {
|
||||||
callout: CFRunLoopTimerCallBack,
|
callout: CFRunLoopTimerCallBack,
|
||||||
context: *mut CFRunLoopTimerContext,
|
context: *mut CFRunLoopTimerContext,
|
||||||
) -> CFRunLoopTimerRef;
|
) -> CFRunLoopTimerRef;
|
||||||
pub fn CFRunLoopAddTimer(
|
pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFRunLoopMode);
|
||||||
rl: CFRunLoopRef,
|
pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime);
|
||||||
timer: CFRunLoopTimerRef,
|
|
||||||
mode: CFRunLoopMode,
|
|
||||||
);
|
|
||||||
pub fn CFRunLoopTimerSetNextFireDate(
|
|
||||||
timer: CFRunLoopTimerRef,
|
|
||||||
fireDate: CFAbsoluteTime,
|
|
||||||
);
|
|
||||||
pub fn CFRunLoopTimerInvalidate(time: CFRunLoopTimerRef);
|
pub fn CFRunLoopTimerInvalidate(time: CFRunLoopTimerRef);
|
||||||
|
|
||||||
pub fn CFRunLoopSourceCreate(
|
pub fn CFRunLoopSourceCreate(
|
||||||
|
@ -49,11 +42,7 @@ extern {
|
||||||
order: CFIndex,
|
order: CFIndex,
|
||||||
context: *mut CFRunLoopSourceContext,
|
context: *mut CFRunLoopSourceContext,
|
||||||
) -> CFRunLoopSourceRef;
|
) -> CFRunLoopSourceRef;
|
||||||
pub fn CFRunLoopAddSource(
|
pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFRunLoopMode);
|
||||||
rl: CFRunLoopRef,
|
|
||||||
source: CFRunLoopSourceRef,
|
|
||||||
mode: CFRunLoopMode,
|
|
||||||
);
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef);
|
pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef);
|
||||||
pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef);
|
pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef);
|
||||||
|
@ -98,15 +87,9 @@ pub const kCFRunLoopAfterWaiting: CFRunLoopActivity = 1 << 6;
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub const kCFRunLoopExit: CFRunLoopActivity = 1 << 7;
|
pub const kCFRunLoopExit: CFRunLoopActivity = 1 << 7;
|
||||||
|
|
||||||
pub type CFRunLoopObserverCallBack = extern "C" fn(
|
pub type CFRunLoopObserverCallBack =
|
||||||
observer: CFRunLoopObserverRef,
|
extern "C" fn(observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void);
|
||||||
activity: CFRunLoopActivity,
|
pub type CFRunLoopTimerCallBack = extern "C" fn(timer: CFRunLoopTimerRef, info: *mut c_void);
|
||||||
info: *mut c_void,
|
|
||||||
);
|
|
||||||
pub type CFRunLoopTimerCallBack = extern "C" fn(
|
|
||||||
timer: CFRunLoopTimerRef,
|
|
||||||
info: *mut c_void
|
|
||||||
);
|
|
||||||
|
|
||||||
pub enum CFRunLoopObserverContext {}
|
pub enum CFRunLoopObserverContext {}
|
||||||
pub enum CFRunLoopTimerContext {}
|
pub enum CFRunLoopTimerContext {}
|
||||||
|
@ -127,7 +110,7 @@ pub struct CFRunLoopSourceContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin is queued with the highest priority to ensure it is processed before other observers
|
// 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,
|
_: CFRunLoopObserverRef,
|
||||||
activity: CFRunLoopActivity,
|
activity: CFRunLoopActivity,
|
||||||
_: *mut c_void,
|
_: *mut c_void,
|
||||||
|
@ -146,7 +129,7 @@ extern fn control_flow_begin_handler(
|
||||||
|
|
||||||
// end is queued with the lowest priority to ensure it is processed after other observers
|
// end is queued with the lowest priority to ensure it is processed after other observers
|
||||||
// without that, LoopDestroyed would get sent after EventsCleared
|
// without that, LoopDestroyed would get sent after EventsCleared
|
||||||
extern fn control_flow_end_handler(
|
extern "C" fn control_flow_end_handler(
|
||||||
_: CFRunLoopObserverRef,
|
_: CFRunLoopObserverRef,
|
||||||
activity: CFRunLoopActivity,
|
activity: CFRunLoopActivity,
|
||||||
_: *mut c_void,
|
_: *mut c_void,
|
||||||
|
@ -158,7 +141,7 @@ extern fn control_flow_end_handler(
|
||||||
AppState::cleared();
|
AppState::cleared();
|
||||||
//trace!("Completed `CFRunLoopBeforeWaiting`");
|
//trace!("Completed `CFRunLoopBeforeWaiting`");
|
||||||
},
|
},
|
||||||
kCFRunLoopExit => (),//unimplemented!(), // not expected to ever happen
|
kCFRunLoopExit => (), //unimplemented!(), // not expected to ever happen
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,7 +162,7 @@ impl RunLoop {
|
||||||
let observer = CFRunLoopObserverCreate(
|
let observer = CFRunLoopObserverCreate(
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
flags,
|
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
|
priority, // The lower the value, the sooner this will run
|
||||||
handler,
|
handler,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
|
@ -204,7 +187,6 @@ pub fn setup_control_flow_observers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct EventLoopWaker {
|
pub struct EventLoopWaker {
|
||||||
timer: CFRunLoopTimerRef,
|
timer: CFRunLoopTimerRef,
|
||||||
}
|
}
|
||||||
|
@ -220,7 +202,7 @@ impl Drop for EventLoopWaker {
|
||||||
|
|
||||||
impl Default for EventLoopWaker {
|
impl Default for EventLoopWaker {
|
||||||
fn default() -> 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 {
|
unsafe {
|
||||||
// create a timer with a 1µs interval (1ns does not work) to mimic polling.
|
// 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
|
// it is initially setup with a first fire time really far into the
|
||||||
|
@ -257,8 +239,8 @@ impl EventLoopWaker {
|
||||||
unsafe {
|
unsafe {
|
||||||
let current = CFAbsoluteTimeGetCurrent();
|
let current = CFAbsoluteTimeGetCurrent();
|
||||||
let duration = instant - now;
|
let duration = instant - now;
|
||||||
let fsecs = duration.subsec_nanos() as f64 / 1_000_000_000.0
|
let fsecs =
|
||||||
+ duration.as_secs() as f64;
|
duration.subsec_nanos() as f64 / 1_000_000_000.0 + duration.as_secs() as f64;
|
||||||
CFRunLoopTimerSetNextFireDate(self.timer, current + fsecs)
|
CFRunLoopTimerSetNextFireDate(self.timer, current + fsecs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ use cocoa::{
|
||||||
};
|
};
|
||||||
use dispatch::ffi::{dispatch_async_f, dispatch_get_main_queue, dispatch_sync_f};
|
use dispatch::ffi::{dispatch_async_f, dispatch_get_main_queue, dispatch_sync_f};
|
||||||
|
|
||||||
use crate::dpi::LogicalSize;
|
use crate::{
|
||||||
use crate::platform_impl::platform::{ffi, util::IdRef, window::SharedState};
|
dpi::LogicalSize,
|
||||||
|
platform_impl::platform::{ffi, util::IdRef, window::SharedState},
|
||||||
|
};
|
||||||
|
|
||||||
unsafe fn set_style_mask(ns_window: id, ns_view: id, mask: NSWindowStyleMask) {
|
unsafe fn set_style_mask(ns_window: id, ns_view: id, mask: NSWindowStyleMask) {
|
||||||
ns_window.setStyleMask_(mask);
|
ns_window.setStyleMask_(mask);
|
||||||
|
@ -26,15 +28,15 @@ struct SetStyleMaskData {
|
||||||
mask: NSWindowStyleMask,
|
mask: NSWindowStyleMask,
|
||||||
}
|
}
|
||||||
impl SetStyleMaskData {
|
impl SetStyleMaskData {
|
||||||
fn new_ptr(
|
fn new_ptr(ns_window: id, ns_view: id, mask: NSWindowStyleMask) -> *mut Self {
|
||||||
ns_window: id,
|
Box::into_raw(Box::new(SetStyleMaskData {
|
||||||
ns_view: id,
|
ns_window,
|
||||||
mask: NSWindowStyleMask,
|
ns_view,
|
||||||
) -> *mut Self {
|
mask,
|
||||||
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 {
|
unsafe {
|
||||||
let context_ptr = context as *mut SetStyleMaskData;
|
let context_ptr = context as *mut SetStyleMaskData;
|
||||||
{
|
{
|
||||||
|
@ -70,14 +72,11 @@ struct SetContentSizeData {
|
||||||
size: LogicalSize,
|
size: LogicalSize,
|
||||||
}
|
}
|
||||||
impl SetContentSizeData {
|
impl SetContentSizeData {
|
||||||
fn new_ptr(
|
fn new_ptr(ns_window: id, size: LogicalSize) -> *mut Self {
|
||||||
ns_window: id,
|
|
||||||
size: LogicalSize,
|
|
||||||
) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(SetContentSizeData { ns_window, size }))
|
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 {
|
unsafe {
|
||||||
let context_ptr = context as *mut SetContentSizeData;
|
let context_ptr = context as *mut SetContentSizeData;
|
||||||
{
|
{
|
||||||
|
@ -109,14 +108,11 @@ struct SetFrameTopLeftPointData {
|
||||||
point: NSPoint,
|
point: NSPoint,
|
||||||
}
|
}
|
||||||
impl SetFrameTopLeftPointData {
|
impl SetFrameTopLeftPointData {
|
||||||
fn new_ptr(
|
fn new_ptr(ns_window: id, point: NSPoint) -> *mut Self {
|
||||||
ns_window: id,
|
|
||||||
point: NSPoint,
|
|
||||||
) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(SetFrameTopLeftPointData { ns_window, point }))
|
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 {
|
unsafe {
|
||||||
let context_ptr = context as *mut SetFrameTopLeftPointData;
|
let context_ptr = context as *mut SetFrameTopLeftPointData;
|
||||||
{
|
{
|
||||||
|
@ -142,14 +138,11 @@ struct SetLevelData {
|
||||||
level: ffi::NSWindowLevel,
|
level: ffi::NSWindowLevel,
|
||||||
}
|
}
|
||||||
impl SetLevelData {
|
impl SetLevelData {
|
||||||
fn new_ptr(
|
fn new_ptr(ns_window: id, level: ffi::NSWindowLevel) -> *mut Self {
|
||||||
ns_window: id,
|
|
||||||
level: ffi::NSWindowLevel,
|
|
||||||
) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(SetLevelData { ns_window, level }))
|
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 {
|
unsafe {
|
||||||
let context_ptr = context as *mut SetLevelData;
|
let context_ptr = context as *mut SetLevelData;
|
||||||
{
|
{
|
||||||
|
@ -190,7 +183,7 @@ impl ToggleFullScreenData {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extern fn toggle_full_screen_callback(context: *mut c_void) {
|
extern "C" fn toggle_full_screen_callback(context: *mut c_void) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let context_ptr = context as *mut ToggleFullScreenData;
|
let context_ptr = context as *mut ToggleFullScreenData;
|
||||||
{
|
{
|
||||||
|
@ -227,12 +220,7 @@ pub unsafe fn toggle_full_screen_async(
|
||||||
not_fullscreen: bool,
|
not_fullscreen: bool,
|
||||||
shared_state: Weak<Mutex<SharedState>>,
|
shared_state: Weak<Mutex<SharedState>>,
|
||||||
) {
|
) {
|
||||||
let context = ToggleFullScreenData::new_ptr(
|
let context = ToggleFullScreenData::new_ptr(ns_window, ns_view, not_fullscreen, shared_state);
|
||||||
ns_window,
|
|
||||||
ns_view,
|
|
||||||
not_fullscreen,
|
|
||||||
shared_state,
|
|
||||||
);
|
|
||||||
dispatch_async_f(
|
dispatch_async_f(
|
||||||
dispatch_get_main_queue(),
|
dispatch_get_main_queue(),
|
||||||
context as *mut _,
|
context as *mut _,
|
||||||
|
@ -325,7 +313,7 @@ impl OrderOutData {
|
||||||
Box::into_raw(Box::new(OrderOutData { ns_window }))
|
Box::into_raw(Box::new(OrderOutData { ns_window }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extern fn order_out_callback(context: *mut c_void) {
|
extern "C" fn order_out_callback(context: *mut c_void) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let context_ptr = context as *mut OrderOutData;
|
let context_ptr = context as *mut OrderOutData;
|
||||||
{
|
{
|
||||||
|
@ -354,7 +342,7 @@ impl MakeKeyAndOrderFrontData {
|
||||||
Box::into_raw(Box::new(MakeKeyAndOrderFrontData { ns_window }))
|
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 {
|
unsafe {
|
||||||
let context_ptr = context as *mut MakeKeyAndOrderFrontData;
|
let context_ptr = context as *mut MakeKeyAndOrderFrontData;
|
||||||
{
|
{
|
||||||
|
@ -415,7 +403,7 @@ impl CloseData {
|
||||||
Box::into_raw(Box::new(CloseData { ns_window }))
|
Box::into_raw(Box::new(CloseData { ns_window }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extern fn close_callback(context: *mut c_void) {
|
extern "C" fn close_callback(context: *mut c_void) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let context_ptr = context as *mut CloseData;
|
let context_ptr = context as *mut CloseData;
|
||||||
{
|
{
|
||||||
|
@ -431,9 +419,5 @@ extern fn close_callback(context: *mut c_void) {
|
||||||
// thread. Though, it's a good idea to look into that more...
|
// thread. Though, it's a good idea to look into that more...
|
||||||
pub unsafe fn close_async(ns_window: id) {
|
pub unsafe fn close_async(ns_window: id) {
|
||||||
let context = CloseData::new_ptr(ns_window);
|
let context = CloseData::new_ptr(ns_window);
|
||||||
dispatch_async_f(
|
dispatch_async_f(dispatch_get_main_queue(), context as *mut _, close_callback);
|
||||||
dispatch_get_main_queue(),
|
|
||||||
context as *mut _,
|
|
||||||
close_callback,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::NSImage, base::{id, nil},
|
appkit::NSImage,
|
||||||
|
base::{id, nil},
|
||||||
foundation::{NSDictionary, NSPoint, NSString},
|
foundation::{NSDictionary, NSPoint, NSString},
|
||||||
};
|
};
|
||||||
use objc::runtime::Sel;
|
use objc::runtime::Sel;
|
||||||
|
@ -22,7 +23,9 @@ impl From<CursorIcon> for Cursor {
|
||||||
CursorIcon::VerticalText => Cursor::Native("IBeamCursorForVerticalLayout"),
|
CursorIcon::VerticalText => Cursor::Native("IBeamCursorForVerticalLayout"),
|
||||||
CursorIcon::Copy => Cursor::Native("dragCopyCursor"),
|
CursorIcon::Copy => Cursor::Native("dragCopyCursor"),
|
||||||
CursorIcon::Alias => Cursor::Native("dragLinkCursor"),
|
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::ContextMenu => Cursor::Native("contextualMenuCursor"),
|
||||||
CursorIcon::Crosshair => Cursor::Native("crosshairCursor"),
|
CursorIcon::Crosshair => Cursor::Native("crosshairCursor"),
|
||||||
CursorIcon::EResize => Cursor::Native("resizeRightCursor"),
|
CursorIcon::EResize => Cursor::Native("resizeRightCursor"),
|
||||||
|
@ -52,7 +55,9 @@ impl From<CursorIcon> for Cursor {
|
||||||
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=522349
|
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=522349
|
||||||
// This is the wrong semantics for `Wait`, but it's the same as
|
// This is the wrong semantics for `Wait`, but it's the same as
|
||||||
// what's used in Safari and Chrome.
|
// 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...
|
// For the rest, we can just snatch the cursors from WebKit...
|
||||||
// They fit the style of the native cursors, and will seem
|
// They fit the style of the native cursors, and will seem
|
||||||
|
@ -75,18 +80,18 @@ impl Cursor {
|
||||||
match self {
|
match self {
|
||||||
Cursor::Native(cursor_name) => {
|
Cursor::Native(cursor_name) => {
|
||||||
let sel = Sel::register(cursor_name);
|
let sel = Sel::register(cursor_name);
|
||||||
msg_send![class!(NSCursor), performSelector:sel]
|
msg_send![class!(NSCursor), performSelector: sel]
|
||||||
},
|
},
|
||||||
Cursor::Undocumented(cursor_name) => {
|
Cursor::Undocumented(cursor_name) => {
|
||||||
let class = class!(NSCursor);
|
let class = class!(NSCursor);
|
||||||
let sel = Sel::register(cursor_name);
|
let sel = Sel::register(cursor_name);
|
||||||
let sel = if msg_send![class, respondsToSelector:sel] {
|
let sel = if msg_send![class, respondsToSelector: sel] {
|
||||||
sel
|
sel
|
||||||
} else {
|
} else {
|
||||||
warn!("Cursor `{}` appears to be invalid", cursor_name);
|
warn!("Cursor `{}` appears to be invalid", cursor_name);
|
||||||
sel!(arrowCursor)
|
sel!(arrowCursor)
|
||||||
};
|
};
|
||||||
msg_send![class, performSelector:sel]
|
msg_send![class, performSelector: sel]
|
||||||
},
|
},
|
||||||
Cursor::WebKit(cursor_name) => load_webkit_cursor(cursor_name),
|
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_x = NSString::alloc(nil).init_str("hotx");
|
||||||
let key_y = NSString::alloc(nil).init_str("hoty");
|
let key_y = NSString::alloc(nil).init_str("hoty");
|
||||||
|
|
||||||
let cursor_path: id = msg_send![cursor_root,
|
let cursor_path: id = msg_send![cursor_root, stringByAppendingPathComponent: cursor_name];
|
||||||
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 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 image = NSImage::alloc(nil).initByReferencingFile_(pdf_path);
|
||||||
let info = NSDictionary::dictionaryWithContentsOfFile_(
|
let info = NSDictionary::dictionaryWithContentsOfFile_(nil, info_path);
|
||||||
nil,
|
|
||||||
info_path,
|
|
||||||
);
|
|
||||||
let x = info.valueForKey_(key_x);
|
let x = info.valueForKey_(key_x);
|
||||||
let y = info.valueForKey_(key_y);
|
let y = info.valueForKey_(key_y);
|
||||||
let point = NSPoint::new(
|
let point = NSPoint::new(msg_send![x, doubleValue], msg_send![y, doubleValue]);
|
||||||
msg_send![x, doubleValue],
|
|
||||||
msg_send![y, doubleValue],
|
|
||||||
);
|
|
||||||
let cursor: id = msg_send![class!(NSCursor), alloc];
|
let cursor: id = msg_send![class!(NSCursor), alloc];
|
||||||
msg_send![cursor,
|
msg_send![cursor,
|
||||||
initWithImage:image
|
initWithImage:image
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
mod r#async;
|
mod r#async;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
|
|
||||||
pub use self::{r#async::*, cursor::*};
|
pub use self::{cursor::*, r#async::*};
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::{BitAnd, Deref};
|
||||||
use std::ops::BitAnd;
|
|
||||||
|
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::{NSApp, NSWindowStyleMask},
|
appkit::{NSApp, NSWindowStyleMask},
|
||||||
|
@ -12,7 +11,7 @@ use cocoa::{
|
||||||
foundation::{NSAutoreleasePool, NSRect, NSUInteger},
|
foundation::{NSAutoreleasePool, NSRect, NSUInteger},
|
||||||
};
|
};
|
||||||
use core_graphics::display::CGDisplay;
|
use core_graphics::display::CGDisplay;
|
||||||
use objc::runtime::{BOOL, Class, Object, Sel, YES};
|
use objc::runtime::{Class, Object, Sel, BOOL, YES};
|
||||||
|
|
||||||
use crate::platform_impl::platform::ffi;
|
use crate::platform_impl::platform::ffi;
|
||||||
|
|
||||||
|
@ -21,8 +20,8 @@ use crate::platform_impl::platform::ffi;
|
||||||
pub enum Never {}
|
pub enum Never {}
|
||||||
|
|
||||||
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
||||||
where T:
|
where
|
||||||
Copy + PartialEq + BitAnd<T, Output = T>
|
T: Copy + PartialEq + BitAnd<T, Output = T>,
|
||||||
{
|
{
|
||||||
bitset & flag == flag
|
bitset & flag == flag
|
||||||
}
|
}
|
||||||
|
@ -48,7 +47,11 @@ impl IdRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn non_nil(self) -> Option<IdRef> {
|
pub fn non_nil(self) -> Option<IdRef> {
|
||||||
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 {
|
pub unsafe fn create_input_context(view: id) -> IdRef {
|
||||||
let input_context: id = msg_send![class!(NSTextInputContext), alloc];
|
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)
|
IdRef::new(input_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub unsafe fn open_emoji_picker() {
|
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
|
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!
|
// If we don't do this, key handling will break. Therefore, never call `setStyleMask` directly!
|
||||||
window.makeFirstResponder_(view);
|
window.makeFirstResponder_(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,39 @@
|
||||||
use std::{
|
use std::{
|
||||||
boxed::Box, collections::VecDeque, os::raw::*, slice, str,
|
boxed::Box,
|
||||||
|
collections::VecDeque,
|
||||||
|
os::raw::*,
|
||||||
|
slice, str,
|
||||||
sync::{Arc, Mutex, Weak},
|
sync::{Arc, Mutex, Weak},
|
||||||
};
|
};
|
||||||
|
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::{NSApp, NSEvent, NSEventModifierFlags, NSEventPhase, NSView, NSWindow},
|
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 crate::{
|
use crate::{
|
||||||
event::{
|
event::{
|
||||||
DeviceEvent, ElementState, Event, KeyboardInput, MouseButton,
|
DeviceEvent, ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase,
|
||||||
MouseScrollDelta, TouchPhase, VirtualKeyCode, WindowEvent,
|
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,
|
window::WindowId,
|
||||||
};
|
};
|
||||||
use crate::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)]
|
#[derive(Default)]
|
||||||
struct Modifiers {
|
struct Modifiers {
|
||||||
|
@ -54,17 +67,18 @@ pub fn new_view(ns_window: id) -> (IdRef, Weak<Mutex<util::Cursor>>) {
|
||||||
// This is free'd in `dealloc`
|
// This is free'd in `dealloc`
|
||||||
let state_ptr = Box::into_raw(Box::new(state)) as *mut c_void;
|
let state_ptr = Box::into_raw(Box::new(state)) as *mut c_void;
|
||||||
let ns_view: id = msg_send![VIEW_CLASS.0, alloc];
|
let ns_view: id = msg_send![VIEW_CLASS.0, alloc];
|
||||||
(IdRef::new(msg_send![ns_view, initWithWinit:state_ptr]), cursor_access)
|
(
|
||||||
|
IdRef::new(msg_send![ns_view, initWithWinit: state_ptr]),
|
||||||
|
cursor_access,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set_ime_position(ns_view: id, input_context: id, x: f64, y: f64) {
|
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_ptr: *mut c_void = *(*ns_view).get_mut_ivar("winitState");
|
||||||
let state = &mut *(state_ptr as *mut ViewState);
|
let state = &mut *(state_ptr as *mut ViewState);
|
||||||
let content_rect = NSWindow::contentRectForFrameRect_(
|
let content_rect =
|
||||||
state.ns_window,
|
NSWindow::contentRectForFrameRect_(state.ns_window, NSWindow::frame(state.ns_window));
|
||||||
NSWindow::frame(state.ns_window),
|
|
||||||
);
|
|
||||||
let base_x = content_rect.origin.x as f64;
|
let base_x = content_rect.origin.x as f64;
|
||||||
let base_y = (content_rect.origin.y + content_rect.size.height) 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));
|
state.ime_spot = Some((base_x + x, base_y - y));
|
||||||
|
@ -79,161 +93,148 @@ lazy_static! {
|
||||||
static ref VIEW_CLASS: ViewClass = unsafe {
|
static ref VIEW_CLASS: ViewClass = unsafe {
|
||||||
let superclass = class!(NSView);
|
let superclass = class!(NSView);
|
||||||
let mut decl = ClassDecl::new("WinitView", superclass).unwrap();
|
let mut decl = ClassDecl::new("WinitView", superclass).unwrap();
|
||||||
decl.add_method(
|
decl.add_method(sel!(dealloc), dealloc as extern "C" fn(&Object, Sel));
|
||||||
sel!(dealloc),
|
|
||||||
dealloc as extern fn(&Object, Sel),
|
|
||||||
);
|
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(initWithWinit:),
|
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(
|
decl.add_method(
|
||||||
sel!(viewDidMoveToWindow),
|
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(
|
decl.add_method(
|
||||||
sel!(drawRect:),
|
sel!(drawRect:),
|
||||||
draw_rect as extern fn(&Object, Sel, id),
|
draw_rect as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(acceptsFirstResponder),
|
sel!(acceptsFirstResponder),
|
||||||
accepts_first_responder as extern fn(&Object, Sel) -> BOOL,
|
accepts_first_responder as extern "C" fn(&Object, Sel) -> BOOL,
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(touchBar),
|
sel!(touchBar),
|
||||||
touch_bar as extern fn(&Object, Sel) -> BOOL,
|
touch_bar as extern "C" fn(&Object, Sel) -> BOOL,
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(resetCursorRects),
|
sel!(resetCursorRects),
|
||||||
reset_cursor_rects as extern fn(&Object, Sel),
|
reset_cursor_rects as extern "C" fn(&Object, Sel),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(hasMarkedText),
|
sel!(hasMarkedText),
|
||||||
has_marked_text as extern fn(&Object, Sel) -> BOOL,
|
has_marked_text as extern "C" fn(&Object, Sel) -> BOOL,
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(markedRange),
|
sel!(markedRange),
|
||||||
marked_range as extern fn(&Object, Sel) -> NSRange,
|
marked_range as extern "C" fn(&Object, Sel) -> NSRange,
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(selectedRange),
|
sel!(selectedRange),
|
||||||
selected_range as extern fn(&Object, Sel) -> NSRange,
|
selected_range as extern "C" fn(&Object, Sel) -> NSRange,
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(setMarkedText:selectedRange:replacementRange:),
|
sel!(setMarkedText:selectedRange:replacementRange:),
|
||||||
set_marked_text as extern fn(&mut Object, Sel, id, NSRange, NSRange),
|
set_marked_text as extern "C" fn(&mut Object, Sel, id, NSRange, NSRange),
|
||||||
);
|
|
||||||
decl.add_method(
|
|
||||||
sel!(unmarkText),
|
|
||||||
unmark_text as extern fn(&Object, Sel),
|
|
||||||
);
|
);
|
||||||
|
decl.add_method(sel!(unmarkText), unmark_text as extern "C" fn(&Object, Sel));
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(validAttributesForMarkedText),
|
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(
|
decl.add_method(
|
||||||
sel!(attributedSubstringForProposedRange:actualRange:),
|
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(
|
decl.add_method(
|
||||||
sel!(insertText:replacementRange:),
|
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(
|
decl.add_method(
|
||||||
sel!(characterIndexForPoint:),
|
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(
|
decl.add_method(
|
||||||
sel!(firstRectForCharacterRange:actualRange:),
|
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(
|
decl.add_method(
|
||||||
sel!(doCommandBySelector:),
|
sel!(doCommandBySelector:),
|
||||||
do_command_by_selector as extern fn(&Object, Sel, Sel),
|
do_command_by_selector as extern "C" 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),
|
|
||||||
);
|
);
|
||||||
|
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(
|
decl.add_method(
|
||||||
sel!(flagsChanged:),
|
sel!(flagsChanged:),
|
||||||
flags_changed as extern fn(&Object, Sel, id),
|
flags_changed as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(insertTab:),
|
sel!(insertTab:),
|
||||||
insert_tab as extern fn(&Object, Sel, id),
|
insert_tab as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(insertBackTab:),
|
sel!(insertBackTab:),
|
||||||
insert_back_tab as extern fn(&Object, Sel, id),
|
insert_back_tab as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(mouseDown:),
|
sel!(mouseDown:),
|
||||||
mouse_down as extern fn(&Object, Sel, id),
|
mouse_down as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
|
||||||
decl.add_method(
|
|
||||||
sel!(mouseUp:),
|
|
||||||
mouse_up as extern fn(&Object, Sel, id),
|
|
||||||
);
|
);
|
||||||
|
decl.add_method(sel!(mouseUp:), mouse_up as extern "C" fn(&Object, Sel, id));
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(rightMouseDown:),
|
sel!(rightMouseDown:),
|
||||||
right_mouse_down as extern fn(&Object, Sel, id),
|
right_mouse_down as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(rightMouseUp:),
|
sel!(rightMouseUp:),
|
||||||
right_mouse_up as extern fn(&Object, Sel, id),
|
right_mouse_up as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(otherMouseDown:),
|
sel!(otherMouseDown:),
|
||||||
other_mouse_down as extern fn(&Object, Sel, id),
|
other_mouse_down as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(otherMouseUp:),
|
sel!(otherMouseUp:),
|
||||||
other_mouse_up as extern fn(&Object, Sel, id),
|
other_mouse_up as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(mouseMoved:),
|
sel!(mouseMoved:),
|
||||||
mouse_moved as extern fn(&Object, Sel, id),
|
mouse_moved as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(mouseDragged:),
|
sel!(mouseDragged:),
|
||||||
mouse_dragged as extern fn(&Object, Sel, id),
|
mouse_dragged as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(rightMouseDragged:),
|
sel!(rightMouseDragged:),
|
||||||
right_mouse_dragged as extern fn(&Object, Sel, id),
|
right_mouse_dragged as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(otherMouseDragged:),
|
sel!(otherMouseDragged:),
|
||||||
other_mouse_dragged as extern fn(&Object, Sel, id),
|
other_mouse_dragged as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(mouseEntered:),
|
sel!(mouseEntered:),
|
||||||
mouse_entered as extern fn(&Object, Sel, id),
|
mouse_entered as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(mouseExited:),
|
sel!(mouseExited:),
|
||||||
mouse_exited as extern fn(&Object, Sel, id),
|
mouse_exited as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(scrollWheel:),
|
sel!(scrollWheel:),
|
||||||
scroll_wheel as extern fn(&Object, Sel, id),
|
scroll_wheel as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(pressureChangeWithEvent:),
|
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(
|
decl.add_method(
|
||||||
sel!(_wantsKeyDownForEvent:),
|
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(
|
decl.add_method(
|
||||||
sel!(cancelOperation:),
|
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::<*mut c_void>("winitState");
|
||||||
decl.add_ivar::<id>("markedText");
|
decl.add_ivar::<id>("markedText");
|
||||||
|
@ -243,7 +244,7 @@ lazy_static! {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn dealloc(this: &Object, _sel: Sel) {
|
extern "C" fn dealloc(this: &Object, _sel: Sel) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let state: *mut c_void = *this.get_ivar("winitState");
|
let state: *mut c_void = *this.get_ivar("winitState");
|
||||||
let marked_text: id = *this.get_ivar("markedText");
|
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 {
|
unsafe {
|
||||||
let this: id = msg_send![this, init];
|
let this: id = msg_send![this, init];
|
||||||
if this != nil {
|
if this != nil {
|
||||||
(*this).set_ivar("winitState", state);
|
(*this).set_ivar("winitState", state);
|
||||||
let marked_text = <id as NSMutableAttributedString>::init(
|
let marked_text =
|
||||||
NSMutableAttributedString::alloc(nil),
|
<id as NSMutableAttributedString>::init(NSMutableAttributedString::alloc(nil));
|
||||||
);
|
|
||||||
(*this).set_ivar("markedText", marked_text);
|
(*this).set_ivar("markedText", marked_text);
|
||||||
}
|
}
|
||||||
this
|
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`");
|
trace!("Triggered `viewDidMoveToWindow`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let rect: NSRect = msg_send![this, visibleRect];
|
let rect: NSRect = msg_send![this, visibleRect];
|
||||||
|
@ -280,7 +280,7 @@ extern fn view_did_move_to_window(this: &Object, _sel: Sel) {
|
||||||
trace!("Completed `viewDidMoveToWindow`");
|
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 {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
let state = &mut *(state_ptr as *mut ViewState);
|
let state = &mut *(state_ptr as *mut ViewState);
|
||||||
|
@ -288,22 +288,22 @@ extern fn draw_rect(this: &Object, _sel: Sel, rect: id) {
|
||||||
AppState::queue_redraw(WindowId(get_window_id(state.ns_window)));
|
AppState::queue_redraw(WindowId(get_window_id(state.ns_window)));
|
||||||
|
|
||||||
let superclass = util::superclass(this);
|
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
|
YES
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is necessary to prevent a beefy terminal error on MacBook Pros:
|
// 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
|
// 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`
|
// 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
|
NO
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn reset_cursor_rects(this: &Object, _sel: Sel) {
|
extern "C" fn reset_cursor_rects(this: &Object, _sel: Sel) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
let state = &mut *(state_ptr as *mut ViewState);
|
let state = &mut *(state_ptr as *mut ViewState);
|
||||||
|
@ -317,8 +317,7 @@ extern fn reset_cursor_rects(this: &Object, _sel: Sel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" fn has_marked_text(this: &Object, _sel: Sel) -> BOOL {
|
||||||
extern fn has_marked_text(this: &Object, _sel: Sel) -> BOOL {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
trace!("Triggered `hasMarkedText`");
|
trace!("Triggered `hasMarkedText`");
|
||||||
let marked_text: id = *this.get_ivar("markedText");
|
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 {
|
unsafe {
|
||||||
trace!("Triggered `markedRange`");
|
trace!("Triggered `markedRange`");
|
||||||
let marked_text: id = *this.get_ivar("markedText");
|
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!("Triggered `selectedRange`");
|
||||||
trace!("Completed `selectedRange`");
|
trace!("Completed `selectedRange`");
|
||||||
util::EMPTY_RANGE
|
util::EMPTY_RANGE
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn set_marked_text(
|
extern "C" fn set_marked_text(
|
||||||
this: &mut Object,
|
this: &mut Object,
|
||||||
_sel: Sel,
|
_sel: Sel,
|
||||||
string: id,
|
string: id,
|
||||||
|
@ -359,7 +358,7 @@ extern fn set_marked_text(
|
||||||
let marked_text_ref: &mut id = this.get_mut_ivar("markedText");
|
let marked_text_ref: &mut id = this.get_mut_ivar("markedText");
|
||||||
let _: () = msg_send![(*marked_text_ref), release];
|
let _: () = msg_send![(*marked_text_ref), release];
|
||||||
let marked_text = NSMutableAttributedString::alloc(nil);
|
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 {
|
if has_attr {
|
||||||
marked_text.initWithAttributedString(string);
|
marked_text.initWithAttributedString(string);
|
||||||
} else {
|
} else {
|
||||||
|
@ -370,7 +369,7 @@ extern fn set_marked_text(
|
||||||
trace!("Completed `setMarkedText`");
|
trace!("Completed `setMarkedText`");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn unmark_text(this: &Object, _sel: Sel) {
|
extern "C" fn unmark_text(this: &Object, _sel: Sel) {
|
||||||
trace!("Triggered `unmarkText`");
|
trace!("Triggered `unmarkText`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let marked_text: id = *this.get_ivar("markedText");
|
let marked_text: id = *this.get_ivar("markedText");
|
||||||
|
@ -382,13 +381,13 @@ extern fn unmark_text(this: &Object, _sel: Sel) {
|
||||||
trace!("Completed `unmarkText`");
|
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!("Triggered `validAttributesForMarkedText`");
|
||||||
trace!("Completed `validAttributesForMarkedText`");
|
trace!("Completed `validAttributesForMarkedText`");
|
||||||
unsafe { msg_send![class!(NSArray), array] }
|
unsafe { msg_send![class!(NSArray), array] }
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn attributed_substring_for_proposed_range(
|
extern "C" fn attributed_substring_for_proposed_range(
|
||||||
_this: &Object,
|
_this: &Object,
|
||||||
_sel: Sel,
|
_sel: Sel,
|
||||||
_range: NSRange,
|
_range: NSRange,
|
||||||
|
@ -399,13 +398,13 @@ extern fn attributed_substring_for_proposed_range(
|
||||||
nil
|
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!("Triggered `characterIndexForPoint`");
|
||||||
trace!("Completed `characterIndexForPoint`");
|
trace!("Completed `characterIndexForPoint`");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn first_rect_for_character_range(
|
extern "C" fn first_rect_for_character_range(
|
||||||
this: &Object,
|
this: &Object,
|
||||||
_sel: Sel,
|
_sel: Sel,
|
||||||
_range: NSRange,
|
_range: NSRange,
|
||||||
|
@ -425,20 +424,17 @@ extern fn first_rect_for_character_range(
|
||||||
(x, y)
|
(x, y)
|
||||||
});
|
});
|
||||||
trace!("Completed `firstRectForCharacterRange`");
|
trace!("Completed `firstRectForCharacterRange`");
|
||||||
NSRect::new(
|
NSRect::new(NSPoint::new(x as _, y as _), NSSize::new(0.0, 0.0))
|
||||||
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`");
|
trace!("Triggered `insertText`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
let state = &mut *(state_ptr as *mut ViewState);
|
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 {
|
let characters = if has_attr {
|
||||||
// This is a *mut NSAttributedString
|
// This is a *mut NSAttributedString
|
||||||
msg_send![string, string]
|
msg_send![string, string]
|
||||||
|
@ -447,10 +443,8 @@ extern fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range:
|
||||||
string
|
string
|
||||||
};
|
};
|
||||||
|
|
||||||
let slice = slice::from_raw_parts(
|
let slice =
|
||||||
characters.UTF8String() as *const c_uchar,
|
slice::from_raw_parts(characters.UTF8String() as *const c_uchar, characters.len());
|
||||||
characters.len(),
|
|
||||||
);
|
|
||||||
let string = str::from_utf8_unchecked(slice);
|
let string = str::from_utf8_unchecked(slice);
|
||||||
state.is_key_down = true;
|
state.is_key_down = true;
|
||||||
|
|
||||||
|
@ -470,7 +464,7 @@ extern fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range:
|
||||||
trace!("Completed `insertText`");
|
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`");
|
trace!("Triggered `doCommandBySelector`");
|
||||||
// Basically, we're sent this message whenever a keyboard event that doesn't generate a "human readable" character
|
// 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.
|
// happens, i.e. newlines, tabs, and Ctrl+C.
|
||||||
|
@ -513,10 +507,8 @@ fn get_characters(event: id, ignore_modifiers: bool) -> String {
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_ne!(characters, nil);
|
assert_ne!(characters, nil);
|
||||||
let slice = slice::from_raw_parts(
|
let slice =
|
||||||
characters.UTF8String() as *const c_uchar,
|
slice::from_raw_parts(characters.UTF8String() as *const c_uchar, characters.len());
|
||||||
characters.len(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let string = str::from_utf8_unchecked(slice);
|
let string = str::from_utf8_unchecked(slice);
|
||||||
string.to_owned()
|
string.to_owned()
|
||||||
|
@ -528,15 +520,15 @@ fn retrieve_keycode(event: id) -> Option<VirtualKeyCode> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_code(ev: id, raw: bool) -> Option<VirtualKeyCode> {
|
fn get_code(ev: id, raw: bool) -> Option<VirtualKeyCode> {
|
||||||
let characters = get_characters(ev, raw);
|
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.
|
// 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.
|
// If we don't get a match, then we fall back to unmodified characters.
|
||||||
let code = get_code(event, false)
|
let code = get_code(event, false).or_else(|| get_code(event, true));
|
||||||
.or_else(|| {
|
|
||||||
get_code(event, true)
|
|
||||||
});
|
|
||||||
|
|
||||||
// We've checked all layout related keys, so fall through to scancode.
|
// 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).
|
// Reaching this code means that the key is layout-independent (e.g. Backspace, Return).
|
||||||
|
@ -546,14 +538,11 @@ fn retrieve_keycode(event: id) -> Option<VirtualKeyCode> {
|
||||||
// in characters property.
|
// in characters property.
|
||||||
code.or_else(|| {
|
code.or_else(|| {
|
||||||
let scancode = get_scancode(event);
|
let scancode = get_scancode(event);
|
||||||
scancode_to_keycode(scancode)
|
scancode_to_keycode(scancode).or_else(|| check_function_keys(&get_characters(event, true)))
|
||||||
.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`");
|
trace!("Triggered `keyDown`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
|
@ -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...
|
// 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
|
// 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.
|
// keys to generate twice as many characters.
|
||||||
let array: id = msg_send![class!(NSArray), arrayWithObject:event];
|
let array: id = msg_send![class!(NSArray), arrayWithObject: event];
|
||||||
let _: () = msg_send![this, interpretKeyEvents:array];
|
let _: () = msg_send![this, interpretKeyEvents: array];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trace!("Completed `keyDown`");
|
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`");
|
trace!("Triggered `keyUp`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
|
@ -637,7 +626,7 @@ extern fn key_up(this: &Object, _sel: Sel, event: id) {
|
||||||
trace!("Completed `keyUp`");
|
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`");
|
trace!("Triggered `flagsChanged`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
|
@ -691,31 +680,31 @@ extern fn flags_changed(this: &Object, _sel: Sel, event: id) {
|
||||||
trace!("Completed `flagsChanged`");
|
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 {
|
unsafe {
|
||||||
let window: id = msg_send![this, window];
|
let window: id = msg_send![this, window];
|
||||||
let first_responder: id = msg_send![window, firstResponder];
|
let first_responder: id = msg_send![window, firstResponder];
|
||||||
let this_ptr = this as *const _ as *mut _;
|
let this_ptr = this as *const _ as *mut _;
|
||||||
if first_responder == this_ptr {
|
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 {
|
unsafe {
|
||||||
let window: id = msg_send![this, window];
|
let window: id = msg_send![this, window];
|
||||||
let first_responder: id = msg_send![window, firstResponder];
|
let first_responder: id = msg_send![window, firstResponder];
|
||||||
let this_ptr = this as *const _ as *mut _;
|
let this_ptr = this as *const _ as *mut _;
|
||||||
if first_responder == this_ptr {
|
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)
|
// Allows us to receive Cmd-. (the shortcut for closing a dialog)
|
||||||
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=300620#c6
|
// 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`");
|
trace!("Triggered `cancelOperation`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
|
@ -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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
let view_rect = NSView::frame(view);
|
||||||
|
|
||||||
if view_point.x.is_sign_negative()
|
if view_point.x.is_sign_negative()
|
||||||
|| view_point.y.is_sign_negative()
|
|| view_point.y.is_sign_negative()
|
||||||
|| view_point.x > view_rect.size.width
|
|| view_point.x > view_rect.size.width
|
||||||
|| view_point.y > view_rect.size.height {
|
|| view_point.y > view_rect.size.height
|
||||||
|
{
|
||||||
// Point is outside of the client area (view)
|
// Point is outside of the client area (view)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -824,23 +814,23 @@ 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);
|
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);
|
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);
|
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);
|
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`");
|
trace!("Triggered `mouseEntered`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
|
@ -848,7 +838,9 @@ extern fn mouse_entered(this: &Object, _sel: Sel, event: id) {
|
||||||
|
|
||||||
let enter_event = Event::WindowEvent {
|
let enter_event = Event::WindowEvent {
|
||||||
window_id: WindowId(get_window_id(state.ns_window)),
|
window_id: WindowId(get_window_id(state.ns_window)),
|
||||||
event: WindowEvent::CursorEntered { device_id: DEVICE_ID },
|
event: WindowEvent::CursorEntered {
|
||||||
|
device_id: DEVICE_ID,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let move_event = {
|
let move_event = {
|
||||||
|
@ -866,7 +858,7 @@ extern fn mouse_entered(this: &Object, _sel: Sel, event: id) {
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
position: (x, y).into(),
|
position: (x, y).into(),
|
||||||
modifiers: event_mods(event),
|
modifiers: event_mods(event),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -876,7 +868,7 @@ extern fn mouse_entered(this: &Object, _sel: Sel, event: id) {
|
||||||
trace!("Completed `mouseEntered`");
|
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`");
|
trace!("Triggered `mouseExited`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
|
@ -884,7 +876,9 @@ extern fn mouse_exited(this: &Object, _sel: Sel, _event: id) {
|
||||||
|
|
||||||
let window_event = Event::WindowEvent {
|
let window_event = Event::WindowEvent {
|
||||||
window_id: WindowId(get_window_id(state.ns_window)),
|
window_id: WindowId(get_window_id(state.ns_window)),
|
||||||
event: WindowEvent::CursorLeft { device_id: DEVICE_ID },
|
event: WindowEvent::CursorLeft {
|
||||||
|
device_id: DEVICE_ID,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
AppState::queue_event(window_event);
|
AppState::queue_event(window_event);
|
||||||
|
@ -892,7 +886,7 @@ extern fn mouse_exited(this: &Object, _sel: Sel, _event: id) {
|
||||||
trace!("Completed `mouseExited`");
|
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`");
|
trace!("Triggered `scrollWheel`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let delta = {
|
let delta = {
|
||||||
|
@ -904,7 +898,9 @@ extern fn scroll_wheel(this: &Object, _sel: Sel, event: id) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let phase = match event.phase() {
|
let phase = match event.phase() {
|
||||||
NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => TouchPhase::Started,
|
NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => {
|
||||||
|
TouchPhase::Started
|
||||||
|
},
|
||||||
NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended,
|
NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended,
|
||||||
_ => TouchPhase::Moved,
|
_ => TouchPhase::Moved,
|
||||||
};
|
};
|
||||||
|
@ -933,7 +929,7 @@ extern fn scroll_wheel(this: &Object, _sel: Sel, event: id) {
|
||||||
trace!("Completed `scrollWheel`");
|
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`");
|
trace!("Triggered `pressureChangeWithEvent`");
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
|
@ -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.
|
// Allows us to receive Ctrl-Tab and Ctrl-Esc.
|
||||||
// Note that this *doesn't* help with any missing Cmd inputs.
|
// 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
|
// 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
|
YES
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,44 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque, f64, os::raw::c_void,
|
collections::VecDeque,
|
||||||
sync::{Arc, atomic::{Ordering, AtomicBool}, Mutex, Weak},
|
f64,
|
||||||
|
os::raw::c_void,
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc, Mutex, Weak,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::{
|
appkit::{
|
||||||
self, CGFloat, NSApp, NSApplication, NSApplicationActivationPolicy,
|
self, CGFloat, NSApp, NSApplication, NSApplicationActivationPolicy,
|
||||||
NSColor, NSRequestUserAttentionType, NSScreen, NSView, NSWindow,
|
NSApplicationPresentationOptions, NSColor, NSRequestUserAttentionType, NSScreen, NSView,
|
||||||
NSWindowButton, NSWindowStyleMask, NSApplicationPresentationOptions
|
NSWindow, NSWindowButton, NSWindowStyleMask,
|
||||||
},
|
},
|
||||||
base::{id, nil},
|
base::{id, nil},
|
||||||
foundation::{NSAutoreleasePool, NSDictionary, NSPoint, NSRect, NSSize, NSString},
|
foundation::{NSAutoreleasePool, NSDictionary, NSPoint, NSRect, NSSize, NSString},
|
||||||
};
|
};
|
||||||
use core_graphics::display::CGDisplay;
|
use core_graphics::display::CGDisplay;
|
||||||
use objc::{runtime::{Class, Object, Sel, BOOL, YES, NO}, declare::ClassDecl};
|
use objc::{
|
||||||
|
declare::ClassDecl,
|
||||||
|
runtime::{Class, Object, Sel, BOOL, NO, YES},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{LogicalPosition, LogicalSize}, icon::Icon,
|
dpi::{LogicalPosition, LogicalSize},
|
||||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
|
icon::Icon,
|
||||||
monitor::MonitorHandle as RootMonitorHandle,
|
monitor::MonitorHandle as RootMonitorHandle,
|
||||||
window::{
|
platform::macos::{ActivationPolicy, WindowExtMacOS},
|
||||||
CursorIcon, WindowAttributes, WindowId as RootWindowId,
|
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},
|
||||||
use crate::platform::macos::{ActivationPolicy, WindowExtMacOS};
|
|
||||||
use crate::platform_impl::platform::{
|
|
||||||
OsError,
|
|
||||||
app_state::AppState, ffi, monitor::{self, MonitorHandle},
|
|
||||||
util::{self, IdRef}, view::{self, new_view},
|
|
||||||
window_delegate::new_delegate,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -112,7 +122,8 @@ fn create_window(
|
||||||
let frame = match screen {
|
let frame = match screen {
|
||||||
Some(screen) => appkit::NSScreen::frame(screen),
|
Some(screen) => appkit::NSScreen::frame(screen),
|
||||||
None => {
|
None => {
|
||||||
let (width, height) = attrs.inner_size
|
let (width, height) = attrs
|
||||||
|
.inner_size
|
||||||
.map(|logical| (logical.width, logical.height))
|
.map(|logical| (logical.width, logical.height))
|
||||||
.unwrap_or_else(|| (800.0, 600.0));
|
.unwrap_or_else(|| (800.0, 600.0));
|
||||||
NSRect::new(NSPoint::new(0.0, 0.0), NSSize::new(width, height))
|
NSRect::new(NSPoint::new(0.0, 0.0), NSSize::new(width, height))
|
||||||
|
@ -122,18 +133,16 @@ fn create_window(
|
||||||
let mut masks = if !attrs.decorations && !screen.is_some() {
|
let mut masks = if !attrs.decorations && !screen.is_some() {
|
||||||
// Resizable UnownedWindow without a titlebar or borders
|
// Resizable UnownedWindow without a titlebar or borders
|
||||||
// if decorations is set to false, ignore pl_attrs
|
// if decorations is set to false, ignore pl_attrs
|
||||||
NSWindowStyleMask::NSBorderlessWindowMask
|
NSWindowStyleMask::NSBorderlessWindowMask | NSWindowStyleMask::NSResizableWindowMask
|
||||||
| NSWindowStyleMask::NSResizableWindowMask
|
|
||||||
} else if pl_attrs.titlebar_hidden {
|
} else if pl_attrs.titlebar_hidden {
|
||||||
// if the titlebar is hidden, ignore other pl_attrs
|
// if the titlebar is hidden, ignore other pl_attrs
|
||||||
NSWindowStyleMask::NSBorderlessWindowMask |
|
NSWindowStyleMask::NSBorderlessWindowMask | NSWindowStyleMask::NSResizableWindowMask
|
||||||
NSWindowStyleMask::NSResizableWindowMask
|
|
||||||
} else {
|
} else {
|
||||||
// default case, resizable window with titlebar and titlebar buttons
|
// default case, resizable window with titlebar and titlebar buttons
|
||||||
NSWindowStyleMask::NSClosableWindowMask |
|
NSWindowStyleMask::NSClosableWindowMask
|
||||||
NSWindowStyleMask::NSMiniaturizableWindowMask |
|
| NSWindowStyleMask::NSMiniaturizableWindowMask
|
||||||
NSWindowStyleMask::NSResizableWindowMask |
|
| NSWindowStyleMask::NSResizableWindowMask
|
||||||
NSWindowStyleMask::NSTitledWindowMask
|
| NSWindowStyleMask::NSTitledWindowMask
|
||||||
};
|
};
|
||||||
|
|
||||||
if !attrs.resizable {
|
if !attrs.resizable {
|
||||||
|
@ -171,7 +180,7 @@ fn create_window(
|
||||||
NSWindowButton::NSWindowZoomButton,
|
NSWindowButton::NSWindowZoomButton,
|
||||||
] {
|
] {
|
||||||
let button = ns_window.standardWindowButton_(*titlebar_button);
|
let button = ns_window.standardWindowButton_(*titlebar_button);
|
||||||
let _: () = msg_send![button, setHidden:YES];
|
let _: () = msg_send![button, setHidden: YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pl_attrs.movable_by_window_background {
|
if pl_attrs.movable_by_window_background {
|
||||||
|
@ -179,7 +188,10 @@ fn create_window(
|
||||||
}
|
}
|
||||||
|
|
||||||
if attrs.always_on_top {
|
if attrs.always_on_top {
|
||||||
let _: () = msg_send![*ns_window, setLevel:ffi::NSWindowLevel::NSFloatingWindowLevel];
|
let _: () = msg_send![
|
||||||
|
*ns_window,
|
||||||
|
setLevel: ffi::NSWindowLevel::NSFloatingWindowLevel
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(increments) = pl_attrs.resize_increments {
|
if let Some(increments) = pl_attrs.resize_increments {
|
||||||
|
@ -206,8 +218,14 @@ lazy_static! {
|
||||||
static ref WINDOW_CLASS: WindowClass = unsafe {
|
static ref WINDOW_CLASS: WindowClass = unsafe {
|
||||||
let window_superclass = class!(NSWindow);
|
let window_superclass = class!(NSWindow);
|
||||||
let mut decl = ClassDecl::new("WinitWindow", window_superclass).unwrap();
|
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(
|
||||||
decl.add_method(sel!(canBecomeKeyWindow), util::yes as extern fn(&Object, Sel) -> BOOL);
|
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())
|
WindowClass(decl.register())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -242,14 +260,14 @@ impl From<WindowAttributes> for SharedState {
|
||||||
// identical, resulting in a no-op.
|
// identical, resulting in a no-op.
|
||||||
fullscreen: None,
|
fullscreen: None,
|
||||||
maximized: attribs.maximized,
|
maximized: attribs.maximized,
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UnownedWindow {
|
pub struct UnownedWindow {
|
||||||
pub ns_window: IdRef, // never changes
|
pub ns_window: IdRef, // never changes
|
||||||
pub ns_view: IdRef, // never changes
|
pub ns_view: IdRef, // never changes
|
||||||
input_context: IdRef, // never changes
|
input_context: IdRef, // never changes
|
||||||
pub shared_state: Arc<Mutex<SharedState>>,
|
pub shared_state: Arc<Mutex<SharedState>>,
|
||||||
decorations: AtomicBool,
|
decorations: AtomicBool,
|
||||||
|
@ -298,15 +316,20 @@ impl UnownedWindow {
|
||||||
|
|
||||||
ns_app.activateIgnoringOtherApps_(YES);
|
ns_app.activateIgnoringOtherApps_(YES);
|
||||||
|
|
||||||
win_attribs.min_inner_size.map(|dim| set_min_inner_size(*ns_window, dim));
|
win_attribs
|
||||||
win_attribs.max_inner_size.map(|dim| set_max_inner_size(*ns_window, dim));
|
.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;
|
use cocoa::foundation::NSArray;
|
||||||
// register for drag and drop operations.
|
// register for drag and drop operations.
|
||||||
let () = msg_send![*ns_window, registerForDraggedTypes:NSArray::arrayWithObject(
|
let () = msg_send![
|
||||||
nil,
|
*ns_window,
|
||||||
appkit::NSFilenamesPboardType,
|
registerForDraggedTypes:
|
||||||
)];
|
NSArray::arrayWithObject(nil, appkit::NSFilenamesPboardType)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since `win_attribs` is put into a mutex below, we'll just copy these
|
// Since `win_attribs` is put into a mutex below, we'll just copy these
|
||||||
|
@ -364,19 +387,11 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_style_mask_async(&self, mask: NSWindowStyleMask) {
|
fn set_style_mask_async(&self, mask: NSWindowStyleMask) {
|
||||||
unsafe { util::set_style_mask_async(
|
unsafe { util::set_style_mask_async(*self.ns_window, *self.ns_view, mask) };
|
||||||
*self.ns_window,
|
|
||||||
*self.ns_view,
|
|
||||||
mask,
|
|
||||||
) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_style_mask_sync(&self, mask: NSWindowStyleMask) {
|
fn set_style_mask_sync(&self, mask: NSWindowStyleMask) {
|
||||||
unsafe { util::set_style_mask_sync(
|
unsafe { util::set_style_mask_sync(*self.ns_window, *self.ns_view, mask) };
|
||||||
*self.ns_window,
|
|
||||||
*self.ns_view,
|
|
||||||
mask,
|
|
||||||
) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> Id {
|
pub fn id(&self) -> Id {
|
||||||
|
@ -405,20 +420,19 @@ impl UnownedWindow {
|
||||||
Ok((
|
Ok((
|
||||||
frame_rect.origin.x as f64,
|
frame_rect.origin.x as f64,
|
||||||
util::bottom_left_to_top_left(frame_rect),
|
util::bottom_left_to_top_left(frame_rect),
|
||||||
).into())
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
||||||
let content_rect = unsafe {
|
let content_rect = unsafe {
|
||||||
NSWindow::contentRectForFrameRect_(
|
NSWindow::contentRectForFrameRect_(*self.ns_window, NSWindow::frame(*self.ns_window))
|
||||||
*self.ns_window,
|
|
||||||
NSWindow::frame(*self.ns_window),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
Ok((
|
Ok((
|
||||||
content_rect.origin.x as f64,
|
content_rect.origin.x as f64,
|
||||||
util::bottom_left_to_top_left(content_rect),
|
util::bottom_left_to_top_left(content_rect),
|
||||||
).into())
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_outer_position(&self, position: LogicalPosition) {
|
pub fn set_outer_position(&self, position: LogicalPosition) {
|
||||||
|
@ -529,7 +543,10 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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 window_position = self.inner_position().unwrap();
|
||||||
let point = appkit::CGPoint {
|
let point = appkit::CGPoint {
|
||||||
x: (cursor_position.x + window_position.x) as CGFloat,
|
x: (cursor_position.x + window_position.x) as CGFloat,
|
||||||
|
@ -548,8 +565,8 @@ impl UnownedWindow {
|
||||||
// we make it resizable temporalily.
|
// we make it resizable temporalily.
|
||||||
let curr_mask = unsafe { self.ns_window.styleMask() };
|
let curr_mask = unsafe { self.ns_window.styleMask() };
|
||||||
|
|
||||||
let required = NSWindowStyleMask::NSTitledWindowMask
|
let required =
|
||||||
| NSWindowStyleMask::NSResizableWindowMask;
|
NSWindowStyleMask::NSTitledWindowMask | NSWindowStyleMask::NSResizableWindowMask;
|
||||||
let needs_temp_mask = !curr_mask.contains(required);
|
let needs_temp_mask = !curr_mask.contains(required);
|
||||||
if needs_temp_mask {
|
if needs_temp_mask {
|
||||||
self.set_style_mask_sync(required);
|
self.set_style_mask_sync(required);
|
||||||
|
@ -566,7 +583,8 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn saved_style(&self, shared_state: &mut SharedState) -> NSWindowStyleMask {
|
fn saved_style(&self, shared_state: &mut SharedState) -> NSWindowStyleMask {
|
||||||
let base_mask = shared_state.saved_style
|
let base_mask = shared_state
|
||||||
|
.saved_style
|
||||||
.take()
|
.take()
|
||||||
.unwrap_or_else(|| unsafe { self.ns_window.styleMask() });
|
.unwrap_or_else(|| unsafe { self.ns_window.styleMask() });
|
||||||
if shared_state.resizable {
|
if shared_state.resizable {
|
||||||
|
@ -620,7 +638,7 @@ impl UnownedWindow {
|
||||||
pub fn set_fullscreen(&self, monitor: Option<RootMonitorHandle>) {
|
pub fn set_fullscreen(&self, monitor: Option<RootMonitorHandle>) {
|
||||||
let shared_state_lock = self.shared_state.lock().unwrap();
|
let shared_state_lock = self.shared_state.lock().unwrap();
|
||||||
if shared_state_lock.is_simple_fullscreen {
|
if shared_state_lock.is_simple_fullscreen {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let not_fullscreen = {
|
let not_fullscreen = {
|
||||||
|
@ -639,12 +657,14 @@ impl UnownedWindow {
|
||||||
current.is_none()
|
current.is_none()
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe { util::toggle_full_screen_async(
|
unsafe {
|
||||||
*self.ns_window,
|
util::toggle_full_screen_async(
|
||||||
*self.ns_view,
|
*self.ns_window,
|
||||||
not_fullscreen,
|
*self.ns_view,
|
||||||
Arc::downgrade(&self.shared_state),
|
not_fullscreen,
|
||||||
) };
|
Arc::downgrade(&self.shared_state),
|
||||||
|
)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -664,7 +684,9 @@ impl UnownedWindow {
|
||||||
|
|
||||||
// If we're in fullscreen mode, we wait to apply decoration changes
|
// If we're in fullscreen mode, we wait to apply decoration changes
|
||||||
// until we're in `window_did_exit_fullscreen`.
|
// until we're in `window_did_exit_fullscreen`.
|
||||||
if fullscreen { return }
|
if fullscreen {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_mask = {
|
let new_mask = {
|
||||||
let mut new_mask = if decorations {
|
let mut new_mask = if decorations {
|
||||||
|
@ -727,7 +749,9 @@ impl UnownedWindow {
|
||||||
let key = IdRef::new(NSString::alloc(nil).init_str("NSScreenNumber"));
|
let key = IdRef::new(NSString::alloc(nil).init_str("NSScreenNumber"));
|
||||||
let value = NSDictionary::valueForKey_(desc, *key);
|
let value = NSDictionary::valueForKey_(desc, *key);
|
||||||
let display_id = msg_send![value, unsignedIntegerValue];
|
let display_id = msg_send![value, unsignedIntegerValue];
|
||||||
RootMonitorHandle { inner: MonitorHandle::new(display_id) }
|
RootMonitorHandle {
|
||||||
|
inner: MonitorHandle::new(display_id),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,7 +803,10 @@ impl WindowExtMacOS for UnownedWindow {
|
||||||
let is_simple_fullscreen = shared_state_lock.is_simple_fullscreen;
|
let is_simple_fullscreen = shared_state_lock.is_simple_fullscreen;
|
||||||
|
|
||||||
// Do nothing if native fullscreen is active.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,7 +826,12 @@ impl WindowExtMacOS for UnownedWindow {
|
||||||
app.setPresentationOptions_(presentation_options);
|
app.setPresentationOptions_(presentation_options);
|
||||||
|
|
||||||
// Hide the titlebar
|
// Hide the titlebar
|
||||||
util::toggle_style_mask(*self.ns_window, *self.ns_view, 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
|
// Set the window frame to the screen frame size
|
||||||
let screen = self.ns_window.screen();
|
let screen = self.ns_window.screen();
|
||||||
|
@ -807,8 +839,18 @@ impl WindowExtMacOS for UnownedWindow {
|
||||||
NSWindow::setFrame_display_(*self.ns_window, screen_frame, YES);
|
NSWindow::setFrame_display_(*self.ns_window, screen_frame, YES);
|
||||||
|
|
||||||
// Fullscreen windows can't be resized, minimized, or moved
|
// Fullscreen windows can't be resized, minimized, or moved
|
||||||
util::toggle_style_mask(*self.ns_window, *self.ns_view, NSWindowStyleMask::NSMiniaturizableWindowMask, false);
|
util::toggle_style_mask(
|
||||||
util::toggle_style_mask(*self.ns_window, *self.ns_view, NSWindowStyleMask::NSResizableWindowMask, false);
|
*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);
|
NSWindow::setMovable_(*self.ns_window, NO);
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
|
@ -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::{
|
use cocoa::{
|
||||||
appkit::{self, NSView, NSWindow}, base::{id, nil},
|
appkit::{self, NSView, NSWindow},
|
||||||
|
base::{id, nil},
|
||||||
foundation::NSAutoreleasePool,
|
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 crate::{dpi::LogicalSize, event::{Event, WindowEvent}, window::WindowId};
|
use crate::{
|
||||||
use crate::platform_impl::platform::{
|
dpi::LogicalSize,
|
||||||
app_state::AppState, util::{self, IdRef},
|
event::{Event, WindowEvent},
|
||||||
window::{get_window_id, UnownedWindow},
|
platform_impl::platform::{
|
||||||
|
app_state::AppState,
|
||||||
|
util::{self, IdRef},
|
||||||
|
window::{get_window_id, UnownedWindow},
|
||||||
|
},
|
||||||
|
window::WindowId,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct WindowDelegateState {
|
pub struct WindowDelegateState {
|
||||||
ns_window: IdRef, // never changes
|
ns_window: IdRef, // never changes
|
||||||
ns_view: IdRef, // never changes
|
ns_view: IdRef, // never changes
|
||||||
|
|
||||||
window: Weak<UnownedWindow>,
|
window: Weak<UnownedWindow>,
|
||||||
|
|
||||||
|
@ -33,10 +46,7 @@ pub struct WindowDelegateState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowDelegateState {
|
impl WindowDelegateState {
|
||||||
pub fn new(
|
pub fn new(window: &Arc<UnownedWindow>, initial_fullscreen: bool) -> Self {
|
||||||
window: &Arc<UnownedWindow>,
|
|
||||||
initial_fullscreen: bool,
|
|
||||||
) -> Self {
|
|
||||||
let dpi_factor = window.hidpi_factor();
|
let dpi_factor = window.hidpi_factor();
|
||||||
|
|
||||||
let mut delegate_state = WindowDelegateState {
|
let mut delegate_state = WindowDelegateState {
|
||||||
|
@ -57,11 +67,10 @@ impl WindowDelegateState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_window<F, T>(&mut self, callback: F) -> Option<T>
|
fn with_window<F, T>(&mut self, callback: F) -> Option<T>
|
||||||
where F: FnOnce(&UnownedWindow) -> T
|
where
|
||||||
|
F: FnOnce(&UnownedWindow) -> T,
|
||||||
{
|
{
|
||||||
self.window
|
self.window.upgrade().map(|ref window| callback(window))
|
||||||
.upgrade()
|
|
||||||
.map(|ref window| callback(window))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emit_event(&mut self, event: WindowEvent) {
|
pub fn emit_event(&mut self, event: WindowEvent) {
|
||||||
|
@ -100,7 +109,7 @@ pub fn new_delegate(window: &Arc<UnownedWindow>, initial_fullscreen: bool) -> Id
|
||||||
// This is free'd in `dealloc`
|
// This is free'd in `dealloc`
|
||||||
let state_ptr = Box::into_raw(Box::new(state)) as *mut c_void;
|
let state_ptr = Box::into_raw(Box::new(state)) as *mut c_void;
|
||||||
let delegate: id = msg_send![WINDOW_DELEGATE_CLASS.0, alloc];
|
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 superclass = class!(NSResponder);
|
||||||
let mut decl = ClassDecl::new("WinitWindowDelegate", superclass).unwrap();
|
let mut decl = ClassDecl::new("WinitWindowDelegate", superclass).unwrap();
|
||||||
|
|
||||||
decl.add_method(
|
decl.add_method(sel!(dealloc), dealloc as extern "C" fn(&Object, Sel));
|
||||||
sel!(dealloc),
|
|
||||||
dealloc as extern fn(&Object, Sel),
|
|
||||||
);
|
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(initWithWinit:),
|
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(
|
decl.add_method(
|
||||||
sel!(windowShouldClose:),
|
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(
|
decl.add_method(
|
||||||
sel!(windowWillClose:),
|
sel!(windowWillClose:),
|
||||||
window_will_close as extern fn(&Object, Sel, id),
|
window_will_close as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(windowDidResize:),
|
sel!(windowDidResize:),
|
||||||
window_did_resize as extern fn(&Object, Sel, id),
|
window_did_resize as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(windowDidMove:),
|
sel!(windowDidMove:),
|
||||||
window_did_move as extern fn(&Object, Sel, id));
|
window_did_move as extern "C" fn(&Object, Sel, id),
|
||||||
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(windowDidChangeScreen:),
|
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(
|
decl.add_method(
|
||||||
sel!(windowDidChangeBackingProperties:),
|
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(
|
decl.add_method(
|
||||||
sel!(windowDidBecomeKey:),
|
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(
|
decl.add_method(
|
||||||
sel!(windowDidResignKey:),
|
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(
|
decl.add_method(
|
||||||
sel!(draggingEntered:),
|
sel!(draggingEntered:),
|
||||||
dragging_entered as extern fn(&Object, Sel, id) -> BOOL,
|
dragging_entered as extern "C" fn(&Object, Sel, id) -> BOOL,
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(prepareForDragOperation:),
|
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(
|
decl.add_method(
|
||||||
sel!(performDragOperation:),
|
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(
|
decl.add_method(
|
||||||
sel!(concludeDragOperation:),
|
sel!(concludeDragOperation:),
|
||||||
conclude_drag_operation as extern fn(&Object, Sel, id),
|
conclude_drag_operation as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(draggingExited:),
|
sel!(draggingExited:),
|
||||||
dragging_exited as extern fn(&Object, Sel, id),
|
dragging_exited as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
|
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(windowDidEnterFullScreen:),
|
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(
|
decl.add_method(
|
||||||
sel!(windowWillEnterFullScreen:),
|
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(
|
decl.add_method(
|
||||||
sel!(windowDidExitFullScreen:),
|
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(
|
decl.add_method(
|
||||||
sel!(windowDidFailToEnterFullScreen:),
|
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");
|
decl.add_ivar::<*mut c_void>("winitState");
|
||||||
|
@ -207,47 +214,47 @@ fn with_state<F: FnOnce(&mut WindowDelegateState) -> T, T>(this: &Object, callba
|
||||||
callback(state_ptr);
|
callback(state_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn dealloc(this: &Object, _sel: Sel) {
|
extern "C" fn dealloc(this: &Object, _sel: Sel) {
|
||||||
with_state(this, |state| unsafe {
|
with_state(this, |state| unsafe {
|
||||||
Box::from_raw(state as *mut WindowDelegateState);
|
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 {
|
unsafe {
|
||||||
let this: id = msg_send![this, init];
|
let this: id = msg_send![this, init];
|
||||||
if this != nil {
|
if this != nil {
|
||||||
(*this).set_ivar("winitState", state);
|
(*this).set_ivar("winitState", state);
|
||||||
with_state(&*this, |state| {
|
with_state(&*this, |state| {
|
||||||
let () = msg_send![*state.ns_window, setDelegate:this];
|
let () = msg_send![*state.ns_window, setDelegate: this];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
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:`");
|
trace!("Triggered `windowShouldClose:`");
|
||||||
with_state(this, |state| state.emit_event(WindowEvent::CloseRequested));
|
with_state(this, |state| state.emit_event(WindowEvent::CloseRequested));
|
||||||
trace!("Completed `windowShouldClose:`");
|
trace!("Completed `windowShouldClose:`");
|
||||||
NO
|
NO
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn window_will_close(this: &Object, _: Sel, _: id) {
|
extern "C" fn window_will_close(this: &Object, _: Sel, _: id) {
|
||||||
trace!("Triggered `windowWillClose:`");
|
trace!("Triggered `windowWillClose:`");
|
||||||
with_state(this, |state| unsafe {
|
with_state(this, |state| unsafe {
|
||||||
// `setDelegate:` retains the previous value and then autoreleases it
|
// `setDelegate:` retains the previous value and then autoreleases it
|
||||||
let pool = NSAutoreleasePool::new(nil);
|
let pool = NSAutoreleasePool::new(nil);
|
||||||
// Since El Capitan, we need to be careful that delegate methods can't
|
// Since El Capitan, we need to be careful that delegate methods can't
|
||||||
// be called after the window closes.
|
// be called after the window closes.
|
||||||
let () = msg_send![*state.ns_window, setDelegate:nil];
|
let () = msg_send![*state.ns_window, setDelegate: nil];
|
||||||
pool.drain();
|
pool.drain();
|
||||||
state.emit_event(WindowEvent::Destroyed);
|
state.emit_event(WindowEvent::Destroyed);
|
||||||
});
|
});
|
||||||
trace!("Completed `windowWillClose:`");
|
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:`");
|
trace!("Triggered `windowDidResize:`");
|
||||||
with_state(this, |state| {
|
with_state(this, |state| {
|
||||||
state.emit_resize_event();
|
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.
|
// 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:`");
|
trace!("Triggered `windowDidMove:`");
|
||||||
with_state(this, |state| {
|
with_state(this, |state| {
|
||||||
state.emit_move_event();
|
state.emit_move_event();
|
||||||
|
@ -265,12 +272,10 @@ extern fn window_did_move(this: &Object, _: Sel, _: id) {
|
||||||
trace!("Completed `windowDidMove:`");
|
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:`");
|
trace!("Triggered `windowDidChangeScreen:`");
|
||||||
with_state(this, |state| {
|
with_state(this, |state| {
|
||||||
let dpi_factor = unsafe {
|
let dpi_factor = unsafe { NSWindow::backingScaleFactor(*state.ns_window) } as f64;
|
||||||
NSWindow::backingScaleFactor(*state.ns_window)
|
|
||||||
} as f64;
|
|
||||||
if state.previous_dpi_factor != dpi_factor {
|
if state.previous_dpi_factor != dpi_factor {
|
||||||
state.previous_dpi_factor = dpi_factor;
|
state.previous_dpi_factor = dpi_factor;
|
||||||
state.emit_event(WindowEvent::HiDpiFactorChanged(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`.
|
// 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:`");
|
trace!("Triggered `windowDidChangeBackingProperties:`");
|
||||||
with_state(this, |state| {
|
with_state(this, |state| {
|
||||||
let dpi_factor = unsafe {
|
let dpi_factor = unsafe { NSWindow::backingScaleFactor(*state.ns_window) } as f64;
|
||||||
NSWindow::backingScaleFactor(*state.ns_window)
|
|
||||||
} as f64;
|
|
||||||
if state.previous_dpi_factor != dpi_factor {
|
if state.previous_dpi_factor != dpi_factor {
|
||||||
state.previous_dpi_factor = dpi_factor;
|
state.previous_dpi_factor = dpi_factor;
|
||||||
state.emit_event(WindowEvent::HiDpiFactorChanged(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:`");
|
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:`");
|
trace!("Triggered `windowDidBecomeKey:`");
|
||||||
with_state(this, |state| {
|
with_state(this, |state| {
|
||||||
// TODO: center the cursor if the window had mouse grab when it
|
// 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:`");
|
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:`");
|
trace!("Triggered `windowDidResignKey:`");
|
||||||
with_state(this, |state| {
|
with_state(this, |state| {
|
||||||
state.emit_event(WindowEvent::Focused(false));
|
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
|
/// 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:`");
|
trace!("Triggered `draggingEntered:`");
|
||||||
|
|
||||||
use cocoa::appkit::NSPasteboard;
|
use cocoa::{appkit::NSPasteboard, foundation::NSFastEnumeration};
|
||||||
use cocoa::foundation::NSFastEnumeration;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
let pb: id = unsafe { msg_send![sender, draggingPasteboard] };
|
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)));
|
state.emit_event(WindowEvent::HoveredFile(PathBuf::from(path)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
trace!("Completed `draggingEntered:`");
|
trace!("Completed `draggingEntered:`");
|
||||||
YES
|
YES
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when the image is released
|
/// 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!("Triggered `prepareForDragOperation:`");
|
||||||
trace!("Completed `prepareForDragOperation:`");
|
trace!("Completed `prepareForDragOperation:`");
|
||||||
YES
|
YES
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked after the released image has been removed from the screen
|
/// 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:`");
|
trace!("Triggered `performDragOperation:`");
|
||||||
|
|
||||||
use cocoa::appkit::NSPasteboard;
|
use cocoa::{appkit::NSPasteboard, foundation::NSFastEnumeration};
|
||||||
use cocoa::foundation::NSFastEnumeration;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
let pb: id = unsafe { msg_send![sender, draggingPasteboard] };
|
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)));
|
state.emit_event(WindowEvent::DroppedFile(PathBuf::from(path)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
trace!("Completed `performDragOperation:`");
|
trace!("Completed `performDragOperation:`");
|
||||||
YES
|
YES
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when the dragging operation is complete
|
/// 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!("Triggered `concludeDragOperation:`");
|
||||||
trace!("Completed `concludeDragOperation:`");
|
trace!("Completed `concludeDragOperation:`");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when the dragging operation is cancelled
|
/// 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:`");
|
trace!("Triggered `draggingExited:`");
|
||||||
with_state(this, |state| state.emit_event(WindowEvent::HoveredFileCancelled));
|
with_state(this, |state| {
|
||||||
|
state.emit_event(WindowEvent::HoveredFileCancelled)
|
||||||
|
});
|
||||||
trace!("Completed `draggingExited:`");
|
trace!("Completed `draggingExited:`");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when before enter fullscreen
|
/// 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:`");
|
trace!("Triggered `windowWillEnterFullscreen:`");
|
||||||
with_state(this, |state| state.with_window(|window| {
|
with_state(this, |state| {
|
||||||
trace!("Locked shared state in `window_will_enter_fullscreen`");
|
state.with_window(|window| {
|
||||||
window.shared_state.lock().unwrap().maximized = window.is_zoomed();
|
trace!("Locked shared state in `window_will_enter_fullscreen`");
|
||||||
trace!("Unlocked 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:`");
|
trace!("Completed `windowWillEnterFullscreen:`");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when entered fullscreen
|
/// 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:`");
|
trace!("Triggered `windowDidEnterFullscreen:`");
|
||||||
with_state(this, |state| {
|
with_state(this, |state| {
|
||||||
state.with_window(|window| {
|
state.with_window(|window| {
|
||||||
|
@ -419,11 +424,13 @@ extern fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when exited fullscreen
|
/// 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:`");
|
trace!("Triggered `windowDidExitFullscreen:`");
|
||||||
with_state(this, |state| state.with_window(|window| {
|
with_state(this, |state| {
|
||||||
window.restore_state_from_fullscreen();
|
state.with_window(|window| {
|
||||||
}));
|
window.restore_state_from_fullscreen();
|
||||||
|
})
|
||||||
|
});
|
||||||
trace!("Completed `windowDidExitFullscreen:`");
|
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.
|
/// 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
|
/// 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.
|
/// 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:`");
|
trace!("Triggered `windowDidFailToEnterFullscreen:`");
|
||||||
with_state(this, |state| {
|
with_state(this, |state| {
|
||||||
if state.initial_fullscreen {
|
if state.initial_fullscreen {
|
||||||
let _: () = unsafe { msg_send![*state.ns_window,
|
let _: () = unsafe {
|
||||||
performSelector:sel!(toggleFullScreen:)
|
msg_send![*state.ns_window,
|
||||||
withObject:nil
|
performSelector:sel!(toggleFullScreen:)
|
||||||
afterDelay: 0.5
|
withObject:nil
|
||||||
] };
|
afterDelay: 0.5
|
||||||
|
]
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
state.with_window(|window| window.restore_state_from_fullscreen());
|
state.with_window(|window| window.restore_state_from_fullscreen());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,40 @@
|
||||||
pub use self::platform::*;
|
pub use self::platform::*;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
#[path="windows/mod.rs"]
|
#[path = "windows/mod.rs"]
|
||||||
mod platform;
|
mod platform;
|
||||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
#[cfg(any(
|
||||||
#[path="linux/mod.rs"]
|
target_os = "linux",
|
||||||
|
target_os = "dragonfly",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
|
#[path = "linux/mod.rs"]
|
||||||
mod platform;
|
mod platform;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[path="macos/mod.rs"]
|
#[path = "macos/mod.rs"]
|
||||||
mod platform;
|
mod platform;
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
#[path="android/mod.rs"]
|
#[path = "android/mod.rs"]
|
||||||
mod platform;
|
mod platform;
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
#[path="ios/mod.rs"]
|
#[path = "ios/mod.rs"]
|
||||||
mod platform;
|
mod platform;
|
||||||
#[cfg(target_os = "emscripten")]
|
#[cfg(target_os = "emscripten")]
|
||||||
#[path="emscripten/mod.rs"]
|
#[path = "emscripten/mod.rs"]
|
||||||
mod platform;
|
mod platform;
|
||||||
|
|
||||||
#[cfg(all(not(target_os = "ios"), not(target_os = "windows"), not(target_os = "linux"),
|
#[cfg(all(
|
||||||
not(target_os = "macos"), not(target_os = "android"), not(target_os = "dragonfly"),
|
not(target_os = "ios"),
|
||||||
not(target_os = "freebsd"), not(target_os = "netbsd"), not(target_os = "openbsd"),
|
not(target_os = "windows"),
|
||||||
not(target_os = "emscripten")))]
|
not(target_os = "linux"),
|
||||||
|
not(target_os = "macos"),
|
||||||
|
not(target_os = "android"),
|
||||||
|
not(target_os = "dragonfly"),
|
||||||
|
not(target_os = "freebsd"),
|
||||||
|
not(target_os = "netbsd"),
|
||||||
|
not(target_os = "openbsd"),
|
||||||
|
not(target_os = "emscripten")
|
||||||
|
))]
|
||||||
compile_error!("The platform you're compiling for is not supported by winit");
|
compile_error!("The platform you're compiling for is not supported by winit");
|
||||||
|
|
|
@ -1,45 +1,43 @@
|
||||||
#![allow(non_snake_case, unused_unsafe)]
|
#![allow(non_snake_case, unused_unsafe)]
|
||||||
|
|
||||||
use std::mem;
|
use std::{
|
||||||
use std::os::raw::c_void;
|
mem,
|
||||||
use std::sync::{Once, ONCE_INIT};
|
os::raw::c_void,
|
||||||
|
sync::{Once, ONCE_INIT},
|
||||||
|
};
|
||||||
|
|
||||||
use winapi::shared::minwindef::{BOOL, UINT, FALSE};
|
use winapi::{
|
||||||
use winapi::shared::windef::{
|
shared::{
|
||||||
DPI_AWARENESS_CONTEXT,
|
minwindef::{BOOL, FALSE, UINT},
|
||||||
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE,
|
windef::{DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, HMONITOR, HWND},
|
||||||
HMONITOR,
|
winerror::S_OK,
|
||||||
HWND,
|
},
|
||||||
|
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 _;
|
const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: DPI_AWARENESS_CONTEXT = -4isize as _;
|
||||||
|
|
||||||
type SetProcessDPIAware = unsafe extern "system" fn () -> BOOL;
|
type SetProcessDPIAware = unsafe extern "system" fn() -> BOOL;
|
||||||
type SetProcessDpiAwareness = unsafe extern "system" fn (
|
type SetProcessDpiAwareness = unsafe extern "system" fn(value: PROCESS_DPI_AWARENESS) -> HRESULT;
|
||||||
value: PROCESS_DPI_AWARENESS,
|
type SetProcessDpiAwarenessContext =
|
||||||
) -> HRESULT;
|
unsafe extern "system" fn(value: DPI_AWARENESS_CONTEXT) -> BOOL;
|
||||||
type SetProcessDpiAwarenessContext = unsafe extern "system" fn (
|
type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> UINT;
|
||||||
value: DPI_AWARENESS_CONTEXT,
|
type GetDpiForMonitor = unsafe extern "system" fn(
|
||||||
) -> BOOL;
|
|
||||||
type GetDpiForWindow = unsafe extern "system" fn (hwnd: HWND) -> UINT;
|
|
||||||
type GetDpiForMonitor = unsafe extern "system" fn (
|
|
||||||
hmonitor: HMONITOR,
|
hmonitor: HMONITOR,
|
||||||
dpi_type: MONITOR_DPI_TYPE,
|
dpi_type: MONITOR_DPI_TYPE,
|
||||||
dpi_x: *mut UINT,
|
dpi_x: *mut UINT,
|
||||||
dpi_y: *mut UINT,
|
dpi_y: *mut UINT,
|
||||||
) -> HRESULT;
|
) -> 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.
|
// Helper function to dynamically load function pointer.
|
||||||
// `library` and `function` must be zero-terminated.
|
// `library` and `function` must be zero-terminated.
|
||||||
|
@ -65,53 +63,48 @@ macro_rules! get_function {
|
||||||
($lib:expr, $func:ident) => {
|
($lib:expr, $func:ident) => {
|
||||||
get_function_impl(concat!($lib, '\0'), concat!(stringify!($func), '\0'))
|
get_function_impl(concat!($lib, '\0'), concat!(stringify!($func), '\0'))
|
||||||
.map(|f| unsafe { mem::transmute::<*const _, $func>(f) })
|
.map(|f| unsafe { mem::transmute::<*const _, $func>(f) })
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref GET_DPI_FOR_WINDOW: Option<GetDpiForWindow> = get_function!(
|
static ref GET_DPI_FOR_WINDOW: Option<GetDpiForWindow> =
|
||||||
"user32.dll",
|
get_function!("user32.dll", GetDpiForWindow);
|
||||||
GetDpiForWindow
|
static ref GET_DPI_FOR_MONITOR: Option<GetDpiForMonitor> =
|
||||||
);
|
get_function!("shcore.dll", GetDpiForMonitor);
|
||||||
static ref GET_DPI_FOR_MONITOR: Option<GetDpiForMonitor> = get_function!(
|
static ref ENABLE_NON_CLIENT_DPI_SCALING: Option<EnableNonClientDpiScaling> =
|
||||||
"shcore.dll",
|
get_function!("user32.dll", EnableNonClientDpiScaling);
|
||||||
GetDpiForMonitor
|
|
||||||
);
|
|
||||||
static ref ENABLE_NON_CLIENT_DPI_SCALING: Option<EnableNonClientDpiScaling> = get_function!(
|
|
||||||
"user32.dll",
|
|
||||||
EnableNonClientDpiScaling
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn become_dpi_aware(enable: bool) {
|
pub fn become_dpi_aware(enable: bool) {
|
||||||
if !enable { return; }
|
if !enable {
|
||||||
|
return;
|
||||||
|
}
|
||||||
static ENABLE_DPI_AWARENESS: Once = ONCE_INIT;
|
static ENABLE_DPI_AWARENESS: Once = ONCE_INIT;
|
||||||
ENABLE_DPI_AWARENESS.call_once(|| { unsafe {
|
ENABLE_DPI_AWARENESS.call_once(|| {
|
||||||
if let Some(SetProcessDpiAwarenessContext) = get_function!(
|
unsafe {
|
||||||
"user32.dll",
|
if let Some(SetProcessDpiAwarenessContext) =
|
||||||
SetProcessDpiAwarenessContext
|
get_function!("user32.dll", SetProcessDpiAwarenessContext)
|
||||||
) {
|
{
|
||||||
// We are on Windows 10 Anniversary Update (1607) or later.
|
// We are on Windows 10 Anniversary Update (1607) or later.
|
||||||
if SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
|
if SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
|
||||||
== FALSE {
|
== FALSE
|
||||||
// V2 only works with Windows 10 Creators Update (1703). Try using the older
|
{
|
||||||
// V1 if we can't set V2.
|
// V2 only works with Windows 10 Creators Update (1703). Try using the older
|
||||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
|
// 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) {
|
pub fn enable_non_client_dpi_scaling(hwnd: HWND) {
|
||||||
|
@ -132,7 +125,7 @@ pub fn get_monitor_dpi(hmonitor: HMONITOR) -> Option<u32> {
|
||||||
// MSDN says that "the values of *dpiX and *dpiY are identical. You only need to
|
// 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".
|
// 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
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,31 @@
|
||||||
use std::ffi::OsString;
|
use std::{
|
||||||
use std::os::windows::ffi::OsStringExt;
|
ffi::OsString,
|
||||||
use std::path::PathBuf;
|
mem,
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
os::windows::ffi::OsStringExt,
|
||||||
use std::{mem, ptr};
|
path::PathBuf,
|
||||||
|
ptr,
|
||||||
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
use winapi::ctypes::c_void;
|
use winapi::{
|
||||||
use winapi::shared::guiddef::REFIID;
|
ctypes::c_void,
|
||||||
use winapi::shared::minwindef::{DWORD, MAX_PATH, UINT, ULONG};
|
shared::{
|
||||||
use winapi::shared::windef::{HWND, POINTL};
|
guiddef::REFIID,
|
||||||
use winapi::shared::winerror::S_OK;
|
minwindef::{DWORD, MAX_PATH, UINT, ULONG},
|
||||||
use winapi::um::objidl::IDataObject;
|
windef::{HWND, POINTL},
|
||||||
use winapi::um::oleidl::{DROPEFFECT_COPY, DROPEFFECT_NONE, IDropTarget, IDropTargetVtbl};
|
winerror::S_OK,
|
||||||
use winapi::um::winnt::HRESULT;
|
},
|
||||||
use winapi::um::{shellapi, unknwnbase};
|
um::{
|
||||||
|
objidl::IDataObject,
|
||||||
|
oleidl::{IDropTarget, IDropTargetVtbl, DROPEFFECT_COPY, DROPEFFECT_NONE},
|
||||||
|
shellapi, unknwnbase,
|
||||||
|
winnt::HRESULT,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::platform_impl::platform::WindowId;
|
use crate::platform_impl::platform::WindowId;
|
||||||
|
|
||||||
use crate::event::Event;
|
use crate::{event::Event, window::WindowId as SuperWindowId};
|
||||||
use crate::window::WindowId as SuperWindowId;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct FileDropHandlerData {
|
pub struct FileDropHandlerData {
|
||||||
|
@ -26,7 +34,7 @@ pub struct FileDropHandlerData {
|
||||||
window: HWND,
|
window: HWND,
|
||||||
send_event: Box<dyn Fn(Event<()>)>,
|
send_event: Box<dyn Fn(Event<()>)>,
|
||||||
cursor_effect: DWORD,
|
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 {
|
pub struct FileDropHandler {
|
||||||
|
@ -155,16 +163,25 @@ impl FileDropHandler {
|
||||||
&mut *(this as *mut _)
|
&mut *(this as *mut _)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn iterate_filenames<F>(data_obj: *const IDataObject, callback: F) -> Option<shellapi::HDROP>
|
unsafe fn iterate_filenames<F>(
|
||||||
|
data_obj: *const IDataObject,
|
||||||
|
callback: F,
|
||||||
|
) -> Option<shellapi::HDROP>
|
||||||
where
|
where
|
||||||
F: Fn(PathBuf),
|
F: Fn(PathBuf),
|
||||||
{
|
{
|
||||||
use winapi::ctypes::wchar_t;
|
use winapi::{
|
||||||
use winapi::shared::winerror::{SUCCEEDED, DV_E_FORMATETC};
|
ctypes::wchar_t,
|
||||||
use winapi::shared::wtypes::{CLIPFORMAT, DVASPECT_CONTENT};
|
shared::{
|
||||||
use winapi::um::objidl::{FORMATETC, TYMED_HGLOBAL};
|
winerror::{DV_E_FORMATETC, SUCCEEDED},
|
||||||
use winapi::um::shellapi::DragQueryFileW;
|
wtypes::{CLIPFORMAT, DVASPECT_CONTENT},
|
||||||
use winapi::um::winuser::CF_HDROP;
|
},
|
||||||
|
um::{
|
||||||
|
objidl::{FORMATETC, TYMED_HGLOBAL},
|
||||||
|
shellapi::DragQueryFileW,
|
||||||
|
winuser::CF_HDROP,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let mut drop_format = FORMATETC {
|
let mut drop_format = FORMATETC {
|
||||||
cfFormat: CF_HDROP as CLIPFORMAT,
|
cfFormat: CF_HDROP as CLIPFORMAT,
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
use std::{char, ptr};
|
use std::{
|
||||||
use std::os::raw::c_int;
|
char,
|
||||||
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
|
os::raw::c_int,
|
||||||
|
ptr,
|
||||||
|
sync::atomic::{AtomicBool, AtomicPtr, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::event::{ScanCode, ModifiersState, VirtualKeyCode};
|
use crate::event::{ModifiersState, ScanCode, VirtualKeyCode};
|
||||||
|
|
||||||
use winapi::shared::minwindef::{WPARAM, LPARAM, UINT, HKL, HKL__};
|
use winapi::{
|
||||||
use winapi::um::winuser;
|
shared::minwindef::{HKL, HKL__, LPARAM, UINT, WPARAM},
|
||||||
|
um::winuser,
|
||||||
|
};
|
||||||
|
|
||||||
fn key_pressed(vkey: c_int) -> bool {
|
fn key_pressed(vkey: c_int) -> bool {
|
||||||
unsafe {
|
unsafe { (winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15) }
|
||||||
(winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_key_mods() -> ModifiersState {
|
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<char> {
|
unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option<char> {
|
||||||
let mut unicode_bytes = [0u16; 5];
|
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 {
|
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 {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -239,7 +252,7 @@ pub fn vkey_to_winit_vkey(vkey: c_int) -> Option<VirtualKeyCode> {
|
||||||
winuser::VK_OEM_5 => map_text_keys(vkey),
|
winuser::VK_OEM_5 => map_text_keys(vkey),
|
||||||
winuser::VK_OEM_6 => map_text_keys(vkey),
|
winuser::VK_OEM_6 => map_text_keys(vkey),
|
||||||
winuser::VK_OEM_7 => 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_OEM_102 => Some(VirtualKeyCode::OEM102),
|
||||||
/*winuser::VK_PROCESSKEY => Some(VirtualKeyCode::Processkey),
|
/*winuser::VK_PROCESSKEY => Some(VirtualKeyCode::Processkey),
|
||||||
winuser::VK_PACKET => Some(VirtualKeyCode::Packet),
|
winuser::VK_PACKET => Some(VirtualKeyCode::Packet),
|
||||||
|
@ -252,49 +265,61 @@ pub fn vkey_to_winit_vkey(vkey: c_int) -> Option<VirtualKeyCode> {
|
||||||
winuser::VK_NONAME => Some(VirtualKeyCode::Noname),
|
winuser::VK_NONAME => Some(VirtualKeyCode::Noname),
|
||||||
winuser::VK_PA1 => Some(VirtualKeyCode::Pa1),
|
winuser::VK_PA1 => Some(VirtualKeyCode::Pa1),
|
||||||
winuser::VK_OEM_CLEAR => Some(VirtualKeyCode::Oem_clear),*/
|
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/
|
// Welcome to hell https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/
|
||||||
let vkey = match vkey {
|
let vkey = match vkey {
|
||||||
winuser::VK_SHIFT => unsafe { winuser::MapVirtualKeyA(
|
winuser::VK_SHIFT => unsafe {
|
||||||
scancode,
|
winuser::MapVirtualKeyA(scancode, winuser::MAPVK_VSC_TO_VK_EX) as _
|
||||||
winuser::MAPVK_VSC_TO_VK_EX,
|
|
||||||
) as _ },
|
|
||||||
winuser::VK_CONTROL => if extended {
|
|
||||||
winuser::VK_RCONTROL
|
|
||||||
} else {
|
|
||||||
winuser::VK_LCONTROL
|
|
||||||
},
|
},
|
||||||
winuser::VK_MENU => if extended {
|
winuser::VK_CONTROL => {
|
||||||
winuser::VK_RMENU
|
if extended {
|
||||||
} else {
|
winuser::VK_RCONTROL
|
||||||
winuser::VK_LMENU
|
} else {
|
||||||
|
winuser::VK_LCONTROL
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => match scancode {
|
winuser::VK_MENU => {
|
||||||
// This is only triggered when using raw input. Without this check, we get two events whenever VK_PAUSE is
|
if extended {
|
||||||
// pressed, the first one having scancode 0x1D but vkey VK_PAUSE...
|
winuser::VK_RMENU
|
||||||
0x1D if vkey == winuser::VK_PAUSE => return None,
|
} else {
|
||||||
// ...and the second having scancode 0x45 but an unmatched vkey!
|
winuser::VK_LMENU
|
||||||
0x45 => winuser::VK_PAUSE,
|
}
|
||||||
// VK_PAUSE and VK_SCROLL have the same scancode when using modifiers, alongside incorrect vkey values.
|
},
|
||||||
0x46 => {
|
_ => {
|
||||||
if extended {
|
match scancode {
|
||||||
scancode = 0x45;
|
// This is only triggered when using raw input. Without this check, we get two events whenever VK_PAUSE is
|
||||||
winuser::VK_PAUSE
|
// pressed, the first one having scancode 0x1D but vkey VK_PAUSE...
|
||||||
} else {
|
0x1D if vkey == winuser::VK_PAUSE => return None,
|
||||||
winuser::VK_SCROLL
|
// ...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.
|
||||||
_ => vkey,
|
0x46 => {
|
||||||
|
if extended {
|
||||||
|
scancode = 0x45;
|
||||||
|
winuser::VK_PAUSE
|
||||||
|
} else {
|
||||||
|
winuser::VK_SCROLL
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => vkey,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Some((vkey, scancode))
|
Some((vkey, scancode))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_key_params(wparam: WPARAM, lparam: LPARAM) -> Option<(ScanCode, Option<VirtualKeyCode>)> {
|
pub fn process_key_params(
|
||||||
|
wparam: WPARAM,
|
||||||
|
lparam: LPARAM,
|
||||||
|
) -> Option<(ScanCode, Option<VirtualKeyCode>)> {
|
||||||
let scancode = ((lparam >> 16) & 0xff) as UINT;
|
let scancode = ((lparam >> 16) & 0xff) as UINT;
|
||||||
let extended = (lparam & 0x01000000) != 0;
|
let extended = (lparam & 0x01000000) != 0;
|
||||||
handle_extended_keys(wparam as _, scancode, extended)
|
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
|
// This is needed as windows doesn't properly distinguish
|
||||||
// some virtual key codes for different keyboard layouts
|
// some virtual key codes for different keyboard layouts
|
||||||
fn map_text_keys(win_virtual_key: i32) -> Option<VirtualKeyCode> {
|
fn map_text_keys(win_virtual_key: i32) -> Option<VirtualKeyCode> {
|
||||||
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) {
|
match char::from_u32(char_key) {
|
||||||
Some(';') => Some(VirtualKeyCode::Semicolon),
|
Some(';') => Some(VirtualKeyCode::Semicolon),
|
||||||
Some('/') => Some(VirtualKeyCode::Slash),
|
Some('/') => Some(VirtualKeyCode::Slash),
|
||||||
|
@ -313,6 +340,6 @@ fn map_text_keys(win_virtual_key: i32) -> Option<VirtualKeyCode> {
|
||||||
Some(']') => Some(VirtualKeyCode::RBracket),
|
Some(']') => Some(VirtualKeyCode::RBracket),
|
||||||
Some('\'') => Some(VirtualKeyCode::Apostrophe),
|
Some('\'') => Some(VirtualKeyCode::Apostrophe),
|
||||||
Some('\\') => Some(VirtualKeyCode::Backslash),
|
Some('\\') => Some(VirtualKeyCode::Backslash),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,13 +1,15 @@
|
||||||
use std::{mem, ptr, io};
|
use std::{io, mem, os::windows::ffi::OsStrExt, path::Path, ptr};
|
||||||
use std::os::windows::ffi::OsStrExt;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use winapi::ctypes::{c_int, wchar_t};
|
use winapi::{
|
||||||
use winapi::shared::minwindef::{BYTE, LPARAM, WPARAM};
|
ctypes::{c_int, wchar_t},
|
||||||
use winapi::shared::windef::{HICON, HWND};
|
shared::{
|
||||||
use winapi::um::winuser;
|
minwindef::{BYTE, LPARAM, WPARAM},
|
||||||
|
windef::{HICON, HWND},
|
||||||
|
},
|
||||||
|
um::winuser,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::icon::{Pixel, PIXEL_SIZE, Icon};
|
use crate::icon::{Icon, Pixel, PIXEL_SIZE};
|
||||||
|
|
||||||
impl Pixel {
|
impl Pixel {
|
||||||
fn to_bgra(&mut self) {
|
fn to_bgra(&mut self) {
|
||||||
|
@ -103,11 +105,6 @@ impl Drop for WinIcon {
|
||||||
|
|
||||||
pub fn unset_for_window(hwnd: HWND, icon_type: IconType) {
|
pub fn unset_for_window(hwnd: HWND, icon_type: IconType) {
|
||||||
unsafe {
|
unsafe {
|
||||||
winuser::SendMessageW(
|
winuser::SendMessageW(hwnd, winuser::WM_SETICON, icon_type as WPARAM, 0 as LPARAM);
|
||||||
hwnd,
|
|
||||||
winuser::WM_SETICON,
|
|
||||||
icon_type as WPARAM,
|
|
||||||
0 as LPARAM,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#![cfg(target_os = "windows")]
|
#![cfg(target_os = "windows")]
|
||||||
|
|
||||||
use winapi;
|
use winapi::{self, shared::windef::HWND};
|
||||||
use winapi::shared::windef::HWND;
|
|
||||||
|
|
||||||
pub use self::event_loop::{EventLoop, EventLoopWindowTarget, EventLoopProxy};
|
pub use self::{
|
||||||
pub use self::monitor::MonitorHandle;
|
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
|
||||||
pub use self::window::Window;
|
monitor::MonitorHandle,
|
||||||
|
window::Window,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::window::Icon;
|
use crate::{event::DeviceId as RootDeviceId, window::Icon};
|
||||||
use crate::event::DeviceId as RootDeviceId;
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct PlatformSpecificWindowBuilderAttributes {
|
pub struct PlatformSpecificWindowBuilderAttributes {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue