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

Switch to a futures-compatible API #126

Merged
merged 14 commits into from
Feb 11, 2017
2 changes: 1 addition & 1 deletion examples/cursor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate winit;

use winit::{Event, ElementState, MouseCursor};
use winit::{WindowEvent as Event, ElementState, MouseCursor};

fn main() {
let window = winit::WindowBuilder::new().build().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion examples/grabbing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate winit;

use winit::{Event, ElementState};
use winit::{WindowEvent as Event, ElementState};

fn main() {
let window = winit::WindowBuilder::new().build().unwrap();
Expand Down
15 changes: 6 additions & 9 deletions examples/window.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
extern crate winit;

fn resize_callback(width: u32, height: u32) {
println!("Window resized to {}x{}", width, height);
}

fn main() {
let events_loop = winit::EventsLoop::new();

let window = winit::WindowBuilder::new()
.with_title("A fantastic window!")
.with_window_resize_callback(resize_callback)
.build()
.build(&events_loop)
.unwrap();

for event in window.wait_events() {
events_loop.run_forever(|event| {
println!("{:?}", event);

match event {
winit::Event::Closed => break,
winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => events_loop.interrupt(),
_ => ()
}
}
});
}
2 changes: 1 addition & 1 deletion src/api/ios/delegate.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use libc;
use std::mem;
use super::DelegateState;
use Event;
use WindowEvent as Event;
use events::{ Touch, TouchPhase };

use objc::runtime::{ Class, Object, Sel, BOOL, YES };
Expand Down
2 changes: 1 addition & 1 deletion src/api/wayland/context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use {Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase};
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase};

use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
Expand Down
2 changes: 1 addition & 1 deletion src/api/wayland/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::sync::{Arc, Mutex};
use wayland_client::{EventQueue, EventQueueHandle, Init};
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};

use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
use {CreationError, MouseCursor, CursorState, WindowEvent as Event, WindowAttributes};
use platform::MonitorId as PlatformMonitorId;

use super::WaylandContext;
Expand Down
6 changes: 3 additions & 3 deletions src/api/x11/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::slice::from_raw_parts;

use WindowAttributes;

use events::Event;
use events::WindowEvent as Event;

use super::{events, ffi};
use super::XConnection;
Expand Down Expand Up @@ -123,7 +123,7 @@ impl XInputEventHandler {
}

