Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Macos Evlp2 #853

Merged
merged 1 commit into from
May 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ serde = { version = "1", optional = true, features = ["serde_derive"] }

[dev-dependencies]
image = "0.21"
env_logger = "0.5"

[target.'cfg(target_os = "android")'.dependencies.android_glue]
version = "0.2"
Expand All @@ -29,10 +30,11 @@ version = "0.2"
objc = "0.2.3"

[target.'cfg(target_os = "macos")'.dependencies]
objc = "0.2.3"
cocoa = "0.18.4"
core-foundation = "0.6"
core-graphics = "0.17.3"
dispatch = "0.1.4"
objc = "0.2.3"

[target.'cfg(target_os = "windows")'.dependencies]
backtrace = "0.3"
Expand Down
7 changes: 3 additions & 4 deletions examples/fullscreen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,11 @@ fn main() {
#[cfg(target_os = "macos")]
{
if macos_use_simple_fullscreen {
use winit::os::macos::WindowExt;
if WindowExt::set_simple_fullscreen(&window, !is_fullscreen) {
use winit::platform::macos::WindowExtMacOS;
if WindowExtMacOS::set_simple_fullscreen(&window, !is_fullscreen) {
is_fullscreen = !is_fullscreen;
}

return ControlFlow::Continue;
return;
}
}

Expand Down
115 changes: 115 additions & 0 deletions examples/multithreaded.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
extern crate env_logger;
extern crate winit;

use std::{collections::HashMap, sync::mpsc, thread, time::Duration};

use winit::{
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::{ControlFlow, EventLoop}, window::{MouseCursor, WindowBuilder},
};

const WINDOW_COUNT: usize = 3;
const WINDOW_SIZE: (u32, u32) = (600, 400);

fn main() {
env_logger::init();
let event_loop = EventLoop::new();
let mut window_senders = HashMap::with_capacity(WINDOW_COUNT);
for _ in 0..WINDOW_COUNT {
let window = WindowBuilder::new()
.with_dimensions(WINDOW_SIZE.into())
.build(&event_loop)
.unwrap();
let (tx, rx) = mpsc::channel();
window_senders.insert(window.id(), tx);
thread::spawn(move || {
while let Ok(event) = rx.recv() {
match event {
WindowEvent::KeyboardInput { input: KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(key),
modifiers,
..
}, .. } => {
window.set_title(&format!("{:?}", key));
let state = !modifiers.shift;
use self::VirtualKeyCode::*;
match key {
A => window.set_always_on_top(state),
C => window.set_cursor(match state {
true => MouseCursor::Progress,
false => MouseCursor::Default,
}),
D => window.set_decorations(!state),
F => window.set_fullscreen(match state {
true => Some(window.get_current_monitor()),
false => None,
}),
G => window.grab_cursor(state).unwrap(),
H => window.hide_cursor(state),
I => {
println!("Info:");
println!("-> position : {:?}", window.get_position());
println!("-> inner_position : {:?}", window.get_inner_position());
println!("-> outer_size : {:?}", window.get_outer_size());
println!("-> inner_size : {:?}", window.get_inner_size());
},
L => window.set_min_dimensions(match state {
true => Some(WINDOW_SIZE.into()),
false => None,
}),
M => window.set_maximized(state),
P => window.set_position({
let mut position = window.get_position().unwrap();
let sign = if state { 1.0 } else { -1.0 };
position.x += 10.0 * sign;
position.y += 10.0 * sign;
position
}),
Q => window.request_redraw(),
R => window.set_resizable(state),
S => window.set_inner_size(match state {
true => (WINDOW_SIZE.0 + 100, WINDOW_SIZE.1 + 100),
false => WINDOW_SIZE,
}.into()),
W => window.set_cursor_position((
WINDOW_SIZE.0 as i32 / 2,
WINDOW_SIZE.1 as i32 / 2,
).into()).unwrap(),
Z => {
window.hide();
thread::sleep(Duration::from_secs(1));
window.show();
},
_ => (),
}
},
_ => (),
}
}
});
}
event_loop.run(move |event, _event_loop, control_flow| {
*control_flow = match !window_senders.is_empty() {
true => ControlFlow::Wait,
false => ControlFlow::Exit,
};
match event {
Event::WindowEvent { event, window_id } => {
match event {
WindowEvent::CloseRequested
| WindowEvent::Destroyed
| WindowEvent::KeyboardInput { input: KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Escape),
.. }, .. } => {
window_senders.remove(&window_id);
},
_ => if let Some(tx) = window_senders.get(&window_id) {
tx.send(event).unwrap();
},
}
}
_ => (),
}
})
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ extern crate objc;
#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate dispatch;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
Expand Down
5 changes: 4 additions & 1 deletion src/platform/macos.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#![cfg(target_os = "macos")]

use std::os::raw::c_void;
use {LogicalSize, MonitorHandle, Window, WindowBuilder};

use crate::dpi::LogicalSize;
use crate::monitor::MonitorHandle;
use crate::window::{Window, WindowBuilder};

