Skip to content
This repository was archived by the owner on Aug 3, 2024. It is now read-only.

Backends #193

Merged
merged 10 commits into from
Jun 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions src/backend/backend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//! A backend contains information about how clients connected and rendered.
//!
//! In nested environments such as Wayland and X11 the compositor is a client to the hosh
//! process.
//!
//! In the headless backend clients aren't rendered and the only OS resources used are
//! the Wayland file descriptor. This is useful for testing.
//!
//! On the DRM backend the compositor controls an entire TTY. This is the most invasive,
//! but also the most useful backend. If there's an infinite loop here then it is very
//! easy to get into a place where the only course of action is restarting the computer.
//!
//! On the multi backend multiple backends could be running at the same time.

use libc;
use wlroots_sys::{self, wlr_backend, wlr_backend_is_wl, wlr_backend_is_x11,
wlr_backend_is_drm, wlr_backend_is_headless, wlr_backend_is_multi,
wlr_backend_is_libinput};

use super::{WaylandBackend, X11Backend, DRMBackend, HeadlessBackend, MultiBackend, LibInputBackend};

/// A custom function to set up the renderer.
pub type UnsafeRenderSetupFunction = unsafe extern "C" fn(*mut wlroots_sys::wlr_egl,
u32,
*mut libc::c_void,
*mut i32, i32)
-> *mut wlroots_sys::wlr_renderer;


#[derive(Debug, Hash, Eq, PartialEq)]
pub enum Backend {
Wayland(WaylandBackend),
X11(X11Backend),
DRM(DRMBackend),
Headless(HeadlessBackend),
LibInput(LibInputBackend),
Multi(MultiBackend)
}

impl Backend {
/// Create a backend from a `*mut wlr_backend`.
pub unsafe fn from_backend(backend: *mut wlr_backend) -> Self {
if wlr_backend_is_wl(backend) {
Backend::Wayland(WaylandBackend{ backend })
} else if wlr_backend_is_x11(backend) {
Backend::X11(X11Backend{ backend })
} else if wlr_backend_is_drm(backend) {
Backend::DRM(DRMBackend{ backend })
} else if wlr_backend_is_headless(backend) {
Backend::Headless(HeadlessBackend{ backend })
} else if wlr_backend_is_multi(backend) {
Backend::Multi(MultiBackend{ backend })
} else if wlr_backend_is_libinput(backend) {
Backend::LibInput(LibInputBackend { backend })
} else {
panic!("Unknown backend {:p}", backend)
}
}

pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_backend {
match *self {
Backend::Wayland(WaylandBackend { backend }) |
Backend::X11(X11Backend { backend }) |
Backend::DRM(DRMBackend { backend }) |
Backend::Headless(HeadlessBackend { backend }) |
Backend::Multi(MultiBackend { backend }) |
Backend::LibInput(LibInputBackend { backend }) => backend
}
}
}
70 changes: 70 additions & 0 deletions src/backend/drm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::ptr;

use libc;
use wlroots_sys::{wlr_backend, wl_display, wlr_drm_backend_create, wlr_output_is_drm,
wlr_drm_backend_get_session};

use Output;
use super::{UnsafeRenderSetupFunction, Session};

/// When the compositor is ran on a TTY and has full control of the system resources.
///
/// This is primarily the backend that end users will use, as they usually want the
/// compositor to run standalone.
///
/// Note that because you have full control of the TTY (and the keyboard, the mouse, and
/// just about everything else) that if there's an infinite loop then you could hard-lock
/// yourself out of the system. At that point you must reboot your computer (or use
/// SysRq).
///
/// Note that if the process exits for any reason (a panic, an abort, or a clean exit)
/// all of the resource handles will automatically be cleaned up properly by the OS.
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct DRMBackend {
pub(crate) backend: *mut wlr_backend
}

impl DRMBackend {
/// Creates a DRM backend using the specified GPU file descriptor (typically from
/// a device node in /dev/dri).
///
/// To slave this to another DRM backend, pass it as the parent (which _must_ be
/// a DRM backend, other kinds of backends raise SIGABRT).
pub unsafe fn new(display: *mut wl_display,
session: Session,
gpu_fd: libc::c_int,
parent: Option<DRMBackend>,
render_setup_func: Option<UnsafeRenderSetupFunction>)
-> Self {
let parent_ptr = parent.map(|backend| backend.as_ptr()).unwrap_or_else(|| ptr::null_mut());
let backend = wlr_drm_backend_create(display,
session.as_ptr(),
gpu_fd,
parent_ptr,
render_setup_func);
if backend.is_null() {
panic!("Could not construct X11 backend");
}
DRMBackend { backend }
}

pub fn output_is_drm(&self, output: &Output) -> bool {
unsafe {
wlr_output_is_drm(output.as_ptr())
}
}

pub fn session(&self) -> Session {
unsafe {
let session_ptr = wlr_drm_backend_get_session(self.backend);
if session_ptr.is_null() {
panic!("Session was null");
}
Session::from_ptr(session_ptr)
}
}

pub unsafe fn as_ptr(&self) -> *mut wlr_backend {
self.backend
}
}
78 changes: 78 additions & 0 deletions src/backend/headless.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use libc;
use wlroots_sys::{wlr_backend, wlr_headless_backend_create, wlr_headless_add_output,
wlr_headless_add_input_device, wlr_input_device_is_headless,
wlr_output_is_headless, wlr_input_device_type, wl_display};

