From 9fc5ad23edca93553137100d167de7b69e88f785 Mon Sep 17 00:00:00 2001
From: Richard <richardsoncusto@gmail.com>
Date: Mon, 5 Jul 2021 16:23:44 -0300
Subject: Initial menu implementation

---
 winit/src/application.rs       |   6 ++
 winit/src/application/state.rs |   2 +
 winit/src/conversion.rs        | 224 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 231 insertions(+), 1 deletion(-)

(limited to 'winit/src')

diff --git a/winit/src/application.rs b/winit/src/application.rs
index 49f2f513..108c6d64 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;
@@ -98,6 +99,11 @@ pub trait Application: Program<Clipboard = Clipboard> {
     fn should_exit(&self) -> bool {
         false
     }
+
+    /// TODO
+    fn menu(&self) -> Menu<Self::Message> {
+        Menu::new()
+    }
 }
 
 /// Runs an [`Application`] with an executor, compositor, and the provided
diff --git a/winit/src/application/state.rs b/winit/src/application/state.rs
index b54d3aed..2994080c 100644
--- a/winit/src/application/state.rs
+++ b/winit/src/application/state.rs
@@ -36,6 +36,8 @@ impl<A: Application> State<A> {
             )
         };
 
+        window.set_menu(Some(conversion::menu(application.menu())));
+
         Self {
             title,
             mode,
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index b850a805..da09ac9d 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -6,7 +6,7 @@ use crate::keyboard;
 use crate::mouse;
 use crate::touch;
 use crate::window;
-use crate::{Event, Mode, Point};
+use crate::{Event, Menu, MenuEntry, Mode, Point};
 
 /// Converts a winit window event into an iced event.
 pub fn window_event(
@@ -156,6 +156,51 @@ pub fn visible(mode: Mode) -> bool {
     }
 }
 
+/// 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 {
+    let mut converted = winit::window::Menu::new();
+
+    for item in menu.iter() {
+        match item {
+            MenuEntry::Item {
+                content, hotkey, ..
+            } => {
+                let hotkey: Option<&keyboard::Hotkey> = hotkey.as_ref().into();
+                converted.add_item(
+                    0,
+                    content,
+                    hotkey.map(|h| self::hotkey(*h)),
+                );
+            }
+            MenuEntry::Dropdown { content, submenu } => {
+                converted.add_dropdown(content, self::menu(submenu));
+            }
+            MenuEntry::Separator => converted.add_separator(),
+        }
+    }
+
+    converted
+}
+
 /// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
 ///
 /// [`winit`]: https://github.com/rust-windowing/winit
@@ -252,6 +297,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
-- 
cgit 


From 1428e9180ae9f4edbf22514bb74c5c7e9df9c712 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Mon, 12 Jul 2021 21:38:54 +0200
Subject: Make `Menu` API a bit more functional

---
 winit/src/conversion.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

(limited to 'winit/src')

diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index da09ac9d..02c21c59 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, Menu, MenuEntry, Mode, Point};
+use crate::{Event, Mode, Point};
 
 /// Converts a winit window event into an iced event.
 pub fn window_event(
@@ -181,7 +182,7 @@ pub fn menu<Message>(menu: Menu<Message>) -> winit::window::Menu {
 
     for item in menu.iter() {
         match item {
-            MenuEntry::Item {
+            menu::Entry::Item {
                 content, hotkey, ..
             } => {
                 let hotkey: Option<&keyboard::Hotkey> = hotkey.as_ref().into();
@@ -191,10 +192,10 @@ pub fn menu<Message>(menu: Menu<Message>) -> winit::window::Menu {
                     hotkey.map(|h| self::hotkey(*h)),
                 );
             }
-            MenuEntry::Dropdown { content, submenu } => {
+            menu::Entry::Dropdown { content, submenu } => {
                 converted.add_dropdown(content, self::menu(submenu));
             }
-            MenuEntry::Separator => converted.add_separator(),
+            menu::Entry::Separator => converted.add_separator(),
         }
     }
 
-- 
cgit 


From b57d567981bb7ef5f9ff397c210778f211d2de5b Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Mon, 12 Jul 2021 22:01:57 +0200
Subject: Use `bitflags` for `keyboard::Modifiers`

---
 winit/src/conversion.rs | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

(limited to 'winit/src')

diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 02c21c59..3aa88c5c 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -165,10 +165,10 @@ 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);
+    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))
 }
