Replace `failure` and `error-chain` by `thiserror`

This commit is contained in:
Victor Berger 2020-04-12 22:35:24 +02:00 committed by Victor Berger
parent 885fd0cff2
commit 6a7d933553
23 changed files with 575 additions and 760 deletions

View File

@ -34,9 +34,10 @@ dbus = { version = "0.8", optional = true }
systemd = { version = "0.4.0", optional = true } systemd = { version = "0.4.0", optional = true }
wayland-protocols = { version = "0.25.0", features = ["unstable_protocols", "server"], optional = true } wayland-protocols = { version = "0.25.0", features = ["unstable_protocols", "server"], optional = true }
image = { version = "0.21.0", optional = true } image = { version = "0.21.0", optional = true }
error-chain = "0.12.0"
lazy_static = "1.0.0" lazy_static = "1.0.0"
failure = { version = "0.1.5", optional = true } thiserror = "1"
# TODO: remove as soon as drm-rs provides an error implementing Error
failure = "0.1"
[dev-dependencies] [dev-dependencies]
slog-term = "2.3" slog-term = "2.3"
@ -47,7 +48,7 @@ gl_generator = { version = "0.10", optional = true }
[features] [features]
default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "backend_session_logind", "renderer_glium", "xwayland", "wayland_frontend"] default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "backend_session_logind", "renderer_glium", "xwayland", "wayland_frontend"]
backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "wayland-egl", "backend_egl", "renderer_gl", "use_system_lib"] backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "wayland-egl", "backend_egl", "renderer_gl", "use_system_lib"]
backend_drm = ["drm", "failure"] backend_drm = ["drm"]
backend_drm_legacy = ["backend_drm"] backend_drm_legacy = ["backend_drm"]
backend_drm_gbm = ["backend_drm", "gbm", "image"] backend_drm_gbm = ["backend_drm", "gbm", "image"]
backend_drm_egl = ["backend_drm", "backend_egl"] backend_drm_egl = ["backend_drm", "backend_egl"]

View File

