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 }
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"]

View File

@ -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,
},
},
},

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 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<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
pub struct EglDevice<B, D>
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<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
L: Into<Option<::slog::Logger>>,
{
@ -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<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
L: Into<Option<::slog::Logger>>,
{
@ -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: <<D as Device>::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<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");
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<ResourceHandles> {
self.dev
.borrow()
.resource_handles()
.chain_err(|| ErrorKind::UnderlyingBackendError)
fn resource_handles(&self) -> Result<ResourceHandles, <Self::Surface as Surface>::Error> {
self.dev.borrow().resource_handles().map_err(Error::Underlying)
}
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 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)
}
}

View File

@ -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<B> + 'static,
<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;
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<Mode> {
@ -64,10 +62,8 @@ where
self.surface.pending_mode()
}
fn use_mode(&self, mode: Option<Mode>) -> Result<()> {
self.surface
.use_mode(mode)
.chain_err(|| ErrorKind::UnderlyingBackendError)
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
self.surface.use_mode(mode).map_err(Error::Underlying)
}
}

View File

@ -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<D: RawDevice + 'static> Backend for Gbm<D> {
unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for GbmDevice<D> {
type Arguments = crtc::Handle;
type Error = Error;
type Error = Error<<<D as Device>::Surface as Surface>::Error>;
fn is_backend(&self) -> bool {
true
}
fn ptr(&self) -> EglResult<ffi::NativeDisplayType> {
fn ptr(&self) -> Result<ffi::NativeDisplayType, EglError> {
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)
}
}
@ -80,7 +79,7 @@ unsafe impl<D: RawDevice + 'static> NativeSurface for GbmSurface<D> {
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

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::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<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;
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
/// 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
L: Into<Option<::slog::Logger>>,
{
@ -74,9 +101,7 @@ impl<D: RawDevice + ControlDevice + 'static> GbmDevice<D> {
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<D: RawDevice + ControlDevice + 'static> DeviceHandler for InternalDeviceHan
}
}
fn error(&mut self, error: <<D as Device>::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<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
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");
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<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
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<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
GbmFormat::ARGB8888,
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
)
.chain_err(|| ErrorKind::BufferCreationFailed)?,
.map_err(Error::BufferCreationFailed)?,
(0, 0),
));
@ -187,12 +214,8 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
self.dev.borrow_mut().process_events()
}
fn resource_handles(&self) -> Result<ResourceHandles> {
self.dev
.borrow()
.resource_handles()
.compat()
.chain_err(|| ErrorKind::UnderlyingBackendError)
fn resource_handles(&self) -> Result<ResourceHandles, Error<<<D as Device>::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<connector::Info, DrmError> {

View File

@ -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<D: RawDevice + 'static> GbmSurfaceInternal<D> {
Ok(())
}
pub fn recreate(&self) -> Result<()> {
let (w, h) = self.pending_mode().chain_err(|| ErrorKind::NoModeSet)?.size();
pub fn recreate(&self) -> Result<(), Error<<<D as Device>::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<D: RawDevice + 'static> GbmSurfaceInternal<D> {
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<D: RawDevice + 'static> GbmSurfaceInternal<D> {
impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
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 {
self.crtc.crtc()
@ -151,16 +151,12 @@ impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
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<Mode> {
@ -171,10 +167,8 @@ impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
self.crtc.pending_mode()
}
fn use_mode(&self, mode: Option<Mode>) -> Result<()> {
self.crtc
.use_mode(mode)
.chain_err(|| ErrorKind::UnderlyingBackendError)
fn use_mode(&self, mode: Option<Mode>) -> 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<LegacyDrmDevice<A>> {
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<()> {
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<Rgba<u8>, Vec<u8>>,
hotspot: (u32, u32),
) -> Result<()>
) -> Result<(), Self::Error>
where
'a: 'b,
{
@ -234,18 +226,18 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal<LegacyDr
GbmFormat::ARGB8888,
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
)
.chain_err(|| ErrorKind::BufferCreationFailed)?;
.map_err(Error::BufferCreationFailed)?;
cursor
.write(&**buffer)
.chain_err(|| ErrorKind::BufferWriteFailed)?
.chain_err(|| ErrorKind::BufferWriteFailed)?;
.map_err(|_| Error::DeviceDestroyed)?
.map_err(Error::BufferWriteFailed)?;
trace!(self.logger, "Setting the new imported cursor");
ResultExt::chain_err(self.crtc.set_cursor_representation(&cursor, hotspot), || {
ErrorKind::UnderlyingBackendError
})?;
self.crtc
.set_cursor_representation(&cursor, hotspot)
.map_err(Error::Underlying)?;
// and store it
self.cursor.set((cursor, hotspot));
@ -305,7 +297,7 @@ impl<D: RawDevice + 'static> GbmSurface<D> {
/// 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<(), <Self as Surface>::Error> {
self.0.recreate()
}
@ -317,7 +309,7 @@ impl<D: RawDevice + 'static> GbmSurface<D> {
impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
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 {
self.0.crtc()
@ -331,11 +323,11 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
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<D: RawDevice + 'static> Surface for GbmSurface<D> {
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)
}
}
@ -355,9 +347,9 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
#[cfg(feature = "backend_drm_legacy")]
impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface<LegacyDrmDevice<A>> {
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)
}
@ -365,7 +357,7 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface<LegacyDrmDevice<
&'b self,
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
hotspot: (u32, u32),
) -> Result<()>
) -> Result<(), Self::Error>
where
'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 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<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
pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
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
/// successful.
pub fn new<L>(dev: A, logger: L) -> Result<Self>
pub fn new<L>(dev: A, logger: L) -> Result<Self, Error>
where
L: Into<Option<::slog::Logger>>,
{
@ -100,7 +138,7 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
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<A: AsRawFd + 'static> LegacyDrmDevice<A> {
};
// 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<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
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) {
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<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
}
}
}
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<ResourceHandles> {
fn resource_handles(&self) -> Result<ResourceHandles, Error> {
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<connector::Info, DrmError> {

View File

@ -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<A>
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<A>
{
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,9 +107,14 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
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<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
.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::<Result<Vec<encoder::Info>>>()?;
.collect::<Result<Vec<encoder::Info>, _>>()?;
// 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<Mode>) -> Result<()> {
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
let mut pending = self.pending.write().unwrap();
// check the connectors to see if this mode is supported
@ -149,13 +176,15 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
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<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
*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<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
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<A> {
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<A: AsRawFd + 'static> Surface for LegacyDrmSurface<A> {
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<Mode>) -> Result<()> {
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
self.0.use_mode(mode)
}
}
@ -322,7 +353,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurface<A> {
self.0.commit_pending()
}
fn commit(&self, framebuffer: framebuffer::Handle) -> Result<()> {
fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
self.0.commit(framebuffer)
}

View File

@ -135,7 +135,7 @@ pub trait Surface {
/// [`pending_connectors`](Surface::pending_connectors)
type Connectors: IntoIterator<Item = connector::Handle>;
/// 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;

View File

@ -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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
attributes: GlAttributes,
reqs: PixelFormatRequirements,
logger: L,
) -> Result<EGLContext<B, N>>
) -> Result<EGLContext<B, N>, Error>
where
L: Into<Option<::slog::Logger>>,
{
@ -60,14 +60,17 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
mut attributes: GlAttributes,
reqs: PixelFormatRequirements,
log: ::slog::Logger,
) -> Result<(
) -> Result<
(
Rc<ffi::egl::types::EGLContext>,
Rc<ffi::egl::types::EGLDisplay>,
ffi::egl::types::EGLConfig,
Vec<c_int>,
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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
}
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<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());
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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
let mut minor: MaybeUninit<ffi::egl::types::EGLint> = 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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
value.as_mut_ptr(),
);
if res == 0 {
bail!(ErrorKind::ConfigFailed);
return Err(Error::ConfigFailed);
}
value.assume_init()
}};
@ -386,8 +389,8 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
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<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
}
/// 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.");
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

