From ec8149b0847104e9247635d361c9c7a7ba030355 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Tue, 7 Mar 2017 11:53:57 +0100 Subject: [PATCH 01/14] Initial glutin backend implementation --- Cargo.toml | 7 +- examples/simple.rs | 36 ++++ src/backend/glium.rs | 38 ++++ src/backend/glutin.rs | 359 +++++++++++++++++++++++++++++++ src/backend/graphics/mod.rs | 6 + src/backend/graphics/opengl.rs | 87 ++++++++ src/backend/graphics/software.rs | 17 ++ src/backend/input.rs | 277 ++++++++++++++++++++++++ src/backend/mod.rs | 28 +++ src/lib.rs | 4 + 10 files changed, 858 insertions(+), 1 deletion(-) create mode 100644 examples/simple.rs create mode 100644 src/backend/glium.rs create mode 100644 src/backend/glutin.rs create mode 100644 src/backend/graphics/mod.rs create mode 100644 src/backend/graphics/opengl.rs create mode 100644 src/backend/graphics/software.rs create mode 100644 src/backend/input.rs create mode 100644 src/backend/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 025a343..c373267 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,11 +4,16 @@ version = "0.1.0" authors = ["Victor Berger "] [dependencies] -wayland-server = "0.8.4" +wayland-server = { version = "0.8.4", features = ["dlopen"] } nix = "0.7.0" +glutin = { version = "~0.7.4", optional = true } +glium = { version = "~0.16.0", optional = true } slog = { version = "~1.5.2", features = ["max_level_trace", "release_max_level_info"] } slog-stdlog = "~1.1.0" clippy = { version = "*", optional = true } [dev-dependencies] slog-term = "~1.5" + +[features] +default = ["glutin"] diff --git a/examples/simple.rs b/examples/simple.rs new file mode 100644 index 0000000..c37f0fa --- /dev/null +++ b/examples/simple.rs @@ -0,0 +1,36 @@ +extern crate wayland_server; +extern crate smithay; + +use smithay::shm::ShmGlobal; +use smithay::backend::glutin; +use wayland_server::protocol::wl_shm; + +fn main() { + let (_, mut event_loop) = wayland_server::create_display(); + + // Insert the ShmGlobal as a handler to your event loop + // Here, we specify tha the standard Argb8888 and Xrgb8888 is the only supported. + let handler_id = event_loop.add_handler_with_init(ShmGlobal::new( + vec![], + None // we don't provide a logger here + )); + + // Register this handler to advertise a wl_shm global of version 1 + let shm_global = event_loop.register_global::(handler_id, 1); + + // Retrieve the shm token for later use to access the buffers + let shm_token = { + let state = event_loop.state(); + state.get_handler::(handler_id).get_token() + }; + + // Initialize a simple backend for testing + let (mut renderer, mut input) = glutin::init_windowed().unwrap(); + + //TODO render stuff + + //TODO put input handling on the event loop + input.process_new_events(); + + event_loop.run(); +} diff --git a/src/backend/glium.rs b/src/backend/glium.rs new file mode 100644 index 0000000..541ebfe --- /dev/null +++ b/src/backend/glium.rs @@ -0,0 +1,38 @@ +use glium::backend::Backend; +use glium::SwapBuffersError as GliumSwapBuffersError; + +use ::backend::graphics::opengl::{OpenglRenderer, SwapBuffersError}; + +impl From for GliumSwapBuffersError +{ + fn from(error: SwapBuffersError) -> Self { + match error { + SwapBuffersError::ContextLost => GliumSwapBuffersError::ContextLost, + SwapBuffersError::AlreadySwapped => GliumSwapBuffersError::AlreadySwapped, + } + } +} + +impl Backend for T +{ + fn swap_buffers(&self) -> Result<(), SwapBuffersError> { + self.swap_buffers().map_err(|x| x.into) + } + + unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void + { + self.get_proc_address(symbol) + } + + fn get_framebuffer_dimensions(&self) -> (u32, u32) { + self.get_framebuffer_dimensions() + } + + fn is_current(&self) -> bool { + self.is_current() + } + + unsafe fn make_current(&self) { + self.make_current() + } +} diff --git a/src/backend/glutin.rs b/src/backend/glutin.rs new file mode 100644 index 0000000..c133e86 --- /dev/null +++ b/src/backend/glutin.rs @@ -0,0 +1,359 @@ +//! Implementation of backend traits for types provided by `glutin` + +use glutin::{ContextError, CreationError, Event, ElementState, MouseScrollDelta, Touch, TouchPhase, GlContext, HeadlessRendererBuilder, HeadlessContext, WindowBuilder, Window}; +use glutin::{Api as GlutinApi, PixelFormat as GlutinPixelFormat, MouseButton as GlutinMouseButton}; +use nix::c_void; +use std::rc::Rc; + +use backend::NewIdType; +use backend::graphics::opengl::{Api, OpenglRenderer, PixelFormat, SwapBuffersError}; +use backend::input::{InputBackend, InputHandler, Seat, KeyState, MouseButton, MouseButtonState, Axis, AxisSource, TouchEvent, TouchSlot}; + +/// Create a new `GlutinHeadlessRenderer` which implements the `OpenglRenderer` graphics +/// backend trait +pub fn init_headless_renderer() -> Result +{ + init_headless_renderer_from_builder(HeadlessRendererBuilder::new(1024, 600)) +} + +/// Create a new `GlutinHeadlessRenderer`, which implements the `OpenglRenderer` graphics +/// backend trait, with a given already configured `HeadlessRendererBuilder` for +/// customization +pub fn init_headless_renderer_from_builder(builder: HeadlessRendererBuilder) -> Result +{ + let (w, h) = builder.dimensions; + let context = builder.build_strict()?; + + Ok(GlutinHeadlessRenderer::new(context, w, h)) +} + +/// Create a new `GlutinWindowedRenderer`, which implements the `OpenglRenderer` graphics +/// backend trait +pub fn init_windowed_renderer() -> Result +{ + init_windowed_renderer_from_builder(WindowBuilder::new()) +} + +/// Create a new `GlutinWindowedRenderer`, which implements the `OpenglRenderer` graphics +/// backend trait, with a given already configured `WindowBuilder` for customization. +pub fn init_windowed_renderer_from_builder(builder: WindowBuilder) -> Result +{ + let window = Rc::new(builder.build_strict()?); + Ok(GlutinWindowedRenderer::new(window)) +} + +/// Create a new `glutin` `Window`. Returns a `GlutinWindowedRenderer` implementing +/// the `OpenglRenderer` graphics backend trait and a `GlutinInputBackend` implementing +/// the `InputBackend` trait. +pub fn init_windowed() -> Result<(GlutinWindowedRenderer, GlutinInputBackend), CreationError> +{ + init_windowed_from_builder(WindowBuilder::new()) +} + +/// Create a new `glutin` `Window` with a given already configured `WindowBuilder` for +/// customization. Returns a `GlutinWindowedRenderer` implementing +/// the `OpenglRenderer` graphics backend trait and a `GlutinInputBackend` implementing +/// the `InputBackend` trait. +pub fn init_windowed_from_builder(builder: WindowBuilder) -> Result<(GlutinWindowedRenderer, GlutinInputBackend), CreationError> +{ + let window = Rc::new(builder.build_strict()?); + Ok(( + GlutinWindowedRenderer::new(window.clone()), + GlutinInputBackend::new(window) + )) +} + +/// Headless Opengl Context created by `glutin`. Implements the `OpenglRenderer` graphics +/// backend trait. +pub struct GlutinHeadlessRenderer +{ + context: HeadlessContext, + w: u32, + h: u32, +} + +impl GlutinHeadlessRenderer +{ + fn new(context: HeadlessContext, w: u32, h: u32) -> GlutinHeadlessRenderer { + GlutinHeadlessRenderer { + context: context, + w: w, + h: h, + } + } +} + +impl OpenglRenderer for GlutinHeadlessRenderer +{ + #[inline] + fn swap_buffers(&self) -> Result<(), SwapBuffersError> { + match self.context.swap_buffers() { + Ok(()) => Ok(()), + Err(ContextError::IoError(e)) => panic!("Error while swapping buffers: {:?}", e), + Err(ContextError::ContextLost) => Err(SwapBuffersError::ContextLost), + } + } + + #[inline] + unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void { + self.context.get_proc_address(symbol) as *const _ + } + + #[inline] + fn get_framebuffer_dimensions(&self) -> (u32, u32) { + (self.w, self.h) + } + + #[inline] + fn is_current(&self) -> bool { + self.context.is_current() + } + + #[inline] + unsafe fn make_current(&self) { + self.context.make_current().unwrap(); + } + + fn get_api(&self) -> Api { + self.context.get_api().into() + } + + fn get_pixel_format(&self) -> PixelFormat { + self.context.get_pixel_format().into() + } +} + +/// Window with an active Opengl Context created by `glutin`. Implements the +/// `OpenglRenderer` graphics backend trait. +pub struct GlutinWindowedRenderer +{ + window: Rc +} + +impl GlutinWindowedRenderer +{ + fn new(window: Rc) -> GlutinWindowedRenderer { + GlutinWindowedRenderer { + window: window, + } + } +} + +impl OpenglRenderer for GlutinWindowedRenderer +{ + #[inline] + fn swap_buffers(&self) -> Result<(), SwapBuffersError> { + match self.window.swap_buffers() { + Ok(()) => Ok(()), + Err(ContextError::IoError(e)) => panic!("Error while swapping buffers: {:?}", e), + Err(ContextError::ContextLost) => Err(SwapBuffersError::ContextLost), + } + } + + #[inline] + unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void { + self.window.get_proc_address(symbol) as *const _ + } + + #[inline] + fn get_framebuffer_dimensions(&self) -> (u32, u32) { + let (width, height) = self.window.get_inner_size().unwrap_or((800, 600)); // TODO: 800x600 ? + let scale = self.window.hidpi_factor(); + ((width as f32 * scale) as u32, (height as f32 * scale) as u32) + } + + #[inline] + fn is_current(&self) -> bool { + self.window.is_current() + } + + #[inline] + unsafe fn make_current(&self) { + self.window.make_current().unwrap(); + } + + fn get_api(&self) -> Api { + self.window.get_api().into() + } + + fn get_pixel_format(&self) -> PixelFormat { + self.window.get_pixel_format().into() + } +} + +/// Errors that may happen when driving the event loop of `GlutinInputBackend` +pub enum GlutinInputError +{ + /// The underlying `glutin` `Window` was closed. No further events can be processed. + /// + /// See `GlutinInputBackend::process_new_events`. + WindowClosed +} + +/// Abstracted event loop of a `glutin` `Window` implementing the `InputBackend` trait +/// +/// You need to call `process_new_events` periodically to receive any events. +pub struct GlutinInputBackend +{ + window: Rc, + time_counter: u32, + seat: Seat, + handler: Option>, +} + +impl InputBackend for GlutinInputBackend +{ + fn set_handler(&mut self, mut handler: H) { + if self.handler.is_some() { + self.clear_handler(); + } + handler.on_seat_created(&self.seat); + self.handler = Some(Box::new(handler)); + } + + fn get_handler(&mut self) -> Option<&mut InputHandler> + { + self.handler.as_mut().map(|handler| handler as &mut InputHandler) + } + + fn clear_handler(&mut self) { + if let Some(ref mut handler) = self.handler { + handler.on_seat_destroyed(&self.seat); + } + self.handler = None; + } + + fn set_cursor_position(&mut self, x: u32, y: u32) -> Result<(), ()> { + if let Some((win_x, win_y)) = self.window.get_position() { + self.window.set_cursor_position(win_x + x as i32, win_y + y as i32) + } else { + Err(()) + } + } +} + +impl GlutinInputBackend +{ + fn new(window: Rc) -> GlutinInputBackend + { + GlutinInputBackend { + window: window, + time_counter: 0, + seat: Seat::new(0), + handler: None, + } + } + + /// Processes new events of the underlying event loop to drive the set `InputHandler`. + /// + /// You need to periodically call this function to keep the underlying event loop and + /// `Window` active. Otherwise the window may no respond to user interaction and no + /// input events will be received by a set `InputHandler`. + /// + /// Returns an error if the `Window` the window has been closed. Calling + /// `process_new_events` again after the `Window` has been closed is considered an + /// application error and unspecified baviour may occur. + /// + /// The linked `GlutinWindowedRenderer` will error with a lost Context and should + /// not be used anymore as well. + pub fn process_new_events(&mut self) -> Result<(), GlutinInputError> + { + for event in self.window.poll_events() + { + if let Some(ref mut handler) = self.handler { + match event { + Event::KeyboardInput(state, key_code/*TODO: Is this really the keycode? glutins docs don't tell*/, _) => handler.on_keyboard_key(&self.seat, self.time_counter, key_code as u32, state.into(), 1), + Event::MouseMoved(x, y) => handler.on_pointer_move(&self.seat, self.time_counter, (x as u32, y as u32)), + Event::MouseWheel(delta, _) => match delta { + MouseScrollDelta::LineDelta(x, y) => { + if x != 0.0 { + handler.on_pointer_scroll(&self.seat, self.time_counter, Axis::Horizontal, AxisSource::Wheel, x as f64); + } + if y != 0.0 { + handler.on_pointer_scroll(&self.seat, self.time_counter, Axis::Vertical, AxisSource::Wheel, y as f64); + } + }, + MouseScrollDelta::PixelDelta(x, y) => { + if x != 0.0 { + handler.on_pointer_scroll(&self.seat, self.time_counter, Axis::Vertical, AxisSource::Continous, x as f64); + } + if y != 0.0 { + handler.on_pointer_scroll(&self.seat, self.time_counter, Axis::Horizontal, AxisSource::Continous, y as f64); + } + }, + }, + Event::MouseInput(state, button) => handler.on_pointer_button(&self.seat, self.time_counter, button.into(), state.into()), + Event::Touch(Touch { phase: TouchPhase::Started, location: (x, y), id}) => handler.on_touch(&self.seat, self.time_counter, TouchEvent::Down { slot: Some(TouchSlot::new(id as u32)), x: x, y: y }), + Event::Touch(Touch { phase: TouchPhase::Moved, location: (x, y), id}) => handler.on_touch(&self.seat, self.time_counter, TouchEvent::Motion { slot: Some(TouchSlot::new(id as u32)), x: x, y: y }), + Event::Touch(Touch { phase: TouchPhase::Ended, location: (x, y), id }) => { + handler.on_touch(&self.seat, self.time_counter, TouchEvent::Motion { slot: Some(TouchSlot::new(id as u32)), x: x, y: y }); + handler.on_touch(&self.seat, self.time_counter, TouchEvent::Up { slot: Some(TouchSlot::new(id as u32)) }); + } + Event::Touch(Touch { phase: TouchPhase::Cancelled, id, ..}) => handler.on_touch(&self.seat, self.time_counter, TouchEvent::Cancel { slot: Some(TouchSlot::new(id as u32)) }), + Event::Closed => return Err(GlutinInputError::WindowClosed), + _ => {}, + } + self.time_counter += 1; + } + } + Ok(()) + } +} + +impl From for Api { + fn from(api: GlutinApi) -> Self { + match api { + GlutinApi::OpenGl => Api::OpenGl, + GlutinApi::OpenGlEs => Api::OpenGlEs, + GlutinApi::WebGl => Api::WebGl, + } + } +} + +impl From for PixelFormat { + fn from(format: GlutinPixelFormat) -> Self { + PixelFormat { + hardware_accelerated: format.hardware_accelerated, + color_bits: format.color_bits, + alpha_bits: format.alpha_bits, + depth_bits: format.depth_bits, + stencil_bits: format.stencil_bits, + stereoscopy: format.stereoscopy, + double_buffer: format.double_buffer, + multisampling: format.multisampling, + srgb: format.srgb, + } + } +} + +impl From for MouseButton +{ + fn from(button: GlutinMouseButton) -> MouseButton { + match button { + GlutinMouseButton::Left => MouseButton::Left, + GlutinMouseButton::Right => MouseButton::Right, + GlutinMouseButton::Middle => MouseButton::Middle, + GlutinMouseButton::Other(num) => MouseButton::Other(num), + } + } +} + +impl From for KeyState +{ + fn from(state: ElementState) -> Self { + match state { + ElementState::Pressed => KeyState::Pressed, + ElementState::Released => KeyState::Released, + } + } +} + +impl From for MouseButtonState +{ + fn from(state: ElementState) -> Self { + match state { + ElementState::Pressed => MouseButtonState::Pressed, + ElementState::Released => MouseButtonState::Released, + } + } +} diff --git a/src/backend/graphics/mod.rs b/src/backend/graphics/mod.rs new file mode 100644 index 0000000..75b2ee6 --- /dev/null +++ b/src/backend/graphics/mod.rs @@ -0,0 +1,6 @@ +//! Common traits for various ways to renderer on a given graphics backend. +//! +//! Note: Not every api may be supported by every backend + +pub mod software; +pub mod opengl; diff --git a/src/backend/graphics/opengl.rs b/src/backend/graphics/opengl.rs new file mode 100644 index 0000000..e29521b --- /dev/null +++ b/src/backend/graphics/opengl.rs @@ -0,0 +1,87 @@ +//! Common traits and types for opengl rendering on graphics backends + +use nix::c_void; + +/// Error that can happen when swapping buffers. +#[derive(Debug, Clone)] +pub enum SwapBuffersError { + /// The OpenGL context has been lost and needs to be recreated. + /// + /// All the objects associated to it (textures, buffers, programs, etc.) + /// need to be recreated from scratch. + /// + /// Operations will have no effect. Functions that read textures, buffers, etc. + /// from OpenGL will return uninitialized data instead. + /// + /// A context loss usually happens on mobile devices when the user puts the + /// application on sleep and wakes it up later. However any OpenGL implementation + /// can theoretically lose the context at any time. + ContextLost, + /// The buffers have already been swapped. + /// + /// This error can be returned when `swap_buffers` has been called multiple times + AlreadySwapped, +} + +/// All APIs related to OpenGL that you can possibly get +/// through OpenglRenderer implementations +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Api { + /// The classical OpenGL. Available on Windows, Linux, OS/X. + OpenGl, + /// OpenGL embedded system. Available on Linux, Android. + OpenGlEs, + /// OpenGL for the web. Very similar to OpenGL ES. + WebGl, +} + +/// Describes the pixel format of the main framebuffer +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PixelFormat { + /// Is the format hardware accelerated + pub hardware_accelerated: bool, + /// bits used for colors + pub color_bits: u8, + /// bits used for alpha channel + pub alpha_bits: u8, + /// bits used for depth channel + pub depth_bits: u8, + /// bits used for stencil buffer + pub stencil_bits: u8, + /// is stereoscopy enabled + pub stereoscopy: bool, + /// is double buffering enabled + pub double_buffer: bool, + /// multisampling format used if enabled + pub multisampling: Option, + /// if the format has srgb enabled + pub srgb: bool, +} + +/// Trait that describes objects that have an OpenGl context +/// and can be used to render upon +pub trait OpenglRenderer +{ + /// Swaps buffers at the end of a frame. + fn swap_buffers(&self) -> Result<(), SwapBuffersError>; + + /// Returns the address of an OpenGL function. + /// + /// Supposes that the context has been made current before this function is called. + unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void; + + /// Returns the dimensions of the window, or screen, etc. + fn get_framebuffer_dimensions(&self) -> (u32, u32); + + /// Returns true if the OpenGL context is the current one in the thread. + fn is_current(&self) -> bool; + + /// Makes the OpenGL context the current context in the current thread. + unsafe fn make_current(&self); + + /// Returns the OpenGL API being used. + fn get_api(&self) -> Api; + + /// Returns the pixel format of the main framebuffer of the context. + fn get_pixel_format(&self) -> PixelFormat; +} diff --git a/src/backend/graphics/software.rs b/src/backend/graphics/software.rs new file mode 100644 index 0000000..d8bb6e0 --- /dev/null +++ b/src/backend/graphics/software.rs @@ -0,0 +1,17 @@ +//! Common traits and types used for software rendering on graphics backends + +use wayland_server::protocol::wl_shm::Format; +use std::error::Error; + +/// Trait that describes objects providing a software rendering implementation +pub trait CpuRender { + /// Render a given buffer of a given format at a specified place in the framebuffer + /// + /// # Error + /// Returns an error if the buffer size does not match the required amount of pixels + /// for the given size or if the position and size is out of scope of the framebuffer. + fn render(&mut self, buffer: &[u8], format: Format, at: (u32, u32), size: (u32, u32)) -> Result<(), E>; + + /// Returns the dimensions of the Framebuffer + fn get_framebuffer_dimensions(&self) -> (u32, u32); +} diff --git a/src/backend/input.rs b/src/backend/input.rs new file mode 100644 index 0000000..d5712f4 --- /dev/null +++ b/src/backend/input.rs @@ -0,0 +1,277 @@ +//! Common traits for input backends to receive input from. + +use backend::NewIdType; + +/// A seat describes a group of input devices and at least one +/// graphics device belonging together. +/// +/// By default only one seat exists for most systems and smithay backends +/// however multiseat configurations are possible and should be treated as +/// separated users, all with their own focus, input and cursor available. +/// +/// Seats can be checked for equality and hashed for differentiation. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Seat { id: u32 } + +impl NewIdType for Seat +{ + fn new(id: u32) -> Seat + { + Seat { id: id } + } +} + +/// State of key on a keyboard. Either pressed or released +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum KeyState { + /// Key is released + Released, + /// Key is pressed + Pressed, +} + +/// A particular mouse button +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum MouseButton { + /// Left mouse button + Left, + /// Middle mouse button + Middle, + /// Right mouse button + Right, + /// Other mouse button with index + Other(u8), +} + +/// State of a button on a mouse. Either pressed or released +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum MouseButtonState { + /// Button is released + Released, + /// Button is pressed + Pressed, +} + +/// Axis when scrolling +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum Axis +{ + /// Vertical axis + Vertical, + /// Horizonal axis + Horizontal, +} + +/// Source of an axis when scrolling +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum AxisSource +{ + /// Finger. Mostly used for trackpads. + /// + /// Guarantees that a scroll sequence is terminated with a scroll value of 0. + /// A caller may use this information to decide on whether kinetic scrolling should + /// be triggered on this scroll sequence. + /// + /// The coordinate system is identical to the + /// cursor movement, i.e. a scroll value of 1 represents the equivalent relative + /// motion of 1. + Finger, + /// Continous scrolling device. Almost identical to `Finger` + /// + /// No terminating event is guaranteed (though it may happen). + /// + /// The coordinate system is identical to + /// the cursor movement, i.e. a scroll value of 1 represents the equivalent relative + /// motion of 1. + Continous, + /// Scroll wheel. + /// + /// No terminating event is guaranteed (though it may happen). Scrolling is in + /// discrete steps. It is up to the caller how to interpret such different step sizes. + Wheel, + /// Scrolling through tilting the scroll wheel. + /// + /// No terminating event is guaranteed (though it may happen). Scrolling is in + /// discrete steps. It is up to the caller how to interpret such different step sizes. + WheelTilt, +} + +/// Slot of a different touch event. +/// +/// Touch events are groubed by slots, usually to identify different +/// fingers on a multi-touch enabled input device. Events should only +/// be interpreted in the context of other events on the same slot. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TouchSlot { id: u32 } + +impl NewIdType for TouchSlot +{ + fn new(id: u32) -> TouchSlot + { + TouchSlot { id: id } + } +} + +/// Touch event +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum TouchEvent +{ + /// The start of an event at a given position (x, y). + /// + /// If the device has multi-touch capabilities a slot is given. + Down { + /// `TouchSlot`, if the device has multi-touch capabilities + slot: Option, + /// Absolute x-coordinate of the touch position. + x: f64, + /// Absolute y-coordinate of the touch position. + y: f64 + }, + /// Movement of a touch on the device surface to a given position (x, y). + /// + /// If the device has multi-touch capabilities a slot is given. + Motion { + /// `TouchSlot`, if the device has multi-touch capabilities + slot: Option, + /// Absolute x-coordinate of the final touch position after the motion. + x: f64, + /// Absolute y-coordinate of the final touch position after the motion. + y: f64 }, + /// Stop of an event chain. + /// + /// If the device has multi-touch capabilities a slot is given. + Up { + /// `TouchSlot`, if the device has multi-touch capabilities + slot: Option + }, + /// Cancel of an event chain. All previous events in the chain should be ignored. + /// + /// If the device has multi-touch capabilities a slot is given. + Cancel { + /// `TouchSlot`, if the device has multi-touch capabilities + slot: Option + }, + /// Signals the end of a set of touchpoints at one device sample time. + Frame +} + +/// Trait that describes objects providing a source of input events. All input backends +/// need to implemenent this and provide the same base gurantees about the presicion of +/// given events. +pub trait InputBackend { + /// Sets a new handler for this `InputBackend` + fn set_handler(&mut self, handler: H); + /// Get a reference to the currently set handler, if any + fn get_handler(&mut self) -> Option<&mut InputHandler>; + /// Clears the currently handler, if one is set + fn clear_handler(&mut self); + /// Sets the cursor position, useful for e.g. pointer wrapping. + /// + /// Not guaranteed to be supported on every backend. The result usually + /// depends on the capability of the backend, but may also fail for certain + /// specific actions. See the backends documentation. + fn set_cursor_position(&mut self, x: u32, y: u32) -> Result<(), ()>; +} + +/// Implement to receive input events from any `InputBackend`. +pub trait InputHandler { + /// Called when a new `Seat` has been created + fn on_seat_created(&mut self, seat: &Seat); + /// Called when an existing `Seat` has been destroyed. + fn on_seat_destroyed(&mut self, seat: &Seat); + /// Called when a new keyboard event was received. + /// + /// # Arguments + /// + /// - `seat` - The `Seat` the event belongs to + /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events. + /// - `key_code` - Code of the pressed key. See linux/input-event-codes.h + /// - `state` - `KeyState` of the event + /// - `count` - Amount of key presses registered + /// + /// # TODO: + /// - check if events can arrive out of order. + /// - Make stronger time guarantees + fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32); + /// Called when a new keyboard event was received. + /// + /// # Arguments + /// + /// - `seat` - The `Seat` the event belongs to + /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events. + /// - `to` - Absolute screen coordinates of the pointer moved to. + /// + /// # TODO: + /// - check if events can arrive out of order. + /// - Make stronger time guarantees + fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32)); + /// Called when a new keyboard event was received. + /// + /// # Arguments + /// + /// - `seat` - The `Seat` the event belongs to + /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events. + /// - `button` - Which button was pressed.. + /// - `state` - `MouseButtonState` of the event + /// + /// # TODO: + /// - check if events can arrive out of order. + /// - Make stronger time guarantees + fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState); + /// Called when a new keyboard event was received. + /// + /// # Arguments + /// + /// - `seat` - The `Seat` the event belongs to + /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events. + /// - `axis` - `Axis` this event was generated for. + /// - `source` - Source of the scroll event. Important for interpretation of `amount`. + /// - `amount` - Amount of scrolling on the given `Axis`. See `source` for interpretation. + /// + /// # TODO: + /// - check if events can arrive out of order. + /// - Make stronger time guarantees + fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64); + /// Called when a new keyboard event was received. + /// + /// # Arguments + /// + /// - `seat` - The `Seat` the event belongs to + /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events. + /// - `event` - Touch event recieved. See `TouchEvent`. + /// + /// # TODO: + /// - check if events can arrive out of order. + /// - Make stronger time guarantees + fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent); +} + +impl InputHandler for Box { + fn on_seat_created(&mut self, seat: &Seat) { + (**self).on_seat_created(seat) + } + + fn on_seat_destroyed(&mut self, seat: &Seat) { + (**self).on_seat_destroyed(seat) + } + + fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32) { + (**self).on_keyboard_key(seat, time, key_code, state, count) + } + + fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32)) { + (**self).on_pointer_move(seat, time, to) + } + + fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState) { + (**self).on_pointer_button(seat, time, button, state) + } + + fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64) { + (**self).on_pointer_scroll(seat, time, axis, source, amount) + } + + fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent) { + (**self).on_touch(seat, time, event) + } +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs new file mode 100644 index 0000000..1793dde --- /dev/null +++ b/src/backend/mod.rs @@ -0,0 +1,28 @@ +//! Backend (rendering/input) creation helpers +//! +//! Collection of common traits and implementation about +//! rendering onto various targets and receiving input +//! from various sources. +//! +//! Supported graphics backends: +//! +//! - glutin (headless/windowed) +//! +//! Supported input backends: +//! +//! - glutin (windowed) + +pub mod input; +pub mod graphics; + +#[cfg(feature = "glutin")] +pub mod glutin; + +#[cfg(feature = "glium")] +mod glium; +#[cfg(feature = "glium")] +pub use glium::*; + +trait NewIdType { + fn new(id: u32) -> Self; +} diff --git a/src/lib.rs b/src/lib.rs index b4eed74..1bb9ed5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,12 @@ extern crate wayland_server; extern crate nix; +#[cfg(feature = "glutin")] +extern crate glutin; + #[macro_use] extern crate slog; extern crate slog_stdlog; pub mod shm; +pub mod backend; From 7ac16ce200f5b65fa434aefbc82e06f8bcc43fcf Mon Sep 17 00:00:00 2001 From: Drakulix Date: Tue, 14 Mar 2017 18:47:46 +0100 Subject: [PATCH 02/14] Update wayland-server dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c373267..6c735f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Victor Berger "] [dependencies] -wayland-server = { version = "0.8.4", features = ["dlopen"] } +wayland-server = { version = "0.8.6", features = ["dlopen"] } nix = "0.7.0" glutin = { version = "~0.7.4", optional = true } glium = { version = "~0.16.0", optional = true } From 728bab5690a3dff1cffb024db54fbac9de35bc5f Mon Sep 17 00:00:00 2001 From: Drakulix Date: Tue, 14 Mar 2017 18:50:48 +0100 Subject: [PATCH 03/14] Code cleanup --- src/backend/glutin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/backend/glutin.rs b/src/backend/glutin.rs index c133e86..456fb68 100644 --- a/src/backend/glutin.rs +++ b/src/backend/glutin.rs @@ -217,10 +217,9 @@ impl InputBackend for GlutinInputBackend } fn clear_handler(&mut self) { - if let Some(ref mut handler) = self.handler { + if let Some(mut handler) = self.handler.take() { handler.on_seat_destroyed(&self.seat); } - self.handler = None; } fn set_cursor_position(&mut self, x: u32, y: u32) -> Result<(), ()> { From 460630d0c8952392399aa575670a64240ddc2f82 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Tue, 14 Mar 2017 19:14:22 +0100 Subject: [PATCH 04/14] Fixup documentation --- src/backend/glutin.rs | 2 +- src/backend/graphics/opengl.rs | 24 ++++++++++++++++-------- src/backend/input.rs | 10 +++++----- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/backend/glutin.rs b/src/backend/glutin.rs index 456fb68..18cf3f7 100644 --- a/src/backend/glutin.rs +++ b/src/backend/glutin.rs @@ -261,7 +261,7 @@ impl GlutinInputBackend { if let Some(ref mut handler) = self.handler { match event { - Event::KeyboardInput(state, key_code/*TODO: Is this really the keycode? glutins docs don't tell*/, _) => handler.on_keyboard_key(&self.seat, self.time_counter, key_code as u32, state.into(), 1), + Event::KeyboardInput(state, key_code, _) => handler.on_keyboard_key(&self.seat, self.time_counter, key_code as u32, state.into(), 1), Event::MouseMoved(x, y) => handler.on_pointer_move(&self.seat, self.time_counter, (x as u32, y as u32)), Event::MouseWheel(delta, _) => match delta { MouseScrollDelta::LineDelta(x, y) => { diff --git a/src/backend/graphics/opengl.rs b/src/backend/graphics/opengl.rs index e29521b..5d41694 100644 --- a/src/backend/graphics/opengl.rs +++ b/src/backend/graphics/opengl.rs @@ -20,6 +20,7 @@ pub enum SwapBuffersError { /// The buffers have already been swapped. /// /// This error can be returned when `swap_buffers` has been called multiple times + /// without any modification in between. AlreadySwapped, } @@ -38,23 +39,23 @@ pub enum Api { /// Describes the pixel format of the main framebuffer #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct PixelFormat { - /// Is the format hardware accelerated + /// is the format hardware accelerated pub hardware_accelerated: bool, - /// bits used for colors + /// number of bits used for colors pub color_bits: u8, - /// bits used for alpha channel + /// number of bits used for alpha channel pub alpha_bits: u8, - /// bits used for depth channel + /// number of bits used for depth channel pub depth_bits: u8, - /// bits used for stencil buffer + /// number of bits used for stencil buffer pub stencil_bits: u8, /// is stereoscopy enabled pub stereoscopy: bool, /// is double buffering enabled pub double_buffer: bool, - /// multisampling format used if enabled + /// number of samples used for multisampling if enabled pub multisampling: Option, - /// if the format has srgb enabled + /// is srgb enabled pub srgb: bool, } @@ -70,13 +71,20 @@ pub trait OpenglRenderer /// Supposes that the context has been made current before this function is called. unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void; - /// Returns the dimensions of the window, or screen, etc. + /// Returns the dimensions of the window, or screen, etc in points. + /// + /// That are the scaled pixels of the underlying graphics backend. + /// For nested compositors this will respect the scaling of the root compositor. + /// For drawing directly onto hardware this unit will be equal to actual pixels. fn get_framebuffer_dimensions(&self) -> (u32, u32); /// Returns true if the OpenGL context is the current one in the thread. fn is_current(&self) -> bool; /// Makes the OpenGL context the current context in the current thread. + /// + /// This function is marked unsafe, because the context cannot be made current + /// on multiple threads. unsafe fn make_current(&self); /// Returns the OpenGL API being used. diff --git a/src/backend/input.rs b/src/backend/input.rs index d5712f4..9306e0d 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -187,13 +187,13 @@ pub trait InputHandler { /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events. /// - `key_code` - Code of the pressed key. See linux/input-event-codes.h /// - `state` - `KeyState` of the event - /// - `count` - Amount of key presses registered + /// - `count` - Total number of keys pressed on all devices on the associated `Seat` /// /// # TODO: /// - check if events can arrive out of order. /// - Make stronger time guarantees fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32); - /// Called when a new keyboard event was received. + /// Called when a new pointer movement event was received. /// /// # Arguments /// @@ -205,7 +205,7 @@ pub trait InputHandler { /// - check if events can arrive out of order. /// - Make stronger time guarantees fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32)); - /// Called when a new keyboard event was received. + /// Called when a new pointer button event was received. /// /// # Arguments /// @@ -218,7 +218,7 @@ pub trait InputHandler { /// - check if events can arrive out of order. /// - Make stronger time guarantees fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState); - /// Called when a new keyboard event was received. + /// Called when a new pointer scroll event was received. /// /// # Arguments /// @@ -232,7 +232,7 @@ pub trait InputHandler { /// - check if events can arrive out of order. /// - Make stronger time guarantees fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64); - /// Called when a new keyboard event was received. + /// Called when a new touch event was received. /// /// # Arguments /// From 8e92c9c9226709dc37136cc417c516c736789ec1 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 18 Mar 2017 17:09:29 +0100 Subject: [PATCH 05/14] Add InputConfig --- src/backend/glutin.rs | 16 ++++++++++++---- src/backend/input.rs | 26 +++++++++++++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/backend/glutin.rs b/src/backend/glutin.rs index 18cf3f7..c63a8e7 100644 --- a/src/backend/glutin.rs +++ b/src/backend/glutin.rs @@ -198,12 +198,15 @@ pub struct GlutinInputBackend window: Rc, time_counter: u32, seat: Seat, - handler: Option>, + input_config: (), + handler: Option + 'static>>, } impl InputBackend for GlutinInputBackend { - fn set_handler(&mut self, mut handler: H) { + type InputConfig = (); + + fn set_handler + 'static>(&mut self, mut handler: H) { if self.handler.is_some() { self.clear_handler(); } @@ -211,9 +214,9 @@ impl InputBackend for GlutinInputBackend self.handler = Some(Box::new(handler)); } - fn get_handler(&mut self) -> Option<&mut InputHandler> + fn get_handler(&mut self) -> Option<&mut InputHandler> { - self.handler.as_mut().map(|handler| handler as &mut InputHandler) + self.handler.as_mut().map(|handler| handler as &mut InputHandler) } fn clear_handler(&mut self) { @@ -222,6 +225,10 @@ impl InputBackend for GlutinInputBackend } } + fn input_config(&mut self) -> &mut Self::InputConfig { + &mut self.input_config + } + fn set_cursor_position(&mut self, x: u32, y: u32) -> Result<(), ()> { if let Some((win_x, win_y)) = self.window.get_position() { self.window.set_cursor_position(win_x + x as i32, win_y + y as i32) @@ -239,6 +246,7 @@ impl GlutinInputBackend window: window, time_counter: 0, seat: Seat::new(0), + input_config: (), handler: None, } } diff --git a/src/backend/input.rs b/src/backend/input.rs index 9306e0d..5bd3164 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -158,13 +158,19 @@ pub enum TouchEvent /// Trait that describes objects providing a source of input events. All input backends /// need to implemenent this and provide the same base gurantees about the presicion of /// given events. -pub trait InputBackend { +pub trait InputBackend: Sized { + /// Type of input device associated with the backend + type InputConfig; /// Sets a new handler for this `InputBackend` - fn set_handler(&mut self, handler: H); + fn set_handler + 'static>(&mut self, handler: H); /// Get a reference to the currently set handler, if any - fn get_handler(&mut self) -> Option<&mut InputHandler>; + fn get_handler(&mut self) -> Option<&mut InputHandler>; /// Clears the currently handler, if one is set fn clear_handler(&mut self); + + /// Get current `InputConfig` + fn input_config(&mut self) -> &mut Self::InputConfig; + /// Sets the cursor position, useful for e.g. pointer wrapping. /// /// Not guaranteed to be supported on every backend. The result usually @@ -174,7 +180,7 @@ pub trait InputBackend { } /// Implement to receive input events from any `InputBackend`. -pub trait InputHandler { +pub trait InputHandler { /// Called when a new `Seat` has been created fn on_seat_created(&mut self, seat: &Seat); /// Called when an existing `Seat` has been destroyed. @@ -244,9 +250,15 @@ pub trait InputHandler { /// - check if events can arrive out of order. /// - Make stronger time guarantees fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent); + + /// Called when the `InputConfig` was changed through an external event. + /// + /// What kind of events can trigger this call is completely backend dependent. + /// E.g. an input devices was attached/detached or changed it's own configuration. + fn on_input_config_changed(&mut self, config: &mut B::InputConfig); } -impl InputHandler for Box { +impl InputHandler for Box> { fn on_seat_created(&mut self, seat: &Seat) { (**self).on_seat_created(seat) } @@ -274,4 +286,8 @@ impl InputHandler for Box { fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent) { (**self).on_touch(seat, time, event) } + + fn on_input_config_changed(&mut self, config: &mut B::InputConfig) { + (**self).on_input_config_changed(config) + } } From 4c2e0f889f71960d2bcdc69dcc52e89c72673503 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 18 Mar 2017 17:26:22 +0100 Subject: [PATCH 06/14] Update features --- Cargo.toml | 6 ++++-- src/backend/mod.rs | 6 +++--- src/lib.rs | 5 ++++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c735f8..e5adedd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Victor Berger "] [dependencies] -wayland-server = { version = "0.8.6", features = ["dlopen"] } +wayland-server = "0.8.6" nix = "0.7.0" glutin = { version = "~0.7.4", optional = true } glium = { version = "~0.16.0", optional = true } @@ -16,4 +16,6 @@ clippy = { version = "*", optional = true } slog-term = "~1.5" [features] -default = ["glutin"] +default = ["backend_glutin", "renderer_glium"] +backend_glutin = ["glutin", "wayland-server/dlopen"] +renderer_glium = ["glium"] diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 1793dde..6047505 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -15,12 +15,12 @@ pub mod input; pub mod graphics; -#[cfg(feature = "glutin")] +#[cfg(feature = "backend_glutin")] pub mod glutin; -#[cfg(feature = "glium")] +#[cfg(feature = "renderer_glium")] mod glium; -#[cfg(feature = "glium")] +#[cfg(feature = "renderer_glium")] pub use glium::*; trait NewIdType { diff --git a/src/lib.rs b/src/lib.rs index 1bb9ed5..56498d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,9 +7,12 @@ extern crate wayland_server; extern crate nix; -#[cfg(feature = "glutin")] +#[cfg(feature = "backend_glutin")] extern crate glutin; +#[cfg(feature = "renderer_glium")] +extern crate glium; + #[macro_use] extern crate slog; extern crate slog_stdlog; From 55e56ffc6df775c7dba2be9c528788ba45cf2cda Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 18 Mar 2017 17:27:38 +0100 Subject: [PATCH 07/14] Rename Renderer to GraphicsBackend --- src/backend/glutin.rs | 10 +++++----- src/backend/graphics/opengl.rs | 2 +- src/backend/graphics/software.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/backend/glutin.rs b/src/backend/glutin.rs index c63a8e7..0478ce7 100644 --- a/src/backend/glutin.rs +++ b/src/backend/glutin.rs @@ -6,7 +6,7 @@ use nix::c_void; use std::rc::Rc; use backend::NewIdType; -use backend::graphics::opengl::{Api, OpenglRenderer, PixelFormat, SwapBuffersError}; +use backend::graphics::opengl::{Api, OpenglGraphicsBackend, PixelFormat, SwapBuffersError}; use backend::input::{InputBackend, InputHandler, Seat, KeyState, MouseButton, MouseButtonState, Axis, AxisSource, TouchEvent, TouchSlot}; /// Create a new `GlutinHeadlessRenderer` which implements the `OpenglRenderer` graphics @@ -63,7 +63,7 @@ pub fn init_windowed_from_builder(builder: WindowBuilder) -> Result<(GlutinWindo )) } -/// Headless Opengl Context created by `glutin`. Implements the `OpenglRenderer` graphics +/// Headless Opengl Context created by `glutin`. Implements the `OpenglGraphicsBackend` graphics /// backend trait. pub struct GlutinHeadlessRenderer { @@ -83,7 +83,7 @@ impl GlutinHeadlessRenderer } } -impl OpenglRenderer for GlutinHeadlessRenderer +impl OpenglGraphicsBackend for GlutinHeadlessRenderer { #[inline] fn swap_buffers(&self) -> Result<(), SwapBuffersError> { @@ -124,7 +124,7 @@ impl OpenglRenderer for GlutinHeadlessRenderer } /// Window with an active Opengl Context created by `glutin`. Implements the -/// `OpenglRenderer` graphics backend trait. +/// `OpenglGraphicsBackend` graphics backend trait. pub struct GlutinWindowedRenderer { window: Rc @@ -139,7 +139,7 @@ impl GlutinWindowedRenderer } } -impl OpenglRenderer for GlutinWindowedRenderer +impl OpenglGraphicsBackend for GlutinWindowedRenderer { #[inline] fn swap_buffers(&self) -> Result<(), SwapBuffersError> { diff --git a/src/backend/graphics/opengl.rs b/src/backend/graphics/opengl.rs index 5d41694..cf6f331 100644 --- a/src/backend/graphics/opengl.rs +++ b/src/backend/graphics/opengl.rs @@ -61,7 +61,7 @@ pub struct PixelFormat { /// Trait that describes objects that have an OpenGl context /// and can be used to render upon -pub trait OpenglRenderer +pub trait OpenglGraphicsBackend { /// Swaps buffers at the end of a frame. fn swap_buffers(&self) -> Result<(), SwapBuffersError>; diff --git a/src/backend/graphics/software.rs b/src/backend/graphics/software.rs index d8bb6e0..d6c732a 100644 --- a/src/backend/graphics/software.rs +++ b/src/backend/graphics/software.rs @@ -4,7 +4,7 @@ use wayland_server::protocol::wl_shm::Format; use std::error::Error; /// Trait that describes objects providing a software rendering implementation -pub trait CpuRender { +pub trait CpuGraphicsBackend { /// Render a given buffer of a given format at a specified place in the framebuffer /// /// # Error From 3120683b2495fd4595d0910b2cf0bb20b0b90f52 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 18 Mar 2017 17:27:49 +0100 Subject: [PATCH 08/14] Fix glium support --- src/backend/glium.rs | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/backend/glium.rs b/src/backend/glium.rs index 541ebfe..2faaf57 100644 --- a/src/backend/glium.rs +++ b/src/backend/glium.rs @@ -1,7 +1,9 @@ use glium::backend::Backend; use glium::SwapBuffersError as GliumSwapBuffersError; -use ::backend::graphics::opengl::{OpenglRenderer, SwapBuffersError}; +use std::os::raw::c_void; + +use ::backend::graphics::opengl::{OpenglGraphicsBackend, SwapBuffersError}; impl From for GliumSwapBuffersError { @@ -13,26 +15,41 @@ impl From for GliumSwapBuffersError } } -impl Backend for T +pub struct GliumGraphicBackend(T); + +pub trait IntoGlium: OpenglGraphicsBackend + Sized { - fn swap_buffers(&self) -> Result<(), SwapBuffersError> { - self.swap_buffers().map_err(|x| x.into) + fn into_glium(self) -> GliumGraphicBackend; +} + +impl IntoGlium for T +{ + fn into_glium(self) -> GliumGraphicBackend + { + GliumGraphicBackend(self) + } +} + +unsafe impl Backend for GliumGraphicBackend +{ + fn swap_buffers(&self) -> Result<(), GliumSwapBuffersError> { + self.0.swap_buffers().map_err(Into::into) } unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void { - self.get_proc_address(symbol) + self.0.get_proc_address(symbol) as *const c_void } fn get_framebuffer_dimensions(&self) -> (u32, u32) { - self.get_framebuffer_dimensions() + self.0.get_framebuffer_dimensions() } fn is_current(&self) -> bool { - self.is_current() + self.0.is_current() } unsafe fn make_current(&self) { - self.make_current() + self.0.make_current() } } From d53a7fcc1d09ef69c970092f4620f963910249d3 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sun, 19 Mar 2017 21:55:32 +0100 Subject: [PATCH 09/14] Added SeatCapabilities --- src/backend/glutin.rs | 60 +++++++++++++++++++++++++++++++------------ src/backend/input.rs | 48 +++++++++++++++++++++++++++++----- src/backend/mod.rs | 8 +++++- 3 files changed, 91 insertions(+), 25 deletions(-) diff --git a/src/backend/glutin.rs b/src/backend/glutin.rs index 0478ce7..6e53401 100644 --- a/src/backend/glutin.rs +++ b/src/backend/glutin.rs @@ -4,10 +4,12 @@ use glutin::{ContextError, CreationError, Event, ElementState, MouseScrollDelta, use glutin::{Api as GlutinApi, PixelFormat as GlutinPixelFormat, MouseButton as GlutinMouseButton}; use nix::c_void; use std::rc::Rc; +use std::error::Error; +use std::fmt; -use backend::NewIdType; +use backend::{SeatInternal, TouchSlotInternal}; use backend::graphics::opengl::{Api, OpenglGraphicsBackend, PixelFormat, SwapBuffersError}; -use backend::input::{InputBackend, InputHandler, Seat, KeyState, MouseButton, MouseButtonState, Axis, AxisSource, TouchEvent, TouchSlot}; +use backend::input::{InputBackend, InputHandler, Seat, SeatCapabilities, KeyState, MouseButton, MouseButtonState, Axis, AxisSource, TouchEvent, TouchSlot}; /// Create a new `GlutinHeadlessRenderer` which implements the `OpenglRenderer` graphics /// backend trait @@ -182,6 +184,7 @@ impl OpenglGraphicsBackend for GlutinWindowedRenderer } /// Errors that may happen when driving the event loop of `GlutinInputBackend` +#[derive(Debug)] pub enum GlutinInputError { /// The underlying `glutin` `Window` was closed. No further events can be processed. @@ -190,6 +193,24 @@ pub enum GlutinInputError WindowClosed } +impl Error for GlutinInputError +{ + fn description(&self) -> &str + { + match *self { + GlutinInputError::WindowClosed => "Glutin Window was closed", + } + } +} + +impl fmt::Display for GlutinInputError +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + { + write!(f, "{}", self.description()) + } +} + /// Abstracted event loop of a `glutin` `Window` implementing the `InputBackend` trait /// /// You need to call `process_new_events` periodically to receive any events. @@ -205,6 +226,7 @@ pub struct GlutinInputBackend impl InputBackend for GlutinInputBackend { type InputConfig = (); + type EventError = GlutinInputError; fn set_handler + 'static>(&mut self, mut handler: H) { if self.handler.is_some() { @@ -236,20 +258,6 @@ impl InputBackend for GlutinInputBackend Err(()) } } -} - -impl GlutinInputBackend -{ - fn new(window: Rc) -> GlutinInputBackend - { - GlutinInputBackend { - window: window, - time_counter: 0, - seat: Seat::new(0), - input_config: (), - handler: None, - } - } /// Processes new events of the underlying event loop to drive the set `InputHandler`. /// @@ -263,7 +271,7 @@ impl GlutinInputBackend /// /// The linked `GlutinWindowedRenderer` will error with a lost Context and should /// not be used anymore as well. - pub fn process_new_events(&mut self) -> Result<(), GlutinInputError> + fn dispatch_new_events(&mut self) -> Result<(), GlutinInputError> { for event in self.window.poll_events() { @@ -307,6 +315,24 @@ impl GlutinInputBackend } } +impl GlutinInputBackend +{ + fn new(window: Rc) -> GlutinInputBackend + { + GlutinInputBackend { + window: window, + time_counter: 0, + seat: Seat::new(0, SeatCapabilities { + pointer: true, + keyboard: true, + touch: true, + }), + input_config: (), + handler: None, + } + } +} + impl From for Api { fn from(api: GlutinApi) -> Self { match api { diff --git a/src/backend/input.rs b/src/backend/input.rs index 5bd3164..b02bd6c 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -1,6 +1,7 @@ //! Common traits for input backends to receive input from. +use backend::{SeatInternal, TouchSlotInternal}; -use backend::NewIdType; +use std::error::Error; /// A seat describes a group of input devices and at least one /// graphics device belonging together. @@ -11,16 +12,35 @@ use backend::NewIdType; /// /// Seats can be checked for equality and hashed for differentiation. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Seat { id: u32 } +pub struct Seat { id: u32, capabilities: SeatCapabilities } -impl NewIdType for Seat +impl SeatInternal for Seat { - fn new(id: u32) -> Seat + fn new(id: u32, capabilities: SeatCapabilities) -> Seat { - Seat { id: id } + Seat { id: id, capabilities: capabilities } } } +impl Seat { + /// Get the currently capabilities of this `Seat` + pub fn capabilities(&self) -> &SeatCapabilities + { + &self.capabilities + } +} + +/// Describes capabilities a `Seat` has. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SeatCapabilities { + /// `Seat` has a pointer + pub pointer: bool, + /// `Seat` has a keyboard + pub keyboard: bool, + /// `Seat` has a touchscreen + pub touch: bool +} + /// State of key on a keyboard. Either pressed or released #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum KeyState { @@ -104,9 +124,9 @@ pub enum AxisSource #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TouchSlot { id: u32 } -impl NewIdType for TouchSlot +impl TouchSlotInternal for TouchSlot { - fn new(id: u32) -> TouchSlot + fn new(id: u32) -> Self { TouchSlot { id: id } } @@ -161,6 +181,10 @@ pub enum TouchEvent pub trait InputBackend: Sized { /// Type of input device associated with the backend type InputConfig; + + /// Type representing errors that may be returned when processing events + type EventError: Error; + /// Sets a new handler for this `InputBackend` fn set_handler + 'static>(&mut self, handler: H); /// Get a reference to the currently set handler, if any @@ -171,6 +195,9 @@ pub trait InputBackend: Sized { /// Get current `InputConfig` fn input_config(&mut self) -> &mut Self::InputConfig; + /// Processes new events of the underlying backend and drives the `InputHandler`. + fn dispatch_new_events(&mut self) -> Result<(), Self::EventError>; + /// Sets the cursor position, useful for e.g. pointer wrapping. /// /// Not guaranteed to be supported on every backend. The result usually @@ -185,6 +212,9 @@ pub trait InputHandler { fn on_seat_created(&mut self, seat: &Seat); /// Called when an existing `Seat` has been destroyed. fn on_seat_destroyed(&mut self, seat: &Seat); + /// Called when a `Seat`'s properties have changed. + fn on_seat_changed(&mut self, seat: &Seat); + /// Called when a new keyboard event was received. /// /// # Arguments @@ -267,6 +297,10 @@ impl InputHandler for Box> { (**self).on_seat_destroyed(seat) } + fn on_seat_changed(&mut self, seat: &Seat) { + (**self).on_seat_changed(seat) + } + fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32) { (**self).on_keyboard_key(seat, time, key_code, state, count) } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 6047505..6e01f97 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -23,6 +23,12 @@ mod glium; #[cfg(feature = "renderer_glium")] pub use glium::*; -trait NewIdType { +/// Internal functions that need to be accessible by the different backend implementations + +trait SeatInternal { + fn new(id: u32, capabilities: input::SeatCapabilities) -> Self; +} + +trait TouchSlotInternal { fn new(id: u32) -> Self; } From 369c8a980e7c70ecfb38bfd95eb5f03025dcab57 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sun, 19 Mar 2017 21:56:10 +0100 Subject: [PATCH 10/14] Updated example --- examples/simple.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index c37f0fa..b53ff49 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -3,6 +3,7 @@ extern crate smithay; use smithay::shm::ShmGlobal; use smithay::backend::glutin; +use smithay::backend::input::InputBackend; use wayland_server::protocol::wl_shm; fn main() { @@ -30,7 +31,7 @@ fn main() { //TODO render stuff //TODO put input handling on the event loop - input.process_new_events(); + input.dispatch_new_events().unwrap(); - event_loop.run(); + event_loop.run().unwrap(); } From ae375624ac96461f898aded7e7dd77253821f0d7 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Mon, 20 Mar 2017 14:33:27 +0100 Subject: [PATCH 11/14] Fix formatting --- examples/simple.rs | 14 +- src/backend/glium.rs | 25 ++-- src/backend/glutin.rs | 238 +++++++++++++++++-------------- src/backend/graphics/opengl.rs | 3 +- src/backend/graphics/software.rs | 2 +- src/backend/input.rs | 52 +++---- 6 files changed, 179 insertions(+), 155 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index b53ff49..e0d828e 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,9 +1,9 @@ extern crate wayland_server; extern crate smithay; -use smithay::shm::ShmGlobal; use smithay::backend::glutin; use smithay::backend::input::InputBackend; +use smithay::shm::ShmGlobal; use wayland_server::protocol::wl_shm; fn main() { @@ -11,13 +11,11 @@ fn main() { // Insert the ShmGlobal as a handler to your event loop // Here, we specify tha the standard Argb8888 and Xrgb8888 is the only supported. - let handler_id = event_loop.add_handler_with_init(ShmGlobal::new( - vec![], - None // we don't provide a logger here - )); + let handler_id = + event_loop.add_handler_with_init(ShmGlobal::new(vec![], None /* we don't provide a logger here */)); // Register this handler to advertise a wl_shm global of version 1 - let shm_global = event_loop.register_global::(handler_id, 1); + let shm_global = event_loop.register_global::(handler_id, 1); // Retrieve the shm token for later use to access the buffers let shm_token = { @@ -28,9 +26,9 @@ fn main() { // Initialize a simple backend for testing let (mut renderer, mut input) = glutin::init_windowed().unwrap(); - //TODO render stuff + // TODO render stuff - //TODO put input handling on the event loop + // TODO put input handling on the event loop input.dispatch_new_events().unwrap(); event_loop.run().unwrap(); diff --git a/src/backend/glium.rs b/src/backend/glium.rs index 2faaf57..7814443 100644 --- a/src/backend/glium.rs +++ b/src/backend/glium.rs @@ -1,12 +1,12 @@ -use glium::backend::Backend; + + +use backend::graphics::opengl::{OpenglGraphicsBackend, SwapBuffersError}; use glium::SwapBuffersError as GliumSwapBuffersError; +use glium::backend::Backend; use std::os::raw::c_void; -use ::backend::graphics::opengl::{OpenglGraphicsBackend, SwapBuffersError}; - -impl From for GliumSwapBuffersError -{ +impl From for GliumSwapBuffersError { fn from(error: SwapBuffersError) -> Self { match error { SwapBuffersError::ContextLost => GliumSwapBuffersError::ContextLost, @@ -17,27 +17,22 @@ impl From for GliumSwapBuffersError pub struct GliumGraphicBackend(T); -pub trait IntoGlium: OpenglGraphicsBackend + Sized -{ +pub trait IntoGlium: OpenglGraphicsBackend + Sized { fn into_glium(self) -> GliumGraphicBackend; } -impl IntoGlium for T -{ - fn into_glium(self) -> GliumGraphicBackend - { +impl IntoGlium for T { + fn into_glium(self) -> GliumGraphicBackend { GliumGraphicBackend(self) } } -unsafe impl Backend for GliumGraphicBackend -{ +unsafe impl Backend for GliumGraphicBackend { fn swap_buffers(&self) -> Result<(), GliumSwapBuffersError> { self.0.swap_buffers().map_err(Into::into) } - unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void - { + unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void { self.0.get_proc_address(symbol) as *const c_void } diff --git a/src/backend/glutin.rs b/src/backend/glutin.rs index 6e53401..ff97418 100644 --- a/src/backend/glutin.rs +++ b/src/backend/glutin.rs @@ -1,28 +1,29 @@ //! Implementation of backend traits for types provided by `glutin` -use glutin::{ContextError, CreationError, Event, ElementState, MouseScrollDelta, Touch, TouchPhase, GlContext, HeadlessRendererBuilder, HeadlessContext, WindowBuilder, Window}; -use glutin::{Api as GlutinApi, PixelFormat as GlutinPixelFormat, MouseButton as GlutinMouseButton}; -use nix::c_void; -use std::rc::Rc; -use std::error::Error; -use std::fmt; use backend::{SeatInternal, TouchSlotInternal}; use backend::graphics::opengl::{Api, OpenglGraphicsBackend, PixelFormat, SwapBuffersError}; -use backend::input::{InputBackend, InputHandler, Seat, SeatCapabilities, KeyState, MouseButton, MouseButtonState, Axis, AxisSource, TouchEvent, TouchSlot}; +use backend::input::{Axis, AxisSource, InputBackend, InputHandler, KeyState, MouseButton, MouseButtonState, + Seat, SeatCapabilities, TouchEvent, TouchSlot}; +use glutin::{Api as GlutinApi, MouseButton as GlutinMouseButton, PixelFormat as GlutinPixelFormat}; +use glutin::{ContextError, CreationError, ElementState, Event, GlContext, HeadlessContext, + HeadlessRendererBuilder, MouseScrollDelta, Touch, TouchPhase, Window, WindowBuilder}; +use nix::c_void; +use std::error::Error; +use std::fmt; +use std::rc::Rc; /// Create a new `GlutinHeadlessRenderer` which implements the `OpenglRenderer` graphics /// backend trait -pub fn init_headless_renderer() -> Result -{ +pub fn init_headless_renderer() -> Result { init_headless_renderer_from_builder(HeadlessRendererBuilder::new(1024, 600)) } /// Create a new `GlutinHeadlessRenderer`, which implements the `OpenglRenderer` graphics /// backend trait, with a given already configured `HeadlessRendererBuilder` for /// customization -pub fn init_headless_renderer_from_builder(builder: HeadlessRendererBuilder) -> Result -{ +pub fn init_headless_renderer_from_builder(builder: HeadlessRendererBuilder) + -> Result { let (w, h) = builder.dimensions; let context = builder.build_strict()?; @@ -31,15 +32,14 @@ pub fn init_headless_renderer_from_builder(builder: HeadlessRendererBuilder) -> /// Create a new `GlutinWindowedRenderer`, which implements the `OpenglRenderer` graphics /// backend trait -pub fn init_windowed_renderer() -> Result -{ +pub fn init_windowed_renderer() -> Result { init_windowed_renderer_from_builder(WindowBuilder::new()) } /// Create a new `GlutinWindowedRenderer`, which implements the `OpenglRenderer` graphics /// backend trait, with a given already configured `WindowBuilder` for customization. -pub fn init_windowed_renderer_from_builder(builder: WindowBuilder) -> Result -{ +pub fn init_windowed_renderer_from_builder(builder: WindowBuilder) + -> Result { let window = Rc::new(builder.build_strict()?); Ok(GlutinWindowedRenderer::new(window)) } @@ -47,8 +47,7 @@ pub fn init_windowed_renderer_from_builder(builder: WindowBuilder) -> Result Result<(GlutinWindowedRenderer, GlutinInputBackend), CreationError> -{ +pub fn init_windowed() -> Result<(GlutinWindowedRenderer, GlutinInputBackend), CreationError> { init_windowed_from_builder(WindowBuilder::new()) } @@ -56,26 +55,21 @@ pub fn init_windowed() -> Result<(GlutinWindowedRenderer, GlutinInputBackend), C /// customization. Returns a `GlutinWindowedRenderer` implementing /// the `OpenglRenderer` graphics backend trait and a `GlutinInputBackend` implementing /// the `InputBackend` trait. -pub fn init_windowed_from_builder(builder: WindowBuilder) -> Result<(GlutinWindowedRenderer, GlutinInputBackend), CreationError> -{ +pub fn init_windowed_from_builder(builder: WindowBuilder) + -> Result<(GlutinWindowedRenderer, GlutinInputBackend), CreationError> { let window = Rc::new(builder.build_strict()?); - Ok(( - GlutinWindowedRenderer::new(window.clone()), - GlutinInputBackend::new(window) - )) + Ok((GlutinWindowedRenderer::new(window.clone()), GlutinInputBackend::new(window))) } /// Headless Opengl Context created by `glutin`. Implements the `OpenglGraphicsBackend` graphics /// backend trait. -pub struct GlutinHeadlessRenderer -{ +pub struct GlutinHeadlessRenderer { context: HeadlessContext, w: u32, h: u32, } -impl GlutinHeadlessRenderer -{ +impl GlutinHeadlessRenderer { fn new(context: HeadlessContext, w: u32, h: u32) -> GlutinHeadlessRenderer { GlutinHeadlessRenderer { context: context, @@ -85,8 +79,7 @@ impl GlutinHeadlessRenderer } } -impl OpenglGraphicsBackend for GlutinHeadlessRenderer -{ +impl OpenglGraphicsBackend for GlutinHeadlessRenderer { #[inline] fn swap_buffers(&self) -> Result<(), SwapBuffersError> { match self.context.swap_buffers() { @@ -127,22 +120,17 @@ impl OpenglGraphicsBackend for GlutinHeadlessRenderer /// Window with an active Opengl Context created by `glutin`. Implements the /// `OpenglGraphicsBackend` graphics backend trait. -pub struct GlutinWindowedRenderer -{ - window: Rc +pub struct GlutinWindowedRenderer { + window: Rc, } -impl GlutinWindowedRenderer -{ +impl GlutinWindowedRenderer { fn new(window: Rc) -> GlutinWindowedRenderer { - GlutinWindowedRenderer { - window: window, - } + GlutinWindowedRenderer { window: window } } } -impl OpenglGraphicsBackend for GlutinWindowedRenderer -{ +impl OpenglGraphicsBackend for GlutinWindowedRenderer { #[inline] fn swap_buffers(&self) -> Result<(), SwapBuffersError> { match self.window.swap_buffers() { @@ -159,7 +147,7 @@ impl OpenglGraphicsBackend for GlutinWindowedRenderer #[inline] fn get_framebuffer_dimensions(&self) -> (u32, u32) { - let (width, height) = self.window.get_inner_size().unwrap_or((800, 600)); // TODO: 800x600 ? + let (width, height) = self.window.get_inner_size().unwrap_or((800, 600)); // TODO: 800x600 ? let scale = self.window.hidpi_factor(); ((width as f32 * scale) as u32, (height as f32 * scale) as u32) } @@ -185,28 +173,23 @@ impl OpenglGraphicsBackend for GlutinWindowedRenderer /// Errors that may happen when driving the event loop of `GlutinInputBackend` #[derive(Debug)] -pub enum GlutinInputError -{ +pub enum GlutinInputError { /// The underlying `glutin` `Window` was closed. No further events can be processed. /// /// See `GlutinInputBackend::process_new_events`. - WindowClosed + WindowClosed, } -impl Error for GlutinInputError -{ - fn description(&self) -> &str - { +impl Error for GlutinInputError { + fn description(&self) -> &str { match *self { GlutinInputError::WindowClosed => "Glutin Window was closed", } } } -impl fmt::Display for GlutinInputError -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result - { +impl fmt::Display for GlutinInputError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) } } @@ -214,8 +197,7 @@ impl fmt::Display for GlutinInputError /// Abstracted event loop of a `glutin` `Window` implementing the `InputBackend` trait /// /// You need to call `process_new_events` periodically to receive any events. -pub struct GlutinInputBackend -{ +pub struct GlutinInputBackend { window: Rc, time_counter: u32, seat: Seat, @@ -223,8 +205,7 @@ pub struct GlutinInputBackend handler: Option + 'static>>, } -impl InputBackend for GlutinInputBackend -{ +impl InputBackend for GlutinInputBackend { type InputConfig = (); type EventError = GlutinInputError; @@ -236,8 +217,7 @@ impl InputBackend for GlutinInputBackend self.handler = Some(Box::new(handler)); } - fn get_handler(&mut self) -> Option<&mut InputHandler> - { + fn get_handler(&mut self) -> Option<&mut InputHandler> { self.handler.as_mut().map(|handler| handler as &mut InputHandler) } @@ -271,42 +251,96 @@ impl InputBackend for GlutinInputBackend /// /// The linked `GlutinWindowedRenderer` will error with a lost Context and should /// not be used anymore as well. - fn dispatch_new_events(&mut self) -> Result<(), GlutinInputError> - { - for event in self.window.poll_events() - { + fn dispatch_new_events(&mut self) -> Result<(), GlutinInputError> { + for event in self.window.poll_events() { if let Some(ref mut handler) = self.handler { match event { - Event::KeyboardInput(state, key_code, _) => handler.on_keyboard_key(&self.seat, self.time_counter, key_code as u32, state.into(), 1), - Event::MouseMoved(x, y) => handler.on_pointer_move(&self.seat, self.time_counter, (x as u32, y as u32)), - Event::MouseWheel(delta, _) => match delta { - MouseScrollDelta::LineDelta(x, y) => { - if x != 0.0 { - handler.on_pointer_scroll(&self.seat, self.time_counter, Axis::Horizontal, AxisSource::Wheel, x as f64); - } - if y != 0.0 { - handler.on_pointer_scroll(&self.seat, self.time_counter, Axis::Vertical, AxisSource::Wheel, y as f64); - } - }, - MouseScrollDelta::PixelDelta(x, y) => { - if x != 0.0 { - handler.on_pointer_scroll(&self.seat, self.time_counter, Axis::Vertical, AxisSource::Continous, x as f64); - } - if y != 0.0 { - handler.on_pointer_scroll(&self.seat, self.time_counter, Axis::Horizontal, AxisSource::Continous, y as f64); - } - }, - }, - Event::MouseInput(state, button) => handler.on_pointer_button(&self.seat, self.time_counter, button.into(), state.into()), - Event::Touch(Touch { phase: TouchPhase::Started, location: (x, y), id}) => handler.on_touch(&self.seat, self.time_counter, TouchEvent::Down { slot: Some(TouchSlot::new(id as u32)), x: x, y: y }), - Event::Touch(Touch { phase: TouchPhase::Moved, location: (x, y), id}) => handler.on_touch(&self.seat, self.time_counter, TouchEvent::Motion { slot: Some(TouchSlot::new(id as u32)), x: x, y: y }), - Event::Touch(Touch { phase: TouchPhase::Ended, location: (x, y), id }) => { - handler.on_touch(&self.seat, self.time_counter, TouchEvent::Motion { slot: Some(TouchSlot::new(id as u32)), x: x, y: y }); - handler.on_touch(&self.seat, self.time_counter, TouchEvent::Up { slot: Some(TouchSlot::new(id as u32)) }); + Event::KeyboardInput(state, key_code, _) => { + handler.on_keyboard_key(&self.seat, + self.time_counter, + key_code as u32, + state.into(), + 1) + } + Event::MouseMoved(x, y) => { + handler.on_pointer_move(&self.seat, self.time_counter, (x as u32, y as u32)) + } + Event::MouseWheel(delta, _) => { + match delta { + MouseScrollDelta::LineDelta(x, y) => { + if x != 0.0 { + handler.on_pointer_scroll(&self.seat, + self.time_counter, + Axis::Horizontal, + AxisSource::Wheel, + x as f64); + } + if y != 0.0 { + handler.on_pointer_scroll(&self.seat, + self.time_counter, + Axis::Vertical, + AxisSource::Wheel, + y as f64); + } + } + MouseScrollDelta::PixelDelta(x, y) => { + if x != 0.0 { + handler.on_pointer_scroll(&self.seat, + self.time_counter, + Axis::Vertical, + AxisSource::Continous, + x as f64); + } + if y != 0.0 { + handler.on_pointer_scroll(&self.seat, + self.time_counter, + Axis::Horizontal, + AxisSource::Continous, + y as f64); + } + } + } + } + Event::MouseInput(state, button) => { + handler.on_pointer_button(&self.seat, self.time_counter, button.into(), state.into()) + } + Event::Touch(Touch { phase: TouchPhase::Started, location: (x, y), id }) => { + handler.on_touch(&self.seat, + self.time_counter, + TouchEvent::Down { + slot: Some(TouchSlot::new(id as u32)), + x: x, + y: y, + }) + } + Event::Touch(Touch { phase: TouchPhase::Moved, location: (x, y), id }) => { + handler.on_touch(&self.seat, + self.time_counter, + TouchEvent::Motion { + slot: Some(TouchSlot::new(id as u32)), + x: x, + y: y, + }) + } + Event::Touch(Touch { phase: TouchPhase::Ended, location: (x, y), id }) => { + handler.on_touch(&self.seat, + self.time_counter, + TouchEvent::Motion { + slot: Some(TouchSlot::new(id as u32)), + x: x, + y: y, + }); + handler.on_touch(&self.seat, + self.time_counter, + TouchEvent::Up { slot: Some(TouchSlot::new(id as u32)) }); + } + Event::Touch(Touch { phase: TouchPhase::Cancelled, id, .. }) => { + handler.on_touch(&self.seat, + self.time_counter, + TouchEvent::Cancel { slot: Some(TouchSlot::new(id as u32)) }) } - Event::Touch(Touch { phase: TouchPhase::Cancelled, id, ..}) => handler.on_touch(&self.seat, self.time_counter, TouchEvent::Cancel { slot: Some(TouchSlot::new(id as u32)) }), Event::Closed => return Err(GlutinInputError::WindowClosed), - _ => {}, + _ => {} } self.time_counter += 1; } @@ -315,18 +349,17 @@ impl InputBackend for GlutinInputBackend } } -impl GlutinInputBackend -{ - fn new(window: Rc) -> GlutinInputBackend - { +impl GlutinInputBackend { + fn new(window: Rc) -> GlutinInputBackend { GlutinInputBackend { window: window, time_counter: 0, - seat: Seat::new(0, SeatCapabilities { - pointer: true, - keyboard: true, - touch: true, - }), + seat: Seat::new(0, + SeatCapabilities { + pointer: true, + keyboard: true, + touch: true, + }), input_config: (), handler: None, } @@ -359,8 +392,7 @@ impl From for PixelFormat { } } -impl From for MouseButton -{ +impl From for MouseButton { fn from(button: GlutinMouseButton) -> MouseButton { match button { GlutinMouseButton::Left => MouseButton::Left, @@ -371,8 +403,7 @@ impl From for MouseButton } } -impl From for KeyState -{ +impl From for KeyState { fn from(state: ElementState) -> Self { match state { ElementState::Pressed => KeyState::Pressed, @@ -381,8 +412,7 @@ impl From for KeyState } } -impl From for MouseButtonState -{ +impl From for MouseButtonState { fn from(state: ElementState) -> Self { match state { ElementState::Pressed => MouseButtonState::Pressed, diff --git a/src/backend/graphics/opengl.rs b/src/backend/graphics/opengl.rs index cf6f331..a03f93b 100644 --- a/src/backend/graphics/opengl.rs +++ b/src/backend/graphics/opengl.rs @@ -61,8 +61,7 @@ pub struct PixelFormat { /// Trait that describes objects that have an OpenGl context /// and can be used to render upon -pub trait OpenglGraphicsBackend -{ +pub trait OpenglGraphicsBackend { /// Swaps buffers at the end of a frame. fn swap_buffers(&self) -> Result<(), SwapBuffersError>; diff --git a/src/backend/graphics/software.rs b/src/backend/graphics/software.rs index d6c732a..278885a 100644 --- a/src/backend/graphics/software.rs +++ b/src/backend/graphics/software.rs @@ -1,7 +1,7 @@ //! Common traits and types used for software rendering on graphics backends -use wayland_server::protocol::wl_shm::Format; use std::error::Error; +use wayland_server::protocol::wl_shm::Format; /// Trait that describes objects providing a software rendering implementation pub trait CpuGraphicsBackend { diff --git a/src/backend/input.rs b/src/backend/input.rs index b02bd6c..03d0ca5 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -1,4 +1,5 @@ //! Common traits for input backends to receive input from. + use backend::{SeatInternal, TouchSlotInternal}; use std::error::Error; @@ -12,20 +13,23 @@ use std::error::Error; /// /// Seats can be checked for equality and hashed for differentiation. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Seat { id: u32, capabilities: SeatCapabilities } +pub struct Seat { + id: u32, + capabilities: SeatCapabilities, +} -impl SeatInternal for Seat -{ - fn new(id: u32, capabilities: SeatCapabilities) -> Seat - { - Seat { id: id, capabilities: capabilities } +impl SeatInternal for Seat { + fn new(id: u32, capabilities: SeatCapabilities) -> Seat { + Seat { + id: id, + capabilities: capabilities, + } } } impl Seat { /// Get the currently capabilities of this `Seat` - pub fn capabilities(&self) -> &SeatCapabilities - { + pub fn capabilities(&self) -> &SeatCapabilities { &self.capabilities } } @@ -38,7 +42,7 @@ pub struct SeatCapabilities { /// `Seat` has a keyboard pub keyboard: bool, /// `Seat` has a touchscreen - pub touch: bool + pub touch: bool, } /// State of key on a keyboard. Either pressed or released @@ -74,8 +78,7 @@ pub enum MouseButtonState { /// Axis when scrolling #[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Axis -{ +pub enum Axis { /// Vertical axis Vertical, /// Horizonal axis @@ -84,8 +87,7 @@ pub enum Axis /// Source of an axis when scrolling #[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum AxisSource -{ +pub enum AxisSource { /// Finger. Mostly used for trackpads. /// /// Guarantees that a scroll sequence is terminated with a scroll value of 0. @@ -122,20 +124,19 @@ pub enum AxisSource /// fingers on a multi-touch enabled input device. Events should only /// be interpreted in the context of other events on the same slot. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct TouchSlot { id: u32 } +pub struct TouchSlot { + id: u32, +} -impl TouchSlotInternal for TouchSlot -{ - fn new(id: u32) -> Self - { +impl TouchSlotInternal for TouchSlot { + fn new(id: u32) -> Self { TouchSlot { id: id } } } /// Touch event #[derive(Debug, PartialEq, Clone, Copy)] -pub enum TouchEvent -{ +pub enum TouchEvent { /// The start of an event at a given position (x, y). /// /// If the device has multi-touch capabilities a slot is given. @@ -145,7 +146,7 @@ pub enum TouchEvent /// Absolute x-coordinate of the touch position. x: f64, /// Absolute y-coordinate of the touch position. - y: f64 + y: f64, }, /// Movement of a touch on the device surface to a given position (x, y). /// @@ -156,23 +157,24 @@ pub enum TouchEvent /// Absolute x-coordinate of the final touch position after the motion. x: f64, /// Absolute y-coordinate of the final touch position after the motion. - y: f64 }, + y: f64, + }, /// Stop of an event chain. /// /// If the device has multi-touch capabilities a slot is given. Up { /// `TouchSlot`, if the device has multi-touch capabilities - slot: Option + slot: Option, }, /// Cancel of an event chain. All previous events in the chain should be ignored. /// /// If the device has multi-touch capabilities a slot is given. Cancel { /// `TouchSlot`, if the device has multi-touch capabilities - slot: Option + slot: Option, }, /// Signals the end of a set of touchpoints at one device sample time. - Frame + Frame, } /// Trait that describes objects providing a source of input events. All input backends From 6d2025634c952ed659468aa03633b2b610794eac Mon Sep 17 00:00:00 2001 From: Drakulix Date: Mon, 20 Mar 2017 15:43:57 +0100 Subject: [PATCH 12/14] Fix travis using outdated rustfmt --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index cb938e1..885f206 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,8 @@ branches: before_script: - export PATH=$HOME/.local/bin:$HOME/.cargo/bin:$PATH - which rustfmt || cargo install rustfmt + - which cargo-install-update || cargo install cargo-update + - cargo install-update -a - pip install 'travis-cargo<0.2' --user - mkdir $(pwd)/socket - export XDG_RUNTIME_DIR="$(pwd)/socket" From a0b8f53e03c7e599e943cc8e0b35dc1296ca92a0 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Mon, 20 Mar 2017 15:53:45 +0100 Subject: [PATCH 13/14] Fix example formatting --- examples/simple.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/simple.rs b/examples/simple.rs index e0d828e..e435792 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -12,7 +12,8 @@ fn main() { // Insert the ShmGlobal as a handler to your event loop // Here, we specify tha the standard Argb8888 and Xrgb8888 is the only supported. let handler_id = - event_loop.add_handler_with_init(ShmGlobal::new(vec![], None /* we don't provide a logger here */)); + event_loop.add_handler_with_init(ShmGlobal::new(vec![], + None /* we don't provide a logger here */)); // Register this handler to advertise a wl_shm global of version 1 let shm_global = event_loop.register_global::(handler_id, 1); From 8a1971f4718cf23ade1c8f2591e3f3051457da54 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Mon, 20 Mar 2017 15:55:18 +0100 Subject: [PATCH 14/14] Turn of Fixme and Todo reporting --- .rustfmt.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index 7e41aae..82fb65d 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -4,8 +4,8 @@ fn_args_layout = "Visual" fn_arg_intent = "Tabbed" reorder_imports = true reorder_imported_names = true -report_todo = "Always" -report_fixme = "Always" +report_todo = "Never" +report_fixme = "Never" normalize_comments = true use_try_shorthand = true max_width = 110