@@ -249,12 +249,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`.
-- 
cgit 


From b3ff522c182590ffcd03113b5147fa4599559059 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Mon, 12 Jul 2021 22:11:06 +0200
Subject: Simplify `Hotkey` conversion in `conversion::menu`

---
 winit/src/conversion.rs | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

(limited to 'winit/src')

diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 3aa88c5c..4dc8bbf5 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -185,12 +185,7 @@ pub fn menu<Message>(menu: Menu<Message>) -> winit::window::Menu {
             menu::Entry::Item {
                 content, hotkey, ..
             } => {
-                let hotkey: Option<&keyboard::Hotkey> = hotkey.as_ref().into();
-                converted.add_item(
-                    0,
-                    content,
-                    hotkey.map(|h| self::hotkey(*h)),
-                );
+                converted.add_item(0, content, hotkey.map(self::hotkey));
             }
             menu::Entry::Dropdown { content, submenu } => {
                 converted.add_dropdown(content, self::menu(submenu));
-- 
cgit 


From 31997d255f263a0f47f5af0d8560f3d5bd37f077 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Mon, 12 Jul 2021 22:28:18 +0200
Subject: Store and synchronize `Menu` in `application::State`

---
 winit/src/application.rs       |  1 +
 winit/src/application/state.rs | 21 ++++++++++++++++++---
 winit/src/conversion.rs        |  2 +-
 3 files changed, 20 insertions(+), 4 deletions(-)

(limited to 'winit/src')

diff --git a/winit/src/application.rs b/winit/src/application.rs
index 108c6d64..bf4b2489 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -151,6 +151,7 @@ where
             application.mode(),
             event_loop.primary_monitor(),
         )
+        .with_menu(Some(conversion::menu(&application.menu())))
         .build(&event_loop)
         .map_err(Error::WindowCreationFailed)?;
 
diff --git a/winit/src/application/state.rs b/winit/src/application/state.rs
index 2994080c..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();
@@ -36,10 +38,9 @@ impl<A: Application> State<A> {
             )
         };
 
-        window.set_menu(Some(conversion::menu(application.menu())));
-
         Self {
             title,
+            menu,
             mode,
             background_color,
             scale_factor,
@@ -52,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
@@ -205,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 4dc8bbf5..22118bf5 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -177,7 +177,7 @@ fn hotkey(hotkey: keyboard::Hotkey) -> winit::window::Hotkey {
 ///
 /// [`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 {
+pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
     let mut converted = winit::window::Menu::new();
 
     for item in menu.iter() {
-- 
cgit 


From f3b056a6fc06248aa068549fc47ab6864829b875 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Tue, 13 Jul 2021 20:46:23 +0200
Subject: Generate unique identifiers for entries in `conversion::menu`

---
 winit/src/conversion.rs | 42 ++++++++++++++++++++++++++++++------------
 1 file changed, 30 insertions(+), 12 deletions(-)

(limited to 'winit/src')

diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 22118bf5..3c483086 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -178,22 +178,40 @@ fn hotkey(hotkey: keyboard::Hotkey) -> winit::window::Hotkey {
 /// [`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 {
-    let mut converted = winit::window::Menu::new();
-
-    for item in menu.iter() {
-        match item {
-            menu::Entry::Item {
-                content, hotkey, ..
-            } => {
-                converted.add_item(0, content, hotkey.map(self::hotkey));
-            }
-            menu::Entry::Dropdown { content, submenu } => {
-                converted.add_dropdown(content, self::menu(submenu));
+    fn menu_i<Message>(
+        starting_id: usize,
+        menu: &Menu<Message>,
+    ) -> (winit::window::Menu, usize) {
+        let mut id = starting_id;
+        let mut converted = winit::window::Menu::new();
+
+        for item in menu.iter() {
+            match item {
+                menu::Entry::Item {
+                    content, hotkey, ..
+                } => {
+                    converted.add_item(id, content, hotkey.map(self::hotkey));
+
+                    id += 1;
+                }
+                menu::Entry::Dropdown { content, submenu } => {
+                    let (submenu, n_children) = menu_i(id, submenu);
+
+                    converted.add_dropdown(content, submenu);
+
+                    id += n_children;
+                }
+                menu::Entry::Separator => {
+                    converted.add_separator();
+                }
             }
-            menu::Entry::Separator => converted.add_separator(),
         }
+
+        (converted, id - starting_id)
     }
 
+    let (converted, _) = menu_i(0, menu);
+
     converted
 }
 
-- 
cgit 


From 6221adf2b1b1e8150931d4175e1e36870d45f6e5 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Tue, 13 Jul 2021 20:55:21 +0200
Subject: Draft `conversion::menu_message` in `iced_winit`

... and wire it up to the runtime loop
---
 winit/src/application.rs | 10 ++++++++++
 winit/src/conversion.rs  | 11 +++++++++++
 2 files changed, 21 insertions(+)

(limited to 'winit/src')

diff --git a/winit/src/application.rs b/winit/src/application.rs
index bf4b2489..ada64dfc 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -386,6 +386,16 @@ async fn run_instance<A, E, C>(
                 // TODO: Handle animations!
                 // Maybe we can use `ControlFlow::WaitUntil` for this.
             }
+            event::Event::WindowEvent {
+                event: event::WindowEvent::MenuEntryActivated(entry_id),
+                ..
+            } => {
+                if let Some(message) =
+                    conversion::menu_message(state.menu(), entry_id)
+                {
+                    messages.push(message);
+                }
+            }
             event::Event::WindowEvent {
                 event: window_event,
                 ..
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 3c483086..51db615b 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -215,6 +215,17 @@ pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::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: isize,
+) -> Option<Message> {
+    println!("Menu entry activated: {}", id);
+
+    None
+}
+
 /// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
 ///
 /// [`winit`]: https://github.com/rust-windowing/winit
-- 
cgit 


From 4abaee8b2354a666a75e4eb5ec9cc9a744936813 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Tue, 13 Jul 2021 21:11:13 +0200
Subject: Use `Menu::default` for root level menu in `conversion::menu`

---
 winit/src/conversion.rs | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

(limited to 'winit/src')

diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 51db615b..75419006 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -179,11 +179,11 @@ fn hotkey(hotkey: keyboard::Hotkey) -> winit::window::Hotkey {
 /// [`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: usize,
         menu: &Menu<Message>,
-    ) -> (winit::window::Menu, usize) {
+    ) -> usize {
         let mut id = starting_id;
-        let mut converted = winit::window::Menu::new();
 
         for item in menu.iter() {
             match item {
@@ -195,9 +195,11 @@ pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
                     id += 1;
                 }
                 menu::Entry::Dropdown { content, submenu } => {
-                    let (submenu, n_children) = menu_i(id, submenu);
+                    let mut converted_submenu = winit::window::Menu::new();
+                    let n_children =
+                        menu_i(&mut converted_submenu, id, submenu);
 
-                    converted.add_dropdown(content, submenu);
+                    converted.add_dropdown(content, converted_submenu);
 
                     id += n_children;
                 }
@@ -207,10 +209,11 @@ pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
             }
         }
 
-        (converted, id - starting_id)
+        id - starting_id
     }
 
-    let (converted, _) = menu_i(0, menu);
+    let mut converted = winit::window::Menu::default();
+    let _ = menu_i(&mut converted, 0, menu);
 
     converted
 }
-- 
cgit 


From 5df2a92f28be1d53d32d5b42a6645459b7d78efe Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Tue, 13 Jul 2021 21:15:07 +0200
Subject: Force `Application::Message` to implement `Clone`

A `Message` should represent an application event (e.g. user
interactions, command results, subscription results...). Therefore, it
should always consist of pure, cloneable data.
---
 winit/src/conversion.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'winit/src')

diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 75419006..687a037e 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -223,7 +223,10 @@ pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
 pub fn menu_message<Message>(
     _menu: &Menu<Message>,
     id: isize,
-) -> Option<Message> {
+) -> Option<Message>
+where
+    Message: Clone,
+{
     println!("Menu entry activated: {}", id);
 
     None
-- 
cgit 


From 2e7eac7d2167b492149e064927e764eca67f98fe Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Tue, 13 Jul 2021 21:31:34 +0200
Subject: Implement `conversion::menu_message`

---
 winit/src/conversion.rs | 50 +++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 44 insertions(+), 6 deletions(-)

(limited to 'winit/src')

diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 687a037e..dc7f90ad 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -220,16 +220,54 @@ pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
 
 /// 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: isize,
-) -> Option<Message>
+pub fn menu_message<Message>(menu: &Menu<Message>, id: isize) -> Option<Message>
 where
     Message: Clone,
 {
-    println!("Menu entry activated: {}", id);
+    use std::convert::TryFrom;
 
-    None
+    fn find_message<Message>(
+        target: usize,
+        starting_id: usize,
+        menu: &Menu<Message>,
+    ) -> Result<Message, usize>
+    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)
+    }
+
+    // TODO: Does `winit` really need to provide an `isize`?
+    if let Ok(id) = usize::try_from(id) {
+        find_message(id, 0, menu).ok()
+    } else {
+        None
+    }
 }
 
 /// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
