Initial glutin backend implementation

This commit is contained in:
Drakulix 2017-03-07 11:53:57 +01:00
parent 30721f24df
commit ec8149b084
10 changed files with 858 additions and 1 deletions

View File

@ -4,11 +4,16 @@ version = "0.1.0"
authors = ["Victor Berger <victor.berger@thalesgroup.com>"] authors = ["Victor Berger <victor.berger@thalesgroup.com>"]
[dependencies] [dependencies]
wayland-server = "0.8.4" wayland-server = { version = "0.8.4", features = ["dlopen"] }
nix = "0.7.0" 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 = { version = "~1.5.2", features = ["max_level_trace", "release_max_level_info"] }
slog-stdlog = "~1.1.0" slog-stdlog = "~1.1.0"
clippy = { version = "*", optional = true } clippy = { version = "*", optional = true }
[dev-dependencies] [dev-dependencies]
slog-term = "~1.5" slog-term = "~1.5"
[features]
default = ["glutin"]

36
examples/simple.rs Normal file
View File

@ -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::<wl_shm::WlShm,ShmGlobal>(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::<ShmGlobal>(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();
}

38
src/backend/glium.rs Normal file
View File

@ -0,0 +1,38 @@
use glium::backend::Backend;
use glium::SwapBuffersError as GliumSwapBuffersError;
use ::backend::graphics::opengl::{OpenglRenderer, SwapBuffersError};
impl From<SwapBuffersError> for GliumSwapBuffersError
{
fn from(error: SwapBuffersError) -> Self {
match error {
SwapBuffersError::ContextLost => GliumSwapBuffersError::ContextLost,
SwapBuffersError::AlreadySwapped => GliumSwapBuffersError::AlreadySwapped,
}
}
}
impl<T: OpenglRenderer> 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()
}
}

359
src/backend/glutin.rs Normal file
View File

@ -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<GlutinHeadlessRenderer, CreationError>
{
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<GlutinHeadlessRenderer, CreationError>
{
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<GlutinWindowedRenderer, CreationError>
{
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<GlutinWindowedRenderer, CreationError>
{
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<Window>
}
impl GlutinWindowedRenderer
{
fn new(window: Rc<Window>) -> 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<Window>,
time_counter: u32,
seat: Seat,
handler: Option<Box<InputHandler + 'static>>,
}
impl InputBackend for GlutinInputBackend
{
fn set_handler<H: InputHandler + 'static>(&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<Window>) -> 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<GlutinApi> for Api {
fn from(api: GlutinApi) -> Self {
match api {
GlutinApi::OpenGl => Api::OpenGl,
GlutinApi::OpenGlEs => Api::OpenGlEs,
GlutinApi::WebGl => Api::WebGl,
}
}
}
impl From<GlutinPixelFormat> 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<GlutinMouseButton> 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<ElementState> for KeyState
{
fn from(state: ElementState) -> Self {
match state {
ElementState::Pressed => KeyState::Pressed,
ElementState::Released => KeyState::Released,
}
}
}
impl From<ElementState> for MouseButtonState
{
fn from(state: ElementState) -> Self {
match state {
ElementState::Pressed => MouseButtonState::Pressed,
ElementState::Released => MouseButtonState::Released,
}
}
}

View File

@ -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;

View File

@ -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<u16>,
/// 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;
}

View File

@ -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<E: Error> {
/// 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);
}

277
src/backend/input.rs Normal file
View File

@ -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<TouchSlot>,
/// 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<TouchSlot>,
/// 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<TouchSlot>
},
/// 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<TouchSlot>
},
/// 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<H: InputHandler + 'static>(&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<InputHandler> {
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)
}
}

28
src/backend/mod.rs Normal file
View File

@ -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;
}

View File

@ -7,8 +7,12 @@
extern crate wayland_server; extern crate wayland_server;
extern crate nix; extern crate nix;
#[cfg(feature = "glutin")]
extern crate glutin;
#[macro_use] #[macro_use]
extern crate slog; extern crate slog;
extern crate slog_stdlog; extern crate slog_stdlog;
pub mod shm; pub mod shm;
pub mod backend;