@ -7,7 +7,7 @@ use slog::Drain;
use smithay::{ use smithay::{
backend::drm::{ backend::drm::{
device_bind, device_bind,
legacy::{error::Error, LegacyDrmDevice, LegacyDrmSurface}, legacy::{Error, LegacyDrmDevice, LegacyDrmSurface},
Device, DeviceHandler, RawSurface, Surface, Device, DeviceHandler, RawSurface, Surface,
}, },
reexports::{ reexports::{
@ -15,10 +15,8 @@ use smithay::{
drm::{ drm::{
buffer::format::PixelFormat, buffer::format::PixelFormat,
control::{ control::{
connector::{self, State as ConnectorState}, connector::State as ConnectorState, crtc, dumbbuffer::DumbBuffer, framebuffer,
crtc, Device as ControlDevice,
dumbbuffer::DumbBuffer,
encoder, framebuffer, Device as ControlDevice,
}, },
}, },
}, },

View File

@ -1,20 +0,0 @@
//!
//! Errors thrown by the [`EglDevice`](::backend::drm::egl::EglDevice)
//! and [`EglSurface`](::backend::drm::egl::EglSurface).
//!
use crate::backend::egl::error as egl;
error_chain! {
errors {
#[doc = "Underlying backend failed"]
UnderlyingBackendError {
description("The underlying backend reported an error"),
display("The underlying backend reported an error"),
}
}
links {
EGL(egl::Error, egl::ErrorKind) #[doc = "EGL error"];
}
}

View File

@ -18,21 +18,29 @@ use wayland_server::Display;
use super::{Device, DeviceHandler, Surface}; use super::{Device, DeviceHandler, Surface};
use crate::backend::egl::context::GlAttributes; use crate::backend::egl::context::GlAttributes;
use crate::backend::egl::error::Result as EGLResult;
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
use crate::backend::egl::EGLContext; use crate::backend::egl::EGLContext;
use crate::backend::egl::Error as EGLError;
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
use crate::backend::egl::{EGLDisplay, EGLGraphicsBackend}; use crate::backend::egl::{EGLDisplay, EGLGraphicsBackend};
pub mod error;
use self::error::*;
mod surface; mod surface;
pub use self::surface::*; pub use self::surface::*;
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
pub mod session; pub mod session;
/// Errors for the DRM/EGL module
#[derive(thiserror::Error, Debug)]
pub enum Error<U: std::error::Error + std::fmt::Debug + std::fmt::Display + 'static> {
/// EGL Error
#[error("EGL error: {0:?}")]
EGL(#[source] EGLError),
/// Underlying backend error
#[error("Underlying backend error: {0:?}")]
Underlying(#[source] U),
}
/// Representation of an egl device to create egl rendering surfaces /// Representation of an egl device to create egl rendering surfaces
pub struct EglDevice<B, D> pub struct EglDevice<B, D>
where where
@ -65,7 +73,7 @@ where
/// ///
/// Returns an error if the file is no valid device or context /// Returns an error if the file is no valid device or context
/// creation was not successful. /// creation was not successful.
pub fn new<L>(dev: D, logger: L) -> Result<Self> pub fn new<L>(dev: D, logger: L) -> Result<Self, Error<<<D as Device>::Surface as Surface>::Error>>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -85,7 +93,11 @@ where
/// ///
/// Returns an error if the file is no valid device or context /// Returns an error if the file is no valid device or context
/// creation was not successful. /// creation was not successful.
pub fn new_with_gl_attr<L>(mut dev: D, attributes: GlAttributes, logger: L) -> Result<Self> pub fn new_with_gl_attr<L>(
mut dev: D,
attributes: GlAttributes,
logger: L,
) -> Result<Self, Error<<<D as Device>::Surface as Surface>::Error>>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -97,7 +109,7 @@ where
Ok(EglDevice { Ok(EglDevice {
// Open the gbm device from the drm device and create a context based on that // Open the gbm device from the drm device and create a context based on that
dev: Rc::new( dev: Rc::new(
EGLContext::new(dev, attributes, Default::default(), log.clone()).map_err(Error::from)?, EGLContext::new(dev, attributes, Default::default(), log.clone()).map_err(Error::EGL)?,
), ),
logger: log, logger: log,
}) })
@ -125,8 +137,7 @@ where
self.handler.vblank(crtc) self.handler.vblank(crtc)
} }
fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) { fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) {
self.handler self.handler.error(Error::Underlying(error));
.error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err())
} }
} }
@ -152,10 +163,13 @@ where
self.dev.borrow_mut().clear_handler() self.dev.borrow_mut().clear_handler()
} }
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<EglSurface<B, D>> { fn create_surface(
&mut self,
crtc: crtc::Handle,
) -> Result<EglSurface<B, D>, <Self::Surface as Surface>::Error> {
info!(self.logger, "Initializing EglSurface"); info!(self.logger, "Initializing EglSurface");
let surface = self.dev.create_surface(crtc)?; let surface = self.dev.create_surface(crtc).map_err(Error::EGL)?;
Ok(EglSurface { Ok(EglSurface {
dev: self.dev.clone(), dev: self.dev.clone(),
@ -167,11 +181,8 @@ where
self.dev.borrow_mut().process_events() self.dev.borrow_mut().process_events()
} }
fn resource_handles(&self) -> Result<ResourceHandles> { fn resource_handles(&self) -> Result<ResourceHandles, <Self::Surface as Surface>::Error> {
self.dev self.dev.borrow().resource_handles().map_err(Error::Underlying)
.borrow()
.resource_handles()
.chain_err(|| ErrorKind::UnderlyingBackendError)
} }
fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> { fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {
@ -201,7 +212,7 @@ where
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static, D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
fn bind_wl_display(&self, display: &Display) -> EGLResult<EGLDisplay> { fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, EGLError> {
self.dev.bind_wl_display(display) self.dev.bind_wl_display(display)
} }
} }

View File

@ -2,7 +2,7 @@ use drm::control::{connector, crtc, Mode};
use nix::libc::c_void; use nix::libc::c_void;
use std::rc::Rc; use std::rc::Rc;
use super::error::*; use super::Error;
use crate::backend::drm::{Device, Surface}; use crate::backend::drm::{Device, Surface};
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
use crate::backend::egl::{EGLContext, EGLSurface}; use crate::backend::egl::{EGLContext, EGLSurface};
@ -29,7 +29,7 @@ where
D: Device + NativeDisplay<B> + 'static, D: Device + NativeDisplay<B> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
type Error = Error; type Error = Error<<<D as Device>::Surface as Surface>::Error>;
type Connectors = <<D as Device>::Surface as Surface>::Connectors; type Connectors = <<D as Device>::Surface as Surface>::Connectors;
fn crtc(&self) -> crtc::Handle { fn crtc(&self) -> crtc::Handle {
@ -44,16 +44,14 @@ where
self.surface.pending_connectors() self.surface.pending_connectors()
} }
fn add_connector(&self, connector: connector::Handle) -> Result<()> { fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
self.surface self.surface.add_connector(connector).map_err(Error::Underlying)
.add_connector(connector)
.chain_err(|| ErrorKind::UnderlyingBackendError)
} }
fn remove_connector(&self, connector: connector::Handle) -> Result<()> { fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
self.surface self.surface
.remove_connector(connector) .remove_connector(connector)
.chain_err(|| ErrorKind::UnderlyingBackendError) .map_err(Error::Underlying)
} }
fn current_mode(&self) -> Option<Mode> { fn current_mode(&self) -> Option<Mode> {
@ -64,10 +62,8 @@ where
self.surface.pending_mode() self.surface.pending_mode()
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<()> { fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
self.surface self.surface.use_mode(mode).map_err(Error::Underlying)
.use_mode(mode)
.chain_err(|| ErrorKind::UnderlyingBackendError)
} }
} }

View File

@ -4,14 +4,13 @@
//! [`GbmDevice`](GbmDevice) and [`GbmSurface`](GbmSurface). //! [`GbmDevice`](GbmDevice) and [`GbmSurface`](GbmSurface).
//! //!
use crate::backend::drm::{Device, RawDevice}; use crate::backend::drm::{Device, RawDevice, Surface};
use crate::backend::egl::error::Result as EglResult;
use crate::backend::egl::ffi; use crate::backend::egl::ffi;
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
use crate::backend::egl::Error as EglError;
use crate::backend::graphics::SwapBuffersError; use crate::backend::graphics::SwapBuffersError;
use super::error::{Error, Result}; use super::{Error, GbmDevice, GbmSurface};
use super::{GbmDevice, GbmSurface};
use drm::control::{crtc, Device as ControlDevice}; use drm::control::{crtc, Device as ControlDevice};
use gbm::AsRaw; use gbm::AsRaw;
@ -54,17 +53,17 @@ impl<D: RawDevice + 'static> Backend for Gbm<D> {
unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for GbmDevice<D> { unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for GbmDevice<D> {
type Arguments = crtc::Handle; type Arguments = crtc::Handle;
type Error = Error; type Error = Error<<<D as Device>::Surface as Surface>::Error>;
fn is_backend(&self) -> bool { fn is_backend(&self) -> bool {
true true
} }
fn ptr(&self) -> EglResult<ffi::NativeDisplayType> { fn ptr(&self) -> Result<ffi::NativeDisplayType, EglError> {
Ok(self.dev.borrow().as_raw() as *const _) Ok(self.dev.borrow().as_raw() as *const _)
} }
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<GbmSurface<D>> { fn create_surface(&mut self, crtc: crtc::Handle) -> Result<GbmSurface<D>, Self::Error> {
Device::create_surface(self, crtc) Device::create_surface(self, crtc)
} }
} }
@ -80,7 +79,7 @@ unsafe impl<D: RawDevice + 'static> NativeSurface for GbmSurface<D> {
fn recreate(&self) -> bool { fn recreate(&self) -> bool {
if let Err(err) = GbmSurface::recreate(self) { if let Err(err) = GbmSurface::recreate(self) {
error!(self.0.logger, "Failure recreating internal resources: {:?}", err); error!(self.0.logger, "Failure recreating internal resources: {}", err);
false false
} else { } else {
true true

View File

@ -1,54 +0,0 @@
//!
//! Errors thrown by the [`GbmDevice`](::backend::drm::gbm::GbmDevice)
//! and [`GbmSurface`](::backend::drm::gbm::GbmSurface).
//!
error_chain! {
errors {
#[doc = "Creation of gbm device failed"]
InitFailed {
description("Creation of gbm device failed"),
display("Creation of gbm device failed"),
}
#[doc = "Creation of gbm surface failed"]
SurfaceCreationFailed {
description("Creation of gbm surface failed"),
display("Creation of gbm surface failed"),
}
#[doc = "No mode is set, blocking the current operation"]
NoModeSet {
description("No mode is currently set"),
display("No mode is currently set"),
}
#[doc = "Creation of gbm buffer object failed"]
BufferCreationFailed {
description("Creation of gbm buffer object failed"),
display("Creation of gbm buffer object failed"),
}
#[doc = "Writing to gbm buffer failed"]
BufferWriteFailed {
description("Writing to gbm buffer failed"),
display("Writing to gbm buffer failed"),
}
#[doc = "Lock of gbm surface front buffer failed"]
FrontBufferLockFailed {
description("Lock of gbm surface front buffer failed"),
display("Lock of gbm surface front buffer failed"),
}
#[doc = "Underlying backend failed"]
UnderlyingBackendError {
description("The underlying backend reported an error"),
display("The underlying backend reported an error"),
}
}
foreign_links {
FailedToSwap(crate::backend::graphics::SwapBuffersError) #[doc = "Swapping front buffers failed"];
}
}

View File

@ -13,18 +13,45 @@ use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface};
use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice}; use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice};
use drm::SystemError as DrmError; use drm::SystemError as DrmError;
use failure::ResultExt as FailureResultExt;
use gbm::{self, BufferObjectFlags, Format as GbmFormat}; use gbm::{self, BufferObjectFlags, Format as GbmFormat};
use nix::libc::dev_t; use nix::libc::dev_t;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::HashMap; use std::collections::HashMap;
use std::io;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use std::sync::Once; use std::sync::Once;
pub mod error; /// Errors thrown by the [`GbmDevice`](::backend::drm::gbm::GbmDevice)
use self::error::*; /// and [`GbmSurface`](::backend::drm::gbm::GbmSurface).
#[derive(thiserror::Error, Debug)]
pub enum Error<U: std::error::Error + std::fmt::Debug + std::fmt::Display + 'static> {
/// Creation of GBM device failed
#[error("Creation of GBM device failed")]
InitFailed(#[source] io::Error),
/// Creation of GBM surface failed
#[error("Creation of GBM surface failed")]
SurfaceCreationFailed(#[source] io::Error),
/// No mode is set, blocking the current operation
#[error("No mode is currently set")]
NoModeSet,
/// Creation of GBM buffer object failed
#[error("Creation of GBM buffer object failed")]
BufferCreationFailed(#[source] io::Error),
/// Writing to GBM buffer failed
#[error("Writing to GBM buffer failed")]
BufferWriteFailed(#[source] io::Error),
/// Lock of GBM surface front buffer failed
#[error("Lock of GBM surface font buffer failed")]
FrontBufferLockFailed,
/// The GBM device was destroyed
#[error("The GBM device was destroyed")]
DeviceDestroyed,
/// Underlying backend error
#[error("Underlying error: {0}")]
Underlying(#[source] U),
}
mod surface; mod surface;
pub use self::surface::GbmSurface; pub use self::surface::GbmSurface;
@ -50,7 +77,7 @@ impl<D: RawDevice + ControlDevice + 'static> GbmDevice<D> {
/// ///
/// Returns an error if the file is no valid drm node or context creation was not /// Returns an error if the file is no valid drm node or context creation was not
/// successful. /// successful.
pub fn new<L>(mut dev: D, logger: L) -> Result<Self> pub fn new<L>(mut dev: D, logger: L) -> Result<Self, Error<<<D as Device>::Surface as Surface>::Error>>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -74,9 +101,7 @@ impl<D: RawDevice + ControlDevice + 'static> GbmDevice<D> {
debug!(log, "Creating gbm device"); debug!(log, "Creating gbm device");
Ok(GbmDevice { Ok(GbmDevice {
// Open the gbm device from the drm device // Open the gbm device from the drm device
dev: Rc::new(RefCell::new( dev: Rc::new(RefCell::new(gbm::Device::new(dev).map_err(Error::InitFailed)?)),
gbm::Device::new(dev).chain_err(|| ErrorKind::InitFailed)?,
)),
backends: Rc::new(RefCell::new(HashMap::new())), backends: Rc::new(RefCell::new(HashMap::new())),
logger: log, logger: log,
}) })
@ -108,8 +133,7 @@ impl<D: RawDevice + ControlDevice + 'static> DeviceHandler for InternalDeviceHan
} }
} }
fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) { fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) {
self.handler self.handler.error(Error::Underlying(error))
.error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err())
} }
} }
@ -132,11 +156,14 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
self.dev.borrow_mut().clear_handler(); self.dev.borrow_mut().clear_handler();
} }
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<GbmSurface<D>> { fn create_surface(
&mut self,
crtc: crtc::Handle,
) -> Result<GbmSurface<D>, Error<<<D as Device>::Surface as Surface>::Error>> {
info!(self.logger, "Initializing GbmSurface"); info!(self.logger, "Initializing GbmSurface");
let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc) let drm_surface =
.chain_err(|| ErrorKind::UnderlyingBackendError)?; Device::create_surface(&mut **self.dev.borrow_mut(), crtc).map_err(Error::Underlying)?;
// initialize the surface // initialize the surface
let (w, h) = drm_surface let (w, h) = drm_surface
@ -152,7 +179,7 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
GbmFormat::XRGB8888, GbmFormat::XRGB8888,
BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
) )
.chain_err(|| ErrorKind::SurfaceCreationFailed)?; .map_err(Error::SurfaceCreationFailed)?;
// initialize a buffer for the cursor image // initialize a buffer for the cursor image
let cursor = Cell::new(( let cursor = Cell::new((
@ -164,7 +191,7 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
GbmFormat::ARGB8888, GbmFormat::ARGB8888,
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
) )
.chain_err(|| ErrorKind::BufferCreationFailed)?, .map_err(Error::BufferCreationFailed)?,
(0, 0), (0, 0),
)); ));
@ -187,12 +214,8 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
self.dev.borrow_mut().process_events() self.dev.borrow_mut().process_events()
} }
fn resource_handles(&self) -> Result<ResourceHandles> { fn resource_handles(&self) -> Result<ResourceHandles, Error<<<D as Device>::Surface as Surface>::Error>> {
self.dev Device::resource_handles(&**self.dev.borrow()).map_err(Error::Underlying)
.borrow()
.resource_handles()
.compat()
.chain_err(|| ErrorKind::UnderlyingBackendError)
} }
fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> { fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {

View File

@ -1,5 +1,5 @@
use super::super::{Device, RawDevice, RawSurface, Surface}; use super::super::{Device, RawDevice, RawSurface, Surface};
use super::error::*; use super::Error;
use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode}; use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode};
use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle}; use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle};
@ -90,8 +90,8 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
Ok(()) Ok(())
} }
pub fn recreate(&self) -> Result<()> { pub fn recreate(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
let (w, h) = self.pending_mode().chain_err(|| ErrorKind::NoModeSet)?.size(); let (w, h) = self.pending_mode().ok_or(Error::NoModeSet)?.size();
// Recreate the surface and the related resources to match the new // Recreate the surface and the related resources to match the new
// resolution. // resolution.
@ -105,7 +105,7 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
GbmFormat::XRGB8888, GbmFormat::XRGB8888,
BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
) )
.chain_err(|| ErrorKind::SurfaceCreationFailed)?; .map_err(Error::SurfaceCreationFailed)?;
// Clean up buffers // Clean up buffers
if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) { if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) {
@ -137,7 +137,7 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> { impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
type Connectors = <<D as Device>::Surface as Surface>::Connectors; type Connectors = <<D as Device>::Surface as Surface>::Connectors;
type Error = Error; type Error = Error<<<D as Device>::Surface as Surface>::Error>;
fn crtc(&self) -> crtc::Handle { fn crtc(&self) -> crtc::Handle {
self.crtc.crtc() self.crtc.crtc()
@ -151,16 +151,12 @@ impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
self.crtc.pending_connectors() self.crtc.pending_connectors()
} }
fn add_connector(&self, connector: connector::Handle) -> Result<()> { fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
self.crtc self.crtc.add_connector(connector).map_err(Error::Underlying)
.add_connector(connector)
.chain_err(|| ErrorKind::UnderlyingBackendError)
} }
fn remove_connector(&self, connector: connector::Handle) -> Result<()> { fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
self.crtc self.crtc.remove_connector(connector).map_err(Error::Underlying)
.remove_connector(connector)
.chain_err(|| ErrorKind::UnderlyingBackendError)
} }
fn current_mode(&self) -> Option<Mode> { fn current_mode(&self) -> Option<Mode> {
@ -171,10 +167,8 @@ impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
self.crtc.pending_mode() self.crtc.pending_mode()
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<()> { fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
self.crtc self.crtc.use_mode(mode).map_err(Error::Underlying)
.use_mode(mode)
.chain_err(|| ErrorKind::UnderlyingBackendError)
} }
} }
@ -205,19 +199,17 @@ where
#[cfg(feature = "backend_drm_legacy")] #[cfg(feature = "backend_drm_legacy")]
impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal<LegacyDrmDevice<A>> { impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal<LegacyDrmDevice<A>> {
type CursorFormat = &'a ImageBuffer<Rgba<u8>, Vec<u8>>; type CursorFormat = &'a ImageBuffer<Rgba<u8>, Vec<u8>>;
type Error = Error; type Error = Error<<<LegacyDrmDevice<A> as Device>::Surface as Surface>::Error>;
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error> {
ResultExt::chain_err(self.crtc.set_cursor_position(x, y), || { self.crtc.set_cursor_position(x, y).map_err(Error::Underlying)
ErrorKind::UnderlyingBackendError
})
} }
fn set_cursor_representation<'b>( fn set_cursor_representation<'b>(
&'b self, &'b self,
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>, buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
hotspot: (u32, u32), hotspot: (u32, u32),
) -> Result<()> ) -> Result<(), Self::Error>
where where
'a: 'b, 'a: 'b,
{ {
@ -234,18 +226,18 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal<LegacyDr
GbmFormat::ARGB8888, GbmFormat::ARGB8888,
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
) )
.chain_err(|| ErrorKind::BufferCreationFailed)?; .map_err(Error::BufferCreationFailed)?;
cursor cursor
.write(&**buffer) .write(&**buffer)
.chain_err(|| ErrorKind::BufferWriteFailed)? .map_err(|_| Error::DeviceDestroyed)?
.chain_err(|| ErrorKind::BufferWriteFailed)?; .map_err(Error::BufferWriteFailed)?;
trace!(self.logger, "Setting the new imported cursor"); trace!(self.logger, "Setting the new imported cursor");
ResultExt::chain_err(self.crtc.set_cursor_representation(&cursor, hotspot), || { self.crtc
ErrorKind::UnderlyingBackendError .set_cursor_representation(&cursor, hotspot)
})?; .map_err(Error::Underlying)?;
// and store it // and store it
self.cursor.set((cursor, hotspot)); self.cursor.set((cursor, hotspot));
@ -305,7 +297,7 @@ impl<D: RawDevice + 'static> GbmSurface<D> {
/// calling [`Surface::use_mode`](Surface::use_mode). /// calling [`Surface::use_mode`](Surface::use_mode).
/// You may check if your [`GbmSurface`] needs recreation through /// You may check if your [`GbmSurface`] needs recreation through
/// [`needs_recreation`](GbmSurface::needs_recreation). /// [`needs_recreation`](GbmSurface::needs_recreation).
pub fn recreate(&self) -> Result<()> { pub fn recreate(&self) -> Result<(), <Self as Surface>::Error> {
self.0.recreate() self.0.recreate()
} }
@ -317,7 +309,7 @@ impl<D: RawDevice + 'static> GbmSurface<D> {
impl<D: RawDevice + 'static> Surface for GbmSurface<D> { impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
type Connectors = <<D as Device>::Surface as Surface>::Connectors; type Connectors = <<D as Device>::Surface as Surface>::Connectors;
type Error = Error; type Error = Error<<<D as Device>::Surface as Surface>::Error>;
fn crtc(&self) -> crtc::Handle { fn crtc(&self) -> crtc::Handle {
self.0.crtc() self.0.crtc()
@ -331,11 +323,11 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
self.0.pending_connectors() self.0.pending_connectors()
} }
fn add_connector(&self, connector: connector::Handle) -> Result<()> { fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
self.0.add_connector(connector) self.0.add_connector(connector)
} }
fn remove_connector(&self, connector: connector::Handle) -> Result<()> { fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
self.0.remove_connector(connector) self.0.remove_connector(connector)
} }
@ -347,7 +339,7 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
self.0.pending_mode() self.0.pending_mode()
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<()> { fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
self.0.use_mode(mode) self.0.use_mode(mode)
} }
} }
@ -355,9 +347,9 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
#[cfg(feature = "backend_drm_legacy")] #[cfg(feature = "backend_drm_legacy")]
impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface<LegacyDrmDevice<A>> { impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface<LegacyDrmDevice<A>> {
type CursorFormat = &'a ImageBuffer<Rgba<u8>, Vec<u8>>; type CursorFormat = &'a ImageBuffer<Rgba<u8>, Vec<u8>>;
type Error = Error; type Error = <Self as Surface>::Error;
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error> {
self.0.set_cursor_position(x, y) self.0.set_cursor_position(x, y)
} }
@ -365,7 +357,7 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface<LegacyDrmDevice<
&'b self, &'b self,
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>, buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
hotspot: (u32, u32), hotspot: (u32, u32),
) -> Result<()> ) -> Result<(), Self::Error>
where where
'a: 'b, 'a: 'b,
{ {

View File

@ -1,54 +0,0 @@
//!
//! Errors thrown by the [`LegacyDrmDevice`](::backend::drm::legacy::LegacyDrmDevice)
//! and [`LegacyDrmSurface`](::backend::drm::legacy::LegacyDrmSurface).
//!
use drm::control::{connector, crtc, Mode};
error_chain! {
errors {
#[doc = "Unable to acquire drm master"]
DrmMasterFailed {
description("Failed to acquire drm master")
}
#[doc = "The `DrmDevice` encountered an access error"]
DrmDev(dev: String) {
description("The drm device encountered an access error"),
display("The drm device ({:?}) encountered an access error", dev),
}
#[doc = "Unable to determine device id of drm device"]
UnableToGetDeviceId {
description("Unable to determine device id of drm device"),
}
#[doc = "Device is currently paused"]
DeviceInactive {
description("Device is currently paused, operation rejected"),
display("Device is currently paused, operation rejected"),
}
#[doc = "Mode is not compatible with all given connectors"]
ModeNotSuitable(mode: Mode) {
description("Mode is not compatible with all given connectors"),
display("Mode ({:?}) is not compatible with all given connectors", mode),
}
#[doc = "The given crtc is already in use by another backend"]
CrtcAlreadyInUse(crtc: crtc::Handle) {
description("The given crtc is already in use by another backend"),
display("The given crtc ({:?}) is already in use by another backend", crtc),
}
#[doc = "No encoder was found for a given connector on the set crtc"]
NoSuitableEncoder(connector: connector::Info, crtc: crtc::Handle) {
description("No encoder found for given connector on set crtc"),
display("No encoder found for the given connector '{:?}' on the set crtc ({:?})", connector.interface(), crtc),
}
}
foreign_links {
FailedToSwap(crate::backend::graphics::SwapBuffersError) #[doc = "Swapping front buffers failed"];
}
}

View File

@ -11,30 +11,68 @@
use super::{DevPath, Device, DeviceHandler, RawDevice}; use super::{DevPath, Device, DeviceHandler, RawDevice};
use drm::control::{ use drm::control::{
connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, ResourceHandles, connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, Mode, ResourceHandles,
}; };
use drm::{Device as BasicDevice, SystemError as DrmError}; use drm::{Device as BasicDevice, SystemError as DrmError};
use failure::ResultExt as FailureResultExt;
use nix::libc::dev_t; use nix::libc::dev_t;
use nix::sys::stat::fstat; use nix::sys::stat::fstat;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf;
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use failure::{Fail, ResultExt};
mod surface; mod surface;
pub use self::surface::LegacyDrmSurface; pub use self::surface::LegacyDrmSurface;
use self::surface::{LegacyDrmSurfaceInternal, State}; use self::surface::{LegacyDrmSurfaceInternal, State};
pub mod error;
use self::error::*;
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
pub mod session; pub mod session;
/// Errors thrown by the [`LegacyDrmDevice`](::backend::drm::legacy::LegacyDrmDevice)
/// and [`LegacyDrmSurface`](::backend::drm::legacy::LegacyDrmSurface).
#[derive(thiserror::Error, Debug)]
pub enum Error {
/// Unable to acquire DRM master
#[error("Failed to aquire DRM master")]
DrmMasterFailed,
/// The `DrmDevice` encountered an access error
#[error("DRM access error: {errmsg} on device `{dev:?}`")]
Access {
/// Error message associated to the access error
errmsg: &'static str,
/// Device on which the error was generated
dev: Option<PathBuf>,
/// Underlying device error
source: failure::Compat<drm::SystemError>,
},
/// Unable to determine device id of drm device
#[error("Unable to determine device id of drm device")]
UnableToGetDeviceId(#[source] nix::Error),
/// Device is currently paused
#[error("Device is currently paused, operation rejected")]
DeviceInactive,
/// Mode is not compatible with all given connectors
#[error("Mode `{0:?}` is not compatible with all given connectors")]
ModeNotSuitable(Mode),
/// The given crtc is already in use by another backend
#[error("Crtc `{0:?}` is already in use by another backend")]
CrtcAlreadyInUse(crtc::Handle),
/// No encoder was found for a given connector on the set crtc
#[error("No encoder found for the given connector '{connector:?}' on crtc `{crtc:?}`")]
NoSuitableEncoder {
/// Connector info
connector: connector::Info,
/// CRTC
crtc: crtc::Handle,
},
}
/// Open raw drm device utilizing legacy mode-setting /// Open raw drm device utilizing legacy mode-setting
pub struct LegacyDrmDevice<A: AsRawFd + 'static> { pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
dev: Rc<Dev<A>>, dev: Rc<Dev<A>>,
@ -92,7 +130,7 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
/// ///
/// Returns an error if the file is no valid drm node or context creation was not /// Returns an error if the file is no valid drm node or context creation was not
/// successful. /// successful.
pub fn new<L>(dev: A, logger: L) -> Result<Self> pub fn new<L>(dev: A, logger: L) -> Result<Self, Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -100,7 +138,7 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
info!(log, "DrmDevice initializing"); info!(log, "DrmDevice initializing");
let dev_id = fstat(dev.as_raw_fd()) let dev_id = fstat(dev.as_raw_fd())
.chain_err(|| ErrorKind::UnableToGetDeviceId)? .map_err(Error::UnableToGetDeviceId)?
.st_rdev; .st_rdev;
let active = Arc::new(AtomicBool::new(true)); let active = Arc::new(AtomicBool::new(true));
@ -119,20 +157,30 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
}; };
// enumerate (and save) the current device state // enumerate (and save) the current device state
let res_handles = ControlDevice::resource_handles(&dev).compat().chain_err(|| { let res_handles = ControlDevice::resource_handles(&dev)
ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", dev.dev_path())) .compat()
})?; .map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: dev.dev_path(),
source,
})?;
for &con in res_handles.connectors() { for &con in res_handles.connectors() {
let con_info = dev.get_connector(con).compat().chain_err(|| { let con_info = dev.get_connector(con).compat().map_err(|source| Error::Access {
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", dev.dev_path())) errmsg: "Error loading connector info",
dev: dev.dev_path(),
source,
})?; })?;
if let Some(enc) = con_info.current_encoder() { if let Some(enc) = con_info.current_encoder() {
let enc_info = dev.get_encoder(enc).compat().chain_err(|| { let enc_info = dev.get_encoder(enc).compat().map_err(|source| Error::Access {
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", dev.dev_path())) errmsg: "Error loading encoder info",
dev: dev.dev_path(),
source,
})?; })?;
if let Some(crtc) = enc_info.crtc() { if let Some(crtc) = enc_info.crtc() {
let info = dev.get_crtc(crtc).compat().chain_err(|| { let info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", dev.dev_path())) errmsg: "Error loading crtc info",
dev: dev.dev_path(),
source,
})?; })?;
dev.old_state dev.old_state
.entry(crtc) .entry(crtc)
@ -178,35 +226,44 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
let _ = self.handler.take(); let _ = self.handler.take();
} }
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<LegacyDrmSurface<A>> { fn create_surface(&mut self, crtc: crtc::Handle) -> Result<LegacyDrmSurface<A>, Error> {
if self.backends.borrow().contains_key(&crtc) { if self.backends.borrow().contains_key(&crtc) {
bail!(ErrorKind::CrtcAlreadyInUse(crtc)); return Err(Error::CrtcAlreadyInUse(crtc));
} }
if !self.active.load(Ordering::SeqCst) { if !self.active.load(Ordering::SeqCst) {
bail!(ErrorKind::DeviceInactive); return Err(Error::DeviceInactive);
} }
// Try to enumarate the current state to set the initial state variable correctly // Try to enumarate the current state to set the initial state variable correctly
let crtc_info = self let crtc_info = self.get_crtc(crtc).compat().map_err(|source| Error::Access {
.get_crtc(crtc) errmsg: "Error loading crtc info",
.compat() dev: self.dev_path(),
.chain_err(|| ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", self.dev_path())))?; source,
})?;
let mode = crtc_info.mode(); let mode = crtc_info.mode();
let mut connectors = HashSet::new(); let mut connectors = HashSet::new();
let res_handles = ControlDevice::resource_handles(self).compat().chain_err(|| { let res_handles = ControlDevice::resource_handles(self)
ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) .compat()
})?; .map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: self.dev_path(),
source,
})?;
for &con in res_handles.connectors() { for &con in res_handles.connectors() {
let con_info = self.get_connector(con).compat().chain_err(|| { let con_info = self.get_connector(con).compat().map_err(|source| Error::Access {
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) errmsg: "Error loading connector info",
dev: self.dev_path(),
source,
})?; })?;
if let Some(enc) = con_info.current_encoder() { if let Some(enc) = con_info.current_encoder() {
let enc_info = self.get_encoder(enc).compat().chain_err(|| { let enc_info = self.get_encoder(enc).compat().map_err(|source| Error::Access {
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) errmsg: "Error loading encoder info",
dev: self.dev_path(),
source,
})?; })?;
if let Some(current_crtc) = enc_info.crtc() { if let Some(current_crtc) = enc_info.crtc() {
if crtc == current_crtc { if crtc == current_crtc {
@ -255,23 +312,26 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
} }
} }
} }
Err(err) => { Err(source) => {
if let Some(handler) = self.handler.as_ref() { if let Some(handler) = self.handler.as_ref() {
handler.borrow_mut().error( handler.borrow_mut().error(Error::Access {
ResultExt::<()>::chain_err(Err(err).compat(), || { errmsg: "Error processing drm events",
ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path())) dev: self.dev_path(),
}) source: source.compat(),
.unwrap_err(), });
);
} }
} }
} }
} }
fn resource_handles(&self) -> Result<ResourceHandles> { fn resource_handles(&self) -> Result<ResourceHandles, Error> {
ControlDevice::resource_handles(self) ControlDevice::resource_handles(self)
.compat() .compat()
.chain_err(|| ErrorKind::DrmDev(format!("Error loading resource info on {:?}", self.dev_path()))) .map_err(|source| Error::Access {
errmsg: "Error loading resource info",
dev: self.dev_path(),
source,
})
} }
fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> { fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {

View File

@ -4,7 +4,6 @@ use drm::control::{
PageFlipFlags, PageFlipFlags,
}; };
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use failure::ResultExt as FailureResultExt;
use std::collections::HashSet; use std::collections::HashSet;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
@ -15,7 +14,9 @@ use crate::backend::drm::{DevPath, RawSurface, Surface};
use crate::backend::graphics::CursorBackend; use crate::backend::graphics::CursorBackend;
use crate::backend::graphics::SwapBuffersError; use crate::backend::graphics::SwapBuffersError;
use super::{error::*, Dev}; use super::{Dev, Error};
use failure::ResultExt;
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct State { pub struct State {
@ -44,14 +45,22 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurfaceInternal<A>
type CursorFormat = &'a dyn Buffer; type CursorFormat = &'a dyn Buffer;
type Error = Error; type Error = Error;
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Error> {
trace!(self.logger, "Move the cursor to {},{}", x, y); trace!(self.logger, "Move the cursor to {},{}", x, y);
self.move_cursor(self.crtc, (x as i32, y as i32)) self.move_cursor(self.crtc, (x as i32, y as i32))
.compat() .compat()
.chain_err(|| ErrorKind::DrmDev(format!("Error moving cursor on {:?}", self.dev_path()))) .map_err(|source| Error::Access {
errmsg: "Error moving cursor",
dev: self.dev_path(),
source,
})
} }
fn set_cursor_representation<'b>(&'b self, buffer: Self::CursorFormat, hotspot: (u32, u32)) -> Result<()> fn set_cursor_representation<'b>(
&'b self,
buffer: Self::CursorFormat,
hotspot: (u32, u32),
) -> Result<(), Error>
where where
'a: 'b, 'a: 'b,
{ {
@ -63,7 +72,11 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurfaceInternal<A>
{ {
self.set_cursor(self.crtc, Some(buffer)) self.set_cursor(self.crtc, Some(buffer))
.compat() .compat()
.chain_err(|| ErrorKind::DrmDev(format!("Failed to set cursor on {:?}", self.dev_path())))?; .map_err(|source| Error::Access {
errmsg: "Failed to set cursor",
dev: self.dev_path(),
source,
})?;
} }
Ok(()) Ok(())
@ -94,10 +107,15 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
self.pending.read().unwrap().mode self.pending.read().unwrap().mode
} }
fn add_connector(&self, conn: connector::Handle) -> Result<()> { fn add_connector(&self, conn: connector::Handle) -> Result<(), Error> {
let info = self.get_connector(conn).compat().chain_err(|| { let info = self
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) .get_connector(conn)
})?; .compat()
.map_err(|source| Error::Access {
errmsg: "Error loading connector info",
dev: self.dev_path(),
source,
})?;
let mut pending = self.pending.write().unwrap(); let mut pending = self.pending.write().unwrap();
@ -110,37 +128,46 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
.filter(|enc| enc.is_some()) .filter(|enc| enc.is_some())
.map(|enc| enc.unwrap()) .map(|enc| enc.unwrap())
.map(|encoder| { .map(|encoder| {
self.get_encoder(encoder).compat().chain_err(|| { self.get_encoder(encoder)
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) .compat()
}) .map_err(|source| Error::Access {
errmsg: "Error loading encoder info",
dev: self.dev_path(),
source,
})
}) })
.collect::<Result<Vec<encoder::Info>>>()?; .collect::<Result<Vec<encoder::Info>, _>>()?;
// and if any encoder supports the selected crtc // and if any encoder supports the selected crtc
let resource_handles = self.resource_handles().compat().chain_err(|| { let resource_handles = self.resource_handles().compat().map_err(|source| Error::Access {
ErrorKind::DrmDev(format!("Error loading resources on {:?}", self.dev_path())) errmsg: "Error loading resources",
dev: self.dev_path(),
source,
})?; })?;
if !encoders if !encoders
.iter() .iter()
.map(|encoder| encoder.possible_crtcs()) .map(|encoder| encoder.possible_crtcs())
.all(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&self.crtc)) .all(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&self.crtc))
{ {
bail!(ErrorKind::NoSuitableEncoder(info, self.crtc)); return Err(Error::NoSuitableEncoder {
connector: info,
crtc: self.crtc,
});
} }
pending.connectors.insert(conn); pending.connectors.insert(conn);
Ok(()) Ok(())
} else { } else {
bail!(ErrorKind::ModeNotSuitable(pending.mode.unwrap())); return Err(Error::ModeNotSuitable(pending.mode.unwrap()));
} }
} }
fn remove_connector(&self, connector: connector::Handle) -> Result<()> { fn remove_connector(&self, connector: connector::Handle) -> Result<(), Error> {
self.pending.write().unwrap().connectors.remove(&connector); self.pending.write().unwrap().connectors.remove(&connector);
Ok(()) Ok(())
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<()> { fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
let mut pending = self.pending.write().unwrap(); let mut pending = self.pending.write().unwrap();
// check the connectors to see if this mode is supported // check the connectors to see if this mode is supported
@ -149,13 +176,15 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
if !self if !self
.get_connector(*connector) .get_connector(*connector)
.compat() .compat()
.chain_err(|| { .map_err(|source| Error::Access {
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) errmsg: "Error loading connector info",
dev: self.dev_path(),
source,
})? })?
.modes() .modes()
.contains(&mode) .contains(&mode)
{ {
bail!(ErrorKind::ModeNotSuitable(mode)); return Err(Error::ModeNotSuitable(mode));
} }
} }
} }
@ -171,7 +200,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
*self.pending.read().unwrap() != *self.state.read().unwrap() *self.pending.read().unwrap() != *self.state.read().unwrap()
} }
fn commit(&self, framebuffer: framebuffer::Handle) -> Result<()> { fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
let mut current = self.state.write().unwrap(); let mut current = self.state.write().unwrap();
let pending = self.pending.read().unwrap(); let pending = self.pending.read().unwrap();
@ -217,12 +246,10 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
pending.mode, pending.mode,
) )
.compat() .compat()
.chain_err(|| { .map_err(|source| Error::Access {
ErrorKind::DrmDev(format!( errmsg: "Error setting crtc",
"Error setting crtc {:?} on {:?}", dev: self.dev_path(),
self.crtc, source,
self.dev_path()
))
})?; })?;
*current = pending.clone(); *current = pending.clone();
@ -268,11 +295,15 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface<A> {
type CursorFormat = &'a dyn Buffer; type CursorFormat = &'a dyn Buffer;
type Error = Error; type Error = Error;
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Error> {
self.0.set_cursor_position(x, y) self.0.set_cursor_position(x, y)
} }
fn set_cursor_representation<'b>(&'b self, buffer: Self::CursorFormat, hotspot: (u32, u32)) -> Result<()> fn set_cursor_representation<'b>(
&'b self,
buffer: Self::CursorFormat,
hotspot: (u32, u32),
) -> Result<(), Error>
where where
'a: 'b, 'a: 'b,
{ {
@ -304,15 +335,15 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurface<A> {
self.0.pending_mode() self.0.pending_mode()
} }
fn add_connector(&self, connector: connector::Handle) -> Result<()> { fn add_connector(&self, connector: connector::Handle) -> Result<(), Error> {
self.0.add_connector(connector) self.0.add_connector(connector)
} }
fn remove_connector(&self, connector: connector::Handle) -> Result<()> { fn remove_connector(&self, connector: connector::Handle) -> Result<(), Error> {
self.0.remove_connector(connector) self.0.remove_connector(connector)
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<()> { fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
self.0.use_mode(mode) self.0.use_mode(mode)
} }
} }
@ -322,7 +353,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurface<A> {
self.0.commit_pending() self.0.commit_pending()
} }
fn commit(&self, framebuffer: framebuffer::Handle) -> Result<()> { fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
self.0.commit(framebuffer) self.0.commit(framebuffer)
} }

