Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit 5f4aa9f
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Fri Dec 21 17:14:14 2018 -0500

    Protect against reentrancy (messily)

commit b75073a
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Fri Dec 21 15:15:27 2018 -0500

    Send resize events immediately

commit 8e9fc01
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Fri Dec 21 16:07:43 2018 -0500

    Don't use struct for window delegate

commit c6853b0
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Wed Dec 19 21:17:48 2018 -0500

    Split up util

commit 262c46b
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Wed Dec 19 20:55:00 2018 -0500

    Use dispatch crate

commit 63152c2
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Wed Dec 19 20:29:13 2018 -0500

    RedrawRequested

commit 27e475c
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Wed Dec 19 19:24:44 2018 -0500

    User events

commit 157418d
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Tue Dec 18 22:38:05 2018 -0500

    Moved out cursor loading

commit b492564
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Tue Dec 18 21:32:12 2018 -0500

    Fixed a bunch of threading issues

commit 4aef63d
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Mon Dec 17 13:54:59 2018 -0500

    Wait works

commit 72ed426
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Fri Dec 14 20:49:10 2018 -0500

    Fixed drag and dropg

commit 658209f
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Fri Dec 14 20:42:42 2018 -0500

    Made mutexes finer for less deadlock risk

commit 8e6b986
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Fri Dec 14 16:45:06 2018 -0500

    Dump (encapsulate) everything into AppState

commit d2dc83d
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Thu Dec 13 17:36:47 2018 -0500

    All window events work!

commit 7c7fcc9
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Wed Dec 12 17:11:09 2018 -0500

    Very rough usage of CFRunLoop

commit 3c7a52f
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Tue Dec 11 15:45:23 2018 -0500

    Fixed deadlocks

commit b74c7fe
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Mon Dec 10 18:59:46 2018 -0500

    Fix keyDown deadlock

commit 3798f9c
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Mon Dec 10 18:44:40 2018 -0500

    It builds!

commit 8c86202
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Fri Dec 7 21:09:55 2018 -0500

    Horribly broken so far

commit 8269ed2
Author: Osspial <osspial@gmail.com>
Date:   Mon Nov 19 23:51:20 2018 -0500

    Fix crash with runner refcell not getting dropped

commit 54ce6a2
Author: Osspial <osspial@gmail.com>
Date:   Sun Nov 18 19:12:45 2018 -0500

    Fix buffered events not getting dispatched

commit 2c18b80
Author: Osspial <osspial@gmail.com>
Date:   Sun Nov 18 18:51:24 2018 -0500

    Fix thread executor not executing closure when called from non-loop thread

commit 5a3a5e2
Author: Osspial <osspial@gmail.com>
Date:   Thu Nov 15 22:43:59 2018 -0500

    Fix some deadlocks that could occur when changing window state

commit 2a3cefd
Author: Osspial <osspial@gmail.com>
Date:   Thu Nov 15 16:45:17 2018 -0500

    Document and implement Debug for EventLoopWindowTarget

commit fa46825
Author: Osspial <osspial@gmail.com>
Date:   Thu Nov 15 16:40:48 2018 -0500

    Replace &EventLoop in callback with &EventLoopWindowTarget

commit 9f36a7a
Author: Osspial <osspial@gmail.com>
Date:   Wed Nov 14 21:28:38 2018 -0500

    Fix freeze when setting decorations

commit d9c3dac
Author: Osspial <osspial@gmail.com>
Date:   Fri Nov 9 20:41:15 2018 -0500

    Fix 1.24.1 build

commit 5289d22
Author: Osspial <osspial@gmail.com>
Date:   Fri Nov 9 00:00:27 2018 -0500

    Remove serde implementations from ControlFlow

commit 92ac3d6
Author: Osspial <osspial@gmail.com>
Date:   Thu Nov 8 23:46:41 2018 -0500

    Remove crossbeam dependency and make drop events work again

commit 8299eb2
Author: Osspial <osspial@gmail.com>
Date:   Thu Sep 13 22:39:40 2018 -0400

    Fix crash when running in release mode

commit bb6ab1b
Author: Osspial <osspial@gmail.com>
Date:   Sun Sep 9 14:28:16 2018 -0400

    Fix unreachable panic after setting ControlFlow to Poll during some RedrawRequested events.

commit 5068ff4
Author: Osspial <osspial@gmail.com>
Date:   Sun Sep 9 14:14:28 2018 -0400

    Improve clarity/fix typos in docs

commit 8ed575f
Author: Osspial <osspial@gmail.com>
Date:   Sun Sep 9 00:19:53 2018 -0400

    Update send test and errors that broke some examples/APIs

commit bf7bfa8
Author: Osspial <osspial@gmail.com>
Date:   Wed Sep 5 22:36:05 2018 -0400

    Fix resize lag when waiting in some situations

commit 70722cc
Author: Osspial <osspial@gmail.com>
Date:   Wed Sep 5 19:58:52 2018 -1100

    When SendEvent is called during event closure, buffer events

