diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bin/fragment.frag | 7 | ||||
| -rw-r--r-- | src/bin/phosphor_test.rs | 97 | ||||
| -rw-r--r-- | src/bin/vertex.vert | 9 | ||||
| -rw-r--r-- | src/keyboard_input.rs | 19 | ||||
| -rw-r--r-- | src/lib.rs | 60 | ||||
| -rw-r--r-- | src/press_state.rs | 26 | ||||
| -rw-r--r-- | src/program_controller.rs | 13 | ||||
| -rw-r--r-- | src/render.rs | 67 | ||||
| -rw-r--r-- | src/render_hint.rs | 33 | ||||
| -rw-r--r-- | src/render_request.rs | 40 | ||||
| -rw-r--r-- | src/window.rs | 177 | ||||
| -rw-r--r-- | src/window/x11.rs | 66 | ||||
| -rw-r--r-- | src/window_controller.rs | 52 | ||||
| -rw-r--r-- | src/window_manager.rs | 192 | 
14 files changed, 333 insertions, 525 deletions
| diff --git a/src/bin/fragment.frag b/src/bin/fragment.frag deleted file mode 100644 index 99826f6..0000000 --- a/src/bin/fragment.frag +++ /dev/null @@ -1,7 +0,0 @@ -#version 330 -out vec4 FragColor; -in vec3 vertexColor; - -void main() { -    FragColor = vec4(vertexColor, 1.0); -} diff --git a/src/bin/phosphor_test.rs b/src/bin/phosphor_test.rs index 40a8558..c3b307d 100644 --- a/src/bin/phosphor_test.rs +++ b/src/bin/phosphor_test.rs @@ -1,89 +1,36 @@ -#![allow(dead_code)] - -// use asbestos::{Shader, ShaderProgram};  use buffer::*;  use phosphor::*; -// use raw_gl_context::GlContext;  fn main() { -    let my_program = MyProgram {}; -    let mut wm = WindowManager::with_program(my_program); -    wm.create_window(MainWindow::new()); +    let mut wm = WindowManager::new(std::time::Duration::from_micros(16666)); +    wm.add_window(Box::new(Window {}));      wm.run()  } -struct MyProgram {} -impl ProgramController for MyProgram {} - -struct MainWindow { -    // program: ShaderProgram, -} -impl MainWindow { -    pub fn new() -> Box<Self> { -        // let vertex_shader = Shader::vertex(include_str!("vertex.vert")); -        // let fragment_shader = Shader::fragment(include_str!("fragment.frag")); -        // let program = ShaderProgram::from_shaders(&[vertex_shader, fragment_shader]); -        // Box::new(Self { program }) -        Box::new(Self {}) +struct Window {} +impl WindowController for Window { +    fn minimum_size(&self) -> Option<phosphor::Dimensions> { +        Some(phosphor::Dimensions::new(200, 200))      } -} -impl WindowController for MainWindow { -    fn render(&mut self, buffer: &mut Buffer, _: RenderHint) { -        println!("Rendering..."); -        buffer.fill(Colour::TEAL); +    fn maximum_size(&self) -> Option<phosphor::Dimensions> { +        Some(phosphor::Dimensions::new(400, 400))      } -    // fn render_gl(&mut self, _context: &mut GlContext) { -    //     println!("Rendering GL..."); -    //     unsafe { -    //         gl::ClearColor(1.0, 0.0, 1.0, 1.0); -    //         gl::Clear(gl::COLOR_BUFFER_BIT); -    //     } -    // } -} - -// type Pos = [f32; 2]; -// type Color = [f32; 3]; -// #[repr(C, packed)] -// struct Vertex(Pos, Color); - -// const VERTICES: [Vertex; 3] = [ -//     Vertex([-0.5, -0.5], [1.0, 0.0, 0.0]), -//     Vertex([0.5,  -0.5], [0.0, 1.0, 0.0]), -//     Vertex([0.0,   0.5], [0.0, 0.0, 1.0]) -// ]; +    fn render_request(&self) -> RenderRequest { +        RenderRequest::None +    } -// pub struct Buffer { -//     pub id: GLuint, -//     target: GLuint, -// } -// impl Buffer { -//     pub unsafe fn new(target: GLuint) -> Self { -//         let mut id: GLuint = 0; -//         gl::GenBuffers(1, &mut id); -//         Self { id, target } -//     } +    fn is_resizable(&self) -> bool { +        false +    } -//     pub unsafe fn bind(&self) { -//         gl::BindBuffer(self.target, self.id); -//     } +    fn on_resize(&mut self, size: phosphor::Dimensions) { +        println!("RESIZE: {size:?}"); +    } -//     pub unsafe fn set_data<D>(&self, data: &[D], usage: GLuint) { -//         self.bind(); -//         let (_, data_bytes, _) = data.align_to::<u8>(); -//         gl::BufferData( -//             self.target, -//             data_bytes.len() as GLsizeiptr, -//             data_bytes.as_ptr() as *const _, -//             usage, -//         ); -//     } -// } +    fn on_render(&mut self, buffer: &mut Buffer, _: RenderHint) { +        println!("RENDER"); +        buffer.fill(Colour::TEAL); +    } +} -// impl Drop for Buffer { -//     fn drop(&mut self) { -//         unsafe { -//             gl::DeleteBuffers(1, [self.id].as_ptr()); -//         } -//     } -// } diff --git a/src/bin/vertex.vert b/src/bin/vertex.vert deleted file mode 100644 index 0fd4f8a..0000000 --- a/src/bin/vertex.vert +++ /dev/null @@ -1,9 +0,0 @@ -#version 330 -in vec2 point; -in vec3 color; -out vec3 vertexColor; - -void main() { -    gl_Point = vec4(point, 0.0, 1.0); -    vertexColor = color; -} diff --git a/src/keyboard_input.rs b/src/keyboard_input.rs deleted file mode 100644 index 139db7e..0000000 --- a/src/keyboard_input.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::*; -use winit::event::KeyboardInput as WinitKeyboardInput; - -#[derive(Copy, Clone)] -pub struct KeyboardInput { -    pub state: PressState, -    pub keycode: Option<KeyCode>, -    pub scancode: u32, -} - -impl From<WinitKeyboardInput> for KeyboardInput { -    fn from(input: WinitKeyboardInput) -> Self { -        Self { -            state: input.state.into(), -            keycode: input.virtual_keycode, -            scancode: input.scancode, -        } -    } -} @@ -1,25 +1,16 @@ -mod keyboard_input; -mod press_state; -mod program_controller; -mod render_hint; -mod render_request; +mod render;  mod window;  mod window_controller;  mod window_manager; -use window::Window; - -pub use keyboard_input::KeyboardInput; -pub use press_state::PressState; -pub use program_controller::{DefaultProgramController, ProgramController}; -pub use render_hint::RenderHint; -pub use render_request::RenderRequest; -pub use window_controller::WindowController; -pub use window_manager::WindowManager; +pub use render::*; +pub use window::*; +pub use window_controller::*; +pub use window_manager::*;  pub use buffer::{Buffer, Colour};  pub use winit::{ -    event::ModifiersState, +    event::{ModifiersState, ElementState},      event::VirtualKeyCode as KeyCode,      window::CursorIcon,  }; @@ -27,3 +18,42 @@ pub use winit::{  pub type Point = geometry::Point<i32>;  pub type Dimensions = geometry::Dimensions<u32>;  pub type Rect = geometry::Rect<i32, u32>; + +// ----------------------------------------------------------------------------- + +#[derive(Copy, Clone)] +pub struct KeyboardInput { +    pub action: Action, +    pub key: KeyCode, +} + +impl TryFrom<winit::event::KeyboardInput> for KeyboardInput { +    type Error = (); + +    fn try_from(input: winit::event::KeyboardInput) -> Result<Self, ()> { +        if let Some(key) = input.virtual_keycode { +            Ok( Self { action: input.state.into(), key } ) +        } else { +            Err(()) +        } +    } +} + +// ----------------------------------------------------------------------------- + +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum Action { Pressed, Released } + +impl Action { +    pub fn is_pressed(&self)  -> bool { *self == Self::Pressed  } +    pub fn is_released(&self) -> bool { *self == Self::Released } +} + +impl From<ElementState> for Action { +    fn from(value: ElementState) -> Self { +        match value { +            ElementState::Pressed => Action::Pressed, +            ElementState::Released => Action::Released, +        } +    } +} diff --git a/src/press_state.rs b/src/press_state.rs deleted file mode 100644 index 5136d66..0000000 --- a/src/press_state.rs +++ /dev/null @@ -1,26 +0,0 @@ -use winit::event::ElementState; - -/// Denotes whether an event was a press event or a release event. -#[derive(Clone, Copy, PartialEq, Debug)] -pub enum PressState { -    Pressed, -    Released, -} - -impl PressState { -    pub fn is_pressed(&self) -> bool { -        *self == Self::Pressed -    } -    pub fn is_released(&self) -> bool { -        *self == Self::Released -    } -} - -impl From<ElementState> for PressState { -    fn from(value: ElementState) -> Self { -        match value { -            ElementState::Pressed => PressState::Pressed, -            ElementState::Released => PressState::Released, -        } -    } -} diff --git a/src/program_controller.rs b/src/program_controller.rs deleted file mode 100644 index 638e5ce..0000000 --- a/src/program_controller.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::*; - -pub trait ProgramController { -    fn initialise(&mut self) {} -    fn on_render(&mut self) {} -    fn on_mouse_moved(&mut self, _position: Point) {} - -    fn on_process(&mut self, _create_window: &mut dyn FnMut(Box<dyn WindowController>)) {} -} - -/// An empty program controller, for when a program has only one window. -pub struct DefaultProgramController {} -impl ProgramController for DefaultProgramController {} diff --git a/src/render.rs b/src/render.rs new file mode 100644 index 0000000..e7ec02d --- /dev/null +++ b/src/render.rs @@ -0,0 +1,67 @@ +/// Tells a window controller whether the previous render state is intact and +/// can be updated, or was destroyed and needs to be fully redrawn. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum RenderHint { +    /// The buffer content is unchanged, only updates are required. +    Update, +    /// The buffer content has been destroyed, a full redraw is required. +    Redraw, +} + +impl RenderHint { +    pub fn is_update(&self) -> bool { *self == RenderHint::Update } +    pub fn is_redraw(&self) -> bool { *self == RenderHint::Redraw } +} + +impl std::ops::BitAnd for RenderHint { +    type Output = RenderHint; +    fn bitand(self, other: RenderHint) -> Self::Output { +        if self == RenderHint::Redraw || other == RenderHint::Redraw { +            RenderHint::Redraw +        } else { +            RenderHint::Update +        } +    } +} + +impl std::ops::BitAndAssign for RenderHint { +    fn bitand_assign(&mut self, other: RenderHint) { +        *self = *self & other; +    } +} + +/// A request to the window manager for a render pass to be run. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum RenderRequest { +    None, +    Render(RenderHint), +} + +impl RenderRequest { +    pub const NONE:   RenderRequest = RenderRequest::None; +    pub const UPDATE: RenderRequest = RenderRequest::Render(RenderHint::Update); +    pub const REDRAW: RenderRequest = RenderRequest::Render(RenderHint::Redraw); + +    pub fn is_none(&self)   -> bool { *self == RenderRequest::None } +    pub fn is_some(&self)   -> bool { *self != RenderRequest::None } +    pub fn is_update(&self) -> bool { *self == RenderRequest::UPDATE } +    pub fn is_redraw(&self) -> bool { *self == RenderRequest::REDRAW } +} + +impl std::ops::BitAnd for RenderRequest { +    type Output = RenderRequest; +    fn bitand(self, other: RenderRequest) -> Self::Output { +        use RenderRequest::*; +        match (self, other) { +            (None, req)  => req, +            (req, None)  => req, +            (Render(a), Render(b)) => Render(a & b), +        } +    } +} + +impl std::ops::BitAndAssign for RenderRequest { +    fn bitand_assign(&mut self, other: RenderRequest) { +        *self = *self & other; +    } +} diff --git a/src/render_hint.rs b/src/render_hint.rs deleted file mode 100644 index e4d37c3..0000000 --- a/src/render_hint.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::ops::*; - -/// A hint to tell a window controller whether the previous render state is -/// intact and can be updated, or was destroyed and needs to be fully redrawn. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum RenderHint { -    /// The buffer contents are intact, only updates need to be drawn. -    Update, -    /// The buffer contents were destroyed, a full redraw is required. -    Redraw, -} - -impl RenderHint { -    pub fn is_update(&self) -> bool { *self == RenderHint::Update } -    pub fn is_redraw(&self) -> bool { *self == RenderHint::Redraw } -} - -impl BitAnd for RenderHint { -    type Output = RenderHint; -    fn bitand(self, other: RenderHint) -> Self::Output { -        if self == RenderHint::Redraw || other == RenderHint::Redraw { -            RenderHint::Redraw -        } else { -            RenderHint::Update -        } -    } -} - -impl BitAndAssign for RenderHint { -    fn bitand_assign(&mut self, other: RenderHint) { -        *self = *self & other; -    } -} diff --git a/src/render_request.rs b/src/render_request.rs deleted file mode 100644 index f336dfc..0000000 --- a/src/render_request.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::*; -use std::ops::*; - -/// A request to the window manager for a render pass to be run. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum RenderRequest { -    /// A render is not required. -    None, -    /// A render is required. -    Render(RenderHint), -} - -impl RenderRequest { -    pub const NONE:   RenderRequest = RenderRequest::None; -    pub const UPDATE: RenderRequest = RenderRequest::Render(RenderHint::Update); -    pub const REDRAW: RenderRequest = RenderRequest::Render(RenderHint::Redraw); - -    pub fn is_none(&self) -> bool { *self == RenderRequest::NONE } -    pub fn is_some(&self) -> bool { *self != RenderRequest::None } -    pub fn is_update(&self) -> bool { *self == RenderRequest::UPDATE } -    pub fn is_redraw(&self) -> bool { *self == RenderRequest::REDRAW } -} - -impl BitAnd for RenderRequest { -    type Output = RenderRequest; -    fn bitand(self, other: RenderRequest) -> Self::Output { -        use RenderRequest::*; -        match (self, other) { -            (None, req)  => req, -            (req, None)  => req, -            (Render(a), Render(b)) => Render(a & b), -        } -    } -} - -impl BitAndAssign for RenderRequest { -    fn bitand_assign(&mut self, other: RenderRequest) { -        *self = *self & other; -    } -} 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));  } diff --git a/src/window/x11.rs b/src/window/x11.rs deleted file mode 100644 index d4bcbe4..0000000 --- a/src/window/x11.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::window::GraphicsContext; -use buffer::Buffer; -use geometry::HasDimensions; -use raw_window_handle::XlibHandle; -use std::os::raw::{c_char, c_uint}; -use x11_dl::xlib::{Display, Visual, Xlib, ZPixmap, GC}; - -pub struct X11GraphicsContext { -    handle: XlibHandle, -    lib: Xlib, -    gc: GC, -    visual: *mut Visual, -    depth: i32, -} - -impl X11GraphicsContext { -    pub unsafe fn new(handle: XlibHandle) -> Self { -        let lib = match Xlib::open() { -            Ok(lib) => lib, -            Err(e) => panic!("{:?}", e), -        }; -        let screen = (lib.XDefaultScreen)(handle.display as *mut Display); -        let gc = (lib.XDefaultGC)(handle.display as *mut Display, screen); -        let visual = (lib.XDefaultVisual)(handle.display as *mut Display, screen); -        let depth = (lib.XDefaultDepth)(handle.display as *mut Display, screen); - -        Self { handle, lib, gc, visual, depth } -    } -} - -impl GraphicsContext for X11GraphicsContext { -    unsafe fn blit(&mut self, buffer: &Buffer) { -        let array = buffer.as_u32_slice(); -        let dimensions = buffer.dimensions(); -        //create image -        let image = (self.lib.XCreateImage)( -            self.handle.display as *mut Display, -            self.visual, -            self.depth as u32, -            ZPixmap, -            0, -            (array.as_ptr()) as *mut c_char, -            dimensions.width as u32, -            dimensions.height as u32, -            32, -            (dimensions.width * 4) as i32, -        ); - -        //push image to window -        (self.lib.XPutImage)( -            self.handle.display as *mut Display, -            self.handle.window, -            self.gc, -            image, -            0, -            0, -            0, -            0, -            dimensions.width as c_uint, -            dimensions.height as c_uint, -        ); - -        (*image).data = std::ptr::null_mut(); -        (self.lib.XDestroyImage)(image); -    } -} diff --git a/src/window_controller.rs b/src/window_controller.rs index d088b99..34f9fd4 100644 --- a/src/window_controller.rs +++ b/src/window_controller.rs @@ -1,42 +1,44 @@  use crate::*; -// use raw_gl_context::GlContext; -/// Controls a single window.  pub trait WindowController {      fn title(&self) -> String { String::from("Phosphor") } -    fn initial_dimensions(&self) -> Dimensions { Dimensions::new(800,600) } -    fn minimum_dimensions(&self) -> Option<Dimensions> { None } -    fn maximum_dimensions(&self) -> Option<Dimensions> { None } -    fn resizable(&self) -> bool { true } +    fn cursor_icon(&self) -> Option<CursorIcon> { None } +    fn initial_size(&self) -> Dimensions { Dimensions::new(800,600) } +    fn minimum_size(&self) -> Option<Dimensions> { None } +    fn maximum_size(&self) -> Option<Dimensions> { None } +    fn pixel_scale(&self) -> u32 { 1 } +    fn render_request(&self) -> RenderRequest { RenderRequest::None } -    fn cursor_icon(&mut self) -> Option<CursorIcon> { None } -    fn cursor_visible(&mut self) -> bool { true } +    fn is_visible(&self) -> bool { true } +    fn is_cursor_visible(&self) -> bool { true } +    fn is_resizable(&self) -> bool { true } -    fn on_resize(&mut self, _dimensions: Dimensions) {} +    fn on_init(&mut self) {} +    fn on_resize(&mut self, _size: Dimensions) {}      fn on_move(&mut self, _position: Point) {} -    fn on_focus_change(&mut self, _focused: bool) {} +    fn on_focus_change(&mut self, _is_focused: bool) {}      fn on_process(&mut self) {} +    fn on_render(&mut self, _buffer: &mut Buffer, _hint: RenderHint) {} +    fn on_close_request(&mut self) {} +    fn on_close(&mut self) {} -    fn on_mouse_enter(&mut self) {} -    fn on_mouse_exit(&mut self) {} -    fn on_mouse_move(&mut self, _position: Point) {} +    fn on_cursor_enter(&mut self) {} +    fn on_cursor_exit(&mut self) {} +    fn on_cursor_move(&mut self, _position: Point) {} -    fn on_left_mouse_button(&mut self, _pressed: PressState) {} -    fn on_middle_mouse_button(&mut self, _pressed: PressState) {} -    fn on_right_mouse_button(&mut self, _pressed: PressState) {} - -    fn on_keyboard_input(&mut self, _input: KeyboardInput) {} -    fn on_keyboard_modifier_change(&mut self, _modifiers: ModifiersState) {} -    fn on_character_received(&mut self, _character: char) {} -    fn on_file_hovered(&mut self, _path: std::path::PathBuf) {} -    fn on_file_dropped(&mut self, _path: std::path::PathBuf) {} +    fn on_left_mouse_button(&mut self, _action: Action) {} +    fn on_middle_mouse_button(&mut self, _action: Action) {} +    fn on_right_mouse_button(&mut self, _action: Action) {}      fn on_line_scroll_horizontal(&mut self, _delta: f64) {}      fn on_line_scroll_vertical(&mut self, _delta: f64) {}      fn on_pixel_scroll_horizontal(&mut self, _delta: f64) {}      fn on_pixel_scroll_vertical(&mut self, _delta: f64) {} -    fn render_request(&mut self) -> RenderRequest { RenderRequest::None } -    fn render(&mut self, _buffer: &mut Buffer, _hint: RenderHint) {} -    // fn render_gl(&mut self, _context: &mut GlContext) {} +    fn on_keyboard_input(&mut self, _input: KeyboardInput) {} +    fn on_keyboard_modifier_change(&mut self, _modifiers: ModifiersState) {} +    fn on_character_input(&mut self, _character: char) {} +    fn on_file_hover(&mut self, _path: std::path::PathBuf) {} +    fn on_file_hover_cancel(&mut self) {} +    fn on_file_drop(&mut self, _path: std::path::PathBuf) {}  } diff --git a/src/window_manager.rs b/src/window_manager.rs index 144f1c3..065d517 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -1,156 +1,134 @@  use crate::*; -use nosferatu::*; -  use std::collections::HashMap; -use winit::event::{Event, MouseButton, StartCause, WindowEvent, MouseScrollDelta}; -use winit::event_loop::EventLoop; -use winit::window::WindowId; +use std::time::Duration; +use winit::{event::*, event_loop::{EventLoop, ControlFlow}, window::WindowId}; -/// Controls the entire program. -pub struct WindowManager<P: ProgramController> { -    limiter: Option<FrameRateLimiter>, -    frame_timer: FrameTimer, +pub struct WindowManager {      event_loop: EventLoop<()>,      windows: HashMap<WindowId, Window>, -    program: P, -} - -impl WindowManager<DefaultProgramController> { -    pub fn without_program() -> Self { -        Self::with_program(DefaultProgramController {}) -    } +    min_frame_duration: Duration,  } -impl<P: 'static + ProgramController> WindowManager<P> { -    pub fn with_program(program: P) -> Self { +impl WindowManager { +    pub fn new(min_frame_duration: Duration) -> Self {          Self { -            limiter: None, -            frame_timer: FrameTimer::one_second(),              event_loop: EventLoop::new(),              windows: HashMap::new(), -            program, +            min_frame_duration,          }      } -    pub fn with_frame_limit(mut self, limit: usize) -> Self { -        self.limiter = Some(FrameRateLimiter::from_frame_rate(limit)); self -    } - -    /// Used to create one or more windows before the event loop starts. -    pub fn create_window(&mut self, controller: Box<dyn WindowController>) { -        let window = unsafe { Window::new(&self.event_loop, controller) }; +    /// Add a window to the window manager before the event loop begins. +    pub fn add_window(&mut self, controller: Box<dyn WindowController>) { +        let window = Window::new(&self.event_loop, controller);          self.windows.insert(window.id(), window);      } -    /// Starts the event loop, causing program control to be passed permanently to the window manager. +    /// Start the event loop, passing program control to the window manager.      pub fn run(mut self) -> ! { -        self.event_loop.run(move |event, window_target, control_flow| { -            control_flow.set_poll(); - +        self.event_loop.run(move |event, _window_target, control_flow| {              match event { -                // Event loop has just initialised (is only ever emitted once) -                Event::NewEvents(StartCause::Init) => self.program.initialise(), +                // Called when the event loop is first initialized. +                Event::NewEvents(StartCause::Init) => (), + +                Event::NewEvents(_) => { +                    control_flow.set_wait_timeout(self.min_frame_duration); +                } + +                // Called when an application suspends on a mobile platform. +                Event::Suspended => (), + +                // Called when an application resumes, or after initialization on non-mobile platforms. +                Event::Resumed => (),                  Event::WindowEvent { window_id, event } => {                      if let Some(window) = self.windows.get_mut(&window_id) {                          use WindowEvent::*; +                          match event { -                            Resized(dim) => window.resize_buffer(Dimensions::new(dim.width, dim.height)), -                            Moved(p) => window.controller.on_move(Point::new(p.x, p.y)), -                            Focused(state) => window.controller.on_focus_change(state), +                            Resized(dim) => window.resize(Dimensions::new(dim.width, dim.height)), +                            Moved(position) => window.controller.on_move(Point::new(position.x, position.y)), +                            Focused(is_focused) => window.controller.on_focus_change(is_focused), -                            CursorEntered { .. } => window.controller.on_mouse_enter(), -                            CursorLeft { .. } => window.controller.on_mouse_exit(), -                            CursorMoved { position, .. } => { -                                let point = Point::new(position.x as i32, position.y as i32); -                                window.move_mouse(point); -                            } -                            MouseWheel {delta, ..} => { -                                match delta { -                                    MouseScrollDelta::LineDelta(x, y) => { -                                        let (x, y) = (x as f64, y as f64); -                                        if x != 0.0 {window.controller.on_line_scroll_horizontal(x)} -                                        if y != 0.0 {window.controller.on_line_scroll_vertical(y)} -                                    } -                                    MouseScrollDelta::PixelDelta(point) => { -                                        let (x, y) = (point.x, point.y); -                                        if x != 0.0 {window.controller.on_pixel_scroll_horizontal(x)} -                                        if y != 0.0 {window.controller.on_pixel_scroll_vertical(y)} -                                    } +                            CursorEntered { .. } => window.controller.on_cursor_enter(), +                            CursorLeft { .. } => window.controller.on_cursor_exit(), +                            CursorMoved { position: p, .. } => { window.move_cursor(Point::new(p.x as i32, p.y as i32)) } + +                            MouseWheel {delta, ..} => match delta { +                                MouseScrollDelta::LineDelta(x, y) => { +                                    let (x, y) = (x as f64, y as f64); +                                    if x != 0.0 {window.controller.on_line_scroll_horizontal(x)} +                                    if y != 0.0 {window.controller.on_line_scroll_vertical(y)}                                  } -                            }, -                            MouseInput { state, button, .. } => { -                                match button { -                                    MouseButton::Left => window.controller.on_left_mouse_button(state.into()), -                                    MouseButton::Middle => window.controller.on_middle_mouse_button(state.into()), -                                    MouseButton::Right => window.controller.on_right_mouse_button(state.into()), -                                    _ => (), +                                MouseScrollDelta::PixelDelta(point) => { +                                    let (x, y) = (point.x, point.y); +                                    if x != 0.0 {window.controller.on_pixel_scroll_horizontal(x)} +                                    if y != 0.0 {window.controller.on_pixel_scroll_vertical(y)}                                  } -                                window.bump_mouse(); - +                            } +                            MouseInput { state, button, .. } => match button { +                                MouseButton::Left => window.controller.on_left_mouse_button(state.into()), +                                MouseButton::Middle => window.controller.on_middle_mouse_button(state.into()), +                                MouseButton::Right => window.controller.on_right_mouse_button(state.into()), +                                MouseButton::Other(_) => (),                              } -                            KeyboardInput { input, .. } => window.controller.on_keyboard_input(input.into()), +                            KeyboardInput { input, .. } => if let Ok(input) = input.try_into() { window.controller.on_keyboard_input(input)},                              ModifiersChanged(state) => window.controller.on_keyboard_modifier_change(state), -                            ReceivedCharacter(c) => window.controller.on_character_received(c), -                            HoveredFile(path) => window.controller.on_file_hovered(path), -                            DroppedFile(path) => window.controller.on_file_dropped(path), +                            ReceivedCharacter(character) => window.controller.on_character_input(character), +                            HoveredFile(path) => window.controller.on_file_hover(path), +                            HoveredFileCancelled => window.controller.on_file_hover_cancel(), +                            DroppedFile(path) => window.controller.on_file_drop(path), -                            // Tell the window, and let it raise its own event to close itself -                            // When all windows are closed: control_flow.set_exit_with_code(0); -                            CloseRequested => todo!("window.controller.on_close_requested()"), -                            _ => (), +                            CloseRequested => { +                                window.controller.on_close_request(); +                                *control_flow = ControlFlow::Exit; +                            }, +                            Destroyed => window.controller.on_close(), + +                            Ime(_) => (), +                            AxisMotion { .. } => (), +                            Touch(_) => (), +                            TouchpadRotate { .. } => (), +                            TouchpadPressure { .. } => (), +                            TouchpadMagnify { .. } => (), +                            SmartMagnify { .. } => (), +                            ScaleFactorChanged { .. } => (), +                            ThemeChanged(_) => (), +                            Occluded(_) => (),                          }                      }                  } -                // Called each loop before any rendering would begin. +                // Called before any render events are called.                  Event::MainEventsCleared => { -                    self.frame_timer.tick(); -                    // println!("{}", self.frame_timer.frame_rate()); - -                    self.program.on_process(&mut |controller: Box<dyn WindowController>| { -                        let window = unsafe { Window::new(window_target, controller) }; -                        self.windows.insert(window.id(), window); -                    });                      for window in self.windows.values_mut() {                          window.controller.on_process(); -                        let cursor_icon = window.controller.cursor_icon(); -                        window.set_cursor_icon(cursor_icon); -                        // let resizable = window.controller.resizable(); -                        // window.set_resizable(resizable); -                        // let cursor_visible = window.controller.cursor_visible(); -                        // window.set_cursor_visible(cursor_visible); -                        window.check_render_request(); -                        let title = window.controller.title(); -                        window.set_title(&title); -                        let minimum_dimensions = window.controller.minimum_dimensions(); -                        window.set_minimum_dimensions(minimum_dimensions); -                        let maximum_dimensions = window.controller.maximum_dimensions(); -                        window.set_maximum_dimensions(maximum_dimensions); +                        window.update_title(); +                        window.update_minimum_size(); +                        window.update_maximum_size(); +                        window.update_resizable(); +                        window.update_cursor_icon(); +                        window.update_cursor_visible(); +                        window.handle_render_request();                      }                  } -                // Called if a render was requested for a window + +                // Called if a window has requested to be rendered.                  Event::RedrawRequested(window_id) => {                      if let Some(window) = self.windows.get_mut(&window_id) {                          window.render();                      }                  } -                // Called after rendering has completed -                Event::RedrawEventsCleared => { -                    if let Some(limiter) = &mut self.limiter { -                        limiter.tick(); -                    } -                } -                _other => {} // todo!("{:?}", other), +                // Called after all rendering has completed, or if there were no render requests. +                Event::RedrawEventsCleared => (), + +                // Called before the program closes. +                Event::LoopDestroyed => (), + +                _ => (),              }          })      }  } - -impl Default for WindowManager<DefaultProgramController> { -    fn default() -> Self { -        Self::without_program() -    } -} | 