pub fn translate_key_event(&self, event: &mut ffi::XKeyEvent) -> Vec<Event> {
use events::Event::{KeyboardInput, ReceivedCharacter};
use events::WindowEvent::{KeyboardInput, ReceivedCharacter};
use events::ElementState::{Pressed, Released};

let mut translated_events = Vec::new();
Expand Down Expand Up @@ -170,7 +170,7 @@ impl XInputEventHandler {
}

pub fn translate_event(&mut self, cookie: &ffi::XGenericEventCookie) -> Option<Event> {
use events::Event::{Focused, MouseEntered, MouseInput, MouseLeft, MouseMoved, MouseWheel};
use events::WindowEvent::{Focused, MouseEntered, MouseInput, MouseLeft, MouseMoved, MouseWheel};
use events::ElementState::{Pressed, Released};
use events::MouseButton::{Left, Right, Middle};
use events::MouseScrollDelta::LineDelta;
Expand Down
8 changes: 4 additions & 4 deletions src/api/x11/window.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use {Event, MouseCursor};
use {WindowEvent as Event, MouseCursor};
use CreationError;
use CreationError::OsError;
use libc;
Expand Down Expand Up @@ -178,7 +178,7 @@ impl<'a> Iterator for PollEventsIterator<'a> {
},

ffi::ClientMessage => {
use events::Event::{Closed, Awakened};
use events::WindowEvent::{Closed, Awakened};
use std::sync::atomic::Ordering::Relaxed;

let client_msg: &ffi::XClientMessageEvent = unsafe { mem::transmute(&xev) };
Expand All @@ -192,7 +192,7 @@ impl<'a> Iterator for PollEventsIterator<'a> {
},

ffi::ConfigureNotify => {
use events::Event::Resized;
use events::WindowEvent::Resized;
let cfg_event: &ffi::XConfigureEvent = unsafe { mem::transmute(&xev) };
let (current_width, current_height) = self.window.current_size.get();
if current_width != cfg_event.width || current_height != cfg_event.height {
Expand All @@ -202,7 +202,7 @@ impl<'a> Iterator for PollEventsIterator<'a> {
},

ffi::Expose => {
use events::Event::Refresh;
use events::WindowEvent::Refresh;
return Some(Refresh);
},

Expand Down
98 changes: 98 additions & 0 deletions src/api_transition.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@

//! This temporary module generates types that wrap around the old API (winit v5 and below) and
//! expose the new API (winit v6 and above).
//!
//! This is temporary so that existing backends can smoothly transition. After all implementations
//! have finished transitionning, this module should disappear.

macro_rules! gen_api_transition {
() => {
pub struct EventsLoop {
windows: ::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>,
interrupted: ::std::sync::atomic::AtomicBool,
}

impl EventsLoop {
pub fn new() -> EventsLoop {
EventsLoop {
windows: ::std::sync::Mutex::new(vec![]),
interrupted: ::std::sync::atomic::AtomicBool::new(false),
}
}

pub fn interrupt(&self) {
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
}

pub fn poll_events<F>(&self, mut callback: F)
where F: FnMut(::Event)
{
let mut windows = self.windows.lock().unwrap();
for window in windows.iter() {
for event in window.poll_events() {
callback(::Event::WindowEvent {
window_id: &**window as *const Window as usize,
event: event,
})
}
}
}

pub fn run_forever<F>(&self, mut callback: F)
where F: FnMut(::Event)
{
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);

// Yeah that's a very bad implementation.
loop {
self.poll_events(|e| callback(e));
::std::thread::sleep_ms(5);
if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
break;
}
}
}
}

pub struct Window2 {
window: ::std::sync::Arc<Window>,
events_loop: ::std::sync::Weak<EventsLoop>,
}

impl ::std::ops::Deref for Window2 {
type Target = Window;
#[inline]
fn deref(&self) -> &Window {
&*self.window
}
}

impl Window2 {
pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
-> Result<Window2, CreationError>
{
let win = ::std::sync::Arc::new(try!(Window::new(window, pl_attribs)));
events_loop.windows.lock().unwrap().push(win.clone());
Ok(Window2 {
window: win,
events_loop: ::std::sync::Arc::downgrade(&events_loop),
})
}

#[inline]
pub fn id(&self) -> usize {
&*self.window as *const Window as usize
}
}

impl Drop for Window2 {
fn drop(&mut self) {
if let Some(ev) = self.events_loop.upgrade() {
let mut windows = ev.windows.lock().unwrap();
windows.retain(|w| &**w as *const Window != &*self.window as *const _);
}
}
}
};
}
15 changes: 11 additions & 4 deletions src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ use std::path::PathBuf;

#[derive(Clone, Debug)]
pub enum Event {
WindowEvent {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variant could probably just be Window as we already know that it is an Event via the enum name, e.g. Event::Window. Otherwise we end up repeating "Event" twice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A window is not an event though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already know that it is an Event though, it is the name of the type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big deal, just a suggestion.

window_id: usize,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this should be it's own Id type defined in the window module? That way we could also document it, specifying that every window will have a unique identifier associated with it for the duration of its lifetime? Maybe this is fine though, I'm not sure.

event: WindowEvent,
}
}

#[derive(Clone, Debug)]
pub enum WindowEvent {
// TODO: remove ; can break the lib internally so be careful
Awakened,

/// The size of the window has changed.
Resized(u32, u32),

Expand Down Expand Up @@ -49,9 +60,6 @@ pub enum Event {
/// is being pressed) and stage (integer representing the click level).
TouchpadPressure(f32, i64),

/// The event loop was woken up by another thread.
Awakened,

/// The window needs to be redrawn.
Refresh,

Expand All @@ -60,7 +68,6 @@ pub enum Event {
/// The parameter is true if app was suspended, and false if it has been resumed.
Suspended(bool),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move this variant to the Event enum? Also perhaps the Awakened variant (although I noticed it looks like you're planning on removing this).

I'm wondering if also the ReceivedCharacter and KeyboardInput variants should be moved there also? Or perhaps they should stay in the WindowEvent enum and only be delivered to the currently focused window?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, the problem with Suspended and Awakened is that I need to change the backends' code if I remove them.

As for the keyboard events, the windows compositor usually sends the event only to the currently focused window, so sending it to a specific window is how it's designed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the problem with Suspended and Awakened is that I need to change the backends' code if I remove them.

I guess it's probably OK to leave for a follow-up PR then. You could do it on another branch and wait for contributors from each backend to do PRs to that branch if you can't do each backend yourself.

As for the keyboard events, the windows compositor usually sends the event only to the currently focused window, so sending it to a specific window is how it's designed.

Now that you mention it, this also seems to be the way macOS windows work too.



/// Touch event has been received
Touch(Touch)
}
Expand Down
Loading