Merge pull request #9 from Drakulix/feature/glutin
First draft of a glutin backend
This commit is contained in:
commit
f40bd92e14
|
@ -4,8 +4,8 @@ fn_args_layout = "Visual"
|
||||||
fn_arg_intent = "Tabbed"
|
fn_arg_intent = "Tabbed"
|
||||||
reorder_imports = true
|
reorder_imports = true
|
||||||
reorder_imported_names = true
|
reorder_imported_names = true
|
||||||
report_todo = "Always"
|
report_todo = "Never"
|
||||||
report_fixme = "Always"
|
report_fixme = "Never"
|
||||||
normalize_comments = true
|
normalize_comments = true
|
||||||
use_try_shorthand = true
|
use_try_shorthand = true
|
||||||
max_width = 110
|
max_width = 110
|
||||||
|
|
|
@ -26,6 +26,8 @@ branches:
|
||||||
before_script:
|
before_script:
|
||||||
- export PATH=$HOME/.local/bin:$HOME/.cargo/bin:$PATH
|
- export PATH=$HOME/.local/bin:$HOME/.cargo/bin:$PATH
|
||||||
- which rustfmt || cargo install rustfmt
|
- which rustfmt || cargo install rustfmt
|
||||||
|
- which cargo-install-update || cargo install cargo-update
|
||||||
|
- cargo install-update -a
|
||||||
- pip install 'travis-cargo<0.2' --user
|
- pip install 'travis-cargo<0.2' --user
|
||||||
- mkdir $(pwd)/socket
|
- mkdir $(pwd)/socket
|
||||||
- export XDG_RUNTIME_DIR="$(pwd)/socket"
|
- export XDG_RUNTIME_DIR="$(pwd)/socket"
|
||||||
|
|
|
@ -4,11 +4,18 @@ 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 = "0.8.6"
|
||||||
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 = ["backend_glutin", "renderer_glium"]
|
||||||
|
backend_glutin = ["glutin", "wayland-server/dlopen"]
|
||||||
|
renderer_glium = ["glium"]
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
extern crate wayland_server;
|
||||||
|
extern crate smithay;
|
||||||
|
|
||||||
|
use smithay::backend::glutin;
|
||||||
|
use smithay::backend::input::InputBackend;
|
||||||
|
use smithay::shm::ShmGlobal;
|
||||||
|
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.dispatch_new_events().unwrap();
|
||||||
|
|
||||||
|
event_loop.run().unwrap();
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
|
||||||
|
use backend::graphics::opengl::{OpenglGraphicsBackend, SwapBuffersError};
|
||||||
|
use glium::SwapBuffersError as GliumSwapBuffersError;
|
||||||
|
use glium::backend::Backend;
|
||||||
|
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
|
impl From<SwapBuffersError> for GliumSwapBuffersError {
|
||||||
|
fn from(error: SwapBuffersError) -> Self {
|
||||||
|
match error {
|
||||||
|
SwapBuffersError::ContextLost => GliumSwapBuffersError::ContextLost,
|
||||||
|
SwapBuffersError::AlreadySwapped => GliumSwapBuffersError::AlreadySwapped,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GliumGraphicBackend<T: OpenglGraphicsBackend>(T);
|
||||||
|
|
||||||
|
pub trait IntoGlium: OpenglGraphicsBackend + Sized {
|
||||||
|
fn into_glium(self) -> GliumGraphicBackend<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: OpenglGraphicsBackend> IntoGlium for T {
|
||||||
|
fn into_glium(self) -> GliumGraphicBackend<Self> {
|
||||||
|
GliumGraphicBackend(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: OpenglGraphicsBackend> Backend for GliumGraphicBackend<T> {
|
||||||
|
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.0.get_proc_address(symbol) as *const c_void
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_framebuffer_dimensions(&self) -> (u32, u32) {
|
||||||
|
self.0.get_framebuffer_dimensions()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_current(&self) -> bool {
|
||||||
|
self.0.is_current()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn make_current(&self) {
|
||||||
|
self.0.make_current()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,422 @@
|
||||||
|
//! Implementation of backend traits for types provided by `glutin`
|
||||||
|
|
||||||
|
|
||||||
|
use backend::{SeatInternal, TouchSlotInternal};
|
||||||
|
use backend::graphics::opengl::{Api, OpenglGraphicsBackend, PixelFormat, SwapBuffersError};
|
||||||
|
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<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 `OpenglGraphicsBackend` 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 OpenglGraphicsBackend 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
|
||||||
|
/// `OpenglGraphicsBackend` graphics backend trait.
|
||||||
|
pub struct GlutinWindowedRenderer {
|
||||||
|
window: Rc<Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlutinWindowedRenderer {
|
||||||
|
fn new(window: Rc<Window>) -> GlutinWindowedRenderer {
|
||||||
|
GlutinWindowedRenderer { window: window }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpenglGraphicsBackend 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`
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GlutinInputError {
|
||||||
|
/// The underlying `glutin` `Window` was closed. No further events can be processed.
|
||||||
|
///
|
||||||
|
/// See `GlutinInputBackend::process_new_events`.
|
||||||
|
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.
|
||||||
|
pub struct GlutinInputBackend {
|
||||||
|
window: Rc<Window>,
|
||||||
|
time_counter: u32,
|
||||||
|
seat: Seat,
|
||||||
|
input_config: (),
|
||||||
|
handler: Option<Box<InputHandler<GlutinInputBackend> + 'static>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputBackend for GlutinInputBackend {
|
||||||
|
type InputConfig = ();
|
||||||
|
type EventError = GlutinInputError;
|
||||||
|
|
||||||
|
fn set_handler<H: InputHandler<Self> + '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>> {
|
||||||
|
self.handler.as_mut().map(|handler| handler as &mut InputHandler<Self>)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_handler(&mut self) {
|
||||||
|
if let Some(mut handler) = self.handler.take() {
|
||||||
|
handler.on_seat_destroyed(&self.seat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
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::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 GlutinInputBackend {
|
||||||
|
fn new(window: Rc<Window>) -> GlutinInputBackend {
|
||||||
|
GlutinInputBackend {
|
||||||
|
window: window,
|
||||||
|
time_counter: 0,
|
||||||
|
seat: Seat::new(0,
|
||||||
|
SeatCapabilities {
|
||||||
|
pointer: true,
|
||||||
|
keyboard: true,
|
||||||
|
touch: true,
|
||||||
|
}),
|
||||||
|
input_config: (),
|
||||||
|
handler: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
@ -0,0 +1,94 @@
|
||||||
|
//! 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
|
||||||
|
/// without any modification in between.
|
||||||
|
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,
|
||||||
|
/// number of bits used for colors
|
||||||
|
pub color_bits: u8,
|
||||||
|
/// number of bits used for alpha channel
|
||||||
|
pub alpha_bits: u8,
|
||||||
|
/// number of bits used for depth channel
|
||||||
|
pub depth_bits: u8,
|
||||||
|
/// 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,
|
||||||
|
/// number of samples used for multisampling if enabled
|
||||||
|
pub multisampling: Option<u16>,
|
||||||
|
/// is srgb enabled
|
||||||
|
pub srgb: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait that describes objects that have an OpenGl context
|
||||||
|
/// and can be used to render upon
|
||||||
|
pub trait OpenglGraphicsBackend {
|
||||||
|
/// 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 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.
|
||||||
|
fn get_api(&self) -> Api;
|
||||||
|
|
||||||
|
/// Returns the pixel format of the main framebuffer of the context.
|
||||||
|
fn get_pixel_format(&self) -> PixelFormat;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
//! Common traits and types used for software rendering on graphics backends
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
use wayland_server::protocol::wl_shm::Format;
|
||||||
|
|
||||||
|
/// Trait that describes objects providing a software rendering implementation
|
||||||
|
pub trait CpuGraphicsBackend<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);
|
||||||
|
}
|
|
@ -0,0 +1,329 @@
|
||||||
|
//! Common traits for input backends to receive input from.
|
||||||
|
|
||||||
|
use backend::{SeatInternal, TouchSlotInternal};
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
/// 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,
|
||||||
|
capabilities: SeatCapabilities,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
&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 {
|
||||||
|
/// 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 TouchSlotInternal for TouchSlot {
|
||||||
|
fn new(id: u32) -> Self {
|
||||||
|
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: 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<H: InputHandler<Self> + 'static>(&mut self, handler: H);
|
||||||
|
/// Get a reference to the currently set handler, if any
|
||||||
|
fn get_handler(&mut self) -> Option<&mut InputHandler<Self>>;
|
||||||
|
/// Clears the currently handler, if one is set
|
||||||
|
fn clear_handler(&mut self);
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
/// 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<B: InputBackend> {
|
||||||
|
/// 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 `Seat`'s properties have changed.
|
||||||
|
fn on_seat_changed(&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` - 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 pointer movement 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 pointer button 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 pointer scroll 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 touch 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);
|
||||||
|
|
||||||
|
/// 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<B: InputBackend> InputHandler<B> for Box<InputHandler<B>> {
|
||||||
|
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_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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_input_config_changed(&mut self, config: &mut B::InputConfig) {
|
||||||
|
(**self).on_input_config_changed(config)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
//! 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 = "backend_glutin")]
|
||||||
|
pub mod glutin;
|
||||||
|
|
||||||
|
#[cfg(feature = "renderer_glium")]
|
||||||
|
mod glium;
|
||||||
|
#[cfg(feature = "renderer_glium")]
|
||||||
|
pub use glium::*;
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
}
|
|
@ -7,8 +7,15 @@
|
||||||
extern crate wayland_server;
|
extern crate wayland_server;
|
||||||
extern crate nix;
|
extern crate nix;
|
||||||
|
|
||||||
|
#[cfg(feature = "backend_glutin")]
|
||||||
|
extern crate glutin;
|
||||||
|
|
||||||
|
#[cfg(feature = "renderer_glium")]
|
||||||
|
extern crate glium;
|
||||||
|
|
||||||
#[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;
|
||||||
|
|
Loading…
Reference in New Issue