From b1d353180b512acfd534c7f3acc6484a2643d671 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 4 Feb 2021 22:26:33 +0100 Subject: [PATCH] Add ability to assign a menu when creating a window on Windows (#1842) --- CHANGELOG.md | 1 + FEATURES.md | 1 + src/platform/windows.rs | 18 +++++++++++++++++- src/platform_impl/windows/mod.rs | 4 +++- src/platform_impl/windows/window.rs | 6 +++++- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 028730ea..979fba4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - On Windows, fix bug causing mouse capture to not be released. - On Windows, fix fullscreen not preserving minimized/maximized state. - On Android, unimplemented events are marked as unhandled on the native event loop. +- On Windows, added `WindowBuilderExtWindows::with_menu` to set a custom menu at window creation time. - On Android, bump `ndk` and `ndk-glue` to 0.3: use predefined constants for event `ident`. # 0.24.0 (2020-12-09) diff --git a/FEATURES.md b/FEATURES.md index dcd91ed3..4ebb6429 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -116,6 +116,7 @@ If your PR makes notable changes to Winit's features, please update this section ### Windows * Setting the taskbar icon * Setting the parent window +* Setting a menu bar * `WS_EX_NOREDIRECTIONBITMAP` support * Theme the title bar according to Windows 10 Dark Mode setting or set a preferred theme diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 05839d89..dd58d758 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -5,7 +5,7 @@ use std::path::Path; use libc; use winapi::shared::minwindef::WORD; -use winapi::shared::windef::HWND; +use winapi::shared::windef::{HMENU, HWND}; use crate::{ dpi::PhysicalSize, @@ -112,6 +112,16 @@ pub trait WindowBuilderExtWindows { /// Sets a parent to the window to be created. fn with_parent_window(self, parent: HWND) -> WindowBuilder; + /// Sets a menu on the window to be created. + /// + /// Parent and menu are mutually exclusive; a child window cannot have a menu! + /// + /// The menu must have been manually created beforehand with [`winapi::um::winuser::CreateMenu`] or similar. + /// + /// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look. + /// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect. + fn with_menu(self, menu: HMENU) -> WindowBuilder; + /// This sets `ICON_BIG`. A good ceiling here is 256x256. fn with_taskbar_icon(self, taskbar_icon: Option) -> WindowBuilder; @@ -137,6 +147,12 @@ impl WindowBuilderExtWindows for WindowBuilder { self } + #[inline] + fn with_menu(mut self, menu: HMENU) -> WindowBuilder { + self.platform_specific.menu = Some(menu); + self + } + #[inline] fn with_taskbar_icon(mut self, taskbar_icon: Option) -> WindowBuilder { self.platform_specific.taskbar_icon = taskbar_icon; diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 5b3f4e11..d748e6f0 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -1,6 +1,6 @@ #![cfg(target_os = "windows")] -use winapi::{self, shared::windef::HWND}; +use winapi::{self, shared::windef::HMENU, shared::windef::HWND}; pub use self::{ event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}, @@ -18,6 +18,7 @@ use crate::window::Theme; #[derive(Clone)] pub struct PlatformSpecificWindowBuilderAttributes { pub parent: Option, + pub menu: Option, pub taskbar_icon: Option, pub no_redirection_bitmap: bool, pub drag_and_drop: bool, @@ -28,6 +29,7 @@ impl Default for PlatformSpecificWindowBuilderAttributes { fn default() -> Self { Self { parent: None, + menu: None, taskbar_icon: None, no_redirection_bitmap: false, drag_and_drop: true, diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 4684f32a..54389b39 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -711,6 +711,10 @@ unsafe fn init( window_flags.set(WindowFlags::CHILD, pl_attribs.parent.is_some()); window_flags.set(WindowFlags::ON_TASKBAR, true); + if pl_attribs.parent.is_some() && pl_attribs.menu.is_some() { + warn!("Setting a menu on windows that have a parent is unsupported"); + } + // creating the real window this time, by using the functions in `extra_functions` let real_window = { let (style, ex_style) = window_flags.to_window_styles(); @@ -724,7 +728,7 @@ unsafe fn init( winuser::CW_USEDEFAULT, winuser::CW_USEDEFAULT, pl_attribs.parent.unwrap_or(ptr::null_mut()), - ptr::null_mut(), + pl_attribs.menu.unwrap_or(ptr::null_mut()), libloaderapi::GetModuleHandleW(ptr::null()), ptr::null_mut(), );