View File

@ -135,7 +135,7 @@ pub trait Surface {
/// [`pending_connectors`](Surface::pending_connectors) /// [`pending_connectors`](Surface::pending_connectors)
type Connectors: IntoIterator<Item = connector::Handle>; type Connectors: IntoIterator<Item = connector::Handle>;
/// Error type returned by methods of this trait /// Error type returned by methods of this trait
type Error: Error + Send; type Error: Error + Send + 'static;
/// Returns the underlying [`crtc`](drm::control::crtc) of this surface /// Returns the underlying [`crtc`](drm::control::crtc) of this surface
fn crtc(&self) -> crtc::Handle; fn crtc(&self) -> crtc::Handle;

View File

@ -1,6 +1,6 @@
//! EGL context related structs //! EGL context related structs
use super::{error::*, ffi, native, EGLSurface}; use super::{ffi, native, EGLSurface, Error};
use crate::backend::graphics::PixelFormat; use crate::backend::graphics::PixelFormat;
use nix::libc::{c_int, c_void}; use nix::libc::{c_int, c_void};
use slog; use slog;
@ -33,7 +33,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
attributes: GlAttributes, attributes: GlAttributes,
reqs: PixelFormatRequirements, reqs: PixelFormatRequirements,
logger: L, logger: L,
) -> Result<EGLContext<B, N>> ) -> Result<EGLContext<B, N>, Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -60,14 +60,17 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
mut attributes: GlAttributes, mut attributes: GlAttributes,
reqs: PixelFormatRequirements, reqs: PixelFormatRequirements,
log: ::slog::Logger, log: ::slog::Logger,
) -> Result<( ) -> Result<
Rc<ffi::egl::types::EGLContext>, (
Rc<ffi::egl::types::EGLDisplay>, Rc<ffi::egl::types::EGLContext>,
ffi::egl::types::EGLConfig, Rc<ffi::egl::types::EGLDisplay>,
Vec<c_int>, ffi::egl::types::EGLConfig,
PixelFormat, Vec<c_int>,
bool, PixelFormat,
)> { bool,
),
Error,
> {
// If no version is given, try OpenGLES 3.0, if available, // If no version is given, try OpenGLES 3.0, if available,
// fallback to 2.0 otherwise // fallback to 2.0 otherwise
let version = match attributes.version { let version = match attributes.version {
@ -88,14 +91,14 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
} }
Some((1, x)) => { Some((1, x)) => {
error!(log, "OpenGLES 1.* is not supported by the EGL renderer backend"); error!(log, "OpenGLES 1.* is not supported by the EGL renderer backend");
bail!(ErrorKind::OpenGlVersionNotSupported((1, x))); return Err(Error::OpenGlVersionNotSupported((1, x)));
} }
Some(version) => { Some(version) => {
error!( error!(
log, log,
"OpenGLES {:?} is unknown and not supported by the EGL renderer backend", version "OpenGLES {:?} is unknown and not supported by the EGL renderer backend", version
); );
bail!(ErrorKind::OpenGlVersionNotSupported(version)); return Err(Error::OpenGlVersionNotSupported(version));
} }
}; };
@ -146,7 +149,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
let display = B::get_display(ptr, |e: &str| dp_extensions.iter().any(|s| s == e), log.clone()); let display = B::get_display(ptr, |e: &str| dp_extensions.iter().any(|s| s == e), log.clone());
if display == ffi::egl::NO_DISPLAY { if display == ffi::egl::NO_DISPLAY {
error!(log, "EGL Display is not valid"); error!(log, "EGL Display is not valid");
bail!(ErrorKind::DisplayNotSupported); return Err(Error::DisplayNotSupported);
} }
let egl_version = { let egl_version = {
@ -154,7 +157,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
let mut minor: MaybeUninit<ffi::egl::types::EGLint> = MaybeUninit::uninit(); let mut minor: MaybeUninit<ffi::egl::types::EGLint> = MaybeUninit::uninit();
if ffi::egl::Initialize(display, major.as_mut_ptr(), minor.as_mut_ptr()) == 0 { if ffi::egl::Initialize(display, major.as_mut_ptr(), minor.as_mut_ptr()) == 0 {
bail!(ErrorKind::InitFailed); return Err(Error::InitFailed);
} }
let major = major.assume_init(); let major = major.assume_init();
let minor = minor.assume_init(); let minor = minor.assume_init();
@ -179,7 +182,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
if egl_version >= (1, 2) && ffi::egl::BindAPI(ffi::egl::OPENGL_ES_API) == 0 { if egl_version >= (1, 2) && ffi::egl::BindAPI(ffi::egl::OPENGL_ES_API) == 0 {
error!(log, "OpenGLES not supported by the underlying EGL implementation"); error!(log, "OpenGLES not supported by the underlying EGL implementation");
bail!(ErrorKind::OpenGlesNotSupported); return Err(Error::OpenGlesNotSupported);
} }
let descriptor = { let descriptor = {
@ -205,7 +208,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
log, log,
"OpenglES 3.* is not supported on EGL Versions lower then 1.3" "OpenglES 3.* is not supported on EGL Versions lower then 1.3"
); );
bail!(ErrorKind::NoAvailablePixelFormat); return Err(Error::NoAvailablePixelFormat);
} }
trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES3"); trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES3");
out.push(ffi::egl::RENDERABLE_TYPE as c_int); out.push(ffi::egl::RENDERABLE_TYPE as c_int);
@ -220,7 +223,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
log, log,
"OpenglES 2.* is not supported on EGL Versions lower then 1.3" "OpenglES 2.* is not supported on EGL Versions lower then 1.3"
); );
bail!(ErrorKind::NoAvailablePixelFormat); return Err(Error::NoAvailablePixelFormat);
} }
trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES2"); trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES2");
out.push(ffi::egl::RENDERABLE_TYPE as c_int); out.push(ffi::egl::RENDERABLE_TYPE as c_int);
@ -289,7 +292,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
if reqs.stereoscopy { if reqs.stereoscopy {
error!(log, "Stereoscopy is currently unsupported (sorry!)"); error!(log, "Stereoscopy is currently unsupported (sorry!)");
bail!(ErrorKind::NoAvailablePixelFormat); return Err(Error::NoAvailablePixelFormat);
} }
out.push(ffi::egl::NONE as c_int); out.push(ffi::egl::NONE as c_int);
@ -307,7 +310,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
num_configs.as_mut_ptr(), num_configs.as_mut_ptr(),
) == 0 ) == 0
{ {
bail!(ErrorKind::ConfigFailed); return Err(Error::ConfigFailed);
} }
let config_id = config_id.assume_init(); let config_id = config_id.assume_init();
@ -315,7 +318,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
if num_configs == 0 { if num_configs == 0 {
error!(log, "No matching color format found"); error!(log, "No matching color format found");
bail!(ErrorKind::NoAvailablePixelFormat); return Err(Error::NoAvailablePixelFormat);
} }
// analyzing each config // analyzing each config
@ -329,7 +332,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
value.as_mut_ptr(), value.as_mut_ptr(),
); );
if res == 0 { if res == 0 {
bail!(ErrorKind::ConfigFailed); return Err(Error::ConfigFailed);
} }
value.assume_init() value.assume_init()
}}; }};
@ -386,8 +389,8 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
if context.is_null() { if context.is_null() {
match ffi::egl::GetError() as u32 { match ffi::egl::GetError() as u32 {
ffi::egl::BAD_ATTRIBUTE => bail!(ErrorKind::CreationFailed), ffi::egl::BAD_ATTRIBUTE => return Err(Error::CreationFailed),
err_no => bail!(ErrorKind::Unknown(err_no)), err_no => return Err(Error::Unknown(err_no)),
} }
} }
debug!(log, "EGL context successfully created"); debug!(log, "EGL context successfully created");
@ -429,13 +432,12 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
} }
/// Creates a surface for rendering /// Creates a surface for rendering
pub fn create_surface(&self, args: N::Arguments) -> Result<EGLSurface<B::Surface>> { pub fn create_surface(&self, args: N::Arguments) -> Result<EGLSurface<B::Surface>, Error> {
trace!(self.logger, "Creating EGL window surface."); trace!(self.logger, "Creating EGL window surface.");
let surface = self let surface = self.native.borrow_mut().create_surface(args).map_err(|e| {
.native error!(self.logger, "EGL surface creation failed: {}", e);
.borrow_mut() Error::SurfaceCreationFailed
.create_surface(args) })?;
.chain_err(|| ErrorKind::SurfaceCreationFailed)?;
EGLSurface::new(self, surface).map(|x| { EGLSurface::new(self, surface).map(|x| {
debug!(self.logger, "EGL surface successfully created"); debug!(self.logger, "EGL surface successfully created");
x x

View File

@ -1,82 +1,49 @@
//! EGL error types #[derive(thiserror::Error, Debug)]
/// EGL errors
error_chain! { pub enum Error {
errors { /// The requested OpenGL version is not supported
#[doc = "The requested OpenGL version is not supported"] #[error("The requested OpenGL version {0:?} is not supported")]
OpenGlVersionNotSupported(version: (u8, u8)) { OpenGlVersionNotSupported((u8, u8)),
description("The requested OpenGL version is not supported."), /// The EGL implementation does not support creating OpenGL ES contexts
display("The requested OpenGL version {:?} is not supported.", version), #[error("The EGL implementation does not support creating OpenGL ES contexts")]
} OpenGlesNotSupported,
/// No available pixel format matched the criteria
#[doc = "The EGL implementation does not support creating OpenGL ES contexts"] #[error("No available pixel format matched the criteria")]
OpenGlesNotSupported { NoAvailablePixelFormat,
description("The EGL implementation does not support creating OpenGL ES contexts") /// Backend does not match the context type
} #[error("The expected backend '{0:?}' does not match the runtime")]
NonMatchingBackend(&'static str),
#[doc = "No available pixel format matched the criteria"] /// Unable to obtain a valid EGL Display
NoAvailablePixelFormat { #[error("Unable to obtain a valid EGL Display")]
description("No available pixel format matched the criteria.") DisplayNotSupported,
} /// `eglInitialize` returned an error
#[error("Failed to initialize EGL")]
#[doc = "Backend does not match the context type"] InitFailed,
NonMatchingBackend(expected: &'static str) { /// Failed to configure the EGL context
description("The expected backend did not match the runtime."), #[error("Failed to configure the EGL context")]
display("The expected backend '{:?}' does not match the runtime.", expected), ConfigFailed,
} /// Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements
#[error("Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements")]
#[doc = "EGL was unable to obtain a valid EGL Display"] CreationFailed,
DisplayNotSupported { /// `eglCreateWindowSurface` failed
description("EGL was unable to obtain a valid EGL Display") #[error("`eglCreateWindowSurface` failed")]
} SurfaceCreationFailed,
/// The required EGL extension is not supported by the underlying EGL implementation
#[doc = "`eglInitialize` returned an error"] #[error("None of the following EGL extensions is supported by the underlying EGL implementation, at least one is required: {0:?}")]
InitFailed { EglExtensionNotSupported(&'static [&'static str]),
description("Failed to initialize EGL") /// Only one EGLDisplay may be bound to a given `WlDisplay` at any time
} #[error("Only one EGLDisplay may be bound to a given `WlDisplay` at any time")]
OtherEGLDisplayAlreadyBound,
#[doc = "Failed to configure the EGL context"] /// No EGLDisplay is currently bound to this `WlDisplay`
ConfigFailed { #[error("No EGLDisplay is currently bound to this `WlDisplay`")]
description("Failed to configure the EGL context") NoEGLDisplayBound,
} /// Index of plane is out of bounds for `EGLImages`
#[error("Index of plane is out of bounds for `EGLImages`")]
#[doc = "Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements"] PlaneIndexOutOfBounds,
CreationFailed { /// Failed to create `EGLImages` from the buffer
description("Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements") #[error("Failed to create `EGLImages` from the buffer")]
} EGLImageCreationFailed,
/// The reason of failure could not be determined
#[doc = "`eglCreateWindowSurface` failed"] #[error("Unknown error: {0}")]
SurfaceCreationFailed { Unknown(u32),
description("Failed to create a new EGLSurface")
}
#[doc = "The required EGL extension is not supported by the underlying EGL implementation"]
EglExtensionNotSupported(extensions: &'static [&'static str]) {
description("The required EGL extension is not supported by the underlying EGL implementation"),
display("None of the following EGL extensions is supported by the underlying EGL implementation,
at least one is required: {:?}", extensions)
}
#[doc = "Only one EGLDisplay may be bound to a given `WlDisplay` at any time"]
OtherEGLDisplayAlreadyBound {
description("Only one EGLDisplay may be bound to a given WlDisplay at any time")
}
#[doc = "No EGLDisplay is currently bound to this `WlDisplay`"]
NoEGLDisplayBound {
description("No EGLDisplay is currently bound to this WlDisplay")
}
#[doc = "Index of plane is out of bounds for `EGLImages`"]
PlaneIndexOutOfBounds {
description("Index of plane is out of bounds for EGLImages")
}
#[doc = "Failed to create `EGLImages` from the buffer"]
EGLImageCreationFailed {
description("Failed to create EGLImages from the buffer")
}
#[doc = "The reason of failure could not be determined"]
Unknown(err_no: u32)
}
} }

View File

@ -33,8 +33,8 @@ use wayland_sys::server::wl_display;
pub mod context; pub mod context;
pub use self::context::EGLContext; pub use self::context::EGLContext;
pub mod error; mod error;
use self::error::*; pub use self::error::Error;
#[allow(non_camel_case_types, dead_code, unused_mut, non_upper_case_globals)] #[allow(non_camel_case_types, dead_code, unused_mut, non_upper_case_globals)]
pub mod ffi; pub mod ffi;
@ -59,27 +59,24 @@ impl fmt::Display for EglExtensionNotSupportedError {
} }
} }
impl ::std::error::Error for EglExtensionNotSupportedError { impl ::std::error::Error for EglExtensionNotSupportedError {}
fn description(&self) -> &str {
"The required EGL extension is not supported by the underlying EGL implementation"
}
fn cause(&self) -> Option<&dyn ::std::error::Error> {
None
}
}
/// Error that can occur when accessing an EGL buffer /// Error that can occur when accessing an EGL buffer
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
#[derive(thiserror::Error)]
pub enum BufferAccessError { pub enum BufferAccessError {
/// The corresponding Context is not alive anymore /// The corresponding Context is not alive anymore
#[error("The corresponding context was lost")]
ContextLost, ContextLost,
/// This buffer is not managed by the EGL buffer /// This buffer is not managed by the EGL buffer
#[error("This buffer is not managed by EGL")]
NotManaged(WlBuffer), NotManaged(WlBuffer),
/// Failed to create `EGLImages` from the buffer /// Failed to create `EGLImages` from the buffer
#[error("Failed to create EGLImages from the buffer")]
EGLImageCreationFailed, EGLImageCreationFailed,
/// The required EGL extension is not supported by the underlying EGL implementation /// The required EGL extension is not supported by the underlying EGL implementation
EglExtensionNotSupported(EglExtensionNotSupportedError), #[error("{0}")]
EglExtensionNotSupported(#[from] EglExtensionNotSupportedError),
} }
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
@ -96,49 +93,11 @@ impl fmt::Debug for BufferAccessError {
} }
} }
#[cfg(feature = "wayland_frontend")]
impl fmt::Display for BufferAccessError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> ::std::result::Result<(), fmt::Error> {
use std::error::Error;
match *self {
BufferAccessError::ContextLost
| BufferAccessError::NotManaged(_)
| BufferAccessError::EGLImageCreationFailed => write!(formatter, "{}", self.description()),
BufferAccessError::EglExtensionNotSupported(ref err) => err.fmt(formatter),
}
}
}
#[cfg(feature = "wayland_frontend")]
impl ::std::error::Error for BufferAccessError {
fn description(&self) -> &str {
match *self {
BufferAccessError::ContextLost => "The corresponding context was lost",
BufferAccessError::NotManaged(_) => "This buffer is not managed by EGL",
BufferAccessError::EGLImageCreationFailed => "Failed to create EGLImages from the buffer",
BufferAccessError::EglExtensionNotSupported(ref err) => err.description(),
}
}
fn cause(&self) -> Option<&dyn ::std::error::Error> {
match *self {
BufferAccessError::EglExtensionNotSupported(ref err) => Some(err),
_ => None,
}
}
}
#[cfg(feature = "wayland_frontend")]
impl From<EglExtensionNotSupportedError> for BufferAccessError {
fn from(error: EglExtensionNotSupportedError) -> Self {
BufferAccessError::EglExtensionNotSupported(error)
}
}
/// Error that might happen when binding an `EGLImage` to a GL texture /// Error that might happen when binding an `EGLImage` to a GL texture
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum TextureCreationError { pub enum TextureCreationError {
/// The given plane index is out of bounds /// The given plane index is out of bounds
#[error("This buffer is not managed by EGL")]
PlaneIndexOutOfBounds, PlaneIndexOutOfBounds,
/// The OpenGL context has been lost and needs to be recreated. /// The OpenGL context has been lost and needs to be recreated.
/// ///
@ -151,48 +110,18 @@ pub enum TextureCreationError {
/// A context loss usually happens on mobile devices when the user puts the /// 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 /// application on sleep and wakes it up later. However any OpenGL implementation
/// can theoretically lose the context at any time. /// can theoretically lose the context at any time.
#[error("The context has been lost, it needs to be recreated")]
ContextLost, ContextLost,
/// Required OpenGL Extension for texture creation is missing /// Required OpenGL Extension for texture creation is missing
#[error("Required OpenGL Extension for texture creation is missing: {0}")]
GLExtensionNotSupported(&'static str), GLExtensionNotSupported(&'static str),
/// Failed to bind the `EGLImage` to the given texture /// Failed to bind the `EGLImage` to the given texture
/// ///
/// The given argument is the GL error code /// The given argument is the GL error code
#[error("Failed to create EGLImages from the buffer (GL error code {0:x}")]
TextureBindingFailed(u32), TextureBindingFailed(u32),
} }
impl fmt::Display for TextureCreationError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> ::std::result::Result<(), fmt::Error> {
use std::error::Error;
match *self {
TextureCreationError::ContextLost => write!(formatter, "{}", self.description()),
TextureCreationError::PlaneIndexOutOfBounds => write!(formatter, "{}", self.description()),
TextureCreationError::GLExtensionNotSupported(ext) => {
write!(formatter, "{}: {:}", self.description(), ext)
}
TextureCreationError::TextureBindingFailed(code) => {
write!(formatter, "{}. Gl error code: {:?}", self.description(), code)
}
}
}
}
impl ::std::error::Error for TextureCreationError {
fn description(&self) -> &str {
match *self {
TextureCreationError::ContextLost => "The context has been lost, it needs to be recreated",
TextureCreationError::PlaneIndexOutOfBounds => "This buffer is not managed by EGL",
TextureCreationError::GLExtensionNotSupported(_) => {
"Required OpenGL Extension for texture creation is missing"
}
TextureCreationError::TextureBindingFailed(_) => "Failed to create EGLImages from the buffer",
}
}
fn cause(&self) -> Option<&dyn ::std::error::Error> {
None
}
}
/// Texture format types /// Texture format types
#[repr(i32)] #[repr(i32)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -320,7 +249,7 @@ pub trait EGLGraphicsBackend {
/// ///
/// This might return [`OtherEGLDisplayAlreadyBound`](ErrorKind::OtherEGLDisplayAlreadyBound) /// This might return [`OtherEGLDisplayAlreadyBound`](ErrorKind::OtherEGLDisplayAlreadyBound)
/// if called for the same [`Display`] multiple times, as only one context may be bound at any given time. /// if called for the same [`Display`] multiple times, as only one context may be bound at any given time.
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay>; fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, Error>;
} }
/// Type to receive [`EGLImages`] for EGL-based [`WlBuffer`]s. /// Type to receive [`EGLImages`] for EGL-based [`WlBuffer`]s.
@ -525,22 +454,20 @@ impl Drop for EGLDisplay {
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
impl<E: EGLGraphicsBackend> EGLGraphicsBackend for Rc<E> { impl<E: EGLGraphicsBackend> EGLGraphicsBackend for Rc<E> {
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> { fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, Error> {
(**self).bind_wl_display(display) (**self).bind_wl_display(display)
} }
} }
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGLContext<B, N> { impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGLContext<B, N> {
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> { fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, Error> {
if !self.wl_drm_support { if !self.wl_drm_support {
bail!(ErrorKind::EglExtensionNotSupported(&[ return Err(Error::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"]));
"EGL_WL_bind_wayland_display"
]));
} }
let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.c_ptr() as *mut _) }; let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.c_ptr() as *mut _) };
if res == 0 { if res == 0 {
bail!(ErrorKind::OtherEGLDisplayAlreadyBound); return Err(Error::OtherEGLDisplayAlreadyBound);
} }
Ok(EGLDisplay::new(self, display.c_ptr())) Ok(EGLDisplay::new(self, display.c_ptr()))
} }

