summaryrefslogtreecommitdiffstats
path: root/winit/src
diff options
context:
space:
mode:
Diffstat (limited to 'winit/src')
-rw-r--r--winit/src/application.rs148
-rw-r--r--winit/src/application/state.rs21
-rw-r--r--winit/src/conversion.rs360
-rw-r--r--winit/src/lib.rs2
-rw-r--r--winit/src/mode.rs3
-rw-r--r--winit/src/position.rs22
-rw-r--r--winit/src/settings.rs71
-rw-r--r--winit/src/settings/macos.rs13
-rw-r--r--winit/src/settings/not_windows.rs6
-rw-r--r--winit/src/settings/other.rs3
-rw-r--r--winit/src/settings/windows.rs16
11 files changed, 611 insertions, 54 deletions
diff --git a/winit/src/application.rs b/winit/src/application.rs
index d7d7660e..b683e592 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -14,6 +14,7 @@ use iced_futures::futures;
use iced_futures::futures::channel::mpsc;
use iced_graphics::window;
use iced_native::program::Program;
+use iced_native::Menu;
use iced_native::{Cache, UserInterface};
use std::mem::ManuallyDrop;
@@ -91,6 +92,20 @@ pub trait Application: Program<Clipboard = Clipboard> {
fn scale_factor(&self) -> f64 {
1.0
}
+
+ /// Returns whether the [`Application`] should be terminated.
+ ///
+ /// By default, it returns `false`.
+ fn should_exit(&self) -> bool {
+ false
+ }
+
+ /// Returns the current system [`Menu`] of the [`Application`].
+ ///
+ /// By default, it returns an empty [`Menu`].
+ fn menu(&self) -> Menu<Self::Message> {
+ Menu::new()
+ }
}
/// Runs an [`Application`] with an executor, compositor, and the provided
@@ -111,8 +126,6 @@ where
let mut debug = Debug::new();
debug.startup_started();
- let (compositor, renderer) = C::new(compositor_settings)?;
-
let event_loop = EventLoop::with_user_event();
let mut runtime = {
@@ -139,20 +152,25 @@ where
&application.title(),
application.mode(),
event_loop.primary_monitor(),
+ settings.id,
)
+ .with_menu(Some(conversion::menu(&application.menu())))
.build(&event_loop)
.map_err(Error::WindowCreationFailed)?;
+ let (compositor, renderer) = C::new(compositor_settings, Some(&window))?;
+
let (mut sender, receiver) = mpsc::unbounded();
let mut instance = Box::pin(run_instance::<A, E, C>(
application,
compositor,
renderer,
- window,
runtime,
debug,
receiver,
+ window,
+ settings.exit_on_close_request,
));
let mut context = task::Context::from_waker(task::noop_waker_ref());
@@ -164,7 +182,22 @@ where
return;
}
- if let Some(event) = event.to_static() {
+ let event = match event {
+ winit::event::Event::WindowEvent {
+ event:
+ winit::event::WindowEvent::ScaleFactorChanged {
+ new_inner_size,
+ ..
+ },
+ window_id,
+ } => Some(winit::event::Event::WindowEvent {
+ event: winit::event::WindowEvent::Resized(*new_inner_size),
+ window_id,
+ }),
+ _ => event.to_static(),
+ };
+
+ if let Some(event) = event {
sender.start_send(event).expect("Send event");
let poll = instance.as_mut().poll(&mut context);
@@ -181,10 +214,11 @@ async fn run_instance<A, E, C>(
mut application: A,
mut compositor: C,
mut renderer: A::Renderer,
- window: winit::window::Window,
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
mut debug: Debug,
mut receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>>,
+ window: winit::window::Window,
+ exit_on_close_request: bool,
) where
A: Application + 'static,
E: Executor + 'static,
@@ -193,20 +227,19 @@ async fn run_instance<A, E, C>(
use iced_futures::futures::stream::StreamExt;
use winit::event;
- let surface = compositor.create_surface(&window);
+ let mut surface = compositor.create_surface(&window);
let mut clipboard = Clipboard::connect(&window);
let mut state = State::new(&application, &window);
let mut viewport_version = state.viewport_version();
- let mut swap_chain = {
- let physical_size = state.physical_size();
- compositor.create_swap_chain(
- &surface,
- physical_size.width,
- physical_size.height,
- )
- };
+ let physical_size = state.physical_size();
+
+ compositor.configure_surface(
+ &mut surface,
+ physical_size.width,
+ physical_size.height,
+ );
let mut user_interface = ManuallyDrop::new(build_user_interface(
&mut application,
@@ -264,6 +297,8 @@ async fn run_instance<A, E, C>(
// Update window
state.synchronize(&application, &window);
+ let should_exit = application.should_exit();
+
user_interface = ManuallyDrop::new(build_user_interface(
&mut application,
cache,
@@ -271,6 +306,10 @@ async fn run_instance<A, E, C>(
state.logical_size(),
&mut debug,
));
+
+ if should_exit {
+ break;
+ }
}
debug.draw_started();
@@ -280,15 +319,30 @@ async fn run_instance<A, E, C>(
window.request_redraw();
}
+ event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
+ event::MacOS::ReceivedUrl(url),
+ )) => {
+ use iced_native::event;
+ events.push(iced_native::Event::PlatformSpecific(
+ event::PlatformSpecific::MacOS(event::MacOS::ReceivedUrl(
+ url,
+ )),
+ ));
+ }
event::Event::UserEvent(message) => {
messages.push(message);
}
event::Event::RedrawRequested(_) => {
+ let physical_size = state.physical_size();
+
+ if physical_size.width == 0 || physical_size.height == 0 {
+ continue;
+ }
+
debug.render_started();
let current_viewport_version = state.viewport_version();
if viewport_version != current_viewport_version {
- let physical_size = state.physical_size();
let logical_size = state.logical_size();
debug.layout_started();
@@ -303,8 +357,8 @@ async fn run_instance<A, E, C>(
.draw(&mut renderer, state.cursor_position());
debug.draw_finished();
- swap_chain = compositor.create_swap_chain(
- &surface,
+ compositor.configure_surface(
+ &mut surface,
physical_size.width,
physical_size.height,
);
@@ -312,33 +366,61 @@ async fn run_instance<A, E, C>(
viewport_version = current_viewport_version;
}
- let new_mouse_interaction = compositor.draw(
+ match compositor.draw(
&mut renderer,
- &mut swap_chain,
+ &mut surface,
state.viewport(),
state.background_color(),
&primitive,
&debug.overlay(),
- );
-
- debug.render_finished();
-
- if new_mouse_interaction != mouse_interaction {
- window.set_cursor_icon(conversion::mouse_interaction(
- new_mouse_interaction,
- ));
-
- mouse_interaction = new_mouse_interaction;
+ ) {
+ Ok(new_mouse_interaction) => {
+ debug.render_finished();
+
+ if new_mouse_interaction != mouse_interaction {
+ window.set_cursor_icon(
+ conversion::mouse_interaction(
+ new_mouse_interaction,
+ ),
+ );
+
+ mouse_interaction = new_mouse_interaction;
+ }
+
+ // TODO: Handle animations!
+ // Maybe we can use `ControlFlow::WaitUntil` for this.
+ }
+ Err(error) => match error {
+ // This is an unrecoverable error.
+ window::SurfaceError::OutOfMemory => {
+ panic!("{}", error);
+ }
+ _ => {
+ debug.render_finished();
+
+ // Try rendering again next frame.
+ window.request_redraw();
+ }
+ },
+ }
+ }
+ event::Event::WindowEvent {
+ event: event::WindowEvent::MenuEntryActivated(entry_id),
+ ..
+ } => {
+ if let Some(message) =
+ conversion::menu_message(state.menu(), entry_id)
+ {
+ messages.push(message);
}
-
- // TODO: Handle animations!
- // Maybe we can use `ControlFlow::WaitUntil` for this.
}
event::Event::WindowEvent {
event: window_event,
..
} => {
- if requests_exit(&window_event, state.modifiers()) {
+ if requests_exit(&window_event, state.modifiers())
+ && exit_on_close_request
+ {
break;
}
diff --git a/winit/src/application/state.rs b/winit/src/application/state.rs
index 46297370..f60f09be 100644
--- a/winit/src/application/state.rs
+++ b/winit/src/application/state.rs
@@ -1,5 +1,5 @@
use crate::conversion;
-use crate::{Application, Color, Debug, Mode, Point, Size, Viewport};
+use crate::{Application, Color, Debug, Menu, Mode, Point, Size, Viewport};
use std::marker::PhantomData;
use winit::event::{Touch, WindowEvent};
@@ -9,6 +9,7 @@ use winit::window::Window;
#[derive(Debug, Clone)]
pub struct State<A: Application> {
title: String,
+ menu: Menu<A::Message>,
mode: Mode,
background_color: Color,
scale_factor: f64,
@@ -23,6 +24,7 @@ impl<A: Application> State<A> {
/// Creates a new [`State`] for the provided [`Application`] and window.
pub fn new(application: &A, window: &Window) -> Self {
let title = application.title();
+ let menu = application.menu();
let mode = application.mode();
let background_color = application.background_color();
let scale_factor = application.scale_factor();
@@ -38,6 +40,7 @@ impl<A: Application> State<A> {
Self {
title,
+ menu,
mode,
background_color,
scale_factor,
@@ -50,6 +53,11 @@ impl<A: Application> State<A> {
}
}
+ /// Returns the current [`Menu`] of the [`State`].
+ pub fn menu(&self) -> &Menu<A::Message> {
+ &self.menu
+ }
+
/// Returns the current background [`Color`] of the [`State`].
pub fn background_color(&self) -> Color {
self.background_color
@@ -182,6 +190,8 @@ impl<A: Application> State<A> {
new_mode,
));
+ window.set_visible(conversion::visible(new_mode));
+
self.mode = new_mode;
}
@@ -201,5 +211,14 @@ impl<A: Application> State<A> {
self.scale_factor = new_scale_factor;
}
+
+ // Update menu
+ let new_menu = application.menu();
+
+ if self.menu != new_menu {
+ window.set_menu(Some(conversion::menu(&new_menu)));
+
+ self.menu = new_menu;
+ }
}
}
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 0e04b35d..8e2dd02d 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -3,10 +3,11 @@
//! [`winit`]: https://github.com/rust-windowing/winit
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
use crate::keyboard;
+use crate::menu::{self, Menu};
use crate::mouse;
use crate::touch;
use crate::window;
-use crate::{Event, Mode, Point};
+use crate::{Event, Mode, Point, Position};
/// Converts a winit window event into an iced event.
pub fn window_event(
@@ -33,6 +34,9 @@ pub fn window_event(
height: logical_size.height,
}))
}
+ WindowEvent::CloseRequested => {
+ Some(Event::Window(window::Event::CloseRequested))
+ }
WindowEvent::CursorMoved { position, .. } => {
let position = position.to_logical::<f64>(scale_factor);
@@ -126,10 +130,59 @@ pub fn window_event(
WindowEvent::Touch(touch) => {
Some(Event::Touch(touch_event(*touch, scale_factor)))
}
+ WindowEvent::Moved(position) => {
+ let winit::dpi::LogicalPosition { x, y } =
+ position.to_logical(scale_factor);
+
+ Some(Event::Window(window::Event::Moved { x, y }))
+ }
_ => None,
}
}
+/// Converts a [`Position`] to a [`winit`] logical position for a given monitor.
+///
+/// [`winit`]: https://github.com/rust-windowing/winit
+pub fn position(
+ monitor: Option<&winit::monitor::MonitorHandle>,
+ (width, height): (u32, u32),
+ position: Position,
+) -> Option<winit::dpi::Position> {
+ match position {
+ Position::Default => None,
+ Position::Specific(x, y) => {
+ Some(winit::dpi::Position::Logical(winit::dpi::LogicalPosition {
+ x: f64::from(x),
+ y: f64::from(y),
+ }))
+ }
+ Position::Centered => {
+ if let Some(monitor) = monitor {
+ let start = monitor.position();
+
+ let resolution: winit::dpi::LogicalSize<f64> =
+ monitor.size().to_logical(monitor.scale_factor());
+
+ let centered: winit::dpi::PhysicalPosition<i32> =
+ winit::dpi::LogicalPosition {
+ x: (resolution.width - f64::from(width)) / 2.0,
+ y: (resolution.height - f64::from(height)) / 2.0,
+ }
+ .to_physical(monitor.scale_factor());
+
+ Some(winit::dpi::Position::Physical(
+ winit::dpi::PhysicalPosition {
+ x: start.x + centered.x,
+ y: start.y + centered.y,
+ },
+ ))
+ } else {
+ None
+ }
+ }
+ }
+}
+
/// Converts a [`Mode`] to a [`winit`] fullscreen mode.
///
/// [`winit`]: https://github.com/rust-windowing/winit
@@ -138,13 +191,125 @@ pub fn fullscreen(
mode: Mode,
) -> Option<winit::window::Fullscreen> {
match mode {
- Mode::Windowed => None,
+ Mode::Windowed | Mode::Hidden => None,
Mode::Fullscreen => {
Some(winit::window::Fullscreen::Borderless(monitor))
}
}
}
+/// Converts a [`Mode`] to a visibility flag.
+pub fn visible(mode: Mode) -> bool {
+ match mode {
+ Mode::Windowed | Mode::Fullscreen => true,
+ Mode::Hidden => false,
+ }
+}
+
+/// Converts a `Hotkey` from [`iced_native`] to a [`winit`] Hotkey.
+///
+/// [`winit`]: https://github.com/rust-windowing/winit
+/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
+fn hotkey(hotkey: keyboard::Hotkey) -> winit::window::Hotkey {
+ use winit::event::ModifiersState;
+
+ let mut modifiers = ModifiersState::empty();
+ modifiers.set(ModifiersState::CTRL, hotkey.modifiers.control());
+ modifiers.set(ModifiersState::SHIFT, hotkey.modifiers.shift());
+ modifiers.set(ModifiersState::ALT, hotkey.modifiers.alt());
+ modifiers.set(ModifiersState::LOGO, hotkey.modifiers.logo());
+
+ winit::window::Hotkey::new(modifiers, to_virtual_keycode(hotkey.key))
+}
+
+/// Converts a `Menu` from [`iced_native`] to a [`winit`] menu.
+///
+/// [`winit`]: https://github.com/rust-windowing/winit
+/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
+pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
+ fn menu_i<Message>(
+ converted: &mut winit::window::Menu,
+ starting_id: u16,
+ menu: &Menu<Message>,
+ ) -> u16 {
+ let mut id = starting_id;
+
+ for item in menu.iter() {
+ match item {
+ menu::Entry::Item { title, hotkey, .. } => {
+ converted.add_item(id, title, hotkey.map(self::hotkey));
+
+ id += 1;
+ }
+ menu::Entry::Dropdown { title, submenu } => {
+ let mut converted_submenu = winit::window::Menu::new();
+ let n_children =
+ menu_i(&mut converted_submenu, id, submenu);
+
+ converted.add_dropdown(title, converted_submenu);
+
+ id += n_children;
+ }
+ menu::Entry::Separator => {
+ converted.add_separator();
+ }
+ }
+ }
+
+ id - starting_id
+ }
+
+ let mut converted = winit::window::Menu::default();
+ let _ = menu_i(&mut converted, 0, menu);
+
+ converted
+}
+
+/// Given a [`Menu`] and an identifier of a [`menu::Entry`], it returns the
+/// `Message` that should be produced when that entry is activated.
+pub fn menu_message<Message>(menu: &Menu<Message>, id: u16) -> Option<Message>
+where
+ Message: Clone,
+{
+ fn find_message<Message>(
+ target: u16,
+ starting_id: u16,
+ menu: &Menu<Message>,
+ ) -> Result<Message, u16>
+ where
+ Message: Clone,
+ {
+ let mut id = starting_id;
+
+ for entry in menu.iter() {
+ match entry {
+ menu::Entry::Item { on_activation, .. } => {
+ if id == target {
+ return Ok(on_activation.clone());
+ }
+
+ id += 1;
+ }
+ menu::Entry::Dropdown { submenu, .. } => {
+ match find_message(target, id, submenu) {
+ Ok(message) => {
+ return Ok(message);
+ }
+ Err(n_children) => {
+ id += n_children;
+ }
+ }
+ }
+ menu::Entry::Separator => {}
+ }
+ }
+
+ Err(id - starting_id)
+ }
+
+ find_message(id, 0, menu).ok()
+}
+
/// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
///
/// [`winit`]: https://github.com/rust-windowing/winit
@@ -192,12 +357,14 @@ pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {
pub fn modifiers(
modifiers: winit::event::ModifiersState,
) -> keyboard::Modifiers {
- keyboard::Modifiers {
- shift: modifiers.shift(),
- control: modifiers.ctrl(),
- alt: modifiers.alt(),
- logo: modifiers.logo(),
- }
+ let mut result = keyboard::Modifiers::empty();
+
+ result.set(keyboard::Modifiers::SHIFT, modifiers.shift());
+ result.set(keyboard::Modifiers::CTRL, modifiers.ctrl());
+ result.set(keyboard::Modifiers::ALT, modifiers.alt());
+ result.set(keyboard::Modifiers::LOGO, modifiers.logo());
+
+ result
}
/// Converts a physical cursor position to a logical `Point`.
@@ -241,6 +408,183 @@ pub fn touch_event(
}
}
+/// Converts a `KeyCode` from [`iced_native`] to an [`winit`] key code.
+///
+/// [`winit`]: https://github.com/rust-windowing/winit
+/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
+fn to_virtual_keycode(
+ keycode: keyboard::KeyCode,
+) -> winit::event::VirtualKeyCode {
+ use keyboard::KeyCode;
+ use winit::event::VirtualKeyCode;
+
+ match keycode {
+ KeyCode::Key1 => VirtualKeyCode::Key1,
+ KeyCode::Key2 => VirtualKeyCode::Key2,
+ KeyCode::Key3 => VirtualKeyCode::Key3,
+ KeyCode::Key4 => VirtualKeyCode::Key4,
+ KeyCode::Key5 => VirtualKeyCode::Key5,
+ KeyCode::Key6 => VirtualKeyCode::Key6,
+ KeyCode::Key7 => VirtualKeyCode::Key7,
+ KeyCode::Key8 => VirtualKeyCode::Key8,
+ KeyCode::Key9 => VirtualKeyCode::Key9,
+ KeyCode::Key0 => VirtualKeyCode::Key0,
+ KeyCode::A => VirtualKeyCode::A,
+ KeyCode::B => VirtualKeyCode::B,
+ KeyCode::C => VirtualKeyCode::C,
+ KeyCode::D => VirtualKeyCode::D,
+ KeyCode::E => VirtualKeyCode::E,
+ KeyCode::F => VirtualKeyCode::F,
+ KeyCode::G => VirtualKeyCode::G,
+ KeyCode::H => VirtualKeyCode::H,
+ KeyCode::I => VirtualKeyCode::I,
+ KeyCode::J => VirtualKeyCode::J,
+ KeyCode::K => VirtualKeyCode::K,
+ KeyCode::L => VirtualKeyCode::L,
+ KeyCode::M => VirtualKeyCode::M,
+ KeyCode::N => VirtualKeyCode::N,
+ KeyCode::O => VirtualKeyCode::O,
+ KeyCode::P => VirtualKeyCode::P,
+ KeyCode::Q => VirtualKeyCode::Q,
+ KeyCode::R => VirtualKeyCode::R,
+ KeyCode::S => VirtualKeyCode::S,
+ KeyCode::T => VirtualKeyCode::T,
+ KeyCode::U => VirtualKeyCode::U,
+ KeyCode::V => VirtualKeyCode::V,
+ KeyCode::W => VirtualKeyCode::W,
+ KeyCode::X => VirtualKeyCode::X,
+ KeyCode::Y => VirtualKeyCode::Y,
+ KeyCode::Z => VirtualKeyCode::Z,
+ KeyCode::Escape => VirtualKeyCode::Escape,
+ KeyCode::F1 => VirtualKeyCode::F1,
+ KeyCode::F2 => VirtualKeyCode::F2,
+ KeyCode::F3 => VirtualKeyCode::F3,
+ KeyCode::F4 => VirtualKeyCode::F4,
+ KeyCode::F5 => VirtualKeyCode::F5,
+ KeyCode::F6 => VirtualKeyCode::F6,
+ KeyCode::F7 => VirtualKeyCode::F7,
+ KeyCode::F8 => VirtualKeyCode::F8,
+ KeyCode::F9 => VirtualKeyCode::F9,
+ KeyCode::F10 => VirtualKeyCode::F10,
+ KeyCode::F11 => VirtualKeyCode::F11,
+ KeyCode::F12 => VirtualKeyCode::F12,
+ KeyCode::F13 => VirtualKeyCode::F13,
+ KeyCode::F14 => VirtualKeyCode::F14,
+ KeyCode::F15 => VirtualKeyCode::F15,
+ KeyCode::F16 => VirtualKeyCode::F16,
+ KeyCode::F17 => VirtualKeyCode::F17,
+ KeyCode::F18 => VirtualKeyCode::F18,
+ KeyCode::F19 => VirtualKeyCode::F19,
+ KeyCode::F20 => VirtualKeyCode::F20,
+ KeyCode::F21 => VirtualKeyCode::F21,
+ KeyCode::F22 => VirtualKeyCode::F22,
+ KeyCode::F23 => VirtualKeyCode::F23,
+ KeyCode::F24 => VirtualKeyCode::F24,
+ KeyCode::Snapshot => VirtualKeyCode::Snapshot,
+ KeyCode::Scroll => VirtualKeyCode::Scroll,
+ KeyCode::Pause => VirtualKeyCode::Pause,
+ KeyCode::Insert => VirtualKeyCode::Insert,
+ KeyCode::Home => VirtualKeyCode::Home,
+ KeyCode::Delete => VirtualKeyCode::Delete,
+ KeyCode::End => VirtualKeyCode::End,
+ KeyCode::PageDown => VirtualKeyCode::PageDown,
+ KeyCode::PageUp => VirtualKeyCode::PageUp,
+ KeyCode::Left => VirtualKeyCode::Left,
+ KeyCode::Up => VirtualKeyCode::Up,
+ KeyCode::Right => VirtualKeyCode::Right,
+ KeyCode::Down => VirtualKeyCode::Down,
+ KeyCode::Backspace => VirtualKeyCode::Back,
+ KeyCode::Enter => VirtualKeyCode::Return,
+ KeyCode::Space => VirtualKeyCode::Space,
+ KeyCode::Compose => VirtualKeyCode::Compose,
+ KeyCode::Caret => VirtualKeyCode::Caret,
+ KeyCode::Numlock => VirtualKeyCode::Numlock,
+ KeyCode::Numpad0 => VirtualKeyCode::Numpad0,
+ KeyCode::Numpad1 => VirtualKeyCode::Numpad1,
+ KeyCode::Numpad2 => VirtualKeyCode::Numpad2,
+ KeyCode::Numpad3 => VirtualKeyCode::Numpad3,
+ KeyCode::Numpad4 => VirtualKeyCode::Numpad4,
+ KeyCode::Numpad5 => VirtualKeyCode::Numpad5,
+ KeyCode::Numpad6 => VirtualKeyCode::Numpad6,
+ KeyCode::Numpad7 => VirtualKeyCode::Numpad7,
+ KeyCode::Numpad8 => VirtualKeyCode::Numpad8,
+ KeyCode::Numpad9 => VirtualKeyCode::Numpad9,
+ KeyCode::AbntC1 => VirtualKeyCode::AbntC1,
+ KeyCode::AbntC2 => VirtualKeyCode::AbntC2,
+ KeyCode::NumpadAdd => VirtualKeyCode::NumpadAdd,
+ KeyCode::Plus => VirtualKeyCode::Plus,
+ KeyCode::Apostrophe => VirtualKeyCode::Apostrophe,
+ KeyCode::Apps => VirtualKeyCode::Apps,
+ KeyCode::At => VirtualKeyCode::At,
+ KeyCode::Ax => VirtualKeyCode::Ax,
+ KeyCode::Backslash => VirtualKeyCode::Backslash,
+ KeyCode::Calculator => VirtualKeyCode::Calculator,
+ KeyCode::Capital => VirtualKeyCode::Capital,
+ KeyCode::Colon => VirtualKeyCode::Colon,
+ KeyCode::Comma => VirtualKeyCode::Comma,
+ KeyCode::Convert => VirtualKeyCode::Convert,
+ KeyCode::NumpadDecimal => VirtualKeyCode::NumpadDecimal,
+ KeyCode::NumpadDivide => VirtualKeyCode::NumpadDivide,
+ KeyCode::Equals => VirtualKeyCode::Equals,
+ KeyCode::Grave => VirtualKeyCode::Grave,
+ KeyCode::Kana => VirtualKeyCode::Kana,
+ KeyCode::Kanji => VirtualKeyCode::Kanji,
+ KeyCode::LAlt => VirtualKeyCode::LAlt,
+ KeyCode::LBracket => VirtualKeyCode::LBracket,
+ KeyCode::LControl => VirtualKeyCode::LControl,
+ KeyCode::LShift => VirtualKeyCode::LShift,
+ KeyCode::LWin => VirtualKeyCode::LWin,
+ KeyCode::Mail => VirtualKeyCode::Mail,
+ KeyCode::MediaSelect => VirtualKeyCode::MediaSelect,
+ KeyCode::MediaStop => VirtualKeyCode::MediaStop,
+ KeyCode::Minus => VirtualKeyCode::Minus,
+ KeyCode::NumpadMultiply => VirtualKeyCode::NumpadMultiply,
+ KeyCode::Mute => VirtualKeyCode::Mute,
+ KeyCode::MyComputer => VirtualKeyCode::MyComputer,
+ KeyCode::NavigateForward => VirtualKeyCode::NavigateForward,
+ KeyCode::NavigateBackward => VirtualKeyCode::NavigateBackward,
+ KeyCode::NextTrack => VirtualKeyCode::NextTrack,
+ KeyCode::NoConvert => VirtualKeyCode::NoConvert,
+ KeyCode::NumpadComma => VirtualKeyCode::NumpadComma,
+ KeyCode::NumpadEnter => VirtualKeyCode::NumpadEnter,
+ KeyCode::NumpadEquals => VirtualKeyCode::NumpadEquals,
+ KeyCode::OEM102 => VirtualKeyCode::OEM102,
+ KeyCode::Period => VirtualKeyCode::Period,
+ KeyCode::PlayPause => VirtualKeyCode::PlayPause,
+ KeyCode::Power => VirtualKeyCode::Power,
+ KeyCode::PrevTrack => VirtualKeyCode::PrevTrack,
+ KeyCode::RAlt => VirtualKeyCode::RAlt,
+ KeyCode::RBracket => VirtualKeyCode::RBracket,
+ KeyCode::RControl => VirtualKeyCode::RControl,
+ KeyCode::RShift => VirtualKeyCode::RShift,
+ KeyCode::RWin => VirtualKeyCode::RWin,
+ KeyCode::Semicolon => VirtualKeyCode::Semicolon,
+ KeyCode::Slash => VirtualKeyCode::Slash,
+ KeyCode::Sleep => VirtualKeyCode::Sleep,
+ KeyCode::Stop => VirtualKeyCode::Stop,
+ KeyCode::NumpadSubtract => VirtualKeyCode::NumpadSubtract,
+ KeyCode::Sysrq => VirtualKeyCode::Sysrq,
+ KeyCode::Tab => VirtualKeyCode::Tab,
+ KeyCode::Underline => VirtualKeyCode::Underline,
+ KeyCode::Unlabeled => VirtualKeyCode::Unlabeled,
+ KeyCode::VolumeDown => VirtualKeyCode::VolumeDown,
+ KeyCode::VolumeUp => VirtualKeyCode::VolumeUp,
+ KeyCode::Wake => VirtualKeyCode::Wake,
+ KeyCode::WebBack => VirtualKeyCode::WebBack,
+ KeyCode::WebFavorites => VirtualKeyCode::WebFavorites,
+ KeyCode::WebForward => VirtualKeyCode::WebForward,
+ KeyCode::WebHome => VirtualKeyCode::WebHome,
+ KeyCode::WebRefresh => VirtualKeyCode::WebRefresh,
+ KeyCode::WebSearch => VirtualKeyCode::WebSearch,
+ KeyCode::WebStop => VirtualKeyCode::WebStop,
+ KeyCode::Yen => VirtualKeyCode::Yen,
+ KeyCode::Copy => VirtualKeyCode::Copy,
+ KeyCode::Paste => VirtualKeyCode::Paste,
+ KeyCode::Cut => VirtualKeyCode::Cut,
+ KeyCode::Asterisk => VirtualKeyCode::Asterisk,
+ }
+}
+
/// Converts a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code.
///
/// [`winit`]: https://github.com/rust-windowing/winit
diff --git a/winit/src/lib.rs b/winit/src/lib.rs
index c9f324dd..1707846a 100644
--- a/winit/src/lib.rs
+++ b/winit/src/lib.rs
@@ -31,12 +31,14 @@ pub mod settings;
mod clipboard;
mod error;
mod mode;
+mod position;
mod proxy;
pub use application::Application;
pub use clipboard::Clipboard;
pub use error::Error;
pub use mode::Mode;
+pub use position::Position;
pub use proxy::Proxy;
pub use settings::Settings;
diff --git a/winit/src/mode.rs b/winit/src/mode.rs
index 37464711..fdce8e23 100644
--- a/winit/src/mode.rs
+++ b/winit/src/mode.rs
@@ -6,4 +6,7 @@ pub enum Mode {
/// The application takes the whole screen of its current monitor.
Fullscreen,
+
+ /// The application is hidden
+ Hidden,
}
diff --git a/winit/src/position.rs b/winit/src/position.rs
new file mode 100644
index 00000000..c260c29e
--- /dev/null
+++ b/winit/src/position.rs
@@ -0,0 +1,22 @@
+/// The position of a window in a given screen.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Position {
+ /// The platform-specific default position for a new window.
+ Default,
+ /// The window is completely centered on the screen.
+ Centered,
+ /// The window is positioned with specific coordinates: `(X, Y)`.
+ ///
+ /// When the decorations of the window are enabled, Windows 10 will add some
+ /// invisible padding to the window. This padding gets included in the
+ /// position. So if you have decorations enabled and want the window to be
+ /// at (0, 0) you would have to set the position to
+ /// `(PADDING_X, PADDING_Y)`.
+ Specific(i32, i32),
+}
+
+impl Default for Position {
+ fn default() -> Self {
+ Self::Default
+ }
+}
diff --git a/winit/src/settings.rs b/winit/src/settings.rs
index 2e8715cd..045cb156 100644
--- a/winit/src/settings.rs
+++ b/winit/src/settings.rs
@@ -2,20 +2,31 @@
#[cfg(target_os = "windows")]
#[path = "settings/windows.rs"]
mod platform;
-#[cfg(not(target_os = "windows"))]
-#[path = "settings/not_windows.rs"]
+
+#[cfg(target_os = "macos")]
+#[path = "settings/macos.rs"]
+mod platform;
+
+#[cfg(not(any(target_os = "windows", target_os = "macos")))]
+#[path = "settings/other.rs"]
mod platform;
pub use platform::PlatformSpecific;
use crate::conversion;
-use crate::Mode;
+use crate::{Mode, Position};
use winit::monitor::MonitorHandle;
use winit::window::WindowBuilder;
/// The settings of an application.
#[derive(Debug, Clone, Default)]
pub struct Settings<Flags> {
+ /// The identifier of the application.
+ ///
+ /// If provided, this identifier may be used to identify the application or
+ /// communicate with it through the windowing system.
+ pub id: Option<String>,
+
/// The [`Window`] settings
pub window: Window,
@@ -23,6 +34,10 @@ pub struct Settings<Flags> {
///
/// [`Application`]: crate::Application
pub flags: Flags,
+
+ /// Whether the [`Application`] should exit when the user requests the
+ /// window to close (e.g. the user presses the close button).
+ pub exit_on_close_request: bool,
}
/// The window settings of an application.
@@ -31,6 +46,9 @@ pub struct Window {
/// The size of the window.
pub size: (u32, u32),
+ /// The position of the window.
+ pub position: Position,
+
/// The minimum size of the window.
pub min_size: Option<(u32, u32)>,
@@ -63,6 +81,7 @@ impl Window {
title: &str,
mode: Mode,
primary_monitor: Option<MonitorHandle>,
+ _id: Option<String>,
) -> WindowBuilder {
let mut window_builder = WindowBuilder::new();
@@ -76,7 +95,15 @@ impl Window {
.with_transparent(self.transparent)
.with_window_icon(self.icon)
.with_always_on_top(self.always_on_top)
- .with_fullscreen(conversion::fullscreen(primary_monitor, mode));
+ .with_visible(conversion::visible(mode));
+
+ if let Some(position) = conversion::position(
+ primary_monitor.as_ref(),
+ self.size,
+ self.position,
+ ) {
+ window_builder = window_builder.with_position(position);
+ }
if let Some((width, height)) = self.min_size {
window_builder = window_builder
@@ -88,6 +115,21 @@ impl Window {
.with_max_inner_size(winit::dpi::LogicalSize { width, height });
}
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ {
+ use ::winit::platform::unix::WindowBuilderExtUnix;
+
+ if let Some(id) = _id {
+ window_builder = window_builder.with_app_id(id);
+ }
+ }
+
#[cfg(target_os = "windows")]
{
use winit::platform::windows::WindowBuilderExtWindows;
@@ -95,8 +137,28 @@ impl Window {
if let Some(parent) = self.platform_specific.parent {
window_builder = window_builder.with_parent_window(parent);
}
+
+ window_builder = window_builder
+ .with_drag_and_drop(self.platform_specific.drag_and_drop);
+ }
+
+ #[cfg(target_os = "macos")]
+ {
+ use winit::platform::macos::WindowBuilderExtMacOS;
+
+ window_builder = window_builder
+ .with_title_hidden(self.platform_specific.title_hidden)
+ .with_titlebar_transparent(
+ self.platform_specific.titlebar_transparent,
+ )
+ .with_fullsize_content_view(
+ self.platform_specific.fullsize_content_view,
+ );
}
+ window_builder = window_builder
+ .with_fullscreen(conversion::fullscreen(primary_monitor, mode));
+
window_builder
}
}
@@ -105,6 +167,7 @@ impl Default for Window {
fn default() -> Window {
Window {
size: (1024, 768),
+ position: Position::default(),
min_size: None,
max_size: None,
resizable: true,
diff --git a/winit/src/settings/macos.rs b/winit/src/settings/macos.rs
new file mode 100644
index 00000000..ad4c8cae
--- /dev/null
+++ b/winit/src/settings/macos.rs
@@ -0,0 +1,13 @@
+#![cfg(target_os = "macos")]
+//! Platform specific settings for macOS.
+
+/// The platform specific window settings of an application.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub struct PlatformSpecific {
+ /// Hides the window title.
+ pub title_hidden: bool,
+ /// Makes the titlebar transparent and allows the content to appear behind it.
+ pub titlebar_transparent: bool,
+ /// Makes the window content appear behind the titlebar.
+ pub fullsize_content_view: bool,
+}
diff --git a/winit/src/settings/not_windows.rs b/winit/src/settings/not_windows.rs
deleted file mode 100644
index 5d703f84..00000000
--- a/winit/src/settings/not_windows.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![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/other.rs b/winit/src/settings/other.rs
new file mode 100644
index 00000000..b1103f62
--- /dev/null
+++ b/winit/src/settings/other.rs
@@ -0,0 +1,3 @@
+/// 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
index 76b8d067..fc26acd7 100644
--- a/winit/src/settings/windows.rs
+++ b/winit/src/settings/windows.rs
@@ -2,8 +2,20 @@
//! Platform specific settings for Windows.
/// The platform specific window settings of an application.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PlatformSpecific {
- /// Parent Window
+ /// Parent window
pub parent: Option<winapi::shared::windef::HWND>,
+
+ /// Drag and drop support
+ pub drag_and_drop: bool,
+}
+
+impl Default for PlatformSpecific {
+ fn default() -> Self {
+ Self {
+ parent: None,
+ drag_and_drop: true,
+ }
+ }
}