diff options
Diffstat (limited to 'winit')
-rw-r--r-- | winit/Cargo.toml | 18 | ||||
-rw-r--r-- | winit/README.md | 2 | ||||
-rw-r--r-- | winit/src/application.rs | 398 | ||||
-rw-r--r-- | winit/src/clipboard.rs | 19 | ||||
-rw-r--r-- | winit/src/conversion.rs | 134 | ||||
-rw-r--r-- | winit/src/debug/basic.rs | 5 | ||||
-rw-r--r-- | winit/src/debug/null.rs | 2 | ||||
-rw-r--r-- | winit/src/lib.rs | 24 | ||||
-rw-r--r-- | winit/src/mode.rs | 9 | ||||
-rw-r--r-- | winit/src/proxy.rs | 58 | ||||
-rw-r--r-- | winit/src/settings.rs | 29 | ||||
-rw-r--r-- | winit/src/settings/mod.rs | 53 | ||||
-rw-r--r-- | winit/src/settings/not_windows.rs | 6 | ||||
-rw-r--r-- | winit/src/settings/windows.rs | 9 | ||||
-rw-r--r-- | winit/src/size.rs | 30 |
15 files changed, 559 insertions, 237 deletions
diff --git a/winit/Cargo.toml b/winit/Cargo.toml index 2a33255d..63df1d63 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -6,12 +6,24 @@ edition = "2018" description = "A winit runtime for Iced" license = "MIT" repository = "https://github.com/hecrj/iced" +documentation = "https://docs.rs/iced_winit" +keywords = ["gui", "ui", "graphics", "interface", "widgets"] +categories = ["gui"] [features] debug = [] [dependencies] -iced_native = { version = "0.1.0-alpha", path = "../native" } -winit = { version = "0.20.0-alpha3", git = "https://github.com/rust-windowing/winit", rev = "709808eb4e69044705fcb214bcc30556db761405"} -futures = { version = "0.3", features = ["thread-pool"] } +winit = "0.21" log = "0.4" + +[dependencies.iced_native] +version = "0.1.0-alpha" +path = "../native" + +[dependencies.window_clipboard] +git = "https://github.com/hecrj/window_clipboard" +rev = "22c6dd6c04cd05d528029b50a30c56417cd4bebf" + +[target.'cfg(target_os = "windows")'.dependencies.winapi] +version = "0.3.6" diff --git a/winit/README.md b/winit/README.md index 01785150..d3309e49 100644 --- a/winit/README.md +++ b/winit/README.md @@ -10,7 +10,7 @@ It exposes a renderer-agnostic `Application` trait that can be implemented and t  -[documentation]: https://docs.rs/iced_winit +[documentation]: https://docs.rs/iced_winit/0.1.0-alpha.1/iced_winit/ [`iced_native`]: ../native [`winit`]: https://github.com/rust-windowing/winit diff --git a/winit/src/application.rs b/winit/src/application.rs index 1042b412..f5aa799c 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -1,9 +1,7 @@ use crate::{ - conversion, - input::{keyboard, mouse}, - renderer::{Target, Windowed}, - Cache, Command, Container, Debug, Element, Event, Length, MouseCursor, - Settings, UserInterface, + conversion, size::Size, window, Cache, Clipboard, Command, Debug, Element, + Executor, Mode, MouseCursor, Proxy, Runtime, Settings, Subscription, + UserInterface, }; /// An interactive, native cross-platform application. @@ -15,10 +13,15 @@ use crate::{ /// An [`Application`](trait.Application.html) can execute asynchronous actions /// by returning a [`Command`](struct.Command.html) in some of its methods. pub trait Application: Sized { - /// The renderer to use to draw the [`Application`]. + /// The graphics backend to use to draw the [`Application`]. /// /// [`Application`]: trait.Application.html - type Renderer: Windowed; + type Backend: window::Backend; + + /// The [`Executor`] that will run commands and subscriptions. + /// + /// [`Executor`]: trait.Executor.html + type Executor: Executor; /// The type of __messages__ your [`Application`] will produce. /// @@ -57,12 +60,35 @@ pub trait Application: Sized { /// [`Command`]: struct.Command.html fn update(&mut self, message: Self::Message) -> Command<Self::Message>; + /// Returns the event `Subscription` for the current state of the + /// application. + /// + /// The messages produced by the `Subscription` will be handled by + /// [`update`](#tymethod.update). + /// + /// A `Subscription` will be kept alive as long as you keep returning it! + fn subscription(&self) -> Subscription<Self::Message>; + /// Returns the widgets to display in the [`Application`]. /// /// These widgets can produce __messages__ based on user interaction. /// /// [`Application`]: trait.Application.html - fn view(&mut self) -> Element<'_, Self::Message, Self::Renderer>; + fn view( + &mut self, + ) -> Element<'_, Self::Message, <Self::Backend as window::Backend>::Renderer>; + + /// Returns the current [`Application`] mode. + /// + /// The runtime will automatically transition your application if a new mode + /// is returned. + /// + /// By default, an application will run in windowed mode. + /// + /// [`Application`]: trait.Application.html + fn mode(&self) -> Mode { + Mode::Windowed + } /// Runs the [`Application`]. /// @@ -72,10 +98,13 @@ pub trait Application: Sized { /// It should probably be that last thing you call in your `main` function. /// /// [`Application`]: trait.Application.html - fn run(settings: Settings) - where + fn run( + settings: Settings, + backend_settings: <Self::Backend as window::Backend>::Settings, + ) where Self: 'static, { + use window::Backend as _; use winit::{ event::{self, WindowEvent}, event_loop::{ControlFlow, EventLoop}, @@ -86,49 +115,75 @@ pub trait Application: Sized { debug.startup_started(); let event_loop = EventLoop::with_user_event(); - let proxy = event_loop.create_proxy(); - let mut thread_pool = - futures::executor::ThreadPool::new().expect("Create thread pool"); let mut external_messages = Vec::new(); - let (mut application, init_command) = Self::new(); - spawn(init_command, &mut thread_pool, &proxy); + let mut runtime = { + let executor = Self::Executor::new().expect("Create executor"); + + Runtime::new(executor, Proxy::new(event_loop.create_proxy())) + }; + + let (mut application, init_command) = runtime.enter(|| Self::new()); + runtime.spawn(init_command); + + let subscription = application.subscription(); + runtime.track(subscription); let mut title = application.title(); + let mut mode = application.mode(); + + let window = { + let mut window_builder = WindowBuilder::new(); - let (width, height) = settings.window.size; + let (width, height) = settings.window.size; - let window = WindowBuilder::new() - .with_title(&title) - .with_inner_size(winit::dpi::LogicalSize { - width: f64::from(width), - height: f64::from(height), - }) - .with_resizable(settings.window.resizable) - .build(&event_loop) - .expect("Open window"); + window_builder = window_builder + .with_title(&title) + .with_inner_size(winit::dpi::LogicalSize { width, height }) + .with_resizable(settings.window.resizable) + .with_decorations(settings.window.decorations) + .with_fullscreen(conversion::fullscreen( + event_loop.primary_monitor(), + mode, + )); - let dpi = window.hidpi_factor(); - let mut size = window.inner_size(); - let mut new_size: Option<winit::dpi::LogicalSize> = None; + #[cfg(target_os = "windows")] + { + use winit::platform::windows::WindowBuilderExtWindows; - let mut renderer = Self::Renderer::new(); + if let Some(parent) = settings.window.platform_specific.parent { + window_builder = window_builder.with_parent_window(parent); + } + } + + window_builder.build(&event_loop).expect("Open window") + }; - let mut target = { - let (width, height) = to_physical(size, dpi); + let mut size = Size::new(window.inner_size(), window.scale_factor()); + let mut resized = false; - <Self::Renderer as Windowed>::Target::new( - &window, width, height, dpi as f32, &renderer, + let clipboard = Clipboard::new(&window); + let (mut backend, mut renderer) = Self::Backend::new(backend_settings); + + let surface = backend.create_surface(&window); + + let mut swap_chain = { + let physical_size = size.physical(); + + backend.create_swap_chain( + &surface, + physical_size.width, + physical_size.height, ) }; - debug.layout_started(); - let user_interface = UserInterface::build( - document(&mut application, size, &mut debug), + let user_interface = build_user_interface( + &mut application, Cache::default(), &mut renderer, + size.logical(), + &mut debug, ); - debug.layout_finished(); debug.draw_started(); let mut primitive = user_interface.draw(&mut renderer); @@ -137,28 +192,43 @@ pub trait Application: Sized { let mut cache = Some(user_interface.into_cache()); let mut events = Vec::new(); let mut mouse_cursor = MouseCursor::OutOfBounds; + let mut modifiers = winit::event::ModifiersState::default(); debug.startup_finished(); window.request_redraw(); event_loop.run(move |event, _, control_flow| match event { event::Event::MainEventsCleared => { + if events.is_empty() && external_messages.is_empty() { + return; + } + // TODO: We should be able to keep a user interface alive // between events once we remove state references. // // This will allow us to rebuild it only when a message is // handled. - debug.layout_started(); - let mut user_interface = UserInterface::build( - document(&mut application, size, &mut debug), + let mut user_interface = build_user_interface( + &mut application, cache.take().unwrap(), &mut renderer, + size.logical(), + &mut debug, ); - debug.layout_finished(); debug.event_processing_started(); - let mut messages = - user_interface.update(&renderer, events.drain(..)); + events + .iter() + .cloned() + .for_each(|event| runtime.broadcast(event)); + + let mut messages = user_interface.update( + events.drain(..), + clipboard + .as_ref() + .map(|c| c as &dyn iced_native::Clipboard), + &renderer, + ); messages.extend(external_messages.drain(..)); debug.event_processing_finished(); @@ -179,12 +249,15 @@ pub trait Application: Sized { debug.log_message(&message); debug.update_started(); - let command = application.update(message); - - spawn(command, &mut thread_pool, &proxy); + let command = + runtime.enter(|| application.update(message)); + runtime.spawn(command); debug.update_finished(); } + let subscription = application.subscription(); + runtime.track(subscription); + // Update window title let new_title = application.title(); @@ -194,13 +267,25 @@ pub trait Application: Sized { title = new_title; } - debug.layout_started(); - let user_interface = UserInterface::build( - document(&mut application, size, &mut debug), + // Update window mode + let new_mode = application.mode(); + + if mode != new_mode { + window.set_fullscreen(conversion::fullscreen( + window.current_monitor(), + new_mode, + )); + + mode = new_mode; + } + + let user_interface = build_user_interface( + &mut application, temp_cache, &mut renderer, + size.logical(), + &mut debug, ); - debug.layout_finished(); debug.draw_started(); primitive = user_interface.draw(&mut renderer); @@ -217,22 +302,25 @@ pub trait Application: Sized { event::Event::RedrawRequested(_) => { debug.render_started(); - if let Some(new_size) = new_size.take() { - let dpi = window.hidpi_factor(); - let (width, height) = to_physical(new_size, dpi); + if resized { + let physical_size = size.physical(); - target.resize( - width, - height, - window.hidpi_factor() as f32, - &renderer, + swap_chain = backend.create_swap_chain( + &surface, + physical_size.width, + physical_size.height, ); - size = new_size; + resized = false; } - let new_mouse_cursor = - renderer.draw(&primitive, &debug.overlay(), &mut target); + let new_mouse_cursor = backend.draw( + &mut renderer, + &mut swap_chain, + &primitive, + size.scale_factor(), + &debug.overlay(), + ); debug.render_finished(); @@ -250,83 +338,56 @@ pub trait Application: Sized { event::Event::WindowEvent { event: window_event, .. - } => match window_event { - WindowEvent::CursorMoved { position, .. } => { - events.push(Event::Mouse(mouse::Event::CursorMoved { - x: position.x as f32, - y: position.y as f32, - })); - } - WindowEvent::MouseInput { button, state, .. } => { - events.push(Event::Mouse(mouse::Event::Input { - button: conversion::mouse_button(button), - state: conversion::button_state(state), - })); - } - WindowEvent::MouseWheel { delta, .. } => match delta { - winit::event::MouseScrollDelta::LineDelta( - delta_x, - delta_y, - ) => { - events.push(Event::Mouse( - mouse::Event::WheelScrolled { - delta: mouse::ScrollDelta::Lines { - x: delta_x, - y: delta_y, - }, - }, - )); + } => { + match window_event { + WindowEvent::Resized(new_size) => { + size = Size::new(new_size, window.scale_factor()); + resized = true; } - winit::event::MouseScrollDelta::PixelDelta(position) => { - events.push(Event::Mouse( - mouse::Event::WheelScrolled { - delta: mouse::ScrollDelta::Pixels { - x: position.x as f32, - y: position.y as f32, - }, - }, - )); + WindowEvent::CloseRequested => { + *control_flow = ControlFlow::Exit; } - }, - WindowEvent::ReceivedCharacter(c) - if !is_private_use_character(c) => - { - events.push(Event::Keyboard( - keyboard::Event::CharacterReceived(c), - )); - } - WindowEvent::KeyboardInput { - input: - winit::event::KeyboardInput { - virtual_keycode: Some(virtual_keycode), - state, - .. - }, - .. - } => { - match (virtual_keycode, state) { - ( - winit::event::VirtualKeyCode::F12, - winit::event::ElementState::Pressed, - ) => debug.toggle(), - _ => {} + #[cfg(target_os = "macos")] + WindowEvent::KeyboardInput { + input: + winit::event::KeyboardInput { + virtual_keycode: + Some(winit::event::VirtualKeyCode::Q), + state: winit::event::ElementState::Pressed, + .. + }, + .. + } if modifiers.logo() => { + *control_flow = ControlFlow::Exit; } - - events.push(Event::Keyboard(keyboard::Event::Input { - key_code: conversion::key_code(virtual_keycode), - state: conversion::button_state(state), - })); - } - WindowEvent::CloseRequested => { - *control_flow = ControlFlow::Exit; + #[cfg(feature = "debug")] + WindowEvent::KeyboardInput { + input: + winit::event::KeyboardInput { + virtual_keycode: + Some(winit::event::VirtualKeyCode::F12), + state: winit::event::ElementState::Pressed, + .. + }, + .. + } => debug.toggle(), + _ => {} } - WindowEvent::Resized(size) => { - new_size = Some(size.into()); - log::debug!("Resized: {:?}", new_size); + if let Some(event) = conversion::window_event( + window_event, + size.scale_factor(), + modifiers, + ) { + events.push(event); } - _ => {} - }, + } + event::Event::DeviceEvent { + event: event::DeviceEvent::ModifiersChanged(new_modifiers), + .. + } => { + modifiers = new_modifiers; + } _ => { *control_flow = ControlFlow::Wait; } @@ -334,63 +395,28 @@ pub trait Application: Sized { } } -fn to_physical(size: winit::dpi::LogicalSize, dpi: f64) -> (u16, u16) { - let physical_size = size.to_physical(dpi); - - ( - physical_size.width.round() as u16, - physical_size.height.round() as u16, - ) -} - -fn document<'a, Application>( - application: &'a mut Application, - size: winit::dpi::LogicalSize, +fn build_user_interface<'a, A: Application>( + application: &'a mut A, + cache: Cache, + renderer: &mut <A::Backend as window::Backend>::Renderer, + size: winit::dpi::LogicalSize<f64>, debug: &mut Debug, -) -> Element<'a, Application::Message, Application::Renderer> -where - Application: self::Application, - Application::Message: 'static, -{ +) -> UserInterface<'a, A::Message, <A::Backend as window::Backend>::Renderer> { debug.view_started(); let view = application.view(); debug.view_finished(); - Container::new(view) - .width(Length::Units(size.width.round() as u16)) - .height(Length::Units(size.height.round() as u16)) - .into() -} - -fn spawn<Message: Send>( - command: Command<Message>, - thread_pool: &mut futures::executor::ThreadPool, - proxy: &winit::event_loop::EventLoopProxy<Message>, -) { - use futures::FutureExt; - - let futures = command.futures(); - - for future in futures { - let proxy = proxy.clone(); - - let future = future.map(move |message| { - proxy - .send_event(message) - .expect("Send command result to event loop"); - }); - - thread_pool.spawn_ok(future); - } -} - -// As defined in: http://www.unicode.org/faq/private_use.html -// TODO: Remove once https://github.com/rust-windowing/winit/pull/1254 lands -fn is_private_use_character(c: char) -> bool { - match c { - '\u{E000}'..='\u{F8FF}' - | '\u{F0000}'..='\u{FFFFD}' - | '\u{100000}'..='\u{10FFFD}' => true, - _ => false, - } + debug.layout_started(); + let user_interface = UserInterface::build( + view, + iced_native::Size::new( + size.width.round() as f32, + size.height.round() as f32, + ), + cache, + renderer, + ); + debug.layout_finished(); + + user_interface } diff --git a/winit/src/clipboard.rs b/winit/src/clipboard.rs new file mode 100644 index 00000000..1ff029ab --- /dev/null +++ b/winit/src/clipboard.rs @@ -0,0 +1,19 @@ +/// A buffer for short-term storage and transfer within and between +/// applications. +#[allow(missing_debug_implementations)] +pub struct Clipboard(window_clipboard::Clipboard); + +impl Clipboard { + /// Creates a new [`Clipboard`] for the given window. + /// + /// [`Clipboard`]: struct.Clipboard.html + pub fn new(window: &winit::window::Window) -> Option<Clipboard> { + window_clipboard::Clipboard::new(window).map(Clipboard).ok() + } +} + +impl iced_native::Clipboard for Clipboard { + fn content(&self) -> Option<String> { + self.0.read().ok() + } +} diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 03d583fb..b6a0b64b 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -3,11 +3,107 @@ //! [`winit`]: https://github.com/rust-windowing/winit //! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native use crate::{ - input::{keyboard::KeyCode, mouse, ButtonState}, - MouseCursor, + input::{ + keyboard::{self, KeyCode, ModifiersState}, + mouse, ButtonState, + }, + window, Event, Mode, MouseCursor, }; -/// Convert a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon. +/// Converts a winit window event into an iced event. +pub fn window_event( + event: winit::event::WindowEvent<'_>, + scale_factor: f64, + modifiers: winit::event::ModifiersState, +) -> Option<Event> { + use winit::event::WindowEvent; + + match event { + WindowEvent::Resized(new_size) => { + let logical_size = new_size.to_logical(scale_factor); + + Some(Event::Window(window::Event::Resized { + width: logical_size.width, + height: logical_size.height, + })) + } + WindowEvent::CursorMoved { position, .. } => { + let position = position.to_logical::<f64>(scale_factor); + + Some(Event::Mouse(mouse::Event::CursorMoved { + x: position.x as f32, + y: position.y as f32, + })) + } + WindowEvent::MouseInput { button, state, .. } => { + Some(Event::Mouse(mouse::Event::Input { + button: mouse_button(button), + state: button_state(state), + })) + } + WindowEvent::MouseWheel { delta, .. } => match delta { + winit::event::MouseScrollDelta::LineDelta(delta_x, delta_y) => { + Some(Event::Mouse(mouse::Event::WheelScrolled { + delta: mouse::ScrollDelta::Lines { + x: delta_x, + y: delta_y, + }, + })) + } + winit::event::MouseScrollDelta::PixelDelta(position) => { + Some(Event::Mouse(mouse::Event::WheelScrolled { + delta: mouse::ScrollDelta::Pixels { + x: position.x as f32, + y: position.y as f32, + }, + })) + } + }, + WindowEvent::ReceivedCharacter(c) if !is_private_use_character(c) => { + Some(Event::Keyboard(keyboard::Event::CharacterReceived(c))) + } + WindowEvent::KeyboardInput { + input: + winit::event::KeyboardInput { + virtual_keycode: Some(virtual_keycode), + state, + .. + }, + .. + } => Some(Event::Keyboard(keyboard::Event::Input { + key_code: key_code(virtual_keycode), + state: button_state(state), + modifiers: modifiers_state(modifiers), + })), + WindowEvent::HoveredFile(path) => { + Some(Event::Window(window::Event::FileHovered(path))) + } + WindowEvent::DroppedFile(path) => { + Some(Event::Window(window::Event::FileDropped(path))) + } + WindowEvent::HoveredFileCancelled => { + Some(Event::Window(window::Event::FilesHoveredLeft)) + } + _ => None, + } +} + +/// Converts a [`Mode`] to a [`winit`] fullscreen mode. +/// +/// [`Mode`]: +pub fn fullscreen( + monitor: winit::monitor::MonitorHandle, + mode: Mode, +) -> Option<winit::window::Fullscreen> { + match mode { + Mode::Windowed => None, + Mode::Fullscreen => { + Some(winit::window::Fullscreen::Borderless(monitor)) + } + } +} + +/// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon. /// /// [`winit`]: https://github.com/rust-windowing/winit /// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native @@ -23,7 +119,7 @@ pub fn mouse_cursor(mouse_cursor: MouseCursor) -> winit::window::CursorIcon { } } -/// Convert a `MouseButton` from [`winit`] to an [`iced_native`] mouse button. +/// Converts a `MouseButton` from [`winit`] to an [`iced_native`] mouse button. /// /// [`winit`]: https://github.com/rust-windowing/winit /// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native @@ -36,7 +132,7 @@ pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button { } } -/// Convert an `ElementState` from [`winit`] to an [`iced_native`] button state. +/// Converts an `ElementState` from [`winit`] to an [`iced_native`] button state. /// /// [`winit`]: https://github.com/rust-windowing/winit /// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native @@ -47,7 +143,23 @@ pub fn button_state(element_state: winit::event::ElementState) -> ButtonState { } } -/// Convert a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code. +/// Converts some `ModifiersState` from [`winit`] to an [`iced_native`] +/// modifiers state. +/// +/// [`winit`]: https://github.com/rust-windowing/winit +/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native +pub fn modifiers_state( + modifiers: winit::event::ModifiersState, +) -> ModifiersState { + ModifiersState { + shift: modifiers.shift(), + control: modifiers.ctrl(), + alt: modifiers.alt(), + logo: modifiers.logo(), + } +} + +/// Converts a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code. /// /// [`winit`]: https://github.com/rust-windowing/winit /// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native @@ -220,3 +332,13 @@ pub fn key_code(virtual_keycode: winit::event::VirtualKeyCode) -> KeyCode { winit::event::VirtualKeyCode::Cut => KeyCode::Cut, } } + +// As defined in: http://www.unicode.org/faq/private_use.html +pub(crate) fn is_private_use_character(c: char) -> bool { + match c { + '\u{E000}'..='\u{F8FF}' + | '\u{F0000}'..='\u{FFFFD}' + | '\u{100000}'..='\u{10FFFD}' => true, + _ => false, + } +} diff --git a/winit/src/debug/basic.rs b/winit/src/debug/basic.rs index 67c6d8a2..d46edba6 100644 --- a/winit/src/debug/basic.rs +++ b/winit/src/debug/basic.rs @@ -1,5 +1,4 @@ -use std::collections::VecDeque; -use std::time; +use std::{collections::VecDeque, time}; #[derive(Debug)] pub struct Debug { @@ -146,7 +145,7 @@ impl Debug { let mut lines = Vec::new(); fn key_value<T: std::fmt::Debug>(key: &str, value: T) -> String { - format!("{: <30} {:?}", key, value) + format!("{} {:?}", key, value) } lines.push(format!( diff --git a/winit/src/debug/null.rs b/winit/src/debug/null.rs index 9c809dd4..2a9430cd 100644 --- a/winit/src/debug/null.rs +++ b/winit/src/debug/null.rs @@ -6,8 +6,6 @@ impl Debug { Self } - pub fn toggle(&mut self) {} - pub fn startup_started(&mut self) {} pub fn startup_finished(&mut self) {} diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 00d200f9..f99e1290 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -18,8 +18,8 @@ #![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] -#![deny(unsafe_code)] -#![deny(rust_2018_idioms)] +#![forbid(unsafe_code)] +#![forbid(rust_2018_idioms)] #[doc(no_inline)] pub use iced_native::*; @@ -29,14 +29,24 @@ pub mod conversion; pub mod settings; mod application; - -pub use application::Application; -pub use settings::Settings; +mod clipboard; +mod mode; +mod proxy; +mod size; // We disable debug capabilities on release builds unless the `debug` feature // is explicitly enabled. -#[cfg_attr(feature = "debug", path = "debug/basic.rs")] -#[cfg_attr(not(feature = "debug"), path = "debug/null.rs")] +#[cfg(feature = "debug")] +#[path = "debug/basic.rs"] +mod debug; +#[cfg(not(feature = "debug"))] +#[path = "debug/null.rs"] mod debug; +pub use application::Application; +pub use clipboard::Clipboard; +pub use mode::Mode; +pub use settings::Settings; + use debug::Debug; +use proxy::Proxy; diff --git a/winit/src/mode.rs b/winit/src/mode.rs new file mode 100644 index 00000000..37464711 --- /dev/null +++ b/winit/src/mode.rs @@ -0,0 +1,9 @@ +/// The mode of a window-based application. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Mode { + /// The application appears in its own window. + Windowed, + + /// The application takes the whole screen of its current monitor. + Fullscreen, +} diff --git a/winit/src/proxy.rs b/winit/src/proxy.rs new file mode 100644 index 00000000..cff6ca72 --- /dev/null +++ b/winit/src/proxy.rs @@ -0,0 +1,58 @@ +use iced_native::futures::{ + channel::mpsc, + task::{Context, Poll}, + Sink, +}; +use std::pin::Pin; + +pub struct Proxy<Message: 'static> { + raw: winit::event_loop::EventLoopProxy<Message>, +} + +impl<Message: 'static> Clone for Proxy<Message> { + fn clone(&self) -> Self { + Self { + raw: self.raw.clone(), + } + } +} + +impl<Message: 'static> Proxy<Message> { + pub fn new(raw: winit::event_loop::EventLoopProxy<Message>) -> Self { + Self { raw } + } +} + +impl<Message: 'static> Sink<Message> for Proxy<Message> { + type Error = mpsc::SendError; + + fn poll_ready( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll<Result<(), Self::Error>> { + Poll::Ready(Ok(())) + } + + fn start_send( + self: Pin<&mut Self>, + message: Message, + ) -> Result<(), Self::Error> { + let _ = self.raw.send_event(message); + + Ok(()) + } + + fn poll_flush( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll<Result<(), Self::Error>> { + Poll::Ready(Ok(())) + } + + fn poll_close( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll<Result<(), Self::Error>> { + Poll::Ready(Ok(())) + } +} diff --git a/winit/src/settings.rs b/winit/src/settings.rs deleted file mode 100644 index d257ecd8..00000000 --- a/winit/src/settings.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Configure your application. - -/// The settings of an application. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct Settings { - /// The [`Window`] settings - /// - /// [`Window`]: struct.Window.html - pub window: Window, -} - -/// The window settings of an application. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Window { - /// The size of the window. - pub size: (u32, u32), - - /// Whether the window should be resizable or not. - pub resizable: bool, -} - -impl Default for Window { - fn default() -> Window { - Window { - size: (1024, 768), - resizable: true, - } - } -} diff --git a/winit/src/settings/mod.rs b/winit/src/settings/mod.rs new file mode 100644 index 00000000..b2290b46 --- /dev/null +++ b/winit/src/settings/mod.rs @@ -0,0 +1,53 @@ +//! Configure your application. +#[cfg(target_os = "windows")] +#[path = "windows.rs"] +mod platform; +#[cfg(not(target_os = "windows"))] +#[path = "not_windows.rs"] +mod platform; + +pub use platform::PlatformSpecific; + +/// The settings of an application. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Settings { + /// The [`Window`] settings + /// + /// [`Window`]: struct.Window.html + pub window: Window, +} + +impl Default for Settings { + fn default() -> Settings { + Settings { + window: Window::default(), + } + } +} + +/// The window settings of an application. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Window { + /// The size of the window. + pub size: (u32, u32), + + /// Whether the window should be resizable or not. + pub resizable: bool, + + /// Whether the window should have a border, a title bar, etc. + pub decorations: bool, + + /// Platform specific settings. + pub platform_specific: platform::PlatformSpecific, +} + +impl Default for Window { + fn default() -> Window { + Window { + size: (1024, 768), + resizable: true, + decorations: true, + platform_specific: Default::default(), + } + } +} diff --git a/winit/src/settings/not_windows.rs b/winit/src/settings/not_windows.rs new file mode 100644 index 00000000..5d703f84 --- /dev/null +++ b/winit/src/settings/not_windows.rs @@ -0,0 +1,6 @@ +#![cfg(not(target_os = "windows"))] +//! Platform specific settings for not Windows. + +/// The platform specific window settings of an application. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct PlatformSpecific {} diff --git a/winit/src/settings/windows.rs b/winit/src/settings/windows.rs new file mode 100644 index 00000000..76b8d067 --- /dev/null +++ b/winit/src/settings/windows.rs @@ -0,0 +1,9 @@ +#![cfg(target_os = "windows")] +//! Platform specific settings for Windows. + +/// The platform specific window settings of an application. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct PlatformSpecific { + /// Parent Window + pub parent: Option<winapi::shared::windef::HWND>, +} diff --git a/winit/src/size.rs b/winit/src/size.rs new file mode 100644 index 00000000..7e3056d4 --- /dev/null +++ b/winit/src/size.rs @@ -0,0 +1,30 @@ +pub struct Size { + physical: winit::dpi::PhysicalSize<u32>, + logical: winit::dpi::LogicalSize<f64>, + scale_factor: f64, +} + +impl Size { + pub fn new( + physical: winit::dpi::PhysicalSize<u32>, + scale_factor: f64, + ) -> Size { + Size { + logical: physical.to_logical(scale_factor), + physical, + scale_factor, + } + } + + pub fn physical(&self) -> winit::dpi::PhysicalSize<u32> { + self.physical + } + + pub fn logical(&self) -> winit::dpi::LogicalSize<f64> { + self.logical + } + + pub fn scale_factor(&self) -> f64 { + self.scale_factor + } +} |