use super::UnsafeRenderSetupFunction;
use {InputDevice, InputHandle, Output, OutputHandle};

/// In this backend the only resource the compositor uses is the Wayland file descriptor.
/// It doesn't try to grab actual keyboard/pointers and it doesn't render anything.
///
/// This backend is useful for testing as you can easily add "fake" inputs and outputs.
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct HeadlessBackend {
pub(crate) backend: *mut wlr_backend
}

impl HeadlessBackend {
/// Creates a headless backend.
///
/// A headless backend has no outputs or inputs by default.
pub unsafe fn new(display: *mut wl_display,
render_setup_func: Option<UnsafeRenderSetupFunction>)
-> Self {
let backend = wlr_headless_backend_create(display, render_setup_func);
if backend.is_null() {
panic!("Could not construct Headless backend");
}
HeadlessBackend { backend }
}


/// Create a new headless output backed by an in-memory EGL framebuffer.
///
/// You can read pixels from this framebuffer via `Renderer::read_pixels`
/// but it is otherwise not displayed.
pub fn add_output(&self, width: libc::c_uint, height: libc::c_uint) -> Option<OutputHandle> {
unsafe {
let output_ptr = wlr_headless_add_output(self.backend, width, height);
if output_ptr.is_null() {
None
} else {
Some(OutputHandle::from_ptr(output_ptr))
}
}
}

/// Creates a new input device.
///
/// The caller is responsible for manually raising any event signals on the
/// new input device if it wants to simulate input events.
pub fn add_input_device(&self, input_type: wlr_input_device_type) -> Option<InputHandle> {
unsafe {
let device = wlr_headless_add_input_device(self.backend, input_type);
if device.is_null() {
None
} else {
Some(InputDevice { device }.device())
}
}
}

pub fn is_headless_input_device(&self, input_device: &InputDevice) -> bool {
unsafe {
wlr_input_device_is_headless(input_device.as_ptr())
}
}

pub fn is_headless_output(&self, output: &Output) -> bool {
unsafe {
wlr_output_is_headless(output.as_ptr())
}
}

pub unsafe fn as_ptr(&self) -> *mut wlr_backend {
self.backend
}
}
29 changes: 29 additions & 0 deletions src/backend/libinput.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use wlroots_sys::{wlr_backend, wl_display, wlr_libinput_backend_create, libinput_device,
wlr_libinput_get_device_handle, wlr_input_device_is_libinput};

use super::Session;
use InputDevice;

#[derive(Debug, Hash, Eq, PartialEq)]
pub struct LibInputBackend {
pub(crate) backend: *mut wlr_backend
}

impl LibInputBackend {
pub unsafe fn new(display: *mut wl_display, session: Session) -> Self {
let backend = wlr_libinput_backend_create(display, session.as_ptr());
if backend.is_null() {
panic!("Could not construct Wayland backend");
}
LibInputBackend { backend }
}

/// Get the underlying libinput_device handle for the given input device.
pub unsafe fn device_handle(input_device: &InputDevice) -> *mut libinput_device {
wlr_libinput_get_device_handle(input_device.as_ptr())
}

pub fn is_libinput_input_device(&self, input_device: &InputDevice) -> bool {
unsafe { wlr_input_device_is_libinput(input_device.as_ptr()) }
}
}
17 changes: 17 additions & 0 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
mod backend;
mod wayland;
mod x11;
mod headless;
mod drm;
mod libinput;
mod multi;
mod session;

pub use self::backend::*;
pub use self::wayland::*;
pub use self::x11::*;
pub use self::headless::*;
pub use self::drm::*;
pub use self::libinput::*;
pub use self::multi::*;
pub use self::session::*;
59 changes: 59 additions & 0 deletions src/backend/multi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use wlroots_sys::{wlr_backend, wlr_backend_autocreate, wl_display, wlr_multi_backend_add,
wlr_multi_backend_remove, wlr_multi_is_empty, wlr_multi_get_session};

use super::{Session, UnsafeRenderSetupFunction};

/// When multiple backends are running or when the compositor writer doesn't care and
/// just used the auto create option in the `CompositorBuilder`.
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct MultiBackend {
pub(crate) backend: *mut wlr_backend
}

impl MultiBackend {
/// Auto create a backend based on the environment.
pub unsafe fn auto_create(display: *mut wl_display,
render_setup_func: Option<UnsafeRenderSetupFunction>)
-> Self {
let backend = wlr_backend_autocreate(display, render_setup_func);
if backend.is_null() {
panic!("Could not auto construct backend");
}
MultiBackend { backend }
}

/// Adds the given backend to the multi backend.
///
/// # Safety
///
/// This should be done before the new backend is started.
pub unsafe fn add_backend(&self, new_backend: *mut wlr_backend) -> bool {
wlr_multi_backend_add(self.backend, new_backend)
}

/// Removes the backend.
///
/// # Safety
///
/// Doesn't check if that backend is valid.
pub unsafe fn remove_backend(&self, backend: *mut wlr_backend) {
wlr_multi_backend_remove(self.backend, backend)
}

pub fn wlr_multi_get_session(&self) -> Option<Session> {
unsafe {
let session = wlr_multi_get_session(self.backend);
if session.is_null() {
None
} else {
Some(Session::from_ptr(session))
}
}
}

pub fn is_empty(&self) -> bool {
unsafe {
wlr_multi_is_empty(self.backend)
}
}
}
Loading