View File

@ -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),
}

View File

@ -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<EglExtensionNotSupportedError> 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<EGLDisplay>;
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, Error>;
}
/// Type to receive [`EGLImages`] for EGL-based [`WlBuffer`]s.
@ -525,22 +454,20 @@ impl Drop for EGLDisplay {
#[cfg(feature = "use_system_lib")]
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)
}
}
#[cfg(feature = "use_system_lib")]
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 {
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()))
}

View File

@ -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<B: Backend> {
/// 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<ffi::NativeDisplayType>;
fn ptr(&self) -> Result<ffi::NativeDisplayType, Error>;
/// Create a surface
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()
}
fn ptr(&self) -> Result<ffi::NativeDisplayType> {
fn ptr(&self) -> Result<ffi::NativeDisplayType, Error> {
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<XlibWindow> {
fn create_surface(&mut self, _args: ()) -> Result<XlibWindow, Error> {
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<Wayland> for WinitWindow {
self.wayland_display().is_some()
}
fn ptr(&self) -> Result<ffi::NativeDisplayType> {
fn ptr(&self) -> Result<ffi::NativeDisplayType, Error> {
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<wegl::WlEglSurface> {
fn create_surface(&mut self, _args: ()) -> Result<wegl::WlEglSurface, Error> {
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"));
}
}
}

View File

@ -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<N: native::NativeSurface> EGLSurface<N> {
pub(crate) fn new<B: native::Backend<Surface = N>, D: native::NativeDisplay<B>>(
context: &EGLContext<B, D>,
native: N,
) -> Result<EGLSurface<N>> {
) -> Result<EGLSurface<N>, Error> {
let surface = unsafe {
ffi::egl::CreateWindowSurface(
*context.display,
@ -47,7 +47,7 @@ impl<N: native::NativeSurface> EGLSurface<N> {
};
if surface.is_null() {
bail!(ErrorKind::SurfaceCreationFailed);
return Err(Error::SurfaceCreationFailed);
}
Ok(EGLSurface {

View File

@ -162,14 +162,14 @@ pub fn auto_session_bind<Data: 'static>(
impl Session for AutoSession {
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 {
#[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<i32> {

View File

@ -83,7 +83,7 @@ pub struct LogindSessionNotifier {
impl LogindSession {
/// 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
L: Into<Option<::slog::Logger>>,
{
@ -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::<DbusPath<'static>>()
.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<Vec<MessageItem>>,
) -> Result<Message>
) -> Result<Message, Error>
where
D: Into<BusName<'d>>,
P: Into<DbusPath<'p>>,
@ -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<I>(&self, signals: I) -> Result<()>
fn handle_signals<I>(&self, signals: I) -> Result<(), Error>
where
I: IntoIterator<Item = ConnectionItem>,
{
@ -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::<u32, u32, String>();
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::<u32, u32, OwnedFd>();
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::<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(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<RawFd> {
fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd, Error> {
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::<OwnedFd, bool>();
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<i32> {

View File

@ -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<L>(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier)>
pub fn new<L>(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier), Error>
where
L: Into<Option<::slog::Logger>>,
{
@ -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("<stdin>")))
dup(0 /*stdin*/).map_err(|source| Error::FailedToOpenTTY(String::from("<stdin>"), 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<Data: 'static>(
}
/// 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::*;

View File

@ -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<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend)>
pub fn init<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error>
where
L: Into<Option<::slog::Logger>>,
{
@ -129,7 +119,7 @@ where
pub fn init_from_builder<L>(
builder: WindowBuilder,
logger: L,
) -> Result<(WinitGraphicsBackend, WinitInputBackend)>
) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error>
where
L: Into<Option<::slog::Logger>>,
{
@ -153,7 +143,7 @@ pub fn init_from_builder_with_gl_attr<L>(
builder: WindowBuilder,
attributes: GlAttributes,
logger: L,
) -> Result<(WinitGraphicsBackend, WinitInputBackend)>
) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error>
where
L: Into<Option<::slog::Logger>>,
{
@ -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<EGLDisplay> {
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, EGLError> {
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 {

View File

@ -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;