Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ And please only add new entries to the top of this list, right below the `# Unre
- On Web, remove unnecessary `Window::is_dark_mode()`, which was replaced with `Window::theme()`.
- On Web, add `WindowBuilderExtWebSys::with_append()` to append the canvas element to the web page on creation.
- On Windows, add `drag_resize_window` method support.
- Add the `platform::popup` module, for a cross-platform strategy for creating popup windows.

# 0.29.0-beta.0

Expand Down
2 changes: 1 addition & 1 deletion FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ Legend:
|Fullscreen toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |**N/A** |
|Exclusive fullscreen |✔️ |✔️ |✔️ |**N/A** |❌ |✔️ |**N/A**|**N/A** |
|HiDPI support |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |❌ |
|Popup windows | |❌ |❌ |❌ |❌ |❌ |**N/A**|**N/A** |
|Popup windows | |❌ |✔ |❌ |❌ |❌ |**N/A**|**N/A** |

### System information
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |Web |Redox OS|
Expand Down
73 changes: 73 additions & 0 deletions examples/window_popup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#[cfg(any(x11_platform, windows_platform))]
#[path = "util/fill.rs"]
mod fill;

#[cfg(any(x11_platform, windows_platform))]
fn main() {
use winit::{
dpi::{LogicalPosition, LogicalSize, Position},
event::{Event, WindowEvent},
event_loop::EventLoop,
platform::popup::WindowBuilderExtPopup,
window::WindowBuilder,
};

let event_loop: EventLoop<()> = EventLoop::new();
let mut parent_window = Some(
WindowBuilder::new()
.with_title("parent window")
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
.with_inner_size(LogicalSize::new(640.0f32, 480.0f32))
.build(&event_loop)
.unwrap(),
);

println!("parent window: {parent_window:?})");

let monitor_size = event_loop.primary_monitor().unwrap().size();
let child_posn = LogicalPosition::new(
(monitor_size.width as f64 - 200.0) / 2.0,
(monitor_size.height as f64 - 200.0) / 2.0,
);
let mut child_window = Some(
WindowBuilder::new()
.with_title("popup window")
.with_inner_size(LogicalSize::new(200.0f32, 200.0f32))
.with_position(Position::Logical(child_posn))
.with_transient_parent(parent_window.as_ref().unwrap())
.build(&event_loop)
.unwrap(),
);

event_loop.run(move |event: Event<'_, ()>, _, control_flow| {
control_flow.set_wait();

if let Event::WindowEvent { event, window_id } = event {
match event {
WindowEvent::CloseRequested
if Some(window_id) == parent_window.as_ref().map(|w| w.id()) =>
{
parent_window.take();
control_flow.set_exit();
}
WindowEvent::CloseRequested
if Some(window_id) == child_window.as_ref().map(|w| w.id()) =>
{
child_window.take();
}
_ => (),
}
} else if let Event::RedrawRequested(wid) = event {
if Some(wid) == parent_window.as_ref().map(|w| w.id()) {
fill::fill_window(parent_window.as_ref().unwrap());
} else if Some(wid) == child_window.as_ref().map(|w| w.id()) {
fill::fill_window(child_window.as_ref().unwrap());
}
}
})
}

#[cfg(not(any(x11_platform, windows_platform)))]
fn main() {
panic!("This example is supported only on x11 and Windows.");
}
3 changes: 3 additions & 0 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ pub mod modifier_supplement;
))]
pub mod run_return;
pub mod scancode;

#[cfg(any(windows_platform, x11_platform))]
pub mod popup;
30 changes: 30 additions & 0 deletions src/platform/popup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//! Extension traits for creating popup windows.

use crate::window::WindowBuilder;
use __private::Sealed;
use raw_window_handle::HasRawWindowHandle;

/// Additional methods on [`WindowBuilder`] to create popup windows.
pub trait WindowBuilderExtPopup: Sealed {
/// Sets this window to be a popup window for the provided parent window.
///
/// This method is only available on Windows and X11. This has no effect on Wayland.
fn with_transient_parent(self, parent: impl HasRawWindowHandle) -> WindowBuilder;
}

impl WindowBuilderExtPopup for WindowBuilder {
fn with_transient_parent(mut self, parent: impl HasRawWindowHandle) -> WindowBuilder {
let hwnd = parent.raw_window_handle();
self.platform_specific.owner = Some(hwnd);
self
}
}

mod __private {
use crate::window::WindowBuilder;

#[doc(hidden)]
pub trait Sealed {}

impl Sealed for WindowBuilder {}
}
7 changes: 6 additions & 1 deletion src/platform/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ pub trait WindowBuilderExtWindows {
/// - An owned window is hidden when its owner is minimized.
///
/// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
#[deprecated = "Use `WindowBuilderExtPopup::with_transient_parent()` instead"]
fn with_owner_window(self, parent: HWND) -> WindowBuilder;

/// Sets a menu on the window to be created.
Expand Down Expand Up @@ -233,7 +234,11 @@ pub trait WindowBuilderExtWindows {
impl WindowBuilderExtWindows for WindowBuilder {
#[inline]
fn with_owner_window(mut self, parent: HWND) -> WindowBuilder {
self.platform_specific.owner = Some(parent);
use raw_window_handle::{RawWindowHandle, Win32WindowHandle};

let mut hwnd = Win32WindowHandle::empty();
hwnd.hwnd = parent as _;
self.platform_specific.owner = Some(RawWindowHandle::Win32(hwnd));
self
}

Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ pub struct PlatformSpecificWindowBuilderAttributes {
pub override_redirect: bool,
#[cfg(x11_platform)]
pub x11_window_types: Vec<XWindowType>,
#[cfg(x11_platform)]
pub owner: Option<RawWindowHandle>,
}

impl Default for PlatformSpecificWindowBuilderAttributes {
Expand All @@ -118,6 +120,8 @@ impl Default for PlatformSpecificWindowBuilderAttributes {
override_redirect: false,
#[cfg(x11_platform)]
x11_window_types: vec![XWindowType::Normal],
#[cfg(x11_platform)]
owner: None,
}
}
}
Expand Down
13 changes: 12 additions & 1 deletion src/platform_impl/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,17 @@ impl UnownedWindow {
),
};

// Set the transient parent if we don't have a parent already.
let owner = if event_loop.root == root {
pl_attribs.owner.map(|owner| match owner {
RawWindowHandle::Xlib(x) => x.window,
RawWindowHandle::Xcb(x) => x.window as u64,
raw => unreachable!("Invalid raw window handle {raw:?} on X11"),
})
} else {
None
};

let window_attributes = {
use xproto::EventMask;

Expand All @@ -258,7 +269,7 @@ impl UnownedWindow {

aux = aux.event_mask(event_mask).border_pixel(0);

if pl_attribs.override_redirect {
if pl_attribs.override_redirect || owner.is_some() {
aux = aux.override_redirect(true as u32);
}

Expand Down
4 changes: 3 additions & 1 deletion src/platform_impl/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ use crate::event::DeviceId as RootDeviceId;
use crate::icon::Icon;
use crate::keyboard::Key;

use raw_window_handle::RawWindowHandle;

#[derive(Clone)]
pub struct PlatformSpecificWindowBuilderAttributes {
pub owner: Option<HWND>,
pub owner: Option<RawWindowHandle>,
pub menu: Option<HMENU>,
pub taskbar_icon: Option<Icon>,
pub no_redirection_bitmap: bool,
Expand Down
5 changes: 3 additions & 2 deletions src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,10 +1140,11 @@ where
}
Some(raw) => unreachable!("Invalid raw window handle {raw:?} on Windows"),
None => match pl_attribs.owner {
Some(parent) => {
Some(RawWindowHandle::Win32(parent)) => {
window_flags.set(WindowFlags::POPUP, true);
Some(parent)
Some(parent.hwnd as _)
}
Some(raw) => unreachable!("Invalid raw window handle {raw:?} on Windows"),
None => {
window_flags.set(WindowFlags::ON_TASKBAR, true);
None
Expand Down