-- 
cgit 


From a2f49a74d08a0cff2e892932b484a88a4034f627 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Mon, 19 Jul 2021 21:01:24 +0700
Subject: Replace `content` with `title` in `menu` module

---
 winit/src/conversion.rs | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

(limited to 'winit/src')

diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index dc7f90ad..e61611aa 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -187,19 +187,17 @@ pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
 
         for item in menu.iter() {
             match item {
-                menu::Entry::Item {
-                    content, hotkey, ..
-                } => {
-                    converted.add_item(id, content, hotkey.map(self::hotkey));
+                menu::Entry::Item { title, hotkey, .. } => {
+                    converted.add_item(id, title, hotkey.map(self::hotkey));
 
                     id += 1;
                 }
-                menu::Entry::Dropdown { content, submenu } => {
+                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(content, converted_submenu);
+                    converted.add_dropdown(title, converted_submenu);
 
                     id += n_children;
                 }
-- 
cgit 


From c8ac77e4e99414746adedf38cf69ac8dcd1601a4 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Mon, 19 Jul 2021 21:05:16 +0700
Subject: Write documentation for `menu` method in `Application`

---
 winit/src/application.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'winit/src')

diff --git a/winit/src/application.rs b/winit/src/application.rs
index ada64dfc..5d1aabf9 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -100,7 +100,9 @@ pub trait Application: Program<Clipboard = Clipboard> {
         false
     }
 
-    /// TODO
+    /// Returns the current system [`Menu`] of the [`Application`].
+    ///
+    /// By default, it returns an empty [`Menu`].
     fn menu(&self) -> Menu<Self::Message> {
         Menu::new()
     }
-- 
cgit 


From 82db3c78b6cfa2cc55ece6ffa46811bfb5195f60 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Tue, 20 Jul 2021 21:34:20 +0700
Subject: Update `winit` and `glutin` dependencies

... and remove crates.io patch
---
 winit/src/conversion.rs | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

(limited to 'winit/src')

diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index e61611aa..5a8b9fd8 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -218,17 +218,15 @@ pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
 
 /// 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: isize) -> Option<Message>
+pub fn menu_message<Message>(menu: &Menu<Message>, id: u32) -> Option<Message>
 where
     Message: Clone,
 {
-    use std::convert::TryFrom;
-
     fn find_message<Message>(
-        target: usize,
-        starting_id: usize,
+        target: u32,
+        starting_id: u32,
         menu: &Menu<Message>,
-    ) -> Result<Message, usize>
+    ) -> Result<Message, u32>
     where
         Message: Clone,
     {
@@ -260,12 +258,7 @@ where
         Err(id - starting_id)
     }
 
-    // TODO: Does `winit` really need to provide an `isize`?
-    if let Ok(id) = usize::try_from(id) {
-        find_message(id, 0, menu).ok()
-    } else {
-        None
-    }
+    find_message(id, 0, menu).ok()
 }
 
 /// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
-- 
cgit