From bb98af80ddb75705fc228fd25f5cb0f1b6f32464 Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Wed, 28 Feb 2024 22:30:25 -0500 Subject: [PATCH 1/4] Separate role-specific methods into their own traits --- winit-core/src/event_loop/mod.rs | 6 ++-- winit-core/src/window.rs | 43 ++++++++++++++++++++------ winit-wayland/examples/window.rs | 10 +++--- winit-wayland/src/event_loop.rs | 2 +- winit-wayland/src/state.rs | 20 ++++++------ winit-wayland/src/window.rs | 52 +++++++++++++++++++------------- 6 files changed, 85 insertions(+), 48 deletions(-) diff --git a/winit-core/src/event_loop/mod.rs b/winit-core/src/event_loop/mod.rs index 84a21c3..3d6f721 100644 --- a/winit-core/src/event_loop/mod.rs +++ b/winit-core/src/event_loop/mod.rs @@ -5,7 +5,7 @@ use raw_window_handle_05::HasRawDisplayHandle as HasRawDisplayHandle05; use crate::application::Application; use crate::monitor::{Monitor, MonitorId}; -use crate::window::{Window, WindowAttributes, WindowId}; +use crate::window::{Surface, WindowAttributes, WindowId}; use self::proxy::EventLoopProxy; @@ -37,9 +37,9 @@ pub trait EventLoopHandle: HasDisplayHandle { fn num_windows(&self) -> usize; - fn get_window(&self, window_id: WindowId) -> Option<&dyn Window>; + fn get_window(&self, window_id: WindowId) -> Option<&dyn Surface>; - fn get_window_mut(&mut self, window_id: WindowId) -> Option<&mut dyn Window>; + fn get_window_mut(&mut self, window_id: WindowId) -> Option<&mut dyn Surface>; fn get_monitor(&self, monitor_id: MonitorId) -> Option<&dyn Monitor>; diff --git a/winit-core/src/window.rs b/winit-core/src/window.rs index 6b3fc62..bbbcbfa 100644 --- a/winit-core/src/window.rs +++ b/winit-core/src/window.rs @@ -1,18 +1,44 @@ // TODO figure out how to do WindowId. +use std::any::Any; + pub use raw_window_handle::HasWindowHandle; pub use raw_window_handle_05::HasRawWindowHandle as HasRawWindowHandle05; -use crate::dpi::{LogicalSize, PhysicalSize, Position, Size}; +use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; use crate::monitor::MonitorId; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct WindowId(pub u128); -/// Common requests to perform on the window. -pub trait Window: HasWindowHandle + HasRawWindowHandle05 { +pub enum WindowRole<'a> { + Toplevel(&'a dyn Toplevel), + Subview(&'a dyn Subview) +} + +pub enum WindowRoleMut<'a> { + Toplevel(&'a mut dyn Toplevel), + Subview(&'a mut dyn Subview) +} + +/// Common API for all rendering targets. +pub trait Surface: HasWindowHandle + HasRawWindowHandle05 { fn id(&self) -> WindowId; + fn scale_factor(&self) -> f64; + + fn request_redraw(&mut self); + + fn inner_size(&self) -> PhysicalSize; + + /// Downcasts this surface to its specific type. + fn role(&self) -> WindowRole; + /// Downcasts this surface to its specific type. Returns a mutable reference. + fn role_mut(&mut self) -> WindowRoleMut; +} + +/// API for toplevel windows and dialogs. +pub trait Toplevel: Surface { /// Gets the current title of the window. fn title(&self) -> &str; @@ -22,12 +48,6 @@ pub trait Window: HasWindowHandle + HasRawWindowHandle05 { fn set_theme(&mut self, theme: Option); - fn scale_factor(&self) -> f64; - - fn request_redraw(&mut self); - - fn inner_size(&self) -> PhysicalSize; - fn set_minimized(&mut self, minimize: bool); fn set_maximized(&mut self, maximized: bool); @@ -37,6 +57,11 @@ pub trait Window: HasWindowHandle + HasRawWindowHandle05 { fn primary_monitor(&self) -> Option; } +/// API for subviews (window style `WS_CHILD` on Windows, `NSView` on MacOS, `wl_subsurface` on Wayland). +pub trait Subview: Surface { + fn set_position(&self, position: PhysicalPosition); +} + /// Attributes to use when creating a window. #[derive(Debug, Clone)] pub struct WindowAttributes { diff --git a/winit-wayland/examples/window.rs b/winit-wayland/examples/window.rs index 2bd4a96..88d053f 100644 --- a/winit-wayland/examples/window.rs +++ b/winit-wayland/examples/window.rs @@ -4,7 +4,7 @@ use std::time::Duration; use winit_core::application::{Application, ApplicationWindow, StartCause}; use winit_core::dpi::PhysicalSize; use winit_core::event_loop::{EventLoopHandle, EventLoopRequests}; -use winit_core::window::WindowId; +use winit_core::window::{Toplevel, WindowId, WindowRole}; use winit_wayland::event_loop::EventLoop; use winit_wayland::MyCoolTrait; @@ -89,9 +89,11 @@ impl ApplicationWindow for State { _ => return, }; - if let Some(monitor_id) = window.current_monitor() { - let monitor = loop_handle.get_monitor(monitor_id).unwrap(); - println!("Current monitor name {:?}", monitor.name()); + if let WindowRole::Toplevel(toplevel) = window.role() { + if let Some(monitor_id) = toplevel.current_monitor() { + let monitor = loop_handle.get_monitor(monitor_id).unwrap(); + println!("Current monitor name {:?}", monitor.name()); + } } let size = window.inner_size(); diff --git a/winit-wayland/src/event_loop.rs b/winit-wayland/src/event_loop.rs index fc8a560..724394b 100644 --- a/winit-wayland/src/event_loop.rs +++ b/winit-wayland/src/event_loop.rs @@ -20,7 +20,7 @@ use sctk::seat::{Capability as SeatCapability, SeatHandler, SeatState}; use winit_core::application::Application; use winit_core::event_loop::proxy::EventLoopProxy as CoreEventLoopProxy; use winit_core::event_loop::{EventLoopHandle, EventLoopRequests}; -use winit_core::window::{Window as CoreWindow, WindowId}; +use winit_core::window::{Surface as CoreSurface, WindowId}; use crate::state::WinitState; use crate::MyCoolTrait; diff --git a/winit-wayland/src/state.rs b/winit-wayland/src/state.rs index 7c6fb8e..2772523 100644 --- a/winit-wayland/src/state.rs +++ b/winit-wayland/src/state.rs @@ -28,8 +28,8 @@ use sctk::subcompositor::SubcompositorState; use winit_core::application::Application; use winit_core::event_loop::proxy::EventLoopProxy as CoreEventLoopProxy; use winit_core::event_loop::EventLoopHandle; -use winit_core::monitor::{Monitor as CoreMonitor, MonitorId}; -use winit_core::window::{Window as CoreWindow, WindowAttributes, WindowId}; +use winit_core::monitor::{Monitor as WinitMonitor, MonitorId}; +use winit_core::window::{Surface as WinitSurface, WindowAttributes, WindowId}; use crate::monitor::Monitor; use crate::window::Window; @@ -52,22 +52,22 @@ impl EventLoopHandle for WinitState { self.windows.len() } - fn get_window(&self, window_id: WindowId) -> Option<&dyn CoreWindow> { + fn get_window(&self, window_id: WindowId) -> Option<&dyn WinitSurface> { let window = self.windows.get(&window_id)?; if window.last_configure.is_none() { return None; } else { - Some(window as &dyn CoreWindow) + Some(window as &dyn WinitSurface) } } - fn get_window_mut(&mut self, window_id: WindowId) -> Option<&mut dyn CoreWindow> { + fn get_window_mut(&mut self, window_id: WindowId) -> Option<&mut dyn WinitSurface> { let window = self.windows.get_mut(&window_id)?; if window.last_configure.is_none() { return None; } else { - Some(window as &mut dyn CoreWindow) + Some(window as &mut dyn WinitSurface) } } @@ -75,15 +75,15 @@ impl EventLoopHandle for WinitState { self.exit = true; } - fn get_monitor(&self, monitor_id: MonitorId) -> Option<&dyn CoreMonitor> { + fn get_monitor(&self, monitor_id: MonitorId) -> Option<&dyn WinitMonitor> { self.monitors .iter() .find(|monitor| monitor.id() == monitor_id) - .map(|monitor| monitor as &dyn CoreMonitor) + .map(|monitor| monitor as &dyn WinitMonitor) } - fn monitors(&self) -> Vec<&dyn CoreMonitor> { - self.monitors.iter().map(|monitor| monitor as &dyn CoreMonitor).collect() + fn monitors(&self) -> Vec<&dyn WinitMonitor> { + self.monitors.iter().map(|monitor| monitor as &dyn WinitMonitor).collect() } } diff --git a/winit-wayland/src/window.rs b/winit-wayland/src/window.rs index 1b70060..fa539d3 100644 --- a/winit-wayland/src/window.rs +++ b/winit-wayland/src/window.rs @@ -23,7 +23,7 @@ use wayland_client::{Connection, QueueHandle}; use winit_core::application::Application; use winit_core::dpi::{LogicalSize, PhysicalSize, Size}; use winit_core::monitor::MonitorId; -use winit_core::window::{Theme, Window as CoreWindow, WindowAttributes, WindowId}; +use winit_core::window::{Surface as WinitSurface, Theme, Toplevel as WinitToplevel, WindowAttributes, WindowId, WindowRole, WindowRoleMut}; use crate::event_loop::RuntimeState; use crate::logical_to_physical_rounded; @@ -295,7 +295,18 @@ impl Window { } } -impl CoreWindow for Window { +impl HasWindowHandle for Window { + fn window_handle(&self) -> Result, HandleError> { + let ptr = self.window.wl_surface().id().as_ptr(); + let handle = WaylandWindowHandle::new({ + std::ptr::NonNull::new(ptr as *mut _).expect("wl_surface should never be null") + }); + + unsafe { Ok(WindowHandle::borrow_raw(handle.into())) } + } +} + +impl WinitSurface for Window { fn id(&self) -> WindowId { crate::make_wid(&self.window.wl_surface()) } @@ -304,6 +315,24 @@ impl CoreWindow for Window { self.redraw = true; } + fn scale_factor(&self) -> f64 { + self.scale_factor + } + + fn inner_size(&self) -> PhysicalSize { + crate::logical_to_physical_rounded(self.size, self.scale_factor) + } + + fn role(&self) -> WindowRole<'_> { + WindowRole::Toplevel(self) + } + + fn role_mut(&mut self) -> WindowRoleMut<'_> { + WindowRoleMut::Toplevel(self) + } +} + +impl WinitToplevel for Window { fn title(&self) -> &str { &self.title } @@ -341,14 +370,6 @@ impl CoreWindow for Window { self.title = title; } - fn scale_factor(&self) -> f64 { - self.scale_factor - } - - fn inner_size(&self) -> PhysicalSize { - crate::logical_to_physical_rounded(self.size, self.scale_factor) - } - fn set_minimized(&mut self, minimize: bool) { if minimize { self.window.set_minimized(); @@ -373,17 +394,6 @@ impl CoreWindow for Window { } } -impl HasWindowHandle for Window { - fn window_handle(&self) -> Result, HandleError> { - let ptr = self.window.wl_surface().id().as_ptr(); - let handle = WaylandWindowHandle::new({ - std::ptr::NonNull::new(ptr as *mut _).expect("wl_surface will never be null") - }); - - unsafe { Ok(WindowHandle::borrow_raw(handle.into())) } - } -} - impl WindowHandler for RuntimeState { fn request_close(&mut self, _: &Connection, _: &QueueHandle, window: &XdgWindow) { let window_id = crate::make_wid(window.wl_surface()); From 30b6efb197bf2c0acb7e6744f8f645f0d9d9235e Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Mon, 22 Apr 2024 14:15:53 -0400 Subject: [PATCH 2/4] refactor window.rs to toplevel.rs --- winit-core/src/window.rs | 2 ++ winit-wayland/src/lib.rs | 2 +- winit-wayland/src/state.rs | 6 +++--- winit-wayland/src/{window.rs => toplevel.rs} | 16 ++++++++++------ 4 files changed, 16 insertions(+), 10 deletions(-) rename winit-wayland/src/{window.rs => toplevel.rs} (97%) diff --git a/winit-core/src/window.rs b/winit-core/src/window.rs index bbbcbfa..0e14a08 100644 --- a/winit-core/src/window.rs +++ b/winit-core/src/window.rs @@ -31,6 +31,8 @@ pub trait Surface: HasWindowHandle + HasRawWindowHandle05 { fn inner_size(&self) -> PhysicalSize; + fn create_subview(&self, attrs: WindowAttributes) -> Box; + /// Downcasts this surface to its specific type. fn role(&self) -> WindowRole; /// Downcasts this surface to its specific type. Returns a mutable reference. diff --git a/winit-wayland/src/lib.rs b/winit-wayland/src/lib.rs index 9e6687f..27935da 100644 --- a/winit-wayland/src/lib.rs +++ b/winit-wayland/src/lib.rs @@ -13,7 +13,7 @@ use winit_core::window::WindowId; pub mod event_loop; pub mod monitor; pub mod state; -pub mod window; +pub mod toplevel; /// Get the WindowId out of the surface. #[inline] diff --git a/winit-wayland/src/state.rs b/winit-wayland/src/state.rs index 2772523..feaeda2 100644 --- a/winit-wayland/src/state.rs +++ b/winit-wayland/src/state.rs @@ -32,7 +32,7 @@ use winit_core::monitor::{Monitor as WinitMonitor, MonitorId}; use winit_core::window::{Surface as WinitSurface, WindowAttributes, WindowId}; use crate::monitor::Monitor; -use crate::window::Window; +use crate::toplevel::Toplevel; use crate::event_loop::{EventLoopProxy, RuntimeState}; @@ -42,7 +42,7 @@ impl EventLoopHandle for WinitState { } fn create_window(&mut self, attributes: &WindowAttributes) -> Result<(), ()> { - let window = Window::new(self, attributes); + let window = Toplevel::new(self, attributes); let window_id = window.id(); self.windows.insert(window_id, window); Ok(()) @@ -130,7 +130,7 @@ pub struct WinitState { /// Currently handled seats. pub seats: HashMap, - pub windows: HashMap>, + pub windows: HashMap>, pub monitors: Vec, diff --git a/winit-wayland/src/window.rs b/winit-wayland/src/toplevel.rs similarity index 97% rename from winit-wayland/src/window.rs rename to winit-wayland/src/toplevel.rs index fa539d3..3803615 100644 --- a/winit-wayland/src/window.rs +++ b/winit-wayland/src/toplevel.rs @@ -38,7 +38,7 @@ type WinitFrame = sctk_adwaita::AdwaitaFrame>; #[cfg(not(feature = "sctk-adwaita"))] type WinitFrame = sctk::shell::xdg::fallback_frame::FallbackFrame; -pub struct Window { +pub struct Toplevel { /// The last received configure. pub last_configure: Option, @@ -98,7 +98,7 @@ pub struct Window { pub window: XdgWindow, } -impl Window { +impl Toplevel { pub fn new(winit: &mut WinitState, attributes: &WindowAttributes) -> Self { let compositor = winit.compositor.clone(); let surface = compositor.create_surface(&winit.queue_handle); @@ -295,7 +295,7 @@ impl Window { } } -impl HasWindowHandle for Window { +impl HasWindowHandle for Toplevel { fn window_handle(&self) -> Result, HandleError> { let ptr = self.window.wl_surface().id().as_ptr(); let handle = WaylandWindowHandle::new({ @@ -306,7 +306,7 @@ impl HasWindowHandle for Window { } } -impl WinitSurface for Window { +impl WinitSurface for Toplevel { fn id(&self) -> WindowId { crate::make_wid(&self.window.wl_surface()) } @@ -330,9 +330,13 @@ impl WinitSurface for Window { fn role_mut(&mut self) -> WindowRoleMut<'_> { WindowRoleMut::Toplevel(self) } + + fn create_subview(&self, attrs: WindowAttributes) -> Box { + todo!() + } } -impl WinitToplevel for Window { +impl WinitToplevel for Toplevel { fn title(&self) -> &str { &self.title } @@ -494,7 +498,7 @@ impl WindowHandler for RuntimeState { } } -unsafe impl HasRawWindowHandle05 for Window { +unsafe impl HasRawWindowHandle05 for Toplevel { fn raw_window_handle(&self) -> raw_window_handle_05::RawWindowHandle { let mut window_handle = raw_window_handle_05::WaylandWindowHandle::empty(); window_handle.surface = self.window.wl_surface().id().as_ptr() as *mut _; From 47c3b3a4b5a666ee8d8df2c75268b368a2cbccf8 Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Sun, 7 Jul 2024 10:55:07 -0400 Subject: [PATCH 3/4] introduce basic popup infrastructure --- winit-core/src/event_loop/mod.rs | 7 +- winit-core/src/window.rs | 129 ++++++++++++++++++-- winit-wayland/examples/window.rs | 41 +++++-- winit-wayland/src/event_loop.rs | 2 +- winit-wayland/src/lib.rs | 2 + winit-wayland/src/popup.rs | 201 +++++++++++++++++++++++++++++++ winit-wayland/src/state.rs | 27 +++-- winit-wayland/src/toplevel.rs | 18 +-- winit-wayland/src/window.rs | 94 +++++++++++++++ 9 files changed, 477 insertions(+), 44 deletions(-) create mode 100644 winit-wayland/src/popup.rs create mode 100644 winit-wayland/src/window.rs diff --git a/winit-core/src/event_loop/mod.rs b/winit-core/src/event_loop/mod.rs index 3d6f721..386910b 100644 --- a/winit-core/src/event_loop/mod.rs +++ b/winit-core/src/event_loop/mod.rs @@ -5,7 +5,7 @@ use raw_window_handle_05::HasRawDisplayHandle as HasRawDisplayHandle05; use crate::application::Application; use crate::monitor::{Monitor, MonitorId}; -use crate::window::{Surface, WindowAttributes, WindowId}; +use crate::window::{PopupAttributes, Surface, WindowAttributes, WindowId}; use self::proxy::EventLoopProxy; @@ -33,7 +33,10 @@ pub trait EventLoopHandle: HasDisplayHandle { fn proxy(&self) -> Arc; /// Request to create a window. - fn create_window(&mut self, attributes: &WindowAttributes) -> Result<(), ()>; + fn create_toplevel(&mut self, attributes: &WindowAttributes) -> Result<(), ()>; + + /// Requests to create a popup. + // fn create_popup(&mut self, parent: WindowId, attributes: &PopupAttributes) -> Result<(), ()>; fn num_windows(&self) -> usize; diff --git a/winit-core/src/window.rs b/winit-core/src/window.rs index 0e14a08..41a31f9 100644 --- a/winit-core/src/window.rs +++ b/winit-core/src/window.rs @@ -5,7 +5,9 @@ use std::any::Any; pub use raw_window_handle::HasWindowHandle; pub use raw_window_handle_05::HasRawWindowHandle as HasRawWindowHandle05; -use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; +use crate::dpi::{ + self, LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size, +}; use crate::monitor::MonitorId; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -13,12 +15,12 @@ pub struct WindowId(pub u128); pub enum WindowRole<'a> { Toplevel(&'a dyn Toplevel), - Subview(&'a dyn Subview) + Popup(&'a dyn Popup), } pub enum WindowRoleMut<'a> { Toplevel(&'a mut dyn Toplevel), - Subview(&'a mut dyn Subview) + Popup(&'a mut dyn Popup), } /// Common API for all rendering targets. @@ -31,8 +33,6 @@ pub trait Surface: HasWindowHandle + HasRawWindowHandle05 { fn inner_size(&self) -> PhysicalSize; - fn create_subview(&self, attrs: WindowAttributes) -> Box; - /// Downcasts this surface to its specific type. fn role(&self) -> WindowRole; /// Downcasts this surface to its specific type. Returns a mutable reference. @@ -59,9 +59,9 @@ pub trait Toplevel: Surface { fn primary_monitor(&self) -> Option; } -/// API for subviews (window style `WS_CHILD` on Windows, `NSView` on MacOS, `wl_subsurface` on Wayland). -pub trait Subview: Surface { - fn set_position(&self, position: PhysicalPosition); +/// API for popups. +pub trait Popup: Surface { + fn set_position(&mut self, position: PhysicalPosition); } /// Attributes to use when creating a window. @@ -318,6 +318,119 @@ impl WindowAttributes { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[repr(u32)] +pub enum AnchorDirection { + Center = 0, + North = 1, + Northeast = 2, + East = 3, + Southeast = 4, + South = 5, + Southwest = 6, + West = 7, + Northwest = 8, +} + +bitflags::bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct AnchorHints: u32 { + const NONE = 0; + const FLIP_X = 1 << 0; + const FLIP_Y = 1 << 1; + const SLIDE_X = 1 << 2; + const SLIDE_Y = 1 << 3; + const RESIZE_X = 1 << 4; + const RESIZE_Y = 1 << 5; + } +} + +#[derive(Debug, Clone)] +pub struct PopupAttributes { + pub inner_size: Size, + pub anchor_rect: (Position, Size), + pub rect_anchor: AnchorDirection, + pub surface_anchor: AnchorDirection, + pub offset: Position, + pub anchor_hints: AnchorHints, +} + +impl Default for PopupAttributes { + fn default() -> Self { + Self { + inner_size: LogicalSize::new(100.0, 75.0).into(), + anchor_rect: ( + LogicalPosition::new(0.0, 0.0).into(), + LogicalSize::new(100.0, 100.0).into(), + ), + rect_anchor: AnchorDirection::Center, + surface_anchor: AnchorDirection::Center, + offset: LogicalPosition::new(0.0, 0.0).into(), + anchor_hints: AnchorHints::NONE, + } + } +} + +impl PopupAttributes { + pub fn inner_size(&self) -> Size { + self.inner_size + } + + pub fn with_inner_size>(mut self, size: S) -> Self { + self.inner_size = size.into(); + self + } + + pub fn anchor_rect(&self) -> (Position, Size) { + self.anchor_rect + } + + pub fn with_anchor_rect, S: Into>( + mut self, + top_left: P, + size: S, + ) -> Self { + self.anchor_rect = (top_left.into(), size.into()); + self + } + + pub fn rect_anchor(&self) -> AnchorDirection { + self.rect_anchor + } + + pub fn with_rect_anchor(mut self, direction: AnchorDirection) -> Self { + self.rect_anchor = direction; + self + } + + pub fn surface_anchor(&self) -> AnchorDirection { + self.surface_anchor + } + + pub fn with_surface_anchor(mut self, direction: AnchorDirection) -> Self { + self.surface_anchor = direction; + self + } + + pub fn offset(&self) -> Position { + self.offset + } + + pub fn with_offset>(mut self, offset: P) -> Self { + self.offset = offset.into(); + self + } + + pub fn anchor_hints(&self) -> AnchorHints { + self.anchor_hints + } + + pub fn with_anchor_hints(mut self, hints: AnchorHints) -> Self { + self.anchor_hints = hints; + self + } +} + /// A window level groups windows with respect to their z-position. /// /// The relative ordering between windows in different window levels is fixed. diff --git a/winit-wayland/examples/window.rs b/winit-wayland/examples/window.rs index 88d053f..fc2ae98 100644 --- a/winit-wayland/examples/window.rs +++ b/winit-wayland/examples/window.rs @@ -11,6 +11,7 @@ use winit_wayland::MyCoolTrait; use softbuffer::{Context, Surface}; const DARK_GRAY: u32 = 0xFF181818; +const ORANGE: u32 = 0xFF_FF8000; pub struct State { context: Context, @@ -39,7 +40,7 @@ impl Application for State { fn new_events(&mut self, loop_handle: &mut dyn EventLoopHandle, start_cause: StartCause) { println!("Start cause {start_cause:?}"); - let _ = loop_handle.create_window(&Default::default()); + let _ = loop_handle.create_toplevel(&Default::default()); } fn about_to_wait(&mut self, _: &mut dyn EventLoopHandle) { @@ -89,19 +90,33 @@ impl ApplicationWindow for State { _ => return, }; - if let WindowRole::Toplevel(toplevel) = window.role() { - if let Some(monitor_id) = toplevel.current_monitor() { - let monitor = loop_handle.get_monitor(monitor_id).unwrap(); - println!("Current monitor name {:?}", monitor.name()); - } + match window.role() { + WindowRole::Toplevel(toplevel) => { + if let Some(monitor_id) = toplevel.current_monitor() { + let monitor = loop_handle.get_monitor(monitor_id).unwrap(); + println!("Current monitor name {:?}", monitor.name()); + } + + let size = window.inner_size(); + let _ = surface.resize( + NonZeroU32::new(size.width).unwrap(), + NonZeroU32::new(size.height).unwrap(), + ); + let mut buffer = surface.buffer_mut().unwrap(); + buffer.fill(DARK_GRAY); + buffer.present().unwrap(); + }, + WindowRole::Popup(popup) => { + let size = window.inner_size(); + let _ = surface.resize( + NonZeroU32::new(size.width).unwrap(), + NonZeroU32::new(size.height).unwrap(), + ); + let mut buffer = surface.buffer_mut().unwrap(); + buffer.fill(ORANGE); + buffer.present().unwrap(); + }, } - - let size = window.inner_size(); - let _ = surface - .resize(NonZeroU32::new(size.width).unwrap(), NonZeroU32::new(size.height).unwrap()); - let mut buffer = surface.buffer_mut().unwrap(); - buffer.fill(DARK_GRAY); - buffer.present().unwrap(); } fn destroyed(&mut self, loop_handle: &mut dyn EventLoopHandle, _: WindowId) { diff --git a/winit-wayland/src/event_loop.rs b/winit-wayland/src/event_loop.rs index 724394b..8b664c0 100644 --- a/winit-wayland/src/event_loop.rs +++ b/winit-wayland/src/event_loop.rs @@ -93,7 +93,7 @@ impl EventLoopRequests for EventLoop { let user = self.state.user.as_mut().unwrap(); for (window_id, window) in &mut winit.windows { - if mem::take(&mut window.redraw) { + if window.take_redraw() { redraw.push(*window_id); } } diff --git a/winit-wayland/src/lib.rs b/winit-wayland/src/lib.rs index 27935da..4c7a945 100644 --- a/winit-wayland/src/lib.rs +++ b/winit-wayland/src/lib.rs @@ -14,6 +14,8 @@ pub mod event_loop; pub mod monitor; pub mod state; pub mod toplevel; +pub mod popup; +pub mod window; /// Get the WindowId out of the surface. #[inline] diff --git a/winit-wayland/src/popup.rs b/winit-wayland/src/popup.rs new file mode 100644 index 0000000..1a04b37 --- /dev/null +++ b/winit-wayland/src/popup.rs @@ -0,0 +1,201 @@ +use std::{marker::PhantomData, ops::Deref, sync::Arc}; + +use raw_window_handle::{HandleError, HasWindowHandle, WaylandWindowHandle, WindowHandle}; +use raw_window_handle_05::HasRawWindowHandle as HasRawWindowHandle05; +use sctk::{compositor::CompositorState, shell::{self, xdg::{popup::{PopupConfigure, PopupHandler, Popup as XdgPopup}, XdgPositioner, XdgSurface}}}; +use wayland_client::Dispatch; +use wayland_protocols::{wp::{fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1, viewporter::client::wp_viewport::WpViewport}, xdg::shell::client::xdg_positioner}; +use winit_core::{application::Application, dpi::Size, window::{AnchorDirection, AnchorHints, PopupAttributes, Surface, Theme, WindowAttributes, WindowId}}; + +use crate::{event_loop::RuntimeState, state::WinitState}; + +pub struct Popup { + /// The last received configure. + pub last_configure: Option, + + pub viewport: Option, + fractional_scale: Option, + + /// The scale factor of the window. + pub scale_factor: f64, + + /// Initial window size provided by the user. Removed on the first + /// configure. + initial_size: Option, + + compositor: Arc, + + /// Whether the window is transparent. + transparent: bool, + + pub redraw: bool, + + // Note, should be the last since it drops the surface. + pub popup: XdgPopup, + + _phantom_tparam_do_not_use: PhantomData +} + +impl Popup { + pub fn new(winit: &mut WinitState, parent: &impl XdgSurface, attributes: &PopupAttributes) -> Self { + let compositor = winit.compositor.clone(); + let surface = compositor.create_surface(&winit.queue_handle); + + let positioner = { + let positioner = XdgPositioner::new(&winit.xdg_shell).unwrap(); + + let anchor_top_left = attributes.anchor_rect().0.to_physical::(1.0); + let anchor_size = attributes.anchor_rect().1.to_physical::(1.0); + positioner.set_anchor_rect(anchor_top_left.x, anchor_top_left.y, anchor_size.width, anchor_size.height); + + let inner_size = attributes.inner_size().to_physical::(1.0); + positioner.set_size(inner_size.width, inner_size.height); + + positioner.set_gravity(to_xdg_positioner_gravity(attributes.surface_anchor())); + positioner.set_anchor(to_xdg_positioner_anchor(attributes.rect_anchor())); + + positioner.set_constraint_adjustment(to_xdg_constraints(attributes.anchor_hints()).bits()); + + positioner + }; + + let popup = XdgPopup::new(parent.xdg_surface(), &positioner.deref(), &winit.queue_handle, &*winit.compositor, &winit.xdg_shell).unwrap(); + let size = attributes.inner_size(); + + Self { + last_configure: None, + viewport: None, + fractional_scale: None, + scale_factor: 1.0, + initial_size: Some(size), + compositor, + transparent: true, + redraw: false, + popup, + _phantom_tparam_do_not_use: PhantomData, + } + } + + pub fn configured(&self) -> bool { + self.last_configure.is_some() + } +} + +impl Surface for Popup { + fn id(&self) -> WindowId { + todo!() + } + + fn scale_factor(&self) -> f64 { + todo!() + } + + fn request_redraw(&mut self) { + todo!() + } + + fn inner_size(&self) -> winit_core::dpi::PhysicalSize { + todo!() + } + + fn role(&self) -> winit_core::window::WindowRole { + todo!() + } + + fn role_mut(&mut self) -> winit_core::window::WindowRoleMut { + todo!() + } +} + +impl HasWindowHandle for Popup { + fn window_handle(&self) -> Result, raw_window_handle::HandleError> { + todo!() + } +} + +unsafe impl HasRawWindowHandle05 for Popup { + fn raw_window_handle(&self) -> raw_window_handle_05::RawWindowHandle { + todo!() + } +} + +impl PopupHandler for RuntimeState { + fn configure( + &mut self, + _: &wayland_client::Connection, + queue_handle: &wayland_client::QueueHandle, + popup: &XdgPopup, + configure: PopupConfigure, + ) { + let winit = &mut self.winit; + let window_id = crate::make_wid(popup.wl_surface()); + } + + fn done(&mut self, conn: &wayland_client::Connection, qh: &wayland_client::QueueHandle, popup: &XdgPopup) { + // nothing + } +} + +impl Dispatch for RuntimeState { + fn event( + state: &mut Self, + proxy: &xdg_positioner::XdgPositioner, + event: ::Event, + data: &U, + conn: &wayland_client::Connection, + qhandle: &wayland_client::QueueHandle, + ) { + // nothing, positioners do not generate events + } +} + +sctk::delegate_xdg_popup!(@ RuntimeState); + +fn to_xdg_positioner_anchor(dir: AnchorDirection) -> xdg_positioner::Anchor { + match dir { + AnchorDirection::Center => xdg_positioner::Anchor::None, + AnchorDirection::North => xdg_positioner::Anchor::Top, + AnchorDirection::Northeast => xdg_positioner::Anchor::TopRight, + AnchorDirection::East => xdg_positioner::Anchor::Right, + AnchorDirection::Southeast => xdg_positioner::Anchor::BottomRight, + AnchorDirection::South => xdg_positioner::Anchor::Bottom, + AnchorDirection::Southwest => xdg_positioner::Anchor::BottomLeft, + AnchorDirection::West => xdg_positioner::Anchor::Left, + AnchorDirection::Northwest => xdg_positioner::Anchor::TopLeft, + } +} +fn to_xdg_positioner_gravity(dir: AnchorDirection) -> xdg_positioner::Gravity { + match dir { + AnchorDirection::Center => xdg_positioner::Gravity::None, + AnchorDirection::North => xdg_positioner::Gravity::Top, + AnchorDirection::Northeast => xdg_positioner::Gravity::TopRight, + AnchorDirection::East => xdg_positioner::Gravity::Right, + AnchorDirection::Southeast => xdg_positioner::Gravity::BottomRight, + AnchorDirection::South => xdg_positioner::Gravity::Bottom, + AnchorDirection::Southwest => xdg_positioner::Gravity::BottomLeft, + AnchorDirection::West => xdg_positioner::Gravity::Left, + AnchorDirection::Northwest => xdg_positioner::Gravity::TopLeft, + } +} +fn to_xdg_constraints(flags: AnchorHints) -> xdg_positioner::ConstraintAdjustment { + let mut res = xdg_positioner::ConstraintAdjustment::None; + if flags.contains(AnchorHints::SLIDE_X) { + res |= xdg_positioner::ConstraintAdjustment::SlideX; + } + if flags.contains(AnchorHints::SLIDE_Y) { + res |= xdg_positioner::ConstraintAdjustment::SlideY; + } + if flags.contains(AnchorHints::FLIP_X) { + res |= xdg_positioner::ConstraintAdjustment::FlipX; + } + if flags.contains(AnchorHints::FLIP_Y) { + res |= xdg_positioner::ConstraintAdjustment::FlipY; + } + if flags.contains(AnchorHints::RESIZE_X) { + res |= xdg_positioner::ConstraintAdjustment::ResizeX; + } + if flags.contains(AnchorHints::RESIZE_Y) { + res |= xdg_positioner::ConstraintAdjustment::ResizeY; + } + res +} \ No newline at end of file diff --git a/winit-wayland/src/state.rs b/winit-wayland/src/state.rs index feaeda2..55b97b2 100644 --- a/winit-wayland/src/state.rs +++ b/winit-wayland/src/state.rs @@ -35,16 +35,17 @@ use crate::monitor::Monitor; use crate::toplevel::Toplevel; use crate::event_loop::{EventLoopProxy, RuntimeState}; +use crate::window::Window; impl EventLoopHandle for WinitState { fn proxy(&self) -> Arc { self.proxy.clone() } - fn create_window(&mut self, attributes: &WindowAttributes) -> Result<(), ()> { + fn create_toplevel(&mut self, attributes: &WindowAttributes) -> Result<(), ()> { let window = Toplevel::new(self, attributes); let window_id = window.id(); - self.windows.insert(window_id, window); + self.windows.insert(window_id, Window::Toplevel(window)); Ok(()) } @@ -55,19 +56,19 @@ impl EventLoopHandle for WinitState { fn get_window(&self, window_id: WindowId) -> Option<&dyn WinitSurface> { let window = self.windows.get(&window_id)?; - if window.last_configure.is_none() { - return None; - } else { + if window.configured() { Some(window as &dyn WinitSurface) + } else { + None } } fn get_window_mut(&mut self, window_id: WindowId) -> Option<&mut dyn WinitSurface> { let window = self.windows.get_mut(&window_id)?; - if window.last_configure.is_none() { - return None; - } else { + if window.configured() { Some(window as &mut dyn WinitSurface) + } else { + None } } @@ -130,7 +131,7 @@ pub struct WinitState { /// Currently handled seats. pub seats: HashMap, - pub windows: HashMap>, + pub windows: HashMap>, pub monitors: Vec, @@ -199,9 +200,13 @@ impl WinitState { ) { let winit = &mut state.winit; let window_id = crate::make_wid(surface); + // let window = match winit.windows.get_mut(&window_id) { + // Some(window) => window, + // None => return, + // }; let window = match winit.windows.get_mut(&window_id) { - Some(window) => window, - None => return, + Some(Window::Toplevel(window)) => window, + _ => return, }; window.set_scale_factor(scale_factor); diff --git a/winit-wayland/src/toplevel.rs b/winit-wayland/src/toplevel.rs index 3803615..83f6a31 100644 --- a/winit-wayland/src/toplevel.rs +++ b/winit-wayland/src/toplevel.rs @@ -23,12 +23,16 @@ use wayland_client::{Connection, QueueHandle}; use winit_core::application::Application; use winit_core::dpi::{LogicalSize, PhysicalSize, Size}; use winit_core::monitor::MonitorId; -use winit_core::window::{Surface as WinitSurface, Theme, Toplevel as WinitToplevel, WindowAttributes, WindowId, WindowRole, WindowRoleMut}; +use winit_core::window::{ + Popup as WinitPopup, Surface as WinitSurface, Theme, Toplevel as WinitToplevel, + WindowAttributes, WindowId, WindowRole, WindowRoleMut, +}; use crate::event_loop::RuntimeState; use crate::logical_to_physical_rounded; use crate::monitor::Monitor; use crate::state::WinitState; +use crate::window::Window; // Minimum window inner size. const MIN_WINDOW_SIZE: LogicalSize = LogicalSize::new(2, 1); @@ -322,18 +326,14 @@ impl WinitSurface for Toplevel { fn inner_size(&self) -> PhysicalSize { crate::logical_to_physical_rounded(self.size, self.scale_factor) } - + fn role(&self) -> WindowRole<'_> { WindowRole::Toplevel(self) } - + fn role_mut(&mut self) -> WindowRoleMut<'_> { WindowRoleMut::Toplevel(self) } - - fn create_subview(&self, attrs: WindowAttributes) -> Box { - todo!() - } } impl WinitToplevel for Toplevel { @@ -420,8 +420,8 @@ impl WindowHandler for RuntimeState { let winit = &mut self.winit; let window_id = crate::make_wid(window.wl_surface()); let window = match winit.windows.get_mut(&window_id) { - Some(window) => window, - None => return, + Some(Window::Toplevel(window)) => window, + _ => return, }; let scale_factor = window.scale_factor; diff --git a/winit-wayland/src/window.rs b/winit-wayland/src/window.rs new file mode 100644 index 0000000..09d2674 --- /dev/null +++ b/winit-wayland/src/window.rs @@ -0,0 +1,94 @@ +use std::mem; + +use raw_window_handle::{HandleError, HasWindowHandle, WaylandWindowHandle, WindowHandle}; +use raw_window_handle_05::HasRawWindowHandle as HasRawWindowHandle05; + +use sctk::shell::xdg::window::WindowConfigure; +use winit_core::{application::Application, window::Surface}; + +use crate::{popup::Popup, toplevel::Toplevel}; + + + +pub(crate) enum Window { + Toplevel(Toplevel), + Popup(Popup) +} + +impl Window { + pub(crate) fn configured(&self) -> bool { + match self { + Window::Toplevel(toplevel) => toplevel.configured(), + Window::Popup(popup) => popup.configured(), + } + } + + pub(crate) fn take_redraw(&mut self) -> bool { + mem::take(match self { + Window::Toplevel(toplevel) => &mut toplevel.redraw, + Window::Popup(popup) => &mut popup.redraw, + }) + } +} + +impl Surface for Window { + fn id(&self) -> winit_core::window::WindowId { + match self { + Window::Toplevel(toplevel) => toplevel.id(), + Window::Popup(popup) => popup.id(), + } + } + + fn scale_factor(&self) -> f64 { + match self { + Window::Toplevel(toplevel) => toplevel.scale_factor(), + Window::Popup(popup) => popup.scale_factor(), + } + } + + fn request_redraw(&mut self) { + match self { + Window::Toplevel(toplevel) => toplevel.request_redraw(), + Window::Popup(popup) => popup.request_redraw(), + } + } + + fn inner_size(&self) -> winit_core::dpi::PhysicalSize { + match self { + Window::Toplevel(toplevel) => toplevel.inner_size(), + Window::Popup(popup) => popup.inner_size(), + } + } + + fn role(&self) -> winit_core::window::WindowRole { + match self { + Window::Toplevel(toplevel) => toplevel.role(), + Window::Popup(popup) => popup.role(), + } + } + + fn role_mut(&mut self) -> winit_core::window::WindowRoleMut { + match self { + Window::Toplevel(toplevel) => toplevel.role_mut(), + Window::Popup(popup) => popup.role_mut(), + } + } +} + +impl HasWindowHandle for Window { + fn window_handle(&self) -> Result, HandleError> { + match self { + Window::Toplevel(toplevel) => toplevel.window_handle(), + Window::Popup(popup) => popup.window_handle(), + } + } +} + +unsafe impl HasRawWindowHandle05 for Window { + fn raw_window_handle(&self) -> raw_window_handle_05::RawWindowHandle { + match self { + Window::Toplevel(toplevel) => toplevel.raw_window_handle(), + Window::Popup(popup) => popup.raw_window_handle(), + } + } +} \ No newline at end of file From 43e38614cccc3422e10f768436222662d82f30bc Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Sun, 7 Jul 2024 17:58:30 -0400 Subject: [PATCH 4/4] implement the create_popup method --- winit-core/src/event_loop/mod.rs | 2 +- winit-core/src/window.rs | 2 +- winit-wayland/src/popup.rs | 161 ++++++++++++++++++++++++------- winit-wayland/src/state.rs | 12 +++ winit-wayland/src/toplevel.rs | 6 +- winit-wayland/src/window.rs | 33 ++++++- 6 files changed, 177 insertions(+), 39 deletions(-) diff --git a/winit-core/src/event_loop/mod.rs b/winit-core/src/event_loop/mod.rs index 386910b..77a3153 100644 --- a/winit-core/src/event_loop/mod.rs +++ b/winit-core/src/event_loop/mod.rs @@ -36,7 +36,7 @@ pub trait EventLoopHandle: HasDisplayHandle { fn create_toplevel(&mut self, attributes: &WindowAttributes) -> Result<(), ()>; /// Requests to create a popup. - // fn create_popup(&mut self, parent: WindowId, attributes: &PopupAttributes) -> Result<(), ()>; + fn create_popup(&mut self, parent: WindowId, attributes: &PopupAttributes) -> Result<(), ()>; fn num_windows(&self) -> usize; diff --git a/winit-core/src/window.rs b/winit-core/src/window.rs index 41a31f9..dbe2966 100644 --- a/winit-core/src/window.rs +++ b/winit-core/src/window.rs @@ -61,7 +61,7 @@ pub trait Toplevel: Surface { /// API for popups. pub trait Popup: Surface { - fn set_position(&mut self, position: PhysicalPosition); + // fn set_position(&mut self, position: PhysicalPosition); } /// Attributes to use when creating a window. diff --git a/winit-wayland/src/popup.rs b/winit-wayland/src/popup.rs index 1a04b37..03e18cd 100644 --- a/winit-wayland/src/popup.rs +++ b/winit-wayland/src/popup.rs @@ -1,13 +1,37 @@ -use std::{marker::PhantomData, ops::Deref, sync::Arc}; +use std::{marker::PhantomData, ops::Deref, ptr::NonNull, sync::Arc}; -use raw_window_handle::{HandleError, HasWindowHandle, WaylandWindowHandle, WindowHandle}; +use raw_window_handle::{ + HandleError, HasWindowHandle, RawWindowHandle, WaylandWindowHandle, WindowHandle, +}; use raw_window_handle_05::HasRawWindowHandle as HasRawWindowHandle05; -use sctk::{compositor::CompositorState, shell::{self, xdg::{popup::{PopupConfigure, PopupHandler, Popup as XdgPopup}, XdgPositioner, XdgSurface}}}; -use wayland_client::Dispatch; -use wayland_protocols::{wp::{fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1, viewporter::client::wp_viewport::WpViewport}, xdg::shell::client::xdg_positioner}; -use winit_core::{application::Application, dpi::Size, window::{AnchorDirection, AnchorHints, PopupAttributes, Surface, Theme, WindowAttributes, WindowId}}; - -use crate::{event_loop::RuntimeState, state::WinitState}; +use sctk::{ + compositor::CompositorState, + shell::{ + self, + xdg::{ + popup::{Popup as XdgPopup, PopupConfigure, PopupHandler}, + XdgPositioner, XdgSurface, + }, + }, +}; +use wayland_client::{Dispatch, Proxy}; +use wayland_protocols::{ + wp::{ + fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1, + viewporter::client::wp_viewport::WpViewport, + }, + xdg::shell::client::xdg_positioner, +}; +use winit_core::{ + application::Application, + dpi::{LogicalSize, PhysicalSize, Size}, + window::{ + AnchorDirection, AnchorHints, Popup as WinitPopup, PopupAttributes, + Surface as WinitSurface, Theme, WindowAttributes, WindowId, WindowRole, WindowRoleMut, + }, +}; + +use crate::{event_loop::RuntimeState, state::WinitState, window::Window}; pub struct Popup { /// The last received configure. @@ -19,6 +43,9 @@ pub struct Popup { /// The scale factor of the window. pub scale_factor: f64, + /// The inner size of the window, as in without client side decorations. + size: LogicalSize, + /// Initial window size provided by the user. Removed on the first /// configure. initial_size: Option, @@ -33,11 +60,17 @@ pub struct Popup { // Note, should be the last since it drops the surface. pub popup: XdgPopup, - _phantom_tparam_do_not_use: PhantomData + _phantom_tparam_do_not_use: PhantomData, } impl Popup { - pub fn new(winit: &mut WinitState, parent: &impl XdgSurface, attributes: &PopupAttributes) -> Self { + pub fn new( + winit: &mut WinitState, + parent: WindowId, + attributes: &PopupAttributes, + ) -> Result { + let parent = winit.windows.get(&parent).ok_or(())?; + let compositor = winit.compositor.clone(); let surface = compositor.create_surface(&winit.queue_handle); @@ -46,7 +79,12 @@ impl Popup { let anchor_top_left = attributes.anchor_rect().0.to_physical::(1.0); let anchor_size = attributes.anchor_rect().1.to_physical::(1.0); - positioner.set_anchor_rect(anchor_top_left.x, anchor_top_left.y, anchor_size.width, anchor_size.height); + positioner.set_anchor_rect( + anchor_top_left.x, + anchor_top_left.y, + anchor_size.width, + anchor_size.height, + ); let inner_size = attributes.inner_size().to_physical::(1.0); positioner.set_size(inner_size.width, inner_size.height); @@ -54,26 +92,35 @@ impl Popup { positioner.set_gravity(to_xdg_positioner_gravity(attributes.surface_anchor())); positioner.set_anchor(to_xdg_positioner_anchor(attributes.rect_anchor())); - positioner.set_constraint_adjustment(to_xdg_constraints(attributes.anchor_hints()).bits()); + positioner + .set_constraint_adjustment(to_xdg_constraints(attributes.anchor_hints()).bits()); positioner }; - let popup = XdgPopup::new(parent.xdg_surface(), &positioner.deref(), &winit.queue_handle, &*winit.compositor, &winit.xdg_shell).unwrap(); + let popup = XdgPopup::new( + parent.xdg_surface(), + &positioner.deref(), + &winit.queue_handle, + &*winit.compositor, + &winit.xdg_shell, + ) + .unwrap(); let size = attributes.inner_size(); - Self { + Ok(Self { last_configure: None, viewport: None, fractional_scale: None, scale_factor: 1.0, + size: size.to_logical(1.0), initial_size: Some(size), compositor, transparent: true, redraw: false, popup, _phantom_tparam_do_not_use: PhantomData, - } + }) } pub fn configured(&self) -> bool { @@ -81,41 +128,54 @@ impl Popup { } } -impl Surface for Popup { +impl WinitSurface for Popup { fn id(&self) -> WindowId { - todo!() + crate::make_wid(self.popup.wl_surface()) } fn scale_factor(&self) -> f64 { - todo!() + self.scale_factor } fn request_redraw(&mut self) { - todo!() + self.redraw = true; } fn inner_size(&self) -> winit_core::dpi::PhysicalSize { - todo!() + crate::logical_to_physical_rounded(self.size, self.scale_factor) } - fn role(&self) -> winit_core::window::WindowRole { - todo!() + fn role(&self) -> WindowRole<'_> { + WindowRole::Popup(self) } - fn role_mut(&mut self) -> winit_core::window::WindowRoleMut { - todo!() + fn role_mut(&mut self) -> WindowRoleMut { + WindowRoleMut::Popup(self) } } +impl WinitPopup for Popup {} + impl HasWindowHandle for Popup { - fn window_handle(&self) -> Result, raw_window_handle::HandleError> { - todo!() + fn window_handle( + &self, + ) -> Result, raw_window_handle::HandleError> { + let ptr = self.popup.wl_surface().id().as_ptr(); + let handle = WaylandWindowHandle::new({ + NonNull::new(ptr as *mut _).expect("wl_surface should never be null") + }); + + unsafe { Ok(WindowHandle::borrow_raw(handle.into())) } } } unsafe impl HasRawWindowHandle05 for Popup { fn raw_window_handle(&self) -> raw_window_handle_05::RawWindowHandle { - todo!() + let ptr = self.popup.wl_surface().id().as_ptr(); + let mut window_handle = raw_window_handle_05::WaylandWindowHandle::empty(); + window_handle.surface = ptr as *mut _; + + raw_window_handle_05::RawWindowHandle::Wayland(window_handle) } } @@ -129,14 +189,51 @@ impl PopupHandler for RuntimeState { ) { let winit = &mut self.winit; let window_id = crate::make_wid(popup.wl_surface()); + let popup = match winit.windows.get_mut(&window_id) { + Some(Window::Popup(window)) => window, + _ => return, + }; + + let scale_factor = popup.scale_factor; + + if let Some(initial_size) = popup.initial_size.take() { + popup.size = initial_size.to_logical(scale_factor); + } + + let user = self.user.as_mut().unwrap(); + let new_size = LogicalSize::::new(configure.width as u32, configure.height as u32); + let initial_configure = popup.last_configure.is_none(); + + if initial_configure { + user.created(winit, window_id); + user.scale_factor_changed(winit, window_id, scale_factor); + } + + user.resized(winit, window_id, crate::logical_to_physical_rounded(new_size, scale_factor)); + + if initial_configure { + user.redraw_requested(winit, window_id); + } } - fn done(&mut self, conn: &wayland_client::Connection, qh: &wayland_client::QueueHandle, popup: &XdgPopup) { - // nothing + fn done( + &mut self, + _: &wayland_client::Connection, + qh: &wayland_client::QueueHandle, + popup: &XdgPopup, + ) { + let winit = &mut self.winit; + let window_id = crate::make_wid(popup.wl_surface()); + let popup = match winit.windows.get_mut(&window_id) { + Some(Window::Popup(window)) => window, + _ => return, + }; + + // todo: figure out what the hell to do here } } -impl Dispatch for RuntimeState { +impl Dispatch for RuntimeState { fn event( state: &mut Self, proxy: &xdg_positioner::XdgPositioner, @@ -149,8 +246,6 @@ impl Dispatch fo } } -sctk::delegate_xdg_popup!(@ RuntimeState); - fn to_xdg_positioner_anchor(dir: AnchorDirection) -> xdg_positioner::Anchor { match dir { AnchorDirection::Center => xdg_positioner::Anchor::None, @@ -198,4 +293,4 @@ fn to_xdg_constraints(flags: AnchorHints) -> xdg_positioner::ConstraintAdjustmen res |= xdg_positioner::ConstraintAdjustment::ResizeY; } res -} \ No newline at end of file +} diff --git a/winit-wayland/src/state.rs b/winit-wayland/src/state.rs index 55b97b2..bb0a369 100644 --- a/winit-wayland/src/state.rs +++ b/winit-wayland/src/state.rs @@ -32,6 +32,7 @@ use winit_core::monitor::{Monitor as WinitMonitor, MonitorId}; use winit_core::window::{Surface as WinitSurface, WindowAttributes, WindowId}; use crate::monitor::Monitor; +use crate::popup::Popup; use crate::toplevel::Toplevel; use crate::event_loop::{EventLoopProxy, RuntimeState}; @@ -49,6 +50,14 @@ impl EventLoopHandle for WinitState { Ok(()) } + // TODO(jgcodes2020): can/should we ensure window type safety here? + fn create_popup(&mut self, parent: WindowId, attributes: &winit_core::window::PopupAttributes) -> Result<(), ()> { + let popup = Popup::new(self, parent, attributes)?; + let popup_id = popup.id(); + self.windows.insert(popup_id, Window::Popup(popup)); + Ok(()) + } + fn num_windows(&self) -> usize { self.windows.len() } @@ -86,6 +95,8 @@ impl EventLoopHandle for WinitState { fn monitors(&self) -> Vec<&dyn WinitMonitor> { self.monitors.iter().map(|monitor| monitor as &dyn WinitMonitor).collect() } + + } impl HasDisplayHandle for WinitState { @@ -307,3 +318,4 @@ sctk::delegate_shm!(@ RuntimeState); sctk::delegate_compositor!(@ RuntimeState); sctk::delegate_xdg_shell!(@ RuntimeState); sctk::delegate_xdg_window!(@ RuntimeState); +sctk::delegate_xdg_popup!(@ RuntimeState); diff --git a/winit-wayland/src/toplevel.rs b/winit-wayland/src/toplevel.rs index 83f6a31..0c3ed6f 100644 --- a/winit-wayland/src/toplevel.rs +++ b/winit-wayland/src/toplevel.rs @@ -472,7 +472,7 @@ impl WindowHandler for RuntimeState { }; let user = self.user.as_mut().unwrap(); - let initial_configue = window.last_configure.is_none(); + let initial_configure = window.last_configure.is_none(); window.last_configure = Some(configure); window.resize(new_size); @@ -485,14 +485,14 @@ impl WindowHandler for RuntimeState { // NOTE: we consider window as created when its initial configure arrives, until // then it's considered as not created and attempt to get it will result in // error. - if initial_configue { + if initial_configure { user.created(winit, window_id); user.scale_factor_changed(winit, window_id, scale_factor); } user.resized(winit, window_id, logical_to_physical_rounded(new_size, scale_factor)); - if initial_configue { + if initial_configure { user.redraw_requested(winit, window_id); } } diff --git a/winit-wayland/src/window.rs b/winit-wayland/src/window.rs index 09d2674..ea48e74 100644 --- a/winit-wayland/src/window.rs +++ b/winit-wayland/src/window.rs @@ -3,7 +3,8 @@ use std::mem; use raw_window_handle::{HandleError, HasWindowHandle, WaylandWindowHandle, WindowHandle}; use raw_window_handle_05::HasRawWindowHandle as HasRawWindowHandle05; -use sctk::shell::xdg::window::WindowConfigure; +use sctk::shell::{xdg::{window::WindowConfigure, XdgSurface}, WaylandSurface}; +use wayland_client::protocol::wl_surface::WlSurface; use winit_core::{application::Application, window::Surface}; use crate::{popup::Popup, toplevel::Toplevel}; @@ -29,6 +30,36 @@ impl Window { Window::Popup(popup) => &mut popup.redraw, }) } + + pub(crate) fn is_xdg_surface(&self) -> bool { + match self { + Window::Toplevel(_) => true, + Window::Popup(_) => true, + #[allow(unreachable_patterns)] + _ => false + } + } +} + +impl WaylandSurface for Window { + fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { + match self { + Window::Toplevel(toplevel) => toplevel.window.wl_surface(), + Window::Popup(popup) => popup.popup.wl_surface(), + } + } +} + +impl XdgSurface for Window { + fn xdg_surface(&self) -> &wayland_protocols::xdg::shell::client::xdg_surface::XdgSurface { + match self { + Window::Toplevel(toplevel) => toplevel.window.xdg_surface(), + Window::Popup(popup) => popup.popup.xdg_surface(), + #[allow(unreachable_patterns)] + _ => panic!("Not an XDG surface") + + } + } } impl Surface for Window {