commit 5337092
Author: Osspial <osspial@gmail.com>
Date:   Sun Aug 26 21:55:51 2018 -0400

    Improve WaitUntil timer precision

commit a654400
Author: Osspial <osspial@gmail.com>
Date:   Thu Aug 23 21:06:19 2018 -0400

    Add CHANGELOG entry

commit deb7d37
Author: Osspial <osspial@gmail.com>
Date:   Thu Aug 23 20:19:56 2018 -0400

    Rename MonitorId to MonitorHandle

commit 8d8d9b7
Author: Osspial <osspial@gmail.com>
Date:   Thu Aug 23 20:16:52 2018 -0400

    Change instances of "events_loop" to "event_loop"

commit 0f34408
Author: Osspial <osspial@gmail.com>
Date:   Thu Aug 23 20:13:53 2018 -0400

    Improve docs for run and run_return

commit fba41f7
Author: Osspial <osspial@gmail.com>
Date:   Thu Aug 23 19:09:53 2018 -0400

    Small changes to examples

commit 42e8a0d
Author: Osspial <osspial@gmail.com>
Date:   Thu Aug 23 19:09:19 2018 -0400

    Improve documentation

commit 4377680
Author: Osspial <osspial@gmail.com>
Date:   Wed Aug 22 23:01:36 2018 -0400

    Re-organize into module structure

commit f20fac9
Author: Osspial <osspial@gmail.com>
Date:   Wed Aug 22 22:07:39 2018 -0400

    Add platform::desktop module with EventLoopExt::run_return

commit dad24d0
Author: Osspial <osspial@gmail.com>
Date:   Wed Aug 22 18:03:41 2018 -0400

    Rename os to platform, add Ext trait postfixes

commit 7df59c6
Author: Osspial <osspial@gmail.com>
Date:   Wed Aug 22 17:59:36 2018 -0400

    Rename platform to platform_impl

commit 99c0f84
Author: Osspial <osspial@gmail.com>
Date:   Wed Aug 22 17:55:27 2018 -0400

    Add request_redraw

commit a0fef1a
Author: Osspial <osspial@gmail.com>
Date:   Mon Aug 20 01:47:11 2018 -0400

    Fully invert windows control flow so win32 calls into winit's callback

commit 2c607ff
Author: Osspial <osspial@gmail.com>
Date:   Sun Aug 19 13:44:22 2018 -0400

    Add ability to send custom user events

commit a0b2bb3
Author: Osspial <osspial@gmail.com>
Date:   Fri Aug 17 17:49:46 2018 -0400

    Add StartCause::Init support, timer example

commit 02f922f
Author: Osspial <osspial@gmail.com>
Date:   Fri Aug 17 17:31:04 2018 -0400

    Implement new ControlFlow and associated events

commit 8b8a767
Author: Osspial <osspial@gmail.com>
Date:   Fri Jul 13 01:48:26 2018 -0400

    Replace windows Mutex with parking_lot Mutex

commit 9feada2
Author: Osspial <osspial@gmail.com>
Date:   Fri Jul 13 01:39:53 2018 -0400

    Update run_forever to hijack thread

commit 2e83bac
Author: Osspial <osspial@gmail.com>
Date:   Thu Jul 12 23:43:58 2018 -0400

    Remove second thread from win32 backend

commit 64b8a9c
Author: Osspial <osspial@gmail.com>
Date:   Thu Jul 12 22:13:07 2018 -0400

    Rename WindowEvent::Refresh to WindowEvent::Redraw

commit 529c085
Author: Osspial <osspial@gmail.com>
Date:   Thu Jul 12 22:04:38 2018 -0400

    Rename EventsLoop and associated types to EventLoop

Signed-off-by: Hal Gentz <zegentzy@protonmail.com>
  • Loading branch information
