#![cfg_attr(not(feature = "unsafe-stable"), feature(optin_builtin_traits))]
#![allow(unknown_lints)]
#![deny(missing_docs, clippy)]
extern crate wlc_sys_with_elogind as ffi;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;
extern crate num_traits;
#[macro_use]
extern crate log;
extern crate libc;
extern crate uinput_sys;
extern crate xkbcommon;
#[cfg(feature = "wayland")]
extern crate wayland_server;
#[cfg(feature = "serialization")]
extern crate serde;
#[cfg(feature = "serialization")]
#[cfg_attr(feature = "serialization", macro_use)]
extern crate serde_derive;
use num_traits::FromPrimitive;
use std::cell::UnsafeCell;
use std::error::Error as ErrorTrait;
use std::ffi::CStr;
use std::fmt;
use std::mem;
#[macro_use]
mod enum_primitive;
#[cfg(feature = "serialization")]
#[cfg_attr(feature = "serialization", macro_use)]
mod serialization;
#[cfg(not(feature = "serialization"))]
macro_rules! bitflags_serde {
( $name:ident { $($variant:ident, )* }) => {}
}
#[cfg(not(feature = "serialization"))]
macro_rules! enum_serde {
( $name:ident { $($variant:ident, )* }) => {}
}
mod output;
mod view;
mod types;
mod userdata;
pub mod event_loop;
pub mod input;
#[cfg(feature = "wayland")]
pub mod wayland;
#[cfg(feature = "render")]
pub mod render;
pub use self::output::{Output, WeakOutput};
use self::output::OUTPUTS;
#[cfg(feature = "render")]
use self::render::*;
pub use self::types::*;
pub use self::userdata::*;
pub use self::view::{Positioner, View, WeakView};
use self::view::VIEWS;
pub use input::keyboard::Key;
pub use input::pointer::Button;
struct NotRequiredThreadSafe<T>(T);
unsafe impl<T> Send for NotRequiredThreadSafe<T> {}
unsafe impl<T> Sync for NotRequiredThreadSafe<T> {}
lazy_static! {
static ref CALLBACK:
NotRequiredThreadSafe<UnsafeCell<Option<Box<Callback>>>>
= NotRequiredThreadSafe(UnsafeCell::new(None));
}
extern "C" fn ffi_output_created(handle: ffi::wlc_handle) -> bool {
match unsafe { &mut *CALLBACK.0.get() }.as_mut() {
Some(ref mut callback) => callback.output_created(output::from_handle(handle)),
None => true,
}
}
extern "C" fn ffi_output_destroyed(handle: ffi::wlc_handle) {
let output = output::from_handle(handle);
OUTPUTS.0.borrow_mut().remove(&handle);
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.output_destroyed(output);
}
let output = output::from_handle(handle);
output.clear_user_data();
}
extern "C" fn ffi_output_focus(handle: ffi::wlc_handle, focus: bool) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.output_focus(output::from_handle(handle), focus)
}
}
extern "C" fn ffi_output_resolution(handle: ffi::wlc_handle, from: *const ffi::wlc_size,
to: *const ffi::wlc_size) {
unsafe {
if let Some(ref mut callback) = (&mut *CALLBACK.0.get()).as_mut() {
callback.output_resolution(output::from_handle(handle),
Size::from_ffi(&*from),
Size::from_ffi(&*to))
}
}
}
#[cfg(not(feature = "render"))]
extern "C" fn ffi_output_render_pre(handle: ffi::wlc_handle) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.output_render_pre(output::from_handle(handle))
}
}
#[cfg(feature = "render")]
extern "C" fn ffi_output_render_pre(handle: ffi::wlc_handle) {
unsafe {
if let Some(ref mut callback) = (&mut *CALLBACK.0.get()).as_mut() {
callback.output_render_pre(mem::transmute(output::from_handle(handle)))
}
}
}
#[cfg(not(feature = "render"))]
extern "C" fn ffi_output_render_post(handle: ffi::wlc_handle) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.output_render_post(output::from_handle(handle))
}
}
#[cfg(feature = "render")]
extern "C" fn ffi_output_render_post(handle: ffi::wlc_handle) {
unsafe {
if let Some(ref mut callback) = (&mut *CALLBACK.0.get()).as_mut() {
callback.output_render_post(mem::transmute(output::from_handle(handle)))
}
}
}
extern "C" fn ffi_output_context_created(handle: ffi::wlc_handle) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.output_context_created(output::from_handle(handle))
}
}
extern "C" fn ffi_output_context_destroyed(handle: ffi::wlc_handle) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.output_context_destroyed(output::from_handle(handle))
}
}
extern "C" fn ffi_view_created(handle: ffi::wlc_handle) -> bool {
match unsafe { &mut *CALLBACK.0.get() }.as_mut() {
Some(ref mut callback) => callback.view_created(view::from_handle(handle)),
None => true,
}
}
extern "C" fn ffi_view_destroyed(handle: ffi::wlc_handle) {
let view = view::from_handle(handle);
VIEWS.0.borrow_mut().remove(&handle);
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.view_destroyed(view);
}
let view = view::from_handle(handle);
view.clear_user_data();
}
extern "C" fn ffi_view_focus(handle: ffi::wlc_handle, focus: bool) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.view_focus(view::from_handle(handle), focus)
}
}
extern "C" fn ffi_view_move_to_output(handle: ffi::wlc_handle, out1: ffi::wlc_handle, out2: ffi::wlc_handle) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.view_move_to_output(view::from_handle(handle),
output::from_handle(out1),
output::from_handle(out2))
}
}
extern "C" fn ffi_view_request_geometry(handle: ffi::wlc_handle, geometry: *const ffi::wlc_geometry) {
unsafe {
if let Some(ref mut callback) = (&mut *CALLBACK.0.get()).as_mut() {
callback.view_request_geometry(view::from_handle(handle), Geometry::from_ffi(&*geometry))
}
}
}
extern "C" fn ffi_view_request_state(handle: ffi::wlc_handle, state: ffi::wlc_view_state_bit, toggle: bool) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.view_request_state(view::from_handle(handle),
ViewState::Flags::from_bits_truncate(state),
toggle)
}
}
extern "C" fn ffi_view_request_move(handle: ffi::wlc_handle, to: *const ffi::wlc_point) {
unsafe {
if let Some(ref mut callback) = (&mut *CALLBACK.0.get()).as_mut() {
callback.view_request_move(view::from_handle(handle), Point::from_ffi(&*to))
}
}
}
extern "C" fn ffi_view_request_resize(handle: ffi::wlc_handle, edges: u32, to: *const ffi::wlc_point) {
unsafe {
if let Some(ref mut callback) = (&mut *CALLBACK.0.get()).as_mut() {
callback.view_request_resize(view::from_handle(handle),
ResizeEdge::Flags::from_bits_truncate(edges),
Point::from_ffi(&*to))
}
}
}
#[cfg(not(feature = "render"))]
extern "C" fn ffi_view_render_pre(handle: ffi::wlc_handle) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.view_render_pre(view::from_handle(handle))
}
}
#[cfg(feature = "render")]
extern "C" fn ffi_view_render_pre(handle: ffi::wlc_handle) {
unsafe {
if let Some(ref mut callback) = (&mut *CALLBACK.0.get()).as_mut() {
callback.view_render_pre(mem::transmute(view::from_handle(handle)))
}
}
}
#[cfg(not(feature = "render"))]
extern "C" fn ffi_view_render_post(handle: ffi::wlc_handle) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.view_render_post(view::from_handle(handle))
}
}
#[cfg(feature = "render")]
extern "C" fn ffi_view_render_post(handle: ffi::wlc_handle) {
unsafe {
if let Some(ref mut callback) = (&mut *CALLBACK.0.get()).as_mut() {
callback.view_render_post(mem::transmute(view::from_handle(handle)))
}
}
}
extern "C" fn ffi_view_properties_updated(handle: ffi::wlc_handle, mask: u32) {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.view_properties_updated(view::from_handle(handle),
ViewPropertyUpdate::Flags::from_bits_truncate(mask))
}
}
extern "C" fn ffi_keyboard_key(handle: ffi::wlc_handle, time: u32, mods: *const ffi::wlc_modifiers,
key: u32, state: ffi::wlc_key_state)
-> bool {
let view = view::from_handle(handle);
unsafe {
match (&mut *CALLBACK.0.get()).as_mut() {
Some(ref mut callback) => {
if let Some(key) = Key::from_u32(key) {
callback.keyboard_key(if handle == 0 { None } else { Some(view) },
time,
Modifiers::from_ffi(&*mods),
key,
KeyState::from_u32(state)
.expect(&format!("Wlc send an unknown KeyState {}. Aborting",
state)))
} else {
warn!("Wlc send unknown key: {}. Ignoring", key);
false
}
}
None => false,
}
}
}
extern "C" fn ffi_pointer_button(handle: ffi::wlc_handle, time: u32, mods: *const ffi::wlc_modifiers,
button: u32, state: ffi::wlc_button_state, at: *const ffi::wlc_point)
-> bool {
let view = view::from_handle(handle);
unsafe {
match (&mut *CALLBACK.0.get()).as_mut() {
Some(ref mut callback) => {
if let Some(button) = Button::from_u32(button) {
callback.pointer_button(if handle == 0 { None } else { Some(view) },
time,
Modifiers::from_ffi(&*mods),
button,
ButtonState::from_u32(state)
.expect(&format!("Wlc send an unknown ButtonState {}. Aborting",
state)),
Point::from_ffi(&*at))
} else {
warn!("Wlc send an unknown Button {}. Ignoring", button);
false
}
}
None => false,
}
}
}
extern "C" fn ffi_pointer_scroll(handle: ffi::wlc_handle, time: u32, mods: *const ffi::wlc_modifiers,
axis_bits: u8, amount: *mut f64)
-> bool {
use std::slice;
let safe_amount = unsafe { slice::from_raw_parts(amount, 2) };
let copy_amount = [safe_amount[0], safe_amount[1]];
let view = view::from_handle(handle);
unsafe {
match (&mut *CALLBACK.0.get()).as_mut() {
Some(ref mut callback) => {
callback.pointer_scroll(if handle == 0 { None } else { Some(view) },
time,
Modifiers::from_ffi(&*mods),
ScrollAxis::Flags::from_bits_truncate(axis_bits),
copy_amount)
}
None => false,
}
}
}
extern "C" fn ffi_pointer_motion(handle: ffi::wlc_handle, time: u32, point: *const ffi::wlc_point) -> bool {
let view = view::from_handle(handle);
unsafe {
match (&mut *CALLBACK.0.get()).as_mut() {
Some(ref mut callback) => {
callback.pointer_motion(if handle == 0 { None } else { Some(view) },
time,
Point::from_ffi(&*point))
}
None => false,
}
}
}
extern "C" fn ffi_touch(handle: ffi::wlc_handle, time: u32, mods: *const ffi::wlc_modifiers,
touch: ffi::wlc_touch_type, slot: i32, point: *const ffi::wlc_point)
-> bool {
let view = view::from_handle(handle);
unsafe {
match (&mut *CALLBACK.0.get()).as_mut() {
Some(ref mut callback) => {
callback.touch(if handle == 0 { None } else { Some(view) },
time,
Modifiers::from_ffi(&*mods),
TouchType::from_u32(touch)
.expect(&format!("Wlc send an unknown TouchType {}. Aborting", touch)),
slot,
Point::from_ffi(&*point))
}
None => false,
}
}
}
extern "C" fn ffi_compositor_ready() {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.compositor_ready()
}
}
extern "C" fn ffi_compositor_terminate() {
if let Some(ref mut callback) = unsafe { &mut *CALLBACK.0.get() }.as_mut() {
callback.compositor_terminate()
}
}
unsafe extern "C" fn ffi_wlc_log_handler(log_type: ffi::wlc_log_type, msg: *const libc::c_char) {
let msg = CStr::from_ptr(msg);
match log_type {
ffi::wlc_log_type_WLC_LOG_ERROR => error!("{:?}", msg),
ffi::wlc_log_type_WLC_LOG_WARN => warn!("{:?}", msg),
ffi::wlc_log_type_WLC_LOG_INFO => info!("{:?}", msg),
ffi::wlc_log_type_WLC_LOG_WAYLAND => debug!("{:?}", msg),
_ => unreachable!(),
};
}
#[allow(unused_variables)]
pub trait Callback {
fn output_created(&mut self, output: &Output) -> bool {
true
}
fn output_destroyed(&mut self, output: &Output) {}
fn output_focus(&mut self, output: &Output, focus: bool) {}
fn output_resolution(&mut self, output: &Output, from: Size, to: Size) {}
#[cfg(not(feature = "render"))]
fn output_render_pre(&mut self, output: &Output) {}
#[cfg(feature = "render")]
fn output_render_pre(&mut self, output: &mut RenderOutput) {}
#[cfg(not(feature = "render"))]
fn output_render_post(&mut self, output: &Output) {}
#[cfg(feature = "render")]
fn output_render_post(&mut self, output: &mut RenderOutput) {}
fn output_context_created(&mut self, output: &Output) {}
fn output_context_destroyed(&mut self, output: &Output) {}
fn view_created(&mut self, view: &View) -> bool {
true
}
fn view_destroyed(&mut self, view: &View) {}
fn view_focus(&mut self, view: &View, focus: bool) {}
fn view_move_to_output(&mut self, view: &View, from: &Output, to: &Output) {}
fn view_request_geometry(&mut self, view: &View, geometry: Geometry) {}
fn view_request_state(&mut self, view: &View, state: ViewState::Flags, toggle: bool) {}
fn view_request_move(&mut self, view: &View, origin: Point) {}
fn view_request_resize(&mut self, view: &View, edges: ResizeEdge::Flags, origin: Point) {}
#[cfg(not(feature = "render"))]
fn view_render_pre(&mut self, view: &View) {}
#[cfg(feature = "render")]
fn view_render_pre(&mut self, view: &mut RenderView) {}
#[cfg(not(feature = "render"))]
fn view_render_post(&mut self, view: &View) {}
#[cfg(feature = "render")]
fn view_render_post(&mut self, view: &mut RenderView) {}
fn view_properties_updated(&mut self, view: &View, mask: ViewPropertyUpdate::Flags) {}
fn keyboard_key(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers, key: Key,
state: KeyState)
-> bool {
false
}
fn pointer_button(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers, button: Button,
state: ButtonState, origin: Point)
-> bool {
false
}
fn pointer_scroll(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers,
axis: ScrollAxis::Flags, amount: [f64; 2])
-> bool {
false
}
fn pointer_motion(&mut self, view: Option<&View>, time: u32, origin: Point) -> bool {
false
}
fn touch(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers, touch_type: TouchType,
slot: i32, origin: Point)
-> bool {
false
}
fn compositor_ready(&mut self) {}
fn compositor_terminate(&mut self) {}
}
impl<C: Callback + ?Sized> Callback for Box<C> {
fn output_created(&mut self, output: &Output) -> bool {
(**self).output_created(output)
}
fn output_destroyed(&mut self, output: &Output) {
(**self).output_destroyed(output)
}
fn output_focus(&mut self, output: &Output, focus: bool) {
(**self).output_focus(output, focus)
}
fn output_resolution(&mut self, output: &Output, from: Size, to: Size) {
(**self).output_resolution(output, from, to)
}
#[cfg(not(feature = "render"))]
fn output_render_pre(&mut self, output: &Output) {
(**self).output_render_pre(output)
}
#[cfg(feature = "render")]
fn output_render_pre(&mut self, output: &mut RenderOutput) {
(**self).output_render_pre(output)
}
#[cfg(not(feature = "render"))]
fn output_render_post(&mut self, output: &Output) {
(**self).output_render_post(output)
}
#[cfg(feature = "render")]
fn output_render_post(&mut self, output: &mut RenderOutput) {
(**self).output_render_post(output)
}
fn output_context_created(&mut self, output: &Output) {
(**self).output_context_created(output)
}
fn output_context_destroyed(&mut self, output: &Output) {
(**self).output_context_destroyed(output)
}
fn view_created(&mut self, view: &View) -> bool {
(**self).view_created(view)
}
fn view_destroyed(&mut self, view: &View) {
(**self).view_destroyed(view)
}
fn view_focus(&mut self, view: &View, focus: bool) {
(**self).view_focus(view, focus)
}
fn view_move_to_output(&mut self, view: &View, from: &Output, to: &Output) {
(**self).view_move_to_output(view, from, to)
}
fn view_request_geometry(&mut self, view: &View, geometry: Geometry) {
(**self).view_request_geometry(view, geometry)
}
fn view_request_state(&mut self, view: &View, state: ViewState::Flags, toggle: bool) {
(**self).view_request_state(view, state, toggle)
}
fn view_request_move(&mut self, view: &View, origin: Point) {
(**self).view_request_move(view, origin)
}
fn view_request_resize(&mut self, view: &View, edges: ResizeEdge::Flags, origin: Point) {
(**self).view_request_resize(view, edges, origin)
}
#[cfg(not(feature = "render"))]
fn view_render_pre(&mut self, view: &View) {
(**self).view_render_pre(view)
}
#[cfg(feature = "render")]
fn view_render_pre(&mut self, view: &mut RenderView) {
(**self).view_render_pre(view)
}
#[cfg(not(feature = "render"))]
fn view_render_post(&mut self, view: &View) {
(**self).view_render_post(view)
}
#[cfg(feature = "render")]
fn view_render_post(&mut self, view: &mut RenderView) {
(**self).view_render_post(view)
}
fn view_properties_updated(&mut self, view: &View, mask: ViewPropertyUpdate::Flags) {
(**self).view_properties_updated(view, mask)
}
fn keyboard_key(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers, key: Key,
state: KeyState)
-> bool {
(**self).keyboard_key(view, time, modifiers, key, state)
}
fn pointer_button(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers, button: Button,
state: ButtonState, origin: Point)
-> bool {
(**self).pointer_button(view, time, modifiers, button, state, origin)
}
fn pointer_scroll(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers,
axis: ScrollAxis::Flags, amount: [f64; 2])
-> bool {
(**self).pointer_scroll(view, time, modifiers, axis, amount)
}
fn pointer_motion(&mut self, view: Option<&View>, time: u32, origin: Point) -> bool {
(**self).pointer_motion(view, time, origin)
}
fn touch(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers, touch_type: TouchType,
slot: i32, origin: Point)
-> bool {
(**self).touch(view, time, modifiers, touch_type, slot, origin)
}
fn compositor_ready(&mut self) {
(**self).compositor_ready()
}
fn compositor_terminate(&mut self) {
(**self).compositor_terminate()
}
}
impl Callback for () {}
pub struct Wlc;
#[cfg(not(feature = "unsafe-stable"))]
impl !Sync for Wlc {}
#[cfg(not(feature = "unsafe-stable"))]
impl !Send for Wlc {}
impl Drop for Wlc {
fn drop(&mut self) {
unsafe {
ffi::wlc_run();
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum Error {
AlreadyRunning,
InternalError,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error starting Wlc: {}", self.description())
}
}
impl ErrorTrait for Error {
fn description(&self) -> &str {
match *self {
Error::AlreadyRunning => "An instance of Wlc is already running",
Error::InternalError => "Wlc encountered an internal Error",
}
}
}
pub fn init<T: Callback + 'static>(callbacks: T) -> Result<Wlc, Error> {
if unsafe { &*CALLBACK.0.get() }.is_some() {
return Err(Error::AlreadyRunning);
}
unsafe {
ffi::wlc_log_set_handler(Some(ffi_wlc_log_handler));
}
unsafe {
ffi::wlc_set_output_created_cb(Some(ffi_output_created));
ffi::wlc_set_output_destroyed_cb(Some(ffi_output_destroyed));
ffi::wlc_set_output_focus_cb(Some(ffi_output_focus));
ffi::wlc_set_output_resolution_cb(Some(ffi_output_resolution));
ffi::wlc_set_output_render_pre_cb(Some(ffi_output_render_pre));
ffi::wlc_set_output_render_post_cb(Some(ffi_output_render_post));
ffi::wlc_set_output_context_created_cb(Some(ffi_output_context_created));
ffi::wlc_set_output_context_destroyed_cb(Some(ffi_output_context_destroyed));
ffi::wlc_set_view_created_cb(Some(ffi_view_created));
ffi::wlc_set_view_destroyed_cb(Some(ffi_view_destroyed));
ffi::wlc_set_view_focus_cb(Some(ffi_view_focus));
ffi::wlc_set_view_move_to_output_cb(Some(ffi_view_move_to_output));
ffi::wlc_set_view_request_geometry_cb(Some(ffi_view_request_geometry));
ffi::wlc_set_view_request_state_cb(Some(ffi_view_request_state));
ffi::wlc_set_view_request_move_cb(Some(ffi_view_request_move));
ffi::wlc_set_view_request_resize_cb(Some(ffi_view_request_resize));
ffi::wlc_set_view_render_pre_cb(Some(ffi_view_render_pre));
ffi::wlc_set_view_render_post_cb(Some(ffi_view_render_post));
ffi::wlc_set_view_properties_updated_cb(Some(ffi_view_properties_updated));
ffi::wlc_set_keyboard_key_cb(Some(ffi_keyboard_key));
ffi::wlc_set_pointer_button_cb(Some(ffi_pointer_button));
ffi::wlc_set_pointer_scroll_cb(Some(ffi_pointer_scroll));
ffi::wlc_set_pointer_motion_cb(Some(ffi_pointer_motion));
ffi::wlc_set_touch_cb(Some(ffi_touch));
ffi::wlc_set_compositor_ready_cb(Some(ffi_compositor_ready));
ffi::wlc_set_compositor_terminate_cb(Some(ffi_compositor_terminate));
}
mem::swap(&mut Some(Box::new(callbacks) as Box<Callback>),
unsafe { &mut *CALLBACK.0.get() });
if unsafe { ffi::wlc_init() } {
Ok(Wlc)
} else {
Err(Error::InternalError)
}
}
pub fn terminate() {
unsafe { ffi::wlc_terminate() }
}
pub fn get_backend_type() -> BackendType {
BackendType::from_u32(unsafe { ffi::wlc_get_backend_type() })
.expect("WLC send an unknown BackendType. Aborting")
}