use std::sync::Arc;
use winit::event::WindowEvent;
use winit::raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use winit::window::Window;
use uzor::core::types::Rect;
use uzor::platform::PlatformEvent;
use uzor::layout::window::{
CornerStyle, RawHandle, ResizeDirection, RgbaIcon, SoftwarePresenter,
WindowDecorations, WindowProvider,
};
pub struct SendSyncHandlePair(pub RawWindowHandle, pub RawDisplayHandle);
unsafe impl Send for SendSyncHandlePair {}
unsafe impl Sync for SendSyncHandlePair {}
pub struct WinitWindowProvider {
window: Arc<Window>,
pending_events: Vec<PlatformEvent>,
should_close: bool,
}
impl WinitWindowProvider {
pub fn new(window: Arc<Window>) -> Self {
Self {
window,
pending_events: Vec::new(),
should_close: false,
}
}
pub fn push_winit_event(&mut self, event: &WindowEvent) {
use crate::event_mapper::EventMapper;
if let Some(ev) = EventMapper::map_window_event(event) {
self.pending_events.push(ev);
}
}
pub fn mark_close(&mut self) {
self.should_close = true;
}
}
impl WindowProvider for WinitWindowProvider {
fn poll_events(&mut self) -> Vec<PlatformEvent> {
std::mem::take(&mut self.pending_events)
}
fn window_rect(&self) -> Rect {
let size = self.window.inner_size();
let scale = self.window.scale_factor();
Rect::new(
0.0,
0.0,
size.width as f64 / scale,
size.height as f64 / scale,
)
}
fn scale_factor(&self) -> f64 {
self.window.scale_factor()
}
fn request_redraw(&mut self) {
self.window.request_redraw();
}
fn should_close(&self) -> bool {
self.should_close
}
fn drag_window(&mut self) {
let _ = self.window.drag_window();
}
fn drag_resize_window(&mut self, direction: ResizeDirection) {
use winit::window::ResizeDirection as W;
let dir = match direction {
ResizeDirection::North => W::North,
ResizeDirection::South => W::South,
ResizeDirection::East => W::East,
ResizeDirection::West => W::West,
ResizeDirection::NorthEast => W::NorthEast,
ResizeDirection::NorthWest => W::NorthWest,
ResizeDirection::SouthEast => W::SouthEast,
ResizeDirection::SouthWest => W::SouthWest,
};
let _ = self.window.drag_resize_window(dir);
}
fn set_minimized(&mut self, on: bool) {
self.window.set_minimized(on);
}
fn set_maximized(&mut self, on: bool) {
self.window.set_maximized(on);
}
fn is_maximized(&self) -> bool {
self.window.is_maximized()
}
fn request_close(&mut self) {
self.mark_close();
}
fn set_window_icon(&mut self, rgba: Option<RgbaIcon>) {
let icon = rgba.and_then(|i| {
winit::window::Icon::from_rgba(i.pixels, i.width, i.height).ok()
});
self.window.set_window_icon(icon);
}
fn set_title(&mut self, title: &str) {
self.window.set_title(title);
}
fn set_visible(&mut self, visible: bool) {
self.window.set_visible(visible);
}
fn raw_window_handle(&self) -> Option<RawHandle> {
use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
let window_handle = self.window.window_handle().ok()?.as_raw();
let display_handle = self.window.display_handle().ok()?.as_raw();
let pair: Box<dyn std::any::Any + Send + Sync> =
Box::new(SendSyncHandlePair(window_handle, display_handle));
Some(RawHandle::RawWindowHandle(pair))
}
fn create_software_presenter(&self) -> Option<Box<dyn SoftwarePresenter>> {
match WinitSoftbufferPresenter::new(self.window.clone()) {
Ok(p) => Some(Box::new(p)),
Err(e) => {
eprintln!("[uzor-window-desktop] softbuffer presenter init failed: {e}");
None
}
}
}
fn push_platform_event(&mut self, ev: PlatformEvent) {
self.pending_events.push(ev);
}
}
impl WindowDecorations for WinitWindowProvider {
fn set_corner_style(&mut self, style: CornerStyle) {
#[cfg(target_os = "windows")]
if let Some(hwnd) = crate::win_dwm::extract_hwnd(&self.window) {
crate::win_dwm::set_dwm_corner_preference(hwnd, style);
}
#[cfg(target_os = "macos")]
{
let _ = style;
eprintln!(
"[uzor-window-desktop] macOS corner/border decorations not yet implemented"
);
}
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
{
let _ = style;
}
}
fn set_border_color(&mut self, color: Option<u32>) {
#[cfg(target_os = "windows")]
if let Some(hwnd) = crate::win_dwm::extract_hwnd(&self.window) {
crate::win_dwm::set_dwm_border_color(hwnd, color);
}
#[cfg(not(target_os = "windows"))]
{
let _ = color;
}
}
fn set_shadow(&mut self, _on: bool) {}
}
pub struct WinitSoftbufferPresenter {
surface: softbuffer::Surface<Arc<Window>, Arc<Window>>,
}
impl WinitSoftbufferPresenter {
fn new(window: Arc<Window>) -> Result<Self, Box<dyn std::error::Error>> {
let ctx = softbuffer::Context::new(window.clone())
.map_err(|e| format!("softbuffer context: {e:?}"))?;
let surface = softbuffer::Surface::new(&ctx, window)
.map_err(|e| format!("softbuffer surface: {e:?}"))?;
Ok(Self { surface })
}
}
impl SoftwarePresenter for WinitSoftbufferPresenter {
fn resize(&mut self, width: u32, height: u32) {
if let (Some(w), Some(h)) = (
std::num::NonZeroU32::new(width),
std::num::NonZeroU32::new(height),
) {
let _ = self.surface.resize(w, h);
}
}
fn present(&mut self, pixels: &[u8], width: u32, height: u32) {
let (Some(w), Some(h)) = (
std::num::NonZeroU32::new(width),
std::num::NonZeroU32::new(height),
) else {
return;
};
if let Err(e) = self.surface.resize(w, h) {
eprintln!("[uzor-window-desktop] softbuffer resize error: {e:?}");
return;
}
let Ok(mut buf) = self.surface.buffer_mut() else {
return;
};
let n = (width as usize).saturating_mul(height as usize);
let available = pixels.len() / 4;
let count = n.min(available).min(buf.len());
for i in 0..count {
let src = i * 4;
let r = pixels[src] as u32;
let g = pixels[src + 1] as u32;
let b = pixels[src + 2] as u32;
buf[i] = (r << 16) | (g << 8) | b;
}
let _ = buf.present();
}
}