goddessfreya committed Apr 25, 2019
1 parent ab1dfaa commit 73b5222
Show file tree
Hide file tree
Showing 15 changed files with 1,931 additions and 12 deletions.
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,41 @@
# Unreleased
- Changes below are considered **breaking**.
- Change all occurrences of `EventsLoop` to `EventLoop`.
- Previously flat API is now exposed through `event`, `event_loop`, `monitor`, and `window` modules.
- `os` module changes:
- Renamed to `platform`.
- All traits now have platform-specific suffixes.
- Exposes new `desktop` module on Windows, Mac, and Linux.
- Changes to event loop types:
- `EventLoopProxy::wakeup` has been removed in favor of `send_event`.
- **Major:** New `run` method drives winit event loop.
- Returns `!` to ensure API behaves identically across all supported platforms.
- This allows `emscripten` implementation to work without lying about the API.
- `ControlFlow`'s variants have been replaced with `Wait`, `WaitUntil(Instant)`, `Poll`, and `Exit`.
- Is read after `EventsCleared` is processed.
- `Wait` waits until new events are available.
- `WaitUntil` waits until either new events are available or the provided time has been reached.
- `Poll` instantly resumes the event loop.
- `Exit` aborts the event loop.
- Takes a closure that implements `'static + FnMut(Event<T>, &EventLoop<T>, &mut ControlFlow)`.
- `&EventLoop<T>` is provided to allow new `Window`s to be created.
- **Major:** `platform::desktop` module exposes `EventLoopExtDesktop` trait with `run_return` method.
- Behaves identically to `run`, but returns control flow to the calling context can take non-`'static` closures.
- `EventLoop`'s `poll_events` and `run_forever` methods have been removed in favor of `run` and `run_return`.
- Changes to events:
- Remove `Event::Awakened` in favor of `Event::UserEvent(T)`.
- Can be sent with `EventLoopProxy::send_event`.
- Rename `WindowEvent::Refresh` to `WindowEvent::RedrawRequested`.
- `RedrawRequested` can be sent by the user with the `Window::request_redraw` method.
- `EventLoop`, `EventLoopProxy`, and `Event` are now generic over `T`, for use in `UserEvent`.
- **Major:** Add `NewEvents(StartCause)`, `EventsCleared`, and `LoopDestroyed` variants to `Event`.
- `NewEvents` is emitted when new events are ready to be processed by event loop.
- `StartCause` describes why new events are available, with `ResumeTimeReached`, `Poll`, `WaitCancelled`, and `Init` (sent once at start of loop).
- `EventsCleared` is emitted when all available events have been processed.
- Can be used to perform logic that depends on all events being processed (e.g. an iteration of a game loop).
- `LoopDestroyed` is emitted when the `run` or `run_return` method is about to exit.
- Rename `MonitorId` to `MonitorHandle`.
- Removed `serde` implementations from `ControlFlow`.

- Changes below are considered **breaking**.
- Change all occurrences of `EventsLoop` to `EventLoop`.
Expand Down
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
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();
},
}
}
_ => (),
}
})
}
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
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);
},
_ => (),
}
}
101 changes: 101 additions & 0 deletions src/platform_impl/macos/app_delegate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use cocoa::base::id;
use objc::{runtime::{Class, Object, Sel, BOOL, YES}, declare::ClassDecl};

use platform_impl::platform::app_state::AppState;

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

lazy_static! {
pub static ref APP_DELEGATE_CLASS: AppDelegateClass = unsafe {
let superclass = class!(NSResponder);
let mut decl = ClassDecl::new("WinitAppDelegate", superclass).unwrap();

decl.add_method(
sel!(applicationDidFinishLaunching:),
did_finish_launching as extern fn(&Object, Sel, id) -> BOOL,
);
decl.add_method(
sel!(applicationDidBecomeActive:),
did_become_active as extern fn(&Object, Sel, id),
);
decl.add_method(
sel!(applicationWillResignActive:),
will_resign_active as extern fn(&Object, Sel, id),
);
decl.add_method(
sel!(applicationWillEnterForeground:),
will_enter_foreground as extern fn(&Object, Sel, id),
);
decl.add_method(
sel!(applicationDidEnterBackground:),
did_enter_background as extern fn(&Object, Sel, id),
);
decl.add_method(
sel!(applicationWillTerminate:),
will_terminate as extern fn(&Object, Sel, id),
);

AppDelegateClass(decl.register())
};
}

extern fn did_finish_launching(_: &Object, _: Sel, _: id) -> BOOL {
trace!("Triggered `didFinishLaunching`");
AppState::launched();
trace!("Completed `didFinishLaunching`");
YES
}

extern fn did_become_active(_: &Object, _: Sel, _: id) {
trace!("Triggered `didBecomeActive`");
/*unsafe {
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(false))
}*/
trace!("Completed `didBecomeActive`");
}

extern fn will_resign_active(_: &Object, _: Sel, _: id) {
trace!("Triggered `willResignActive`");
/*unsafe {
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(true))
}*/
trace!("Completed `willResignActive`");
}

extern fn will_enter_foreground(_: &Object, _: Sel, _: id) {
trace!("Triggered `willEnterForeground`");
trace!("Completed `willEnterForeground`");
}

extern fn did_enter_background(_: &Object, _: Sel, _: id) {
trace!("Triggered `didEnterBackground`");
trace!("Completed `didEnterBackground`");
}

extern fn will_terminate(_: &Object, _: Sel, _: id) {
trace!("Triggered `willTerminate`");
/*unsafe {
let app: id = msg_send![class!(UIApplication), sharedApplication];
let windows: id = msg_send![app, windows];
let windows_enum: id = msg_send![windows, objectEnumerator];
let mut events = Vec::new();
loop {
let window: id = msg_send![windows_enum, nextObject];
if window == nil {
break
}
let is_winit_window: BOOL = msg_send![window, isKindOfClass:class!(WinitUIWindow)];
if is_winit_window == YES {
events.push(Event::WindowEvent {
window_id: RootWindowId(window.into()),
event: WindowEvent::Destroyed,
});
}
}
HANDLER.lock().unwrap().handle_nonuser_events(events);
HANDLER.lock().unwrap().terminated();
}*/
trace!("Completed `willTerminate`");
}
Loading

0 comments on commit 73b5222

Please sign in to comment.