diff options
Diffstat (limited to 'src/window.rs')
-rw-r--r-- | src/window.rs | 177 |
1 files changed, 87 insertions, 90 deletions
diff --git a/src/window.rs b/src/window.rs index 45e37c9..ffe35e8 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,136 +1,133 @@ -mod x11; use crate::*; -use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; + +use std::num::NonZeroU32; use winit::dpi::{Size, PhysicalSize}; use winit::event_loop::EventLoopWindowTarget; -use winit::window::{WindowId, Window as WinitWindow, WindowBuilder as WinitWindowBuilder}; -// use raw_gl_context::{GlConfig, GlContext}; +use winit::window::WindowId; pub struct Window { pub controller: Box<dyn WindowController>, - cursor_position: Option<Point>, - winit_window: WinitWindow, + window: winit::window::Window, buffer: Buffer, dimensions: Dimensions, - /// The most recent render request for this window. - render_hint: RenderHint, - graphics_context: Box<dyn GraphicsContext>, - // gl_context: GlContext, + #[allow(dead_code)] context: softbuffer::Context, + surface: softbuffer::Surface, + current_render_hint: RenderHint, + previous_cursor_position: Option<Point>, } impl Window { - pub unsafe fn new(event_loop: &EventLoopWindowTarget<()>, controller: Box<dyn WindowController>) -> Self { - let mut builder = WinitWindowBuilder::new(); - builder = builder.with_resizable(controller.resizable()); - builder = builder.with_inner_size({ - let dim = controller.initial_dimensions(); - Size::Physical(PhysicalSize::new(dim.width, dim.height)) - }); - if let Some(dim) = controller.minimum_dimensions() { - let size = Size::Physical(PhysicalSize { width: dim.width, height: dim.height }); - builder = builder.with_min_inner_size(size); - } - if let Some(dim) = controller.maximum_dimensions() { - let size = Size::Physical(PhysicalSize { width: dim.width, height: dim.height }); - builder = builder.with_max_inner_size(size); - } - let winit_window = builder.build(event_loop).unwrap(); + pub fn new(event_loop: &EventLoopWindowTarget<()>, controller: Box<dyn WindowController>) -> Self { + let window = winit::window::WindowBuilder::new() + .with_title(controller.title()) + .with_resizable(controller.is_resizable()) + .with_inner_size(dim_to_size(controller.initial_size())) + .build(event_loop) + .unwrap(); + + let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); + let surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); - let graphics_context: Box<dyn GraphicsContext> = match winit_window.raw_window_handle() { - RawWindowHandle::Xlib(xlib_handle) => Box::new(x11::X11GraphicsContext::new(xlib_handle)), - _ => panic!("Unknown window handle type"), - }; - // let gl_context = GlContext::create(&winit_window, GlConfig::default()).unwrap(); - // gl_context.make_current(); - // gl::load_with(|symbol| { - // println!("Loaded '{}'", symbol); - // gl_context.get_proc_address(symbol) as *const _ - // }); Self { - winit_window, controller, - graphics_context, - render_hint: RenderHint::Redraw, - // gl_context, + window, buffer: Buffer::new(Dimensions::ZERO), dimensions: Dimensions::ZERO, - cursor_position: None, + context, + surface, + previous_cursor_position: None, + current_render_hint: RenderHint::Redraw, } } pub fn id(&self) -> WindowId { - self.winit_window.id() + self.window.id() } - pub fn set_minimum_dimensions(&mut self, dimensions: Option<Dimensions>) { - self.winit_window.set_min_inner_size(dimensions.map(|dim| { - Size::Physical(PhysicalSize { width:dim.width, height:dim.height }) - })) + pub fn update_title(&mut self) { + self.window.set_title(&self.controller.title()); } - pub fn set_maximum_dimensions(&mut self, dimensions: Option<Dimensions>) { - self.winit_window.set_max_inner_size(dimensions.map(|dim| { - Size::Physical(PhysicalSize { width:dim.width, height:dim.height }) - })) + + pub fn update_cursor_icon(&mut self) { + let icon = self.controller.cursor_icon().unwrap_or(CursorIcon::Default); + self.window.set_cursor_icon(icon); } - pub fn set_title(&mut self, title: &str) { - self.winit_window.set_title(title); + + pub fn update_minimum_size(&mut self) { + let size = self.controller.minimum_size().map(|d| dim_to_size(d)); + self.window.set_min_inner_size(size); } - /// Call to update the frame buffer to the new size of the window. - pub fn resize_buffer(&mut self, dimensions: Dimensions) { - if self.dimensions == dimensions { return } - self.dimensions = dimensions; - self.buffer.resize(dimensions); - self.controller.on_resize(dimensions); - self.render_hint = RenderHint::Redraw; + pub fn update_maximum_size(&mut self) { + let size = self.controller.maximum_size().map(|d| dim_to_size(d)); + self.window.set_max_inner_size(size); } - pub fn set_cursor_icon(&mut self, icon: Option<CursorIcon>) { - match icon { - Some(icon) => self.winit_window.set_cursor_icon(icon), - None => self.winit_window.set_cursor_icon(CursorIcon::Default), - }; + pub fn update_cursor_visible(&mut self) { + self.window.set_cursor_visible(self.controller.is_cursor_visible()); } - /// Call this after a mouse click so that the cursor-hovering callbacks are - /// rerun. This is useful where a click changes the UI layout and a new - /// element that has an on-hover effect appears beneath the cursor. - pub fn bump_mouse(&mut self) { - if let Some(position) = self.cursor_position { - self.controller.on_mouse_move(position) + pub fn update_resizable(&mut self) { + let is_resizable = self.controller.is_resizable(); + self.window.set_resizable(is_resizable); + // Hack to force window to be impossible to resize on DWM, where the + // 'is_resizable' window attribute isn't respected. + if !is_resizable { + self.window.set_min_inner_size(Some(self.window.inner_size())); + self.window.set_max_inner_size(Some(self.window.inner_size())); } } - pub fn move_mouse(&mut self, position: Point) { - if self.cursor_position != Some(position) { - self.cursor_position = Some(position); - self.controller.on_mouse_move(position); + /// Resize the frame buffer to be the new size of the window. + pub fn resize(&mut self, dimensions: Dimensions) { + if self.dimensions == dimensions { return } + self.dimensions = dimensions; + self.buffer.resize(dimensions); + if let Some((width, height)) = dim_to_nonzero_size(dimensions) { + self.surface.resize(width, height).unwrap(); + }; + self.controller.on_resize(dimensions); + self.current_render_hint = RenderHint::Redraw; + } + + pub fn move_cursor(&mut self, position: Point) { + // The cursor position is rounded to i32 from f64, so we need to ignore + // duplicate consecutive cursor positions. + if self.previous_cursor_position != Some(position) { + self.previous_cursor_position = Some(position); + self.controller.on_cursor_move(position); } } - pub fn check_render_request(&mut self) { + pub fn handle_render_request(&mut self) { if let RenderRequest::Render(hint) = self.controller.render_request() { - self.render_hint &= hint; - self.winit_window.request_redraw(); + self.current_render_hint &= hint; + self.window.request_redraw(); } } pub fn render(&mut self) { - self.controller.render(&mut self.buffer, self.render_hint); - unsafe { self.graphics_context.blit(&self.buffer); } - // Reset the render_hint back to the lowest variant. - self.render_hint = RenderHint::Update; + let size = self.window.inner_size(); + let dim = Dimensions::new(size.width, size.height); + self.resize(dim); + self.controller.on_render(&mut self.buffer, self.current_render_hint); + let buffer = self.buffer.as_u32_slice(); + let mut surface = self.surface.buffer_mut().unwrap(); + let buffer_len = buffer.len(); + let surface_len = surface.len(); + surface[..buffer_len].copy_from_slice(&buffer[..surface_len]); + surface.present().unwrap(); + // Reset current_render_hint back to the lowest variant for the next frame. + self.current_render_hint = RenderHint::Update; } +} - // pub fn render_gl(&mut self) { - // self.gl_context.make_current(); - // self.controller.render_gl(&mut self.gl_context); - // self.gl_context.swap_buffers(); - // self.gl_context.make_not_current(); - // } +fn dim_to_size(dimensions: Dimensions) -> Size { + Size::Physical( PhysicalSize { width:dimensions.width, height:dimensions.height }) } -trait GraphicsContext { - /// Fill the graphics context with the contents of the provided buffer. - unsafe fn blit(&mut self, buffer: &Buffer); +fn dim_to_nonzero_size(dimensions: Dimensions) -> Option<(NonZeroU32, NonZeroU32)> { + let width = NonZeroU32::new(dimensions.width)?; + let height = NonZeroU32::new(dimensions.height)?; + return Some((width, height)); } |