/// Additional methods on `Window` that are specific to MacOS.
pub trait WindowExtMacOS {
Expand Down
6 changes: 3 additions & 3 deletions src/platform/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ pub trait EventLoopExtUnix {
#[doc(hidden)]
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>>;

/// Returns a pointer to the `wl_display` object of wayland that is used by this `EventsLoop`.
/// Returns a pointer to the `wl_display` object of wayland that is used by this `EventLoop`.
///
/// Returns `None` if the `EventsLoop` doesn't use wayland (if it uses xlib for example).
/// Returns `None` if the `EventLoop` doesn't use wayland (if it uses xlib for example).
///
/// The pointer will become invalid when the glutin `EventsLoop` is destroyed.
/// The pointer will become invalid when the glutin `EventLoop` is destroyed.
fn get_wayland_display(&self) -> Option<*mut raw::c_void>;
}

Expand Down
1 change: 1 addition & 0 deletions src/platform_impl/linux/x11/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ 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 change: 1 addition & 0 deletions src/platform_impl/linux/x11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ impl<T: 'static> EventLoop<T> {
sticky_exit_callback(evt, &self.target, &mut control_flow, &mut callback);
}
}

// Empty the user event buffer
{
let mut guard = self.pending_user_events.borrow_mut();
Expand Down
2 changes: 0 additions & 2 deletions src/platform_impl/linux/x11/util/window_property.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std;

use super::*;

pub type Cardinal = c_long;
Expand Down
8 changes: 8 additions & 0 deletions src/platform_impl/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,14 @@ impl UnownedWindow {
None => ffi::CopyFromParent,
},
ffi::InputOutput as c_uint,
// TODO: If window wants transparency and `visual_infos` is None,
// we need to find our own visual which has an `alphaMask` which
// is > 0, like we do in glutin.
//
// It is non obvious which masks, if any, we should pass to
// `XGetVisualInfo`. winit doesn't recieve any info about what
// properties the user wants. Users should consider choosing the
// visual themselves as glutin does.
match pl_attribs.visual_infos {
Some(vi) => vi.visual,
None => ffi::CopyFromParent as *mut ffi::Visual,
Expand Down
3 changes: 3 additions & 0 deletions src/platform_impl/linux/x11/xdisplay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct XConnection {
pub xcursor: ffi::Xcursor,
pub xinput2: ffi::XInput2,
pub xlib_xcb: ffi::Xlib_xcb,
pub xrender: ffi::Xrender,
pub display: *mut ffi::Display,
pub x11_fd: c_int,
pub latest_error: Mutex<Option<XError>>,
Expand All @@ -37,6 +38,7 @@ impl XConnection {
let xrandr_1_5 = ffi::Xrandr::open().ok();
let xinput2 = ffi::XInput2::open()?;
let xlib_xcb = ffi::Xlib_xcb::open()?;
let xrender = ffi::Xrender::open()?;

unsafe { (xlib.XInitThreads)() };
unsafe { (xlib.XSetErrorHandler)(error_handler) };
Expand All @@ -62,6 +64,7 @@ impl XConnection {
xcursor,
xinput2,
xlib_xcb,
xrender,
display,
x11_fd: fd,
latest_error: Mutex::new(None),
Expand Down
88 changes: 88 additions & 0 deletions src/platform_impl/macos/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::collections::VecDeque;

use cocoa::{appkit::{self, NSEvent}, base::id};
use objc::{declare::ClassDecl, runtime::{Class, Object, Sel}};

use event::{DeviceEvent, Event};
use platform_impl::platform::{app_state::AppState, DEVICE_ID, util};

pub struct AppClass(pub *const Class);
unsafe impl Send for AppClass {}
unsafe impl Sync for AppClass {}

lazy_static! {
pub static ref APP_CLASS: AppClass = unsafe {
let superclass = class!(NSApplication);
let mut decl = ClassDecl::new("WinitApp", superclass).unwrap();

decl.add_method(
sel!(sendEvent:),
send_event as extern fn(&Object, Sel, id),
);

AppClass(decl.register())
};
}

// Normally, holding Cmd + any key never sends us a `keyUp` event for that key.
// Overriding `sendEvent:` like this fixes that. (https://stackoverflow.com/a/15294196)
// Fun fact: Firefox still has this bug! (https://bugzilla.mozilla.org/show_bug.cgi?id=1299553)
extern fn send_event(this: &Object, _sel: Sel, event: id) {
unsafe {
// For posterity, there are some undocumented event types
// (https://github.com/servo/cocoa-rs/issues/155)
// but that doesn't really matter here.
let event_type = event.eventType();
let modifier_flags = event.modifierFlags();
if event_type == appkit::NSKeyUp && util::has_flag(
modifier_flags,
appkit::NSEventModifierFlags::NSCommandKeyMask,
) {
let key_window: id = msg_send![this, keyWindow];
let _: () = msg_send![key_window, sendEvent:event];
} else {
maybe_dispatch_device_event(event);
let superclass = util::superclass(this);
let _: () = msg_send![super(this, superclass), sendEvent:event];
}
}
}

unsafe fn maybe_dispatch_device_event(event: id) {
let event_type = event.eventType();
match event_type {
appkit::NSMouseMoved |
appkit::NSLeftMouseDragged |
appkit::NSOtherMouseDragged |
appkit::NSRightMouseDragged => {
let mut events = VecDeque::with_capacity(3);

let delta_x = event.deltaX() as f64;
let delta_y = event.deltaY() as f64;

if delta_x != 0.0 {
events.push_back(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::Motion { axis: 0, value: delta_x },
});
}

if delta_y != 0.0 {
events.push_back(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::Motion { axis: 1, value: delta_y },
});
}

if delta_x != 0.0 || delta_y != 0.0 {
events.push_back(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::MouseMotion { delta: (delta_x, delta_y) },
});
}

AppState::queue_events(events);
},
_ => (),
}
}
Loading