diff --git a/Cargo.toml b/Cargo.toml index ac4e80e..1aac5ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,9 +34,10 @@ dbus = { version = "0.8", optional = true } systemd = { version = "0.4.0", optional = true } wayland-protocols = { version = "0.25.0", features = ["unstable_protocols", "server"], optional = true } image = { version = "0.21.0", optional = true } -error-chain = "0.12.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] slog-term = "2.3" @@ -47,7 +48,7 @@ gl_generator = { version = "0.10", optional = true } [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"] 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_gbm = ["backend_drm", "gbm", "image"] backend_drm_egl = ["backend_drm", "backend_egl"] diff --git a/examples/raw_drm.rs b/examples/raw_drm.rs index 08ecdef..a540bac 100644 --- a/examples/raw_drm.rs +++ b/examples/raw_drm.rs @@ -7,7 +7,7 @@ use slog::Drain; use smithay::{ backend::drm::{ device_bind, - legacy::{error::Error, LegacyDrmDevice, LegacyDrmSurface}, + legacy::{Error, LegacyDrmDevice, LegacyDrmSurface}, Device, DeviceHandler, RawSurface, Surface, }, reexports::{ @@ -15,10 +15,8 @@ use smithay::{ drm::{ buffer::format::PixelFormat, control::{ - connector::{self, State as ConnectorState}, - crtc, - dumbbuffer::DumbBuffer, - encoder, framebuffer, Device as ControlDevice, + connector::State as ConnectorState, crtc, dumbbuffer::DumbBuffer, framebuffer, + Device as ControlDevice, }, }, }, diff --git a/src/backend/drm/egl/error.rs b/src/backend/drm/egl/error.rs deleted file mode 100644 index 66fd2d1..0000000 --- a/src/backend/drm/egl/error.rs +++ /dev/null @@ -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"]; - } -} diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index 0c6b77c..4750d1c 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -18,21 +18,29 @@ use wayland_server::Display; use super::{Device, DeviceHandler, Surface}; 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::EGLContext; +use crate::backend::egl::Error as EGLError; #[cfg(feature = "use_system_lib")] use crate::backend::egl::{EGLDisplay, EGLGraphicsBackend}; -pub mod error; -use self::error::*; - mod surface; pub use self::surface::*; #[cfg(feature = "backend_session")] pub mod session; +/// Errors for the DRM/EGL module +#[derive(thiserror::Error, Debug)] +pub enum Error { + /// 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 pub struct EglDevice where @@ -65,7 +73,7 @@ where /// /// Returns an error if the file is no valid device or context /// creation was not successful. - pub fn new(dev: D, logger: L) -> Result + pub fn new(dev: D, logger: L) -> Result::Surface as Surface>::Error>> where L: Into>, { @@ -85,7 +93,11 @@ where /// /// Returns an error if the file is no valid device or context /// creation was not successful. - pub fn new_with_gl_attr(mut dev: D, attributes: GlAttributes, logger: L) -> Result + pub fn new_with_gl_attr( + mut dev: D, + attributes: GlAttributes, + logger: L, + ) -> Result::Surface as Surface>::Error>> where L: Into>, { @@ -97,7 +109,7 @@ where Ok(EglDevice { // Open the gbm device from the drm device and create a context based on that 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, }) @@ -125,8 +137,7 @@ where self.handler.vblank(crtc) } fn error(&mut self, error: <::Surface as Surface>::Error) { - self.handler - .error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err()) + self.handler.error(Error::Underlying(error)); } } @@ -152,10 +163,13 @@ where self.dev.borrow_mut().clear_handler() } - fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { + fn create_surface( + &mut self, + crtc: crtc::Handle, + ) -> Result, ::Error> { 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 { dev: self.dev.clone(), @@ -167,11 +181,8 @@ where self.dev.borrow_mut().process_events() } - fn resource_handles(&self) -> Result { - self.dev - .borrow() - .resource_handles() - .chain_err(|| ErrorKind::UnderlyingBackendError) + fn resource_handles(&self) -> Result::Error> { + self.dev.borrow().resource_handles().map_err(Error::Underlying) } fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result { @@ -201,7 +212,7 @@ where D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { - fn bind_wl_display(&self, display: &Display) -> EGLResult { + fn bind_wl_display(&self, display: &Display) -> Result { self.dev.bind_wl_display(display) } } diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs index 7ed7b20..3b84b2e 100644 --- a/src/backend/drm/egl/surface.rs +++ b/src/backend/drm/egl/surface.rs @@ -2,7 +2,7 @@ use drm::control::{connector, crtc, Mode}; use nix::libc::c_void; use std::rc::Rc; -use super::error::*; +use super::Error; use crate::backend::drm::{Device, Surface}; use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use crate::backend::egl::{EGLContext, EGLSurface}; @@ -29,7 +29,7 @@ where D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { - type Error = Error; + type Error = Error<<::Surface as Surface>::Error>; type Connectors = <::Surface as Surface>::Connectors; fn crtc(&self) -> crtc::Handle { @@ -44,16 +44,14 @@ where self.surface.pending_connectors() } - fn add_connector(&self, connector: connector::Handle) -> Result<()> { - self.surface - .add_connector(connector) - .chain_err(|| ErrorKind::UnderlyingBackendError) + fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> { + self.surface.add_connector(connector).map_err(Error::Underlying) } - fn remove_connector(&self, connector: connector::Handle) -> Result<()> { + fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> { self.surface .remove_connector(connector) - .chain_err(|| ErrorKind::UnderlyingBackendError) + .map_err(Error::Underlying) } fn current_mode(&self) -> Option { @@ -64,10 +62,8 @@ where self.surface.pending_mode() } - fn use_mode(&self, mode: Option) -> Result<()> { - self.surface - .use_mode(mode) - .chain_err(|| ErrorKind::UnderlyingBackendError) + fn use_mode(&self, mode: Option) -> Result<(), Self::Error> { + self.surface.use_mode(mode).map_err(Error::Underlying) } } diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index d2d32e7..201d653 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -4,14 +4,13 @@ //! [`GbmDevice`](GbmDevice) and [`GbmSurface`](GbmSurface). //! -use crate::backend::drm::{Device, RawDevice}; -use crate::backend::egl::error::Result as EglResult; +use crate::backend::drm::{Device, RawDevice, Surface}; use crate::backend::egl::ffi; use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface}; +use crate::backend::egl::Error as EglError; use crate::backend::graphics::SwapBuffersError; -use super::error::{Error, Result}; -use super::{GbmDevice, GbmSurface}; +use super::{Error, GbmDevice, GbmSurface}; use drm::control::{crtc, Device as ControlDevice}; use gbm::AsRaw; @@ -54,17 +53,17 @@ impl Backend for Gbm { unsafe impl NativeDisplay> for GbmDevice { type Arguments = crtc::Handle; - type Error = Error; + type Error = Error<<::Surface as Surface>::Error>; fn is_backend(&self) -> bool { true } - fn ptr(&self) -> EglResult { + fn ptr(&self) -> Result { Ok(self.dev.borrow().as_raw() as *const _) } - fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { + fn create_surface(&mut self, crtc: crtc::Handle) -> Result, Self::Error> { Device::create_surface(self, crtc) } } @@ -80,7 +79,7 @@ unsafe impl NativeSurface for GbmSurface { fn recreate(&self) -> bool { 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 } else { true diff --git a/src/backend/drm/gbm/error.rs b/src/backend/drm/gbm/error.rs deleted file mode 100644 index 3b1c751..0000000 --- a/src/backend/drm/gbm/error.rs +++ /dev/null @@ -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"]; - } -} diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 91f9eaa..a292792 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -13,18 +13,45 @@ use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface}; use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice}; use drm::SystemError as DrmError; -use failure::ResultExt as FailureResultExt; use gbm::{self, BufferObjectFlags, Format as GbmFormat}; use nix::libc::dev_t; use std::cell::{Cell, RefCell}; use std::collections::HashMap; +use std::io; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::{Rc, Weak}; use std::sync::Once; -pub mod error; -use self::error::*; +/// Errors thrown by the [`GbmDevice`](::backend::drm::gbm::GbmDevice) +/// and [`GbmSurface`](::backend::drm::gbm::GbmSurface). +#[derive(thiserror::Error, Debug)] +pub enum Error { + /// 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; pub use self::surface::GbmSurface; @@ -50,7 +77,7 @@ impl GbmDevice { /// /// Returns an error if the file is no valid drm node or context creation was not /// successful. - pub fn new(mut dev: D, logger: L) -> Result + pub fn new(mut dev: D, logger: L) -> Result::Surface as Surface>::Error>> where L: Into>, { @@ -74,9 +101,7 @@ impl GbmDevice { debug!(log, "Creating gbm device"); Ok(GbmDevice { // Open the gbm device from the drm device - dev: Rc::new(RefCell::new( - gbm::Device::new(dev).chain_err(|| ErrorKind::InitFailed)?, - )), + dev: Rc::new(RefCell::new(gbm::Device::new(dev).map_err(Error::InitFailed)?)), backends: Rc::new(RefCell::new(HashMap::new())), logger: log, }) @@ -108,8 +133,7 @@ impl DeviceHandler for InternalDeviceHan } } fn error(&mut self, error: <::Surface as Surface>::Error) { - self.handler - .error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err()) + self.handler.error(Error::Underlying(error)) } } @@ -132,11 +156,14 @@ impl Device for GbmDevice { self.dev.borrow_mut().clear_handler(); } - fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { + fn create_surface( + &mut self, + crtc: crtc::Handle, + ) -> Result, Error<<::Surface as Surface>::Error>> { info!(self.logger, "Initializing GbmSurface"); - let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc) - .chain_err(|| ErrorKind::UnderlyingBackendError)?; + let drm_surface = + Device::create_surface(&mut **self.dev.borrow_mut(), crtc).map_err(Error::Underlying)?; // initialize the surface let (w, h) = drm_surface @@ -152,7 +179,7 @@ impl Device for GbmDevice { GbmFormat::XRGB8888, BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, ) - .chain_err(|| ErrorKind::SurfaceCreationFailed)?; + .map_err(Error::SurfaceCreationFailed)?; // initialize a buffer for the cursor image let cursor = Cell::new(( @@ -164,7 +191,7 @@ impl Device for GbmDevice { GbmFormat::ARGB8888, BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, ) - .chain_err(|| ErrorKind::BufferCreationFailed)?, + .map_err(Error::BufferCreationFailed)?, (0, 0), )); @@ -187,12 +214,8 @@ impl Device for GbmDevice { self.dev.borrow_mut().process_events() } - fn resource_handles(&self) -> Result { - self.dev - .borrow() - .resource_handles() - .compat() - .chain_err(|| ErrorKind::UnderlyingBackendError) + fn resource_handles(&self) -> Result::Surface as Surface>::Error>> { + Device::resource_handles(&**self.dev.borrow()).map_err(Error::Underlying) } fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result { diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index db19d8a..60d4f22 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -1,5 +1,5 @@ use super::super::{Device, RawDevice, RawSurface, Surface}; -use super::error::*; +use super::Error; use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode}; use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle}; @@ -90,8 +90,8 @@ impl GbmSurfaceInternal { Ok(()) } - pub fn recreate(&self) -> Result<()> { - let (w, h) = self.pending_mode().chain_err(|| ErrorKind::NoModeSet)?.size(); + pub fn recreate(&self) -> Result<(), Error<<::Surface as Surface>::Error>> { + let (w, h) = self.pending_mode().ok_or(Error::NoModeSet)?.size(); // Recreate the surface and the related resources to match the new // resolution. @@ -105,7 +105,7 @@ impl GbmSurfaceInternal { GbmFormat::XRGB8888, BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, ) - .chain_err(|| ErrorKind::SurfaceCreationFailed)?; + .map_err(Error::SurfaceCreationFailed)?; // Clean up buffers if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) { @@ -137,7 +137,7 @@ impl GbmSurfaceInternal { impl Surface for GbmSurfaceInternal { type Connectors = <::Surface as Surface>::Connectors; - type Error = Error; + type Error = Error<<::Surface as Surface>::Error>; fn crtc(&self) -> crtc::Handle { self.crtc.crtc() @@ -151,16 +151,12 @@ impl Surface for GbmSurfaceInternal { self.crtc.pending_connectors() } - fn add_connector(&self, connector: connector::Handle) -> Result<()> { - self.crtc - .add_connector(connector) - .chain_err(|| ErrorKind::UnderlyingBackendError) + fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> { + self.crtc.add_connector(connector).map_err(Error::Underlying) } - fn remove_connector(&self, connector: connector::Handle) -> Result<()> { - self.crtc - .remove_connector(connector) - .chain_err(|| ErrorKind::UnderlyingBackendError) + fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> { + self.crtc.remove_connector(connector).map_err(Error::Underlying) } fn current_mode(&self) -> Option { @@ -171,10 +167,8 @@ impl Surface for GbmSurfaceInternal { self.crtc.pending_mode() } - fn use_mode(&self, mode: Option) -> Result<()> { - self.crtc - .use_mode(mode) - .chain_err(|| ErrorKind::UnderlyingBackendError) + fn use_mode(&self, mode: Option) -> Result<(), Self::Error> { + self.crtc.use_mode(mode).map_err(Error::Underlying) } } @@ -205,19 +199,17 @@ where #[cfg(feature = "backend_drm_legacy")] impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal> { type CursorFormat = &'a ImageBuffer, Vec>; - type Error = Error; + type Error = Error<< as Device>::Surface as Surface>::Error>; - fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { - ResultExt::chain_err(self.crtc.set_cursor_position(x, y), || { - ErrorKind::UnderlyingBackendError - }) + fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error> { + self.crtc.set_cursor_position(x, y).map_err(Error::Underlying) } fn set_cursor_representation<'b>( &'b self, buffer: &ImageBuffer, Vec>, hotspot: (u32, u32), - ) -> Result<()> + ) -> Result<(), Self::Error> where 'a: 'b, { @@ -234,18 +226,18 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal GbmSurface { /// calling [`Surface::use_mode`](Surface::use_mode). /// You may check if your [`GbmSurface`] needs recreation through /// [`needs_recreation`](GbmSurface::needs_recreation). - pub fn recreate(&self) -> Result<()> { + pub fn recreate(&self) -> Result<(), ::Error> { self.0.recreate() } @@ -317,7 +309,7 @@ impl GbmSurface { impl Surface for GbmSurface { type Connectors = <::Surface as Surface>::Connectors; - type Error = Error; + type Error = Error<<::Surface as Surface>::Error>; fn crtc(&self) -> crtc::Handle { self.0.crtc() @@ -331,11 +323,11 @@ impl Surface for GbmSurface { 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) } - fn remove_connector(&self, connector: connector::Handle) -> Result<()> { + fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> { self.0.remove_connector(connector) } @@ -347,7 +339,7 @@ impl Surface for GbmSurface { self.0.pending_mode() } - fn use_mode(&self, mode: Option) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<(), Self::Error> { self.0.use_mode(mode) } } @@ -355,9 +347,9 @@ impl Surface for GbmSurface { #[cfg(feature = "backend_drm_legacy")] impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface> { type CursorFormat = &'a ImageBuffer, Vec>; - 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<(), Self::Error> { self.0.set_cursor_position(x, y) } @@ -365,7 +357,7 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface, Vec>, hotspot: (u32, u32), - ) -> Result<()> + ) -> Result<(), Self::Error> where 'a: 'b, { diff --git a/src/backend/drm/legacy/error.rs b/src/backend/drm/legacy/error.rs deleted file mode 100644 index 2b88830..0000000 --- a/src/backend/drm/legacy/error.rs +++ /dev/null @@ -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"]; - } -} diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index 63e088a..26a467d 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -11,30 +11,68 @@ use super::{DevPath, Device, DeviceHandler, RawDevice}; 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 failure::ResultExt as FailureResultExt; use nix::libc::dev_t; use nix::sys::stat::fstat; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::os::unix::io::{AsRawFd, RawFd}; +use std::path::PathBuf; use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, RwLock}; +use failure::{Fail, ResultExt}; + mod surface; pub use self::surface::LegacyDrmSurface; use self::surface::{LegacyDrmSurfaceInternal, State}; -pub mod error; -use self::error::*; - #[cfg(feature = "backend_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, + /// Underlying device error + source: failure::Compat, + }, + /// 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 pub struct LegacyDrmDevice { dev: Rc>, @@ -92,7 +130,7 @@ impl LegacyDrmDevice { /// /// Returns an error if the file is no valid drm node or context creation was not /// successful. - pub fn new(dev: A, logger: L) -> Result + pub fn new(dev: A, logger: L) -> Result where L: Into>, { @@ -100,7 +138,7 @@ impl LegacyDrmDevice { info!(log, "DrmDevice initializing"); let dev_id = fstat(dev.as_raw_fd()) - .chain_err(|| ErrorKind::UnableToGetDeviceId)? + .map_err(Error::UnableToGetDeviceId)? .st_rdev; let active = Arc::new(AtomicBool::new(true)); @@ -119,20 +157,30 @@ impl LegacyDrmDevice { }; // enumerate (and save) the current device state - let res_handles = ControlDevice::resource_handles(&dev).compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", dev.dev_path())) - })?; + let res_handles = ControlDevice::resource_handles(&dev) + .compat() + .map_err(|source| Error::Access { + errmsg: "Error loading drm resources", + dev: dev.dev_path(), + source, + })?; for &con in res_handles.connectors() { - let con_info = dev.get_connector(con).compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading connector info on {:?}", dev.dev_path())) + let con_info = dev.get_connector(con).compat().map_err(|source| Error::Access { + errmsg: "Error loading connector info", + dev: dev.dev_path(), + source, })?; if let Some(enc) = con_info.current_encoder() { - let enc_info = dev.get_encoder(enc).compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", dev.dev_path())) + let enc_info = dev.get_encoder(enc).compat().map_err(|source| Error::Access { + errmsg: "Error loading encoder info", + dev: dev.dev_path(), + source, })?; if let Some(crtc) = enc_info.crtc() { - let info = dev.get_crtc(crtc).compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", dev.dev_path())) + let info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access { + errmsg: "Error loading crtc info", + dev: dev.dev_path(), + source, })?; dev.old_state .entry(crtc) @@ -178,35 +226,44 @@ impl Device for LegacyDrmDevice { let _ = self.handler.take(); } - fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { + fn create_surface(&mut self, crtc: crtc::Handle) -> Result, Error> { if self.backends.borrow().contains_key(&crtc) { - bail!(ErrorKind::CrtcAlreadyInUse(crtc)); + return Err(Error::CrtcAlreadyInUse(crtc)); } 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 - let crtc_info = self - .get_crtc(crtc) - .compat() - .chain_err(|| ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", self.dev_path())))?; + let crtc_info = self.get_crtc(crtc).compat().map_err(|source| Error::Access { + errmsg: "Error loading crtc info", + dev: self.dev_path(), + source, + })?; let mode = crtc_info.mode(); let mut connectors = HashSet::new(); - let res_handles = ControlDevice::resource_handles(self).compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) - })?; + let res_handles = ControlDevice::resource_handles(self) + .compat() + .map_err(|source| Error::Access { + errmsg: "Error loading drm resources", + dev: self.dev_path(), + source, + })?; for &con in res_handles.connectors() { - let con_info = self.get_connector(con).compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) + let con_info = self.get_connector(con).compat().map_err(|source| Error::Access { + errmsg: "Error loading connector info", + dev: self.dev_path(), + source, })?; if let Some(enc) = con_info.current_encoder() { - let enc_info = self.get_encoder(enc).compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) + let enc_info = self.get_encoder(enc).compat().map_err(|source| Error::Access { + errmsg: "Error loading encoder info", + dev: self.dev_path(), + source, })?; if let Some(current_crtc) = enc_info.crtc() { if crtc == current_crtc { @@ -255,23 +312,26 @@ impl Device for LegacyDrmDevice { } } } - Err(err) => { + Err(source) => { if let Some(handler) = self.handler.as_ref() { - handler.borrow_mut().error( - ResultExt::<()>::chain_err(Err(err).compat(), || { - ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path())) - }) - .unwrap_err(), - ); + handler.borrow_mut().error(Error::Access { + errmsg: "Error processing drm events", + dev: self.dev_path(), + source: source.compat(), + }); } } } } - fn resource_handles(&self) -> Result { + fn resource_handles(&self) -> Result { ControlDevice::resource_handles(self) .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 { diff --git a/src/backend/drm/legacy/surface.rs b/src/backend/drm/legacy/surface.rs index af0e93d..232b9a6 100644 --- a/src/backend/drm/legacy/surface.rs +++ b/src/backend/drm/legacy/surface.rs @@ -4,7 +4,6 @@ use drm::control::{ PageFlipFlags, }; use drm::Device as BasicDevice; -use failure::ResultExt as FailureResultExt; use std::collections::HashSet; 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::SwapBuffersError; -use super::{error::*, Dev}; +use super::{Dev, Error}; + +use failure::ResultExt; #[derive(Debug, PartialEq, Eq, Clone)] pub struct State { @@ -44,14 +45,22 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurfaceInternal type CursorFormat = &'a dyn Buffer; 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); self.move_cursor(self.crtc, (x as i32, y as i32)) .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 'a: 'b, { @@ -63,7 +72,11 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurfaceInternal { self.set_cursor(self.crtc, Some(buffer)) .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(()) @@ -94,10 +107,15 @@ impl Surface for LegacyDrmSurfaceInternal { self.pending.read().unwrap().mode } - fn add_connector(&self, conn: connector::Handle) -> Result<()> { - let info = self.get_connector(conn).compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) - })?; + fn add_connector(&self, conn: connector::Handle) -> Result<(), Error> { + let info = self + .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(); @@ -110,37 +128,46 @@ impl Surface for LegacyDrmSurfaceInternal { .filter(|enc| enc.is_some()) .map(|enc| enc.unwrap()) .map(|encoder| { - self.get_encoder(encoder).compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) - }) + self.get_encoder(encoder) + .compat() + .map_err(|source| Error::Access { + errmsg: "Error loading encoder info", + dev: self.dev_path(), + source, + }) }) - .collect::>>()?; + .collect::, _>>()?; // and if any encoder supports the selected crtc - let resource_handles = self.resource_handles().compat().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading resources on {:?}", self.dev_path())) + let resource_handles = self.resource_handles().compat().map_err(|source| Error::Access { + errmsg: "Error loading resources", + dev: self.dev_path(), + source, })?; if !encoders .iter() .map(|encoder| encoder.possible_crtcs()) .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); Ok(()) } 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); Ok(()) } - fn use_mode(&self, mode: Option) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<(), Error> { let mut pending = self.pending.write().unwrap(); // check the connectors to see if this mode is supported @@ -149,13 +176,15 @@ impl Surface for LegacyDrmSurfaceInternal { if !self .get_connector(*connector) .compat() - .chain_err(|| { - ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) + .map_err(|source| Error::Access { + errmsg: "Error loading connector info", + dev: self.dev_path(), + source, })? .modes() .contains(&mode) { - bail!(ErrorKind::ModeNotSuitable(mode)); + return Err(Error::ModeNotSuitable(mode)); } } } @@ -171,7 +200,7 @@ impl RawSurface for LegacyDrmSurfaceInternal { *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 pending = self.pending.read().unwrap(); @@ -217,12 +246,10 @@ impl RawSurface for LegacyDrmSurfaceInternal { pending.mode, ) .compat() - .chain_err(|| { - ErrorKind::DrmDev(format!( - "Error setting crtc {:?} on {:?}", - self.crtc, - self.dev_path() - )) + .map_err(|source| Error::Access { + errmsg: "Error setting crtc", + dev: self.dev_path(), + source, })?; *current = pending.clone(); @@ -268,11 +295,15 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface { type CursorFormat = &'a dyn Buffer; 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) } - 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 'a: 'b, { @@ -304,15 +335,15 @@ impl Surface for LegacyDrmSurface { 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) } - fn remove_connector(&self, connector: connector::Handle) -> Result<()> { + fn remove_connector(&self, connector: connector::Handle) -> Result<(), Error> { self.0.remove_connector(connector) } - fn use_mode(&self, mode: Option) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<(), Error> { self.0.use_mode(mode) } } @@ -322,7 +353,7 @@ impl RawSurface for LegacyDrmSurface { self.0.commit_pending() } - fn commit(&self, framebuffer: framebuffer::Handle) -> Result<()> { + fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> { self.0.commit(framebuffer) } diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index b001253..c171435 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -135,7 +135,7 @@ pub trait Surface { /// [`pending_connectors`](Surface::pending_connectors) type Connectors: IntoIterator; /// 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 fn crtc(&self) -> crtc::Handle; diff --git a/src/backend/egl/context.rs b/src/backend/egl/context.rs index cf527e7..1bd1571 100644 --- a/src/backend/egl/context.rs +++ b/src/backend/egl/context.rs @@ -1,6 +1,6 @@ //! EGL context related structs -use super::{error::*, ffi, native, EGLSurface}; +use super::{ffi, native, EGLSurface, Error}; use crate::backend::graphics::PixelFormat; use nix::libc::{c_int, c_void}; use slog; @@ -33,7 +33,7 @@ impl> EGLContext { attributes: GlAttributes, reqs: PixelFormatRequirements, logger: L, - ) -> Result> + ) -> Result, Error> where L: Into>, { @@ -60,14 +60,17 @@ impl> EGLContext { mut attributes: GlAttributes, reqs: PixelFormatRequirements, log: ::slog::Logger, - ) -> Result<( - Rc, - Rc, - ffi::egl::types::EGLConfig, - Vec, - PixelFormat, - bool, - )> { + ) -> Result< + ( + Rc, + Rc, + ffi::egl::types::EGLConfig, + Vec, + PixelFormat, + bool, + ), + Error, + > { // If no version is given, try OpenGLES 3.0, if available, // fallback to 2.0 otherwise let version = match attributes.version { @@ -88,14 +91,14 @@ impl> EGLContext { } Some((1, x)) => { 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) => { error!( log, "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> EGLContext { let display = B::get_display(ptr, |e: &str| dp_extensions.iter().any(|s| s == e), log.clone()); if display == ffi::egl::NO_DISPLAY { error!(log, "EGL Display is not valid"); - bail!(ErrorKind::DisplayNotSupported); + return Err(Error::DisplayNotSupported); } let egl_version = { @@ -154,7 +157,7 @@ impl> EGLContext { let mut minor: MaybeUninit = MaybeUninit::uninit(); 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 minor = minor.assume_init(); @@ -179,7 +182,7 @@ impl> EGLContext { if egl_version >= (1, 2) && ffi::egl::BindAPI(ffi::egl::OPENGL_ES_API) == 0 { error!(log, "OpenGLES not supported by the underlying EGL implementation"); - bail!(ErrorKind::OpenGlesNotSupported); + return Err(Error::OpenGlesNotSupported); } let descriptor = { @@ -205,7 +208,7 @@ impl> EGLContext { log, "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"); out.push(ffi::egl::RENDERABLE_TYPE as c_int); @@ -220,7 +223,7 @@ impl> EGLContext { log, "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"); out.push(ffi::egl::RENDERABLE_TYPE as c_int); @@ -289,7 +292,7 @@ impl> EGLContext { if reqs.stereoscopy { error!(log, "Stereoscopy is currently unsupported (sorry!)"); - bail!(ErrorKind::NoAvailablePixelFormat); + return Err(Error::NoAvailablePixelFormat); } out.push(ffi::egl::NONE as c_int); @@ -307,7 +310,7 @@ impl> EGLContext { num_configs.as_mut_ptr(), ) == 0 { - bail!(ErrorKind::ConfigFailed); + return Err(Error::ConfigFailed); } let config_id = config_id.assume_init(); @@ -315,7 +318,7 @@ impl> EGLContext { if num_configs == 0 { error!(log, "No matching color format found"); - bail!(ErrorKind::NoAvailablePixelFormat); + return Err(Error::NoAvailablePixelFormat); } // analyzing each config @@ -329,7 +332,7 @@ impl> EGLContext { value.as_mut_ptr(), ); if res == 0 { - bail!(ErrorKind::ConfigFailed); + return Err(Error::ConfigFailed); } value.assume_init() }}; @@ -386,8 +389,8 @@ impl> EGLContext { if context.is_null() { match ffi::egl::GetError() as u32 { - ffi::egl::BAD_ATTRIBUTE => bail!(ErrorKind::CreationFailed), - err_no => bail!(ErrorKind::Unknown(err_no)), + ffi::egl::BAD_ATTRIBUTE => return Err(Error::CreationFailed), + err_no => return Err(Error::Unknown(err_no)), } } debug!(log, "EGL context successfully created"); @@ -429,13 +432,12 @@ impl> EGLContext { } /// Creates a surface for rendering - pub fn create_surface(&self, args: N::Arguments) -> Result> { + pub fn create_surface(&self, args: N::Arguments) -> Result, Error> { trace!(self.logger, "Creating EGL window surface."); - let surface = self - .native - .borrow_mut() - .create_surface(args) - .chain_err(|| ErrorKind::SurfaceCreationFailed)?; + let surface = self.native.borrow_mut().create_surface(args).map_err(|e| { + error!(self.logger, "EGL surface creation failed: {}", e); + Error::SurfaceCreationFailed + })?; EGLSurface::new(self, surface).map(|x| { debug!(self.logger, "EGL surface successfully created"); x diff --git a/src/backend/egl/error.rs b/src/backend/egl/error.rs index 28fbd47..f0b0e7a 100644 --- a/src/backend/egl/error.rs +++ b/src/backend/egl/error.rs @@ -1,82 +1,49 @@ -//! EGL error types - -error_chain! { - errors { - #[doc = "The requested OpenGL version is not supported"] - OpenGlVersionNotSupported(version: (u8, u8)) { - description("The requested OpenGL version is not supported."), - display("The requested OpenGL version {:?} is not supported.", version), - } - - #[doc = "The EGL implementation does not support creating OpenGL ES contexts"] - OpenGlesNotSupported { - description("The EGL implementation does not support creating OpenGL ES contexts") - } - - #[doc = "No available pixel format matched the criteria"] - NoAvailablePixelFormat { - description("No available pixel format matched the criteria.") - } - - #[doc = "Backend does not match the context type"] - NonMatchingBackend(expected: &'static str) { - description("The expected backend did not match the runtime."), - display("The expected backend '{:?}' does not match the runtime.", expected), - } - - #[doc = "EGL was unable to obtain a valid EGL Display"] - DisplayNotSupported { - description("EGL was unable to obtain a valid EGL Display") - } - - #[doc = "`eglInitialize` returned an error"] - InitFailed { - description("Failed to initialize EGL") - } - - #[doc = "Failed to configure the EGL context"] - ConfigFailed { - description("Failed to configure the EGL context") - } - - #[doc = "Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements"] - CreationFailed { - description("Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements") - } - - #[doc = "`eglCreateWindowSurface` failed"] - SurfaceCreationFailed { - 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) - } +#[derive(thiserror::Error, Debug)] +/// EGL errors +pub enum Error { + /// The requested OpenGL version is not supported + #[error("The requested OpenGL version {0:?} is not supported")] + OpenGlVersionNotSupported((u8, u8)), + /// The EGL implementation does not support creating OpenGL ES contexts + #[error("The EGL implementation does not support creating OpenGL ES contexts")] + OpenGlesNotSupported, + /// No available pixel format matched the criteria + #[error("No available pixel format matched the criteria")] + NoAvailablePixelFormat, + /// Backend does not match the context type + #[error("The expected backend '{0:?}' does not match the runtime")] + NonMatchingBackend(&'static str), + /// Unable to obtain a valid EGL Display + #[error("Unable to obtain a valid EGL Display")] + DisplayNotSupported, + /// `eglInitialize` returned an error + #[error("Failed to initialize EGL")] + InitFailed, + /// Failed to configure the EGL context + #[error("Failed to configure the EGL context")] + 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")] + CreationFailed, + /// `eglCreateWindowSurface` failed + #[error("`eglCreateWindowSurface` failed")] + SurfaceCreationFailed, + /// The required EGL extension is not supported by the underlying EGL implementation + #[error("None of the following EGL extensions is supported by the underlying EGL implementation, at least one is required: {0:?}")] + EglExtensionNotSupported(&'static [&'static str]), + /// 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, + /// No EGLDisplay is currently bound to this `WlDisplay` + #[error("No EGLDisplay is currently bound to this `WlDisplay`")] + NoEGLDisplayBound, + /// Index of plane is out of bounds for `EGLImages` + #[error("Index of plane is out of bounds for `EGLImages`")] + PlaneIndexOutOfBounds, + /// Failed to create `EGLImages` from the buffer + #[error("Failed to create `EGLImages` from the buffer")] + EGLImageCreationFailed, + /// The reason of failure could not be determined + #[error("Unknown error: {0}")] + Unknown(u32), } diff --git a/src/backend/egl/mod.rs b/src/backend/egl/mod.rs index d466804..a4b4d90 100644 --- a/src/backend/egl/mod.rs +++ b/src/backend/egl/mod.rs @@ -33,8 +33,8 @@ use wayland_sys::server::wl_display; pub mod context; pub use self::context::EGLContext; -pub mod error; -use self::error::*; +mod error; +pub use self::error::Error; #[allow(non_camel_case_types, dead_code, unused_mut, non_upper_case_globals)] pub mod ffi; @@ -59,27 +59,24 @@ impl fmt::Display 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 - } -} +impl ::std::error::Error for EglExtensionNotSupportedError {} /// Error that can occur when accessing an EGL buffer #[cfg(feature = "wayland_frontend")] +#[derive(thiserror::Error)] pub enum BufferAccessError { /// The corresponding Context is not alive anymore + #[error("The corresponding context was lost")] ContextLost, /// This buffer is not managed by the EGL buffer + #[error("This buffer is not managed by EGL")] NotManaged(WlBuffer), /// Failed to create `EGLImages` from the buffer + #[error("Failed to create EGLImages from the buffer")] EGLImageCreationFailed, /// The required EGL extension is not supported by the underlying EGL implementation - EglExtensionNotSupported(EglExtensionNotSupportedError), + #[error("{0}")] + EglExtensionNotSupported(#[from] EglExtensionNotSupportedError), } #[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 for BufferAccessError { - fn from(error: EglExtensionNotSupportedError) -> Self { - BufferAccessError::EglExtensionNotSupported(error) - } -} - /// 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 { /// The given plane index is out of bounds + #[error("This buffer is not managed by EGL")] PlaneIndexOutOfBounds, /// 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 /// application on sleep and wakes it up later. However any OpenGL implementation /// can theoretically lose the context at any time. + #[error("The context has been lost, it needs to be recreated")] ContextLost, /// Required OpenGL Extension for texture creation is missing + #[error("Required OpenGL Extension for texture creation is missing: {0}")] GLExtensionNotSupported(&'static str), /// Failed to bind the `EGLImage` to the given texture /// /// The given argument is the GL error code + #[error("Failed to create EGLImages from the buffer (GL error code {0:x}")] 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 #[repr(i32)] #[allow(non_camel_case_types)] @@ -320,7 +249,7 @@ pub trait EGLGraphicsBackend { /// /// 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. - fn bind_wl_display(&self, display: &Display) -> Result; + fn bind_wl_display(&self, display: &Display) -> Result; } /// Type to receive [`EGLImages`] for EGL-based [`WlBuffer`]s. @@ -525,22 +454,20 @@ impl Drop for EGLDisplay { #[cfg(feature = "use_system_lib")] impl EGLGraphicsBackend for Rc { - fn bind_wl_display(&self, display: &Display) -> Result { + fn bind_wl_display(&self, display: &Display) -> Result { (**self).bind_wl_display(display) } } #[cfg(feature = "use_system_lib")] impl> EGLGraphicsBackend for EGLContext { - fn bind_wl_display(&self, display: &Display) -> Result { + fn bind_wl_display(&self, display: &Display) -> Result { if !self.wl_drm_support { - bail!(ErrorKind::EglExtensionNotSupported(&[ - "EGL_WL_bind_wayland_display" - ])); + return Err(Error::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"])); } let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.c_ptr() as *mut _) }; if res == 0 { - bail!(ErrorKind::OtherEGLDisplayAlreadyBound); + return Err(Error::OtherEGLDisplayAlreadyBound); } Ok(EGLDisplay::new(self, display.c_ptr())) } diff --git a/src/backend/egl/native.rs b/src/backend/egl/native.rs index 17417c8..ad4c508 100644 --- a/src/backend/egl/native.rs +++ b/src/backend/egl/native.rs @@ -1,6 +1,6 @@ //! Type safe native types for safe context/surface creation -use super::{error::*, ffi}; +use super::{ffi, Error}; use crate::backend::graphics::SwapBuffersError; #[cfg(feature = "backend_winit")] @@ -105,7 +105,7 @@ pub unsafe trait NativeDisplay { /// if the expected [`Backend`] is used at runtime. fn is_backend(&self) -> bool; /// Return a raw pointer EGL will accept for context creation. - fn ptr(&self) -> Result; + fn ptr(&self) -> Result; /// Create a surface fn create_surface(&mut self, args: Self::Arguments) -> ::std::result::Result; } @@ -119,16 +119,16 @@ unsafe impl NativeDisplay for WinitWindow { self.xlib_display().is_some() } - fn ptr(&self) -> Result { + fn ptr(&self) -> Result { self.xlib_display() .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 { + fn create_surface(&mut self, _args: ()) -> Result { self.xlib_window() .map(XlibWindow) - .ok_or_else(|| ErrorKind::NonMatchingBackend("X11").into()) + .ok_or_else(|| Error::NonMatchingBackend("X11")) } } @@ -141,20 +141,20 @@ unsafe impl NativeDisplay for WinitWindow { self.wayland_display().is_some() } - fn ptr(&self) -> Result { + fn ptr(&self) -> Result { self.wayland_display() .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 { + fn create_surface(&mut self, _args: ()) -> Result { if let Some(surface) = self.wayland_surface() { let size = self.inner_size(); Ok(unsafe { wegl::WlEglSurface::new_from_raw(surface as *mut _, size.width as i32, size.height as i32) }) } else { - bail!(ErrorKind::NonMatchingBackend("Wayland")) + return Err(Error::NonMatchingBackend("Wayland")); } } } diff --git a/src/backend/egl/surface.rs b/src/backend/egl/surface.rs index 45e8814..71d16ac 100644 --- a/src/backend/egl/surface.rs +++ b/src/backend/egl/surface.rs @@ -1,6 +1,6 @@ //! EGL surface related structs -use super::{error::*, ffi, native, EGLContext}; +use super::{ffi, native, EGLContext, Error}; use crate::backend::graphics::SwapBuffersError; use nix::libc::c_int; use std::{ @@ -36,7 +36,7 @@ impl EGLSurface { pub(crate) fn new, D: native::NativeDisplay>( context: &EGLContext, native: N, - ) -> Result> { + ) -> Result, Error> { let surface = unsafe { ffi::egl::CreateWindowSurface( *context.display, @@ -47,7 +47,7 @@ impl EGLSurface { }; if surface.is_null() { - bail!(ErrorKind::SurfaceCreationFailed); + return Err(Error::SurfaceCreationFailed); } Ok(EGLSurface { diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index 86883c7..9514b3c 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -162,14 +162,14 @@ pub fn auto_session_bind( impl Session for AutoSession { type Error = Error; - fn open(&mut self, path: &Path, flags: OFlag) -> Result { + fn open(&mut self, path: &Path, flags: OFlag) -> Result { match *self { #[cfg(feature = "backend_session_logind")] 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()), } } - fn close(&mut self, fd: RawFd) -> Result<()> { + fn close(&mut self, fd: RawFd) -> Result<(), Error> { match *self { #[cfg(feature = "backend_session_logind")] 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 { #[cfg(feature = "backend_session_logind")] 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 -pub mod errors { +#[derive(thiserror::Error, Debug)] +pub enum Error { #[cfg(feature = "backend_session_logind")] - use super::logind::errors as logind; - - error_chain! { - links { - Logind(logind::Error, logind::ErrorKind) #[cfg(feature = "backend_session_logind")] #[doc = "Underlying logind session error"]; - } - - foreign_links { - Direct(::nix::Error) #[doc = "Underlying direct tty session error"]; - } - } + /// Logind session error + #[error("Logind session error: {0}")] + Logind(#[from] logind::Error), + /// Direct session error + #[error("Direct session error: {0}")] + Direct(#[from] direct::Error), + /// Nix error + #[error("Nix error: {0}")] + Nix(#[from] nix::Error), } -use self::errors::*; impl AsErrno for Error { fn as_errno(&self) -> Option { diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index a1deb65..b613563 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -83,7 +83,7 @@ pub struct LogindSessionNotifier { impl LogindSession { /// Tries to create a new session via the logind dbus interface. - pub fn new(logger: L) -> Result<(LogindSession, LogindSessionNotifier)> + pub fn new(logger: L) -> Result<(LogindSession, LogindSessionNotifier), Error> where L: Into>, { @@ -91,12 +91,12 @@ impl LogindSession { .new(o!("smithay_module" => "backend_session", "session_type" => "logind")); // Acquire session_id, seat and vt (if any) via libsystemd - let session_id = login::get_session(None).chain_err(|| ErrorKind::FailedToGetSession)?; - let seat = login::get_seat(session_id.clone()).chain_err(|| ErrorKind::FailedToGetSeat)?; + let session_id = login::get_session(None).map_err(Error::FailedToGetSession)?; + let seat = login::get_seat(session_id.clone()).map_err(Error::FailedToGetSeat)?; let vt = login::get_vt(session_id.clone()).ok(); // 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 let session_path = LogindSessionImpl::blocking_call( &conn, @@ -107,7 +107,7 @@ impl LogindSession { Some(vec![session_id.clone().into()]), )? .get1::>() - .chain_err(|| ErrorKind::UnexpectedMethodReturn)?; + .ok_or(Error::UnexpectedMethodReturn)?; // Match all signals that we want to receive and handle let match1 = String::from( @@ -118,7 +118,7 @@ impl LogindSession { path='/org/freedesktop/login1'", ); conn.add_match(&match1) - .chain_err(|| ErrorKind::DbusMatchFailed(match1))?; + .map_err(|source| Error::DbusMatchFailed(match1, source))?; let match2 = format!( "type='signal',\ sender='org.freedesktop.login1',\ @@ -128,7 +128,7 @@ impl LogindSession { &session_path ); conn.add_match(&match2) - .chain_err(|| ErrorKind::DbusMatchFailed(match2))?; + .map_err(|source| Error::DbusMatchFailed(match2, source))?; let match3 = format!( "type='signal',\ sender='org.freedesktop.login1',\ @@ -138,7 +138,7 @@ impl LogindSession { &session_path ); conn.add_match(&match3) - .chain_err(|| ErrorKind::DbusMatchFailed(match3))?; + .map_err(|source| Error::DbusMatchFailed(match3, source))?; let match4 = format!( "type='signal',\ sender='org.freedesktop.login1',\ @@ -148,7 +148,7 @@ impl LogindSession { &session_path ); conn.add_match(&match4) - .chain_err(|| ErrorKind::DbusMatchFailed(match4))?; + .map_err(|source| Error::DbusMatchFailed(match4, source))?; // Activate (switch to) the session and take control LogindSessionImpl::blocking_call( @@ -209,7 +209,7 @@ impl LogindSessionImpl { interface: I, method: M, arguments: Option>, - ) -> Result + ) -> Result where D: Into>, P: Into>, @@ -227,30 +227,29 @@ impl LogindSessionImpl { message.append_items(&arguments) }; - let mut message = conn.send_with_reply_and_block(message, 1000).chain_err(|| { - ErrorKind::FailedToSendDbusCall( - destination.clone(), - path.clone(), - interface.clone(), - method.clone(), - ) - })?; + let mut message = + conn.send_with_reply_and_block(message, 1000) + .map_err(|source| Error::FailedToSendDbusCall { + bus: destination.clone(), + path: path.clone(), + interface: interface.clone(), + member: method.clone(), + source, + })?; match message.as_result() { Ok(_) => Ok(message), - Err(err) => Err(Error::with_chain( - err, - ErrorKind::DbusCallFailed( - destination.clone(), - path.clone(), - interface.clone(), - method.clone(), - ), - )), + Err(err) => Err(Error::DbusCallFailed { + bus: destination.clone(), + path: path.clone(), + interface: interface.clone(), + member: method.clone(), + source: err, + }), } } - fn handle_signals(&self, signals: I) -> Result<()> + fn handle_signals(&self, signals: I) -> Result<(), Error> where I: IntoIterator, { @@ -278,9 +277,9 @@ impl LogindSessionImpl { } else if &*message.interface().unwrap() == "org.freedesktop.login1.Session" { if &*message.member().unwrap() == "PauseDevice" { let (major, minor, pause_type) = message.get3::(); - let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; - let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; - let pause_type = pause_type.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; + let major = major.ok_or(Error::UnexpectedMethodReturn)?; + let minor = minor.ok_or(Error::UnexpectedMethodReturn)?; + let pause_type = pause_type.ok_or(Error::UnexpectedMethodReturn)?; debug!( self.logger, "Request of type \"{}\" to close device ({},{})", pause_type, major, minor @@ -306,9 +305,9 @@ impl LogindSessionImpl { } } else if &*message.member().unwrap() == "ResumeDevice" { let (major, minor, fd) = message.get3::(); - let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; - let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; - let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd(); + let major = major.ok_or(Error::UnexpectedMethodReturn)?; + let minor = minor.ok_or(Error::UnexpectedMethodReturn)?; + let fd = fd.ok_or(Error::UnexpectedMethodReturn)?.into_fd(); debug!(self.logger, "Reactivating device ({},{})", major, minor); for signal in &mut *self.signals.borrow_mut() { if let &mut Some(ref mut signal) = signal { @@ -323,7 +322,7 @@ impl LogindSessionImpl { let (_, changed, _) = message.get3::>, 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(active) = Get::get(&mut value.0) { self.active.store(active, Ordering::SeqCst); @@ -338,9 +337,9 @@ impl LogindSessionImpl { impl Session for LogindSession { type Error = Error; - fn open(&mut self, path: &Path, _flags: OFlag) -> Result { + fn open(&mut self, path: &Path, _flags: OFlag) -> Result { 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 let (fd, _paused) = LogindSessionImpl::blocking_call( &*session.conn.borrow(), @@ -354,16 +353,16 @@ impl Session for LogindSession { ]), )? .get2::(); - let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd(); + let fd = fd.ok_or(Error::UnexpectedMethodReturn)?.into_fd(); Ok(fd) } 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() { - let stat = fstat(fd).chain_err(|| ErrorKind::FailedToStatDevice)?; + let stat = fstat(fd).map_err(Error::FailedToStatDevice)?; LogindSessionImpl::blocking_call( &*session.conn.borrow(), "org.freedesktop.login1", @@ -377,7 +376,7 @@ impl Session for LogindSession { ) .map(|_| ()) } else { - bail!(ErrorKind::SessionLost) + return Err(Error::SessionLost); } } @@ -393,7 +392,7 @@ impl Session for LogindSession { 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() { LogindSessionImpl::blocking_call( &*session.conn.borrow_mut(), @@ -405,7 +404,7 @@ impl Session for LogindSession { ) .map(|_| ()) } else { - bail!(ErrorKind::SessionLost) + return Err(Error::SessionLost); } } } @@ -532,67 +531,53 @@ impl LogindSessionNotifier { } /// Errors related to logind sessions -pub mod errors { - use dbus::strings::{BusName, Interface, Member, Path as DbusPath}; - - error_chain! { - errors { - #[doc = "Failed to connect to dbus system socket"] - FailedDbusConnection { - description("Failed to connect to dbus system socket"), - } - - #[doc = "Failed to get session from logind"] - FailedToGetSession { - description("Failed to get session from logind") - } - - #[doc = "Failed to get seat from logind"] - FailedToGetSeat { - description("Failed to get seat from logind") - } - - #[doc = "Failed to get vt from logind"] - FailedToGetVT { - description("Failed to get vt from logind") - } - - #[doc = "Failed to call dbus method"] - FailedToSendDbusCall(bus: BusName<'static>, path: DbusPath<'static>, interface: Interface<'static>, member: Member<'static>) { - description("Failed to call dbus method") - display("Failed to call dbus method for service: {:?}, path: {:?}, interface: {:?}, member: {:?}", bus, path, interface, member), - } - - #[doc = "Dbus method call failed"] - DbusCallFailed(bus: BusName<'static>, path: DbusPath<'static>, interface: Interface<'static>, member: Member<'static>) { - description("Dbus method call failed") - display("Dbus message call failed for service: {:?}, path: {:?}, interface: {:?}, member: {:?}", bus, path, interface, member), - } - - #[doc = "Dbus method return had unexpected format"] - UnexpectedMethodReturn { - description("Dbus method return returned unexpected format") - } - - #[doc = "Failed to setup dbus match rule"] - DbusMatchFailed(rule: String) { - description("Failed to setup dbus match rule"), - display("Failed to setup dbus match rule {}", rule), - } - - #[doc = "Failed to stat device"] - FailedToStatDevice { - description("Failed to stat device") - } - - #[doc = "Session is already closed"] - SessionLost { - description("Session is already closed") - } - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + /// Failed to connect to dbus system socket + #[error("Failed to connect to dbus system socket")] + FailedDbusConnection(#[source] dbus::Error), + /// Failed to get session from logind + #[error("Failed to get session from logind")] + FailedToGetSession(#[source] IoError), + /// Failed to get seat from logind + #[error("Failed to get seat from logind")] + FailedToGetSeat(#[source] IoError), + /// Failed to get vt from logind + #[error("Failed to get vt from logind")] + FailedToGetVT, + /// Failed call to a dbus method + #[error("Failed to call dbus method for service: {bus:?}, path: {path:?}, interface: {interface:?}, member: {member:?}")] + FailedToSendDbusCall { + bus: BusName<'static>, + path: DbusPath<'static>, + interface: Interface<'static>, + member: Member<'static>, + #[source] + source: dbus::Error, + }, + /// DBus method call failed + #[error("Dbus message call failed for service: {bus:?}, path: {path:?}, interface: {interface:?}, member: {member:?}")] + DbusCallFailed { + bus: BusName<'static>, + path: DbusPath<'static>, + interface: Interface<'static>, + member: Member<'static>, + #[source] + source: dbus::Error, + }, + /// Dbus method return had unexpected format + #[error("Dbus method return had unexpected format")] + UnexpectedMethodReturn, + /// Failed to setup dbus match rule + #[error("Failed to setup dbus match rule {0}")] + DbusMatchFailed(String, #[source] dbus::Error), + /// Failed to stat device + #[error("Failed to stat device")] + FailedToStatDevice(#[source] nix::Error), + /// Session is already closed, + #[error("Session is already closed")] + SessionLost, } -use self::errors::*; impl AsErrno for Error { fn as_errno(&self) -> Option { diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index 15a243d..2bb6057 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -169,7 +169,7 @@ impl DirectSession { /// 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. - pub fn new(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier)> + pub fn new(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier), Error> where L: Into>, { @@ -183,10 +183,10 @@ impl DirectSession { fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC, 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(|| { - dup(0 /*stdin*/).chain_err(|| ErrorKind::FailedToOpenTTY(String::from(""))) + dup(0 /*stdin*/).map_err(|source| Error::FailedToOpenTTY(String::from(""), source)) })?; 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)> { - let stat = fstat(tty).chain_err(|| ErrorKind::NotRunningFromTTY)?; + fn setup_tty( + 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) { - bail!(ErrorKind::NotRunningFromTTY); + return Err(Error::NotRunningFromTTY); } let vt_num = minor(stat.st_rdev) as i32; @@ -226,24 +230,27 @@ impl DirectSession { let mut mode = 0; 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 { - bail!(ErrorKind::TTYAlreadyInGraphicsMode); + return Err(Error::TTYAlreadyInGraphicsMode); } unsafe { - tty::vt_activate(tty, vt_num as c_int).chain_err(|| ErrorKind::FailedToActivateTTY(vt_num))?; - tty::vt_wait_active(tty, vt_num as c_int).chain_err(|| ErrorKind::FailedToWaitForTTY(vt_num))?; + tty::vt_activate(tty, vt_num as c_int) + .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; unsafe { tty::kd_get_kb_mode(tty, &mut old_keyboard_mode) - .chain_err(|| ErrorKind::FailedToSaveTTYState(vt_num))?; - tty::kd_set_kb_mode(tty, tty::K_OFF).chain_err(|| ErrorKind::FailedToSetTTYKbMode(vt_num))?; + .map_err(|source| Error::FailedToSaveTTYState(vt_num, source))?; + 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) - .chain_err(|| ErrorKind::FailedToSetTTYMode(vt_num))?; + .map_err(|source| Error::FailedToSetTTYMode(vt_num, source))?; } // TODO: Support realtime signals @@ -265,7 +272,7 @@ impl DirectSession { }; 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)) @@ -440,62 +447,33 @@ pub fn direct_session_bind( } /// Errors related to direct/tty sessions -pub mod errors { - error_chain! { - errors { - #[doc = "Failed to open tty"] - FailedToOpenTTY(path: String) { - description("Failed to open tty"), - display("Failed to open tty ({:?})", path), - } - - #[doc = "Not running from a tty"] - NotRunningFromTTY { - description("Not running from a tty"), - } - - #[doc = "tty is already in KB_GRAPHICS mode"] - TTYAlreadyInGraphicsMode { - description("The tty is already in KB_GRAPHICS mode"), - display("The tty is already in graphics mode, is already a compositor running?"), - } - - #[doc = "Failed to activate open tty"] - FailedToActivateTTY(num: i32) { - description("Failed to activate open tty"), - display("Failed to activate open tty ({:?})", num), - } - - #[doc = "Failed to wait for tty to become active"] - FailedToWaitForTTY(num: i32) { - description("Failed to wait for tty to become active"), - 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), - } - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + /// Failed to open TTY + #[error("Failed to open TTY `{0}`")] + FailedToOpenTTY(String, #[source] nix::Error), + /// Not running from a TTY + #[error("Not running from a TTY")] + NotRunningFromTTY, + /// TTY is already in KB_GRAPHICS mode + #[error("The tty is already in graphics mode, is already a compositor running?")] + TTYAlreadyInGraphicsMode, + /// Failed to activate open tty + #[error("Failed to activate open tty ({0})")] + FailedToActivateTTY(i32, #[source] nix::Error), + /// Failed to wait for tty to become active + #[error("Failed to wait for tty {0} to become active")] + FailedToWaitForTTY(i32, #[source] nix::Error), + /// Failed to save old tty state + #[error("Failed to save old tty ({0}) state")] + FailedToSaveTTYState(i32, #[source] nix::Error), + /// Failed to set tty kb mode + #[error("Failed to set tty {0} kb mode to K_OFF")] + FailedToSetTTYKbMode(i32, #[source] nix::Error), + /// Failed to set tty mode + #[error("Failed to set tty {0} mode into graphics mode")] + FailedToSetTTYMode(i32, #[source] nix::Error), + /// Failed to set tty in process mode + #[error("Failed to take control of tty {0}")] + FailedToTakeControlOfTTY(i32, #[source] nix::Error), } -use self::errors::*; diff --git a/src/backend/winit.rs b/src/backend/winit.rs index a0eb0ee..f821730 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -2,8 +2,8 @@ use crate::backend::{ egl::{ - context::GlAttributes, error::Result as EGLResult, native, EGLContext, EGLDisplay, - EGLGraphicsBackend, EGLSurface, + context::GlAttributes, native, EGLContext, EGLDisplay, EGLGraphicsBackend, EGLSurface, + Error as EGLError, }, graphics::{gl::GLGraphicsBackend, CursorBackend, PixelFormat, SwapBuffersError}, input::{ @@ -16,7 +16,7 @@ use crate::backend::{ use nix::libc::c_void; use std::{ cell::{Ref, RefCell}, - cmp, fmt, + cmp, rc::Rc, time::Instant, }; @@ -34,28 +34,18 @@ use winit::{ }; /// Errors thrown by the `winit` backends -pub mod errors { - use crate::backend::egl::error as egl_error; - - error_chain! { - errors { - #[doc = "Failed to initialize a window"] - InitFailed { - description("Failed to initialize a window") - } - - #[doc = "Context creation is not supported on the current window system"] - NotSupported { - description("Context creation is not supported on the current window system.") - } - } - - links { - EGL(egl_error::Error, egl_error::ErrorKind) #[doc = "EGL error"]; - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + /// Failed to initialize a window + #[error("Failed to initialize a window")] + InitFailed(#[from] winit::error::OsError), + /// Context creation is not supported on the current window system + #[error("Context creation is not supported on the current window system")] + NotSupported, + /// EGL error + #[error("EGL error: {0}")] + EGL(#[from] EGLError), } -use self::errors::*; enum Window { Wayland { @@ -110,7 +100,7 @@ pub struct WinitInputBackend { /// Create a new [`WinitGraphicsBackend`], which implements the [`EGLGraphicsBackend`] /// and [`GLGraphicsBackend`] graphics backend trait and a corresponding [`WinitInputBackend`], /// which implements the [`InputBackend`] trait -pub fn init(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend)> +pub fn init(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error> where L: Into>, { @@ -129,7 +119,7 @@ where pub fn init_from_builder( builder: WindowBuilder, logger: L, -) -> Result<(WinitGraphicsBackend, WinitInputBackend)> +) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error> where L: Into>, { @@ -153,7 +143,7 @@ pub fn init_from_builder_with_gl_attr( builder: WindowBuilder, attributes: GlAttributes, logger: L, -) -> Result<(WinitGraphicsBackend, WinitInputBackend)> +) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error> where L: Into>, { @@ -161,7 +151,7 @@ where info!(log, "Initializing a winit backend"); 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"); @@ -178,7 +168,7 @@ where let surface = context.create_surface(())?; Window::X11 { context, surface } } else { - bail!(ErrorKind::NotSupported); + return Err(Error::NotSupported); }, ); @@ -316,7 +306,7 @@ impl GLGraphicsBackend for WinitGraphicsBackend { } impl EGLGraphicsBackend for WinitGraphicsBackend { - fn bind_wl_display(&self, display: &Display) -> EGLResult { + fn bind_wl_display(&self, display: &Display) -> Result { match *self.window { Window::Wayland { 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`] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)] pub enum WinitInputError { /// The underlying [`WinitWindow`] was closed. No further events can be processed. /// /// See `dispatch_new_events`. + #[error("Winit window was closed")] 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)] /// Winit-Backend internal event wrapping `winit`'s types into a [`KeyboardKeyEvent`] pub struct WinitKeyboardInputEvent { diff --git a/src/lib.rs b/src/lib.rs index c6a0796..78b7f2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,8 +13,6 @@ pub extern crate nix; #[macro_use] extern crate slog; #[macro_use] -extern crate error_chain; -#[macro_use] extern crate lazy_static; #[macro_use] extern crate bitflags;