View File

@ -1,6 +1,6 @@
//! Type safe native types for safe context/surface creation //! Type safe native types for safe context/surface creation
use super::{error::*, ffi}; use super::{ffi, Error};
use crate::backend::graphics::SwapBuffersError; use crate::backend::graphics::SwapBuffersError;
#[cfg(feature = "backend_winit")] #[cfg(feature = "backend_winit")]
@ -105,7 +105,7 @@ pub unsafe trait NativeDisplay<B: Backend> {
/// if the expected [`Backend`] is used at runtime. /// if the expected [`Backend`] is used at runtime.
fn is_backend(&self) -> bool; fn is_backend(&self) -> bool;
/// Return a raw pointer EGL will accept for context creation. /// Return a raw pointer EGL will accept for context creation.
fn ptr(&self) -> Result<ffi::NativeDisplayType>; fn ptr(&self) -> Result<ffi::NativeDisplayType, Error>;
/// Create a surface /// Create a surface
fn create_surface(&mut self, args: Self::Arguments) -> ::std::result::Result<B::Surface, Self::Error>; fn create_surface(&mut self, args: Self::Arguments) -> ::std::result::Result<B::Surface, Self::Error>;
} }
@ -119,16 +119,16 @@ unsafe impl NativeDisplay<X11> for WinitWindow {
self.xlib_display().is_some() self.xlib_display().is_some()
} }
fn ptr(&self) -> Result<ffi::NativeDisplayType> { fn ptr(&self) -> Result<ffi::NativeDisplayType, Error> {
self.xlib_display() self.xlib_display()
.map(|ptr| ptr as *const _) .map(|ptr| ptr as *const _)
.ok_or_else(|| ErrorKind::NonMatchingBackend("X11").into()) .ok_or_else(|| Error::NonMatchingBackend("X11"))
} }
fn create_surface(&mut self, _args: ()) -> Result<XlibWindow> { fn create_surface(&mut self, _args: ()) -> Result<XlibWindow, Error> {
self.xlib_window() self.xlib_window()
.map(XlibWindow) .map(XlibWindow)
.ok_or_else(|| ErrorKind::NonMatchingBackend("X11").into()) .ok_or_else(|| Error::NonMatchingBackend("X11"))
} }
} }
@ -141,20 +141,20 @@ unsafe impl NativeDisplay<Wayland> for WinitWindow {
self.wayland_display().is_some() self.wayland_display().is_some()
} }
fn ptr(&self) -> Result<ffi::NativeDisplayType> { fn ptr(&self) -> Result<ffi::NativeDisplayType, Error> {
self.wayland_display() self.wayland_display()
.map(|ptr| ptr as *const _) .map(|ptr| ptr as *const _)
.ok_or_else(|| ErrorKind::NonMatchingBackend("Wayland").into()) .ok_or_else(|| Error::NonMatchingBackend("Wayland"))
} }
fn create_surface(&mut self, _args: ()) -> Result<wegl::WlEglSurface> { fn create_surface(&mut self, _args: ()) -> Result<wegl::WlEglSurface, Error> {
if let Some(surface) = self.wayland_surface() { if let Some(surface) = self.wayland_surface() {
let size = self.inner_size(); let size = self.inner_size();
Ok(unsafe { Ok(unsafe {
wegl::WlEglSurface::new_from_raw(surface as *mut _, size.width as i32, size.height as i32) wegl::WlEglSurface::new_from_raw(surface as *mut _, size.width as i32, size.height as i32)
}) })
} else { } else {
bail!(ErrorKind::NonMatchingBackend("Wayland")) return Err(Error::NonMatchingBackend("Wayland"));
} }
} }
} }

View File

@ -1,6 +1,6 @@
//! EGL surface related structs //! EGL surface related structs
use super::{error::*, ffi, native, EGLContext}; use super::{ffi, native, EGLContext, Error};
use crate::backend::graphics::SwapBuffersError; use crate::backend::graphics::SwapBuffersError;
use nix::libc::c_int; use nix::libc::c_int;
use std::{ use std::{
@ -36,7 +36,7 @@ impl<N: native::NativeSurface> EGLSurface<N> {
pub(crate) fn new<B: native::Backend<Surface = N>, D: native::NativeDisplay<B>>( pub(crate) fn new<B: native::Backend<Surface = N>, D: native::NativeDisplay<B>>(
context: &EGLContext<B, D>, context: &EGLContext<B, D>,
native: N, native: N,
) -> Result<EGLSurface<N>> { ) -> Result<EGLSurface<N>, Error> {
let surface = unsafe { let surface = unsafe {
ffi::egl::CreateWindowSurface( ffi::egl::CreateWindowSurface(
*context.display, *context.display,
@ -47,7 +47,7 @@ impl<N: native::NativeSurface> EGLSurface<N> {
}; };
if surface.is_null() { if surface.is_null() {
bail!(ErrorKind::SurfaceCreationFailed); return Err(Error::SurfaceCreationFailed);
} }
Ok(EGLSurface { Ok(EGLSurface {

View File

@ -162,14 +162,14 @@ pub fn auto_session_bind<Data: 'static>(
impl Session for AutoSession { impl Session for AutoSession {
type Error = Error; type Error = Error;
fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd> { fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd, Error> {
match *self { match *self {
#[cfg(feature = "backend_session_logind")] #[cfg(feature = "backend_session_logind")]
AutoSession::Logind(ref mut logind) => logind.open(path, flags).map_err(|e| e.into()), AutoSession::Logind(ref mut logind) => logind.open(path, flags).map_err(|e| e.into()),
AutoSession::Direct(ref mut direct) => direct.open(path, flags).map_err(|e| e.into()), AutoSession::Direct(ref mut direct) => direct.open(path, flags).map_err(|e| e.into()),
} }
} }
fn close(&mut self, fd: RawFd) -> Result<()> { fn close(&mut self, fd: RawFd) -> Result<(), Error> {
match *self { match *self {
#[cfg(feature = "backend_session_logind")] #[cfg(feature = "backend_session_logind")]
AutoSession::Logind(ref mut logind) => logind.close(fd).map_err(|e| e.into()), AutoSession::Logind(ref mut logind) => logind.close(fd).map_err(|e| e.into()),
@ -177,7 +177,7 @@ impl Session for AutoSession {
} }
} }
fn change_vt(&mut self, vt: i32) -> Result<()> { fn change_vt(&mut self, vt: i32) -> Result<(), Error> {
match *self { match *self {
#[cfg(feature = "backend_session_logind")] #[cfg(feature = "backend_session_logind")]
AutoSession::Logind(ref mut logind) => logind.change_vt(vt).map_err(|e| e.into()), AutoSession::Logind(ref mut logind) => logind.change_vt(vt).map_err(|e| e.into()),
@ -244,21 +244,19 @@ impl BoundAutoSession {
} }
/// Errors related to auto sessions /// Errors related to auto sessions
pub mod errors { #[derive(thiserror::Error, Debug)]
pub enum Error {
#[cfg(feature = "backend_session_logind")] #[cfg(feature = "backend_session_logind")]
use super::logind::errors as logind; /// Logind session error
#[error("Logind session error: {0}")]
error_chain! { Logind(#[from] logind::Error),
links { /// Direct session error
Logind(logind::Error, logind::ErrorKind) #[cfg(feature = "backend_session_logind")] #[doc = "Underlying logind session error"]; #[error("Direct session error: {0}")]
} Direct(#[from] direct::Error),
/// Nix error
foreign_links { #[error("Nix error: {0}")]
Direct(::nix::Error) #[doc = "Underlying direct tty session error"]; Nix(#[from] nix::Error),
}
}
} }
use self::errors::*;
impl AsErrno for Error { impl AsErrno for Error {
fn as_errno(&self) -> Option<i32> { fn as_errno(&self) -> Option<i32> {

View File

@ -83,7 +83,7 @@ pub struct LogindSessionNotifier {
impl LogindSession { impl LogindSession {
/// Tries to create a new session via the logind dbus interface. /// Tries to create a new session via the logind dbus interface.
pub fn new<L>(logger: L) -> Result<(LogindSession, LogindSessionNotifier)> pub fn new<L>(logger: L) -> Result<(LogindSession, LogindSessionNotifier), Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -91,12 +91,12 @@ impl LogindSession {
.new(o!("smithay_module" => "backend_session", "session_type" => "logind")); .new(o!("smithay_module" => "backend_session", "session_type" => "logind"));
// Acquire session_id, seat and vt (if any) via libsystemd // Acquire session_id, seat and vt (if any) via libsystemd
let session_id = login::get_session(None).chain_err(|| ErrorKind::FailedToGetSession)?; let session_id = login::get_session(None).map_err(Error::FailedToGetSession)?;
let seat = login::get_seat(session_id.clone()).chain_err(|| ErrorKind::FailedToGetSeat)?; let seat = login::get_seat(session_id.clone()).map_err(Error::FailedToGetSeat)?;
let vt = login::get_vt(session_id.clone()).ok(); let vt = login::get_vt(session_id.clone()).ok();
// Create dbus connection // Create dbus connection
let conn = Connection::get_private(BusType::System).chain_err(|| ErrorKind::FailedDbusConnection)?; let conn = Connection::get_private(BusType::System).map_err(Error::FailedDbusConnection)?;
// and get the session path // and get the session path
let session_path = LogindSessionImpl::blocking_call( let session_path = LogindSessionImpl::blocking_call(
&conn, &conn,
@ -107,7 +107,7 @@ impl LogindSession {
Some(vec![session_id.clone().into()]), Some(vec![session_id.clone().into()]),
)? )?
.get1::<DbusPath<'static>>() .get1::<DbusPath<'static>>()
.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; .ok_or(Error::UnexpectedMethodReturn)?;
// Match all signals that we want to receive and handle // Match all signals that we want to receive and handle
let match1 = String::from( let match1 = String::from(
@ -118,7 +118,7 @@ impl LogindSession {
path='/org/freedesktop/login1'", path='/org/freedesktop/login1'",
); );
conn.add_match(&match1) conn.add_match(&match1)
.chain_err(|| ErrorKind::DbusMatchFailed(match1))?; .map_err(|source| Error::DbusMatchFailed(match1, source))?;
let match2 = format!( let match2 = format!(
"type='signal',\ "type='signal',\
sender='org.freedesktop.login1',\ sender='org.freedesktop.login1',\
@ -128,7 +128,7 @@ impl LogindSession {
&session_path &session_path
); );
conn.add_match(&match2) conn.add_match(&match2)
.chain_err(|| ErrorKind::DbusMatchFailed(match2))?; .map_err(|source| Error::DbusMatchFailed(match2, source))?;
let match3 = format!( let match3 = format!(
"type='signal',\ "type='signal',\
sender='org.freedesktop.login1',\ sender='org.freedesktop.login1',\
@ -138,7 +138,7 @@ impl LogindSession {
&session_path &session_path
); );
conn.add_match(&match3) conn.add_match(&match3)
.chain_err(|| ErrorKind::DbusMatchFailed(match3))?; .map_err(|source| Error::DbusMatchFailed(match3, source))?;
let match4 = format!( let match4 = format!(
"type='signal',\ "type='signal',\
sender='org.freedesktop.login1',\ sender='org.freedesktop.login1',\
@ -148,7 +148,7 @@ impl LogindSession {
&session_path &session_path
); );
conn.add_match(&match4) conn.add_match(&match4)
.chain_err(|| ErrorKind::DbusMatchFailed(match4))?; .map_err(|source| Error::DbusMatchFailed(match4, source))?;
// Activate (switch to) the session and take control // Activate (switch to) the session and take control
LogindSessionImpl::blocking_call( LogindSessionImpl::blocking_call(
@ -209,7 +209,7 @@ impl LogindSessionImpl {
interface: I, interface: I,
method: M, method: M,
arguments: Option<Vec<MessageItem>>, arguments: Option<Vec<MessageItem>>,
) -> Result<Message> ) -> Result<Message, Error>
where where
D: Into<BusName<'d>>, D: Into<BusName<'d>>,
P: Into<DbusPath<'p>>, P: Into<DbusPath<'p>>,
@ -227,30 +227,29 @@ impl LogindSessionImpl {
message.append_items(&arguments) message.append_items(&arguments)
}; };
let mut message = conn.send_with_reply_and_block(message, 1000).chain_err(|| { let mut message =
ErrorKind::FailedToSendDbusCall( conn.send_with_reply_and_block(message, 1000)
destination.clone(), .map_err(|source| Error::FailedToSendDbusCall {
path.clone(), bus: destination.clone(),
interface.clone(), path: path.clone(),
method.clone(), interface: interface.clone(),
) member: method.clone(),
})?; source,
})?;
match message.as_result() { match message.as_result() {
Ok(_) => Ok(message), Ok(_) => Ok(message),
Err(err) => Err(Error::with_chain( Err(err) => Err(Error::DbusCallFailed {
err, bus: destination.clone(),
ErrorKind::DbusCallFailed( path: path.clone(),
destination.clone(), interface: interface.clone(),
path.clone(), member: method.clone(),
interface.clone(), source: err,
method.clone(), }),
),
)),
} }
} }
fn handle_signals<I>(&self, signals: I) -> Result<()> fn handle_signals<I>(&self, signals: I) -> Result<(), Error>
where where
I: IntoIterator<Item = ConnectionItem>, I: IntoIterator<Item = ConnectionItem>,
{ {
@ -278,9 +277,9 @@ impl LogindSessionImpl {
} else if &*message.interface().unwrap() == "org.freedesktop.login1.Session" { } else if &*message.interface().unwrap() == "org.freedesktop.login1.Session" {
if &*message.member().unwrap() == "PauseDevice" { if &*message.member().unwrap() == "PauseDevice" {
let (major, minor, pause_type) = message.get3::<u32, u32, String>(); let (major, minor, pause_type) = message.get3::<u32, u32, String>();
let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; let major = major.ok_or(Error::UnexpectedMethodReturn)?;
let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; let minor = minor.ok_or(Error::UnexpectedMethodReturn)?;
let pause_type = pause_type.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; let pause_type = pause_type.ok_or(Error::UnexpectedMethodReturn)?;
debug!( debug!(
self.logger, self.logger,
"Request of type \"{}\" to close device ({},{})", pause_type, major, minor "Request of type \"{}\" to close device ({},{})", pause_type, major, minor
@ -306,9 +305,9 @@ impl LogindSessionImpl {
} }
} else if &*message.member().unwrap() == "ResumeDevice" { } else if &*message.member().unwrap() == "ResumeDevice" {
let (major, minor, fd) = message.get3::<u32, u32, OwnedFd>(); let (major, minor, fd) = message.get3::<u32, u32, OwnedFd>();
let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; let major = major.ok_or(Error::UnexpectedMethodReturn)?;
let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; let minor = minor.ok_or(Error::UnexpectedMethodReturn)?;
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd(); let fd = fd.ok_or(Error::UnexpectedMethodReturn)?.into_fd();
debug!(self.logger, "Reactivating device ({},{})", major, minor); debug!(self.logger, "Reactivating device ({},{})", major, minor);
for signal in &mut *self.signals.borrow_mut() { for signal in &mut *self.signals.borrow_mut() {
if let &mut Some(ref mut signal) = signal { if let &mut Some(ref mut signal) = signal {
@ -323,7 +322,7 @@ impl LogindSessionImpl {
let (_, changed, _) = let (_, changed, _) =
message.get3::<String, Dict<'_, String, Variant<Iter<'_>>, Iter<'_>>, Array<'_, String, Iter<'_>>>(); message.get3::<String, Dict<'_, String, Variant<Iter<'_>>, Iter<'_>>, Array<'_, String, Iter<'_>>>();
let mut changed = changed.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; let mut changed = changed.ok_or(Error::UnexpectedMethodReturn)?;
if let Some((_, mut value)) = changed.find(|&(ref key, _)| &*key == "Active") { if let Some((_, mut value)) = changed.find(|&(ref key, _)| &*key == "Active") {
if let Some(active) = Get::get(&mut value.0) { if let Some(active) = Get::get(&mut value.0) {
self.active.store(active, Ordering::SeqCst); self.active.store(active, Ordering::SeqCst);
@ -338,9 +337,9 @@ impl LogindSessionImpl {
impl Session for LogindSession { impl Session for LogindSession {
type Error = Error; type Error = Error;
fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd> { fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd, Error> {
if let Some(session) = self.internal.upgrade() { if let Some(session) = self.internal.upgrade() {
let stat = stat(path).chain_err(|| ErrorKind::FailedToStatDevice)?; let stat = stat(path).map_err(Error::FailedToStatDevice)?;
// TODO handle paused // TODO handle paused
let (fd, _paused) = LogindSessionImpl::blocking_call( let (fd, _paused) = LogindSessionImpl::blocking_call(
&*session.conn.borrow(), &*session.conn.borrow(),
@ -354,16 +353,16 @@ impl Session for LogindSession {
]), ]),
)? )?
.get2::<OwnedFd, bool>(); .get2::<OwnedFd, bool>();
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd(); let fd = fd.ok_or(Error::UnexpectedMethodReturn)?.into_fd();
Ok(fd) Ok(fd)
} else { } else {
bail!(ErrorKind::SessionLost) return Err(Error::SessionLost);
} }
} }
fn close(&mut self, fd: RawFd) -> Result<()> { fn close(&mut self, fd: RawFd) -> Result<(), Error> {
if let Some(session) = self.internal.upgrade() { if let Some(session) = self.internal.upgrade() {
let stat = fstat(fd).chain_err(|| ErrorKind::FailedToStatDevice)?; let stat = fstat(fd).map_err(Error::FailedToStatDevice)?;
LogindSessionImpl::blocking_call( LogindSessionImpl::blocking_call(
&*session.conn.borrow(), &*session.conn.borrow(),
"org.freedesktop.login1", "org.freedesktop.login1",
@ -377,7 +376,7 @@ impl Session for LogindSession {
) )
.map(|_| ()) .map(|_| ())
} else { } else {
bail!(ErrorKind::SessionLost) return Err(Error::SessionLost);
} }
} }
@ -393,7 +392,7 @@ impl Session for LogindSession {
self.seat.clone() self.seat.clone()
} }
fn change_vt(&mut self, vt_num: i32) -> Result<()> { fn change_vt(&mut self, vt_num: i32) -> Result<(), Error> {
if let Some(session) = self.internal.upgrade() { if let Some(session) = self.internal.upgrade() {
LogindSessionImpl::blocking_call( LogindSessionImpl::blocking_call(
&*session.conn.borrow_mut(), &*session.conn.borrow_mut(),
@ -405,7 +404,7 @@ impl Session for LogindSession {
) )
.map(|_| ()) .map(|_| ())
} else { } else {
bail!(ErrorKind::SessionLost) return Err(Error::SessionLost);
} }
} }
} }
@ -532,67 +531,53 @@ impl LogindSessionNotifier {
} }
/// Errors related to logind sessions /// Errors related to logind sessions
pub mod errors { #[derive(thiserror::Error, Debug)]
use dbus::strings::{BusName, Interface, Member, Path as DbusPath}; pub enum Error {
/// Failed to connect to dbus system socket
error_chain! { #[error("Failed to connect to dbus system socket")]
errors { FailedDbusConnection(#[source] dbus::Error),
#[doc = "Failed to connect to dbus system socket"] /// Failed to get session from logind
FailedDbusConnection { #[error("Failed to get session from logind")]
description("Failed to connect to dbus system socket"), FailedToGetSession(#[source] IoError),
} /// Failed to get seat from logind
#[error("Failed to get seat from logind")]
#[doc = "Failed to get session from logind"] FailedToGetSeat(#[source] IoError),
FailedToGetSession { /// Failed to get vt from logind
description("Failed to get session from logind") #[error("Failed to get vt from logind")]
} FailedToGetVT,
/// Failed call to a dbus method
#[doc = "Failed to get seat from logind"] #[error("Failed to call dbus method for service: {bus:?}, path: {path:?}, interface: {interface:?}, member: {member:?}")]
FailedToGetSeat { FailedToSendDbusCall {
description("Failed to get seat from logind") bus: BusName<'static>,
} path: DbusPath<'static>,
interface: Interface<'static>,
#[doc = "Failed to get vt from logind"] member: Member<'static>,
FailedToGetVT { #[source]
description("Failed to get vt from logind") source: dbus::Error,
} },
/// DBus method call failed
#[doc = "Failed to call dbus method"] #[error("Dbus message call failed for service: {bus:?}, path: {path:?}, interface: {interface:?}, member: {member:?}")]
FailedToSendDbusCall(bus: BusName<'static>, path: DbusPath<'static>, interface: Interface<'static>, member: Member<'static>) { DbusCallFailed {
description("Failed to call dbus method") bus: BusName<'static>,
display("Failed to call dbus method for service: {:?}, path: {:?}, interface: {:?}, member: {:?}", bus, path, interface, member), path: DbusPath<'static>,
} interface: Interface<'static>,
member: Member<'static>,
#[doc = "Dbus method call failed"] #[source]
DbusCallFailed(bus: BusName<'static>, path: DbusPath<'static>, interface: Interface<'static>, member: Member<'static>) { source: dbus::Error,
description("Dbus method call failed") },
display("Dbus message call failed for service: {:?}, path: {:?}, interface: {:?}, member: {:?}", bus, path, interface, member), /// Dbus method return had unexpected format
} #[error("Dbus method return had unexpected format")]
UnexpectedMethodReturn,
#[doc = "Dbus method return had unexpected format"] /// Failed to setup dbus match rule
UnexpectedMethodReturn { #[error("Failed to setup dbus match rule {0}")]
description("Dbus method return returned unexpected format") DbusMatchFailed(String, #[source] dbus::Error),
} /// Failed to stat device
#[error("Failed to stat device")]
#[doc = "Failed to setup dbus match rule"] FailedToStatDevice(#[source] nix::Error),
DbusMatchFailed(rule: String) { /// Session is already closed,
description("Failed to setup dbus match rule"), #[error("Session is already closed")]
display("Failed to setup dbus match rule {}", rule), SessionLost,
}
#[doc = "Failed to stat device"]
FailedToStatDevice {
description("Failed to stat device")
}
#[doc = "Session is already closed"]
SessionLost {
description("Session is already closed")
}
}
}
} }
use self::errors::*;
impl AsErrno for Error { impl AsErrno for Error {
fn as_errno(&self) -> Option<i32> { fn as_errno(&self) -> Option<i32> {

View File

@ -169,7 +169,7 @@ impl DirectSession {
/// Tries to create a new session via the legacy virtual terminal interface. /// Tries to create a new session via the legacy virtual terminal interface.
/// ///
/// If you do not provide a tty device path, it will try to open the currently active tty if any. /// If you do not provide a tty device path, it will try to open the currently active tty if any.
pub fn new<L>(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier)> pub fn new<L>(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier), Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -183,10 +183,10 @@ impl DirectSession {
fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC, fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC,
Mode::empty(), Mode::empty(),
) )
.chain_err(|| ErrorKind::FailedToOpenTTY(String::from(path.to_string_lossy()))) .map_err(|source| Error::FailedToOpenTTY(String::from(path.to_string_lossy()), source))
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {
dup(0 /*stdin*/).chain_err(|| ErrorKind::FailedToOpenTTY(String::from("<stdin>"))) dup(0 /*stdin*/).map_err(|source| Error::FailedToOpenTTY(String::from("<stdin>"), source))
})?; })?;
let active = Arc::new(AtomicBool::new(true)); let active = Arc::new(AtomicBool::new(true));
@ -215,10 +215,14 @@ impl DirectSession {
} }
} }
fn setup_tty(path: Option<&Path>, tty: RawFd, logger: ::slog::Logger) -> Result<(i32, i32, Signal)> { fn setup_tty(
let stat = fstat(tty).chain_err(|| ErrorKind::NotRunningFromTTY)?; path: Option<&Path>,
tty: RawFd,
logger: ::slog::Logger,
) -> Result<(i32, i32, Signal), Error> {
let stat = fstat(tty).map_err(|_| Error::NotRunningFromTTY)?;
if !is_tty_device(stat.st_dev, path) { if !is_tty_device(stat.st_dev, path) {
bail!(ErrorKind::NotRunningFromTTY); return Err(Error::NotRunningFromTTY);
} }
let vt_num = minor(stat.st_rdev) as i32; let vt_num = minor(stat.st_rdev) as i32;
@ -226,24 +230,27 @@ impl DirectSession {
let mut mode = 0; let mut mode = 0;
unsafe { unsafe {
tty::kd_get_mode(tty, &mut mode).chain_err(|| ErrorKind::NotRunningFromTTY)?; tty::kd_get_mode(tty, &mut mode).map_err(|_| Error::NotRunningFromTTY)?;
} }
if mode != tty::KD_TEXT { if mode != tty::KD_TEXT {
bail!(ErrorKind::TTYAlreadyInGraphicsMode); return Err(Error::TTYAlreadyInGraphicsMode);
} }
unsafe { unsafe {
tty::vt_activate(tty, vt_num as c_int).chain_err(|| ErrorKind::FailedToActivateTTY(vt_num))?; tty::vt_activate(tty, vt_num as c_int)
tty::vt_wait_active(tty, vt_num as c_int).chain_err(|| ErrorKind::FailedToWaitForTTY(vt_num))?; .map_err(|source| Error::FailedToActivateTTY(vt_num, source))?;
tty::vt_wait_active(tty, vt_num as c_int)
.map_err(|source| Error::FailedToWaitForTTY(vt_num, source))?;
} }
let mut old_keyboard_mode = 0; let mut old_keyboard_mode = 0;
unsafe { unsafe {
tty::kd_get_kb_mode(tty, &mut old_keyboard_mode) tty::kd_get_kb_mode(tty, &mut old_keyboard_mode)
.chain_err(|| ErrorKind::FailedToSaveTTYState(vt_num))?; .map_err(|source| Error::FailedToSaveTTYState(vt_num, source))?;
tty::kd_set_kb_mode(tty, tty::K_OFF).chain_err(|| ErrorKind::FailedToSetTTYKbMode(vt_num))?; tty::kd_set_kb_mode(tty, tty::K_OFF)
.map_err(|source| Error::FailedToSetTTYKbMode(vt_num, source))?;
tty::kd_set_mode(tty, tty::KD_GRAPHICS as i32) tty::kd_set_mode(tty, tty::KD_GRAPHICS as i32)
.chain_err(|| ErrorKind::FailedToSetTTYMode(vt_num))?; .map_err(|source| Error::FailedToSetTTYMode(vt_num, source))?;
} }
// TODO: Support realtime signals // TODO: Support realtime signals
@ -265,7 +272,7 @@ impl DirectSession {
}; };
unsafe { unsafe {
tty::vt_set_mode(tty, &mode).chain_err(|| ErrorKind::FailedToTakeControlOfTTY(vt_num))?; tty::vt_set_mode(tty, &mode).map_err(|source| Error::FailedToTakeControlOfTTY(vt_num, source))?;
} }
Ok((vt_num, old_keyboard_mode, Signal::SIGUSR2)) Ok((vt_num, old_keyboard_mode, Signal::SIGUSR2))
@ -440,62 +447,33 @@ pub fn direct_session_bind<Data: 'static>(
} }
/// Errors related to direct/tty sessions /// Errors related to direct/tty sessions
pub mod errors { #[derive(thiserror::Error, Debug)]
error_chain! { pub enum Error {
errors { /// Failed to open TTY
#[doc = "Failed to open tty"] #[error("Failed to open TTY `{0}`")]
FailedToOpenTTY(path: String) { FailedToOpenTTY(String, #[source] nix::Error),
description("Failed to open tty"), /// Not running from a TTY
display("Failed to open tty ({:?})", path), #[error("Not running from a TTY")]
} NotRunningFromTTY,
/// TTY is already in KB_GRAPHICS mode
#[doc = "Not running from a tty"] #[error("The tty is already in graphics mode, is already a compositor running?")]
NotRunningFromTTY { TTYAlreadyInGraphicsMode,
description("Not running from a tty"), /// Failed to activate open tty
} #[error("Failed to activate open tty ({0})")]
FailedToActivateTTY(i32, #[source] nix::Error),
#[doc = "tty is already in KB_GRAPHICS mode"] /// Failed to wait for tty to become active
TTYAlreadyInGraphicsMode { #[error("Failed to wait for tty {0} to become active")]
description("The tty is already in KB_GRAPHICS mode"), FailedToWaitForTTY(i32, #[source] nix::Error),
display("The tty is already in graphics mode, is already a compositor running?"), /// Failed to save old tty state
} #[error("Failed to save old tty ({0}) state")]
FailedToSaveTTYState(i32, #[source] nix::Error),
#[doc = "Failed to activate open tty"] /// Failed to set tty kb mode
FailedToActivateTTY(num: i32) { #[error("Failed to set tty {0} kb mode to K_OFF")]
description("Failed to activate open tty"), FailedToSetTTYKbMode(i32, #[source] nix::Error),
display("Failed to activate open tty ({:?})", num), /// Failed to set tty mode
} #[error("Failed to set tty {0} mode into graphics mode")]
FailedToSetTTYMode(i32, #[source] nix::Error),
#[doc = "Failed to wait for tty to become active"] /// Failed to set tty in process mode
FailedToWaitForTTY(num: i32) { #[error("Failed to take control of tty {0}")]
description("Failed to wait for tty to become active"), FailedToTakeControlOfTTY(i32, #[source] nix::Error),
display("Failed to wait for tty ({:?}) to become active", num),
}
#[doc = "Failed to save old tty state"]
FailedToSaveTTYState(num: i32) {
description("Failed to save old tty state"),
display("Failed to save old tty ({:?}) state", num),
}
#[doc = "Failed to set tty kb mode"]
FailedToSetTTYKbMode(num: i32) {
description("Failed to set tty kb mode to K_OFF"),
display("Failed to set tty ({:?}) kb mode to K_OFF", num),
}
#[doc = "Failed to set tty mode"]
FailedToSetTTYMode(num: i32) {
description("Failed to set tty mode to KD_GRAPHICS"),
display("Failed to set tty ({:?}) mode into graphics mode", num),
}
#[doc = "Failed to set tty in process mode"]
FailedToTakeControlOfTTY(num: i32) {
description("Failed to set tty mode to VT_PROCESS"),
display("Failed to take control of tty ({:?})", num),
}
}
}
} }
use self::errors::*;

View File

@ -2,8 +2,8 @@
use crate::backend::{ use crate::backend::{
egl::{ egl::{
context::GlAttributes, error::Result as EGLResult, native, EGLContext, EGLDisplay, context::GlAttributes, native, EGLContext, EGLDisplay, EGLGraphicsBackend, EGLSurface,
EGLGraphicsBackend, EGLSurface, Error as EGLError,
}, },
graphics::{gl::GLGraphicsBackend, CursorBackend, PixelFormat, SwapBuffersError}, graphics::{gl::GLGraphicsBackend, CursorBackend, PixelFormat, SwapBuffersError},
input::{ input::{
@ -16,7 +16,7 @@ use crate::backend::{
use nix::libc::c_void; use nix::libc::c_void;
use std::{ use std::{
cell::{Ref, RefCell}, cell::{Ref, RefCell},
cmp, fmt, cmp,
rc::Rc, rc::Rc,
time::Instant, time::Instant,
}; };
@ -34,28 +34,18 @@ use winit::{
}; };
/// Errors thrown by the `winit` backends /// Errors thrown by the `winit` backends
pub mod errors { #[derive(thiserror::Error, Debug)]
use crate::backend::egl::error as egl_error; pub enum Error {
/// Failed to initialize a window
error_chain! { #[error("Failed to initialize a window")]
errors { InitFailed(#[from] winit::error::OsError),
#[doc = "Failed to initialize a window"] /// Context creation is not supported on the current window system
InitFailed { #[error("Context creation is not supported on the current window system")]
description("Failed to initialize a window") NotSupported,
} /// EGL error
#[error("EGL error: {0}")]
#[doc = "Context creation is not supported on the current window system"] EGL(#[from] EGLError),
NotSupported {
description("Context creation is not supported on the current window system.")
}
}
links {
EGL(egl_error::Error, egl_error::ErrorKind) #[doc = "EGL error"];
}
}
} }
use self::errors::*;
enum Window { enum Window {
Wayland { Wayland {
@ -110,7 +100,7 @@ pub struct WinitInputBackend {
/// Create a new [`WinitGraphicsBackend`], which implements the [`EGLGraphicsBackend`] /// Create a new [`WinitGraphicsBackend`], which implements the [`EGLGraphicsBackend`]
/// and [`GLGraphicsBackend`] graphics backend trait and a corresponding [`WinitInputBackend`], /// and [`GLGraphicsBackend`] graphics backend trait and a corresponding [`WinitInputBackend`],
/// which implements the [`InputBackend`] trait /// which implements the [`InputBackend`] trait
pub fn init<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend)> pub fn init<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -129,7 +119,7 @@ where
pub fn init_from_builder<L>( pub fn init_from_builder<L>(
builder: WindowBuilder, builder: WindowBuilder,
logger: L, logger: L,
) -> Result<(WinitGraphicsBackend, WinitInputBackend)> ) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -153,7 +143,7 @@ pub fn init_from_builder_with_gl_attr<L>(
builder: WindowBuilder, builder: WindowBuilder,
attributes: GlAttributes, attributes: GlAttributes,
logger: L, logger: L,
) -> Result<(WinitGraphicsBackend, WinitInputBackend)> ) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -161,7 +151,7 @@ where
info!(log, "Initializing a winit backend"); info!(log, "Initializing a winit backend");
let events_loop = EventLoop::new(); let events_loop = EventLoop::new();
let winit_window = builder.build(&events_loop).chain_err(|| ErrorKind::InitFailed)?; let winit_window = builder.build(&events_loop).map_err(Error::InitFailed)?;
debug!(log, "Window created"); debug!(log, "Window created");
@ -178,7 +168,7 @@ where
let surface = context.create_surface(())?; let surface = context.create_surface(())?;
Window::X11 { context, surface } Window::X11 { context, surface }
} else { } else {
bail!(ErrorKind::NotSupported); return Err(Error::NotSupported);
}, },
); );
@ -316,7 +306,7 @@ impl GLGraphicsBackend for WinitGraphicsBackend {
} }
impl EGLGraphicsBackend for WinitGraphicsBackend { impl EGLGraphicsBackend for WinitGraphicsBackend {
fn bind_wl_display(&self, display: &Display) -> EGLResult<EGLDisplay> { fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, EGLError> {
match *self.window { match *self.window {
Window::Wayland { ref context, .. } => context.bind_wl_display(display), Window::Wayland { ref context, .. } => context.bind_wl_display(display),
Window::X11 { ref context, .. } => context.bind_wl_display(display), Window::X11 { ref context, .. } => context.bind_wl_display(display),
@ -325,28 +315,15 @@ impl EGLGraphicsBackend for WinitGraphicsBackend {
} }
/// Errors that may happen when driving the event loop of [`WinitInputBackend`] /// Errors that may happen when driving the event loop of [`WinitInputBackend`]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
pub enum WinitInputError { pub enum WinitInputError {
/// The underlying [`WinitWindow`] was closed. No further events can be processed. /// The underlying [`WinitWindow`] was closed. No further events can be processed.
/// ///
/// See `dispatch_new_events`. /// See `dispatch_new_events`.
#[error("Winit window was closed")]
WindowClosed, WindowClosed,
} }
impl ::std::error::Error for WinitInputError {
fn description(&self) -> &str {
match *self {
WinitInputError::WindowClosed => "Glutin Window was closed",
}
}
}
impl fmt::Display for WinitInputError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use std::error::Error;
write!(f, "{}", self.description())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// Winit-Backend internal event wrapping `winit`'s types into a [`KeyboardKeyEvent`] /// Winit-Backend internal event wrapping `winit`'s types into a [`KeyboardKeyEvent`]
pub struct WinitKeyboardInputEvent { pub struct WinitKeyboardInputEvent {

View File

@ -13,8 +13,6 @@ pub extern crate nix;
#[macro_use] #[macro_use]
extern crate slog; extern crate slog;
#[macro_use] #[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;