Replace `failure` and `error-chain` by `thiserror`
This commit is contained in:
parent
885fd0cff2
commit
6a7d933553
|
@ -34,9 +34,10 @@ dbus = { version = "0.8", optional = true }
|
||||||
systemd = { version = "0.4.0", optional = true }
|
systemd = { version = "0.4.0", optional = true }
|
||||||
wayland-protocols = { version = "0.25.0", features = ["unstable_protocols", "server"], optional = true }
|
wayland-protocols = { version = "0.25.0", features = ["unstable_protocols", "server"], optional = true }
|
||||||
image = { version = "0.21.0", optional = true }
|
image = { version = "0.21.0", optional = true }
|
||||||
error-chain = "0.12.0"
|
|
||||||
lazy_static = "1.0.0"
|
lazy_static = "1.0.0"
|
||||||
failure = { version = "0.1.5", optional = true }
|
thiserror = "1"
|
||||||
|
# TODO: remove as soon as drm-rs provides an error implementing Error
|
||||||
|
failure = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
slog-term = "2.3"
|
slog-term = "2.3"
|
||||||
|
@ -47,7 +48,7 @@ gl_generator = { version = "0.10", optional = true }
|
||||||
[features]
|
[features]
|
||||||
default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "backend_session_logind", "renderer_glium", "xwayland", "wayland_frontend"]
|
default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "backend_session_logind", "renderer_glium", "xwayland", "wayland_frontend"]
|
||||||
backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "wayland-egl", "backend_egl", "renderer_gl", "use_system_lib"]
|
backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "wayland-egl", "backend_egl", "renderer_gl", "use_system_lib"]
|
||||||
backend_drm = ["drm", "failure"]
|
backend_drm = ["drm"]
|
||||||
backend_drm_legacy = ["backend_drm"]
|
backend_drm_legacy = ["backend_drm"]
|
||||||
backend_drm_gbm = ["backend_drm", "gbm", "image"]
|
backend_drm_gbm = ["backend_drm", "gbm", "image"]
|
||||||
backend_drm_egl = ["backend_drm", "backend_egl"]
|
backend_drm_egl = ["backend_drm", "backend_egl"]
|
||||||
|
|
|
@ -7,7 +7,7 @@ use slog::Drain;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::drm::{
|
backend::drm::{
|
||||||
device_bind,
|
device_bind,
|
||||||
legacy::{error::Error, LegacyDrmDevice, LegacyDrmSurface},
|
legacy::{Error, LegacyDrmDevice, LegacyDrmSurface},
|
||||||
Device, DeviceHandler, RawSurface, Surface,
|
Device, DeviceHandler, RawSurface, Surface,
|
||||||
},
|
},
|
||||||
reexports::{
|
reexports::{
|
||||||
|
@ -15,10 +15,8 @@ use smithay::{
|
||||||
drm::{
|
drm::{
|
||||||
buffer::format::PixelFormat,
|
buffer::format::PixelFormat,
|
||||||
control::{
|
control::{
|
||||||
connector::{self, State as ConnectorState},
|
connector::State as ConnectorState, crtc, dumbbuffer::DumbBuffer, framebuffer,
|
||||||
crtc,
|
Device as ControlDevice,
|
||||||
dumbbuffer::DumbBuffer,
|
|
||||||
encoder, framebuffer, Device as ControlDevice,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -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"];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,21 +18,29 @@ use wayland_server::Display;
|
||||||
|
|
||||||
use super::{Device, DeviceHandler, Surface};
|
use super::{Device, DeviceHandler, Surface};
|
||||||
use crate::backend::egl::context::GlAttributes;
|
use crate::backend::egl::context::GlAttributes;
|
||||||
use crate::backend::egl::error::Result as EGLResult;
|
|
||||||
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
|
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
|
||||||
use crate::backend::egl::EGLContext;
|
use crate::backend::egl::EGLContext;
|
||||||
|
use crate::backend::egl::Error as EGLError;
|
||||||
#[cfg(feature = "use_system_lib")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
use crate::backend::egl::{EGLDisplay, EGLGraphicsBackend};
|
use crate::backend::egl::{EGLDisplay, EGLGraphicsBackend};
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
use self::error::*;
|
|
||||||
|
|
||||||
mod surface;
|
mod surface;
|
||||||
pub use self::surface::*;
|
pub use self::surface::*;
|
||||||
|
|
||||||
#[cfg(feature = "backend_session")]
|
#[cfg(feature = "backend_session")]
|
||||||
pub mod session;
|
pub mod session;
|
||||||
|
|
||||||
|
/// Errors for the DRM/EGL module
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error<U: std::error::Error + std::fmt::Debug + std::fmt::Display + 'static> {
|
||||||
|
/// EGL Error
|
||||||
|
#[error("EGL error: {0:?}")]
|
||||||
|
EGL(#[source] EGLError),
|
||||||
|
/// Underlying backend error
|
||||||
|
#[error("Underlying backend error: {0:?}")]
|
||||||
|
Underlying(#[source] U),
|
||||||
|
}
|
||||||
|
|
||||||
/// Representation of an egl device to create egl rendering surfaces
|
/// Representation of an egl device to create egl rendering surfaces
|
||||||
pub struct EglDevice<B, D>
|
pub struct EglDevice<B, D>
|
||||||
where
|
where
|
||||||
|
@ -65,7 +73,7 @@ where
|
||||||
///
|
///
|
||||||
/// Returns an error if the file is no valid device or context
|
/// Returns an error if the file is no valid device or context
|
||||||
/// creation was not successful.
|
/// creation was not successful.
|
||||||
pub fn new<L>(dev: D, logger: L) -> Result<Self>
|
pub fn new<L>(dev: D, logger: L) -> Result<Self, Error<<<D as Device>::Surface as Surface>::Error>>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -85,7 +93,11 @@ where
|
||||||
///
|
///
|
||||||
/// Returns an error if the file is no valid device or context
|
/// Returns an error if the file is no valid device or context
|
||||||
/// creation was not successful.
|
/// creation was not successful.
|
||||||
pub fn new_with_gl_attr<L>(mut dev: D, attributes: GlAttributes, logger: L) -> Result<Self>
|
pub fn new_with_gl_attr<L>(
|
||||||
|
mut dev: D,
|
||||||
|
attributes: GlAttributes,
|
||||||
|
logger: L,
|
||||||
|
) -> Result<Self, Error<<<D as Device>::Surface as Surface>::Error>>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -97,7 +109,7 @@ where
|
||||||
Ok(EglDevice {
|
Ok(EglDevice {
|
||||||
// Open the gbm device from the drm device and create a context based on that
|
// Open the gbm device from the drm device and create a context based on that
|
||||||
dev: Rc::new(
|
dev: Rc::new(
|
||||||
EGLContext::new(dev, attributes, Default::default(), log.clone()).map_err(Error::from)?,
|
EGLContext::new(dev, attributes, Default::default(), log.clone()).map_err(Error::EGL)?,
|
||||||
),
|
),
|
||||||
logger: log,
|
logger: log,
|
||||||
})
|
})
|
||||||
|
@ -125,8 +137,7 @@ where
|
||||||
self.handler.vblank(crtc)
|
self.handler.vblank(crtc)
|
||||||
}
|
}
|
||||||
fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) {
|
fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) {
|
||||||
self.handler
|
self.handler.error(Error::Underlying(error));
|
||||||
.error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,10 +163,13 @@ where
|
||||||
self.dev.borrow_mut().clear_handler()
|
self.dev.borrow_mut().clear_handler()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<EglSurface<B, D>> {
|
fn create_surface(
|
||||||
|
&mut self,
|
||||||
|
crtc: crtc::Handle,
|
||||||
|
) -> Result<EglSurface<B, D>, <Self::Surface as Surface>::Error> {
|
||||||
info!(self.logger, "Initializing EglSurface");
|
info!(self.logger, "Initializing EglSurface");
|
||||||
|
|
||||||
let surface = self.dev.create_surface(crtc)?;
|
let surface = self.dev.create_surface(crtc).map_err(Error::EGL)?;
|
||||||
|
|
||||||
Ok(EglSurface {
|
Ok(EglSurface {
|
||||||
dev: self.dev.clone(),
|
dev: self.dev.clone(),
|
||||||
|
@ -167,11 +181,8 @@ where
|
||||||
self.dev.borrow_mut().process_events()
|
self.dev.borrow_mut().process_events()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resource_handles(&self) -> Result<ResourceHandles> {
|
fn resource_handles(&self) -> Result<ResourceHandles, <Self::Surface as Surface>::Error> {
|
||||||
self.dev
|
self.dev.borrow().resource_handles().map_err(Error::Underlying)
|
||||||
.borrow()
|
|
||||||
.resource_handles()
|
|
||||||
.chain_err(|| ErrorKind::UnderlyingBackendError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {
|
fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {
|
||||||
|
@ -201,7 +212,7 @@ where
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
fn bind_wl_display(&self, display: &Display) -> EGLResult<EGLDisplay> {
|
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, EGLError> {
|
||||||
self.dev.bind_wl_display(display)
|
self.dev.bind_wl_display(display)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use drm::control::{connector, crtc, Mode};
|
||||||
use nix::libc::c_void;
|
use nix::libc::c_void;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::error::*;
|
use super::Error;
|
||||||
use crate::backend::drm::{Device, Surface};
|
use crate::backend::drm::{Device, Surface};
|
||||||
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
|
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
|
||||||
use crate::backend::egl::{EGLContext, EGLSurface};
|
use crate::backend::egl::{EGLContext, EGLSurface};
|
||||||
|
@ -29,7 +29,7 @@ where
|
||||||
D: Device + NativeDisplay<B> + 'static,
|
D: Device + NativeDisplay<B> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
type Error = Error;
|
type Error = Error<<<D as Device>::Surface as Surface>::Error>;
|
||||||
type Connectors = <<D as Device>::Surface as Surface>::Connectors;
|
type Connectors = <<D as Device>::Surface as Surface>::Connectors;
|
||||||
|
|
||||||
fn crtc(&self) -> crtc::Handle {
|
fn crtc(&self) -> crtc::Handle {
|
||||||
|
@ -44,16 +44,14 @@ where
|
||||||
self.surface.pending_connectors()
|
self.surface.pending_connectors()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_connector(&self, connector: connector::Handle) -> Result<()> {
|
fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
|
||||||
self.surface
|
self.surface.add_connector(connector).map_err(Error::Underlying)
|
||||||
.add_connector(connector)
|
|
||||||
.chain_err(|| ErrorKind::UnderlyingBackendError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_connector(&self, connector: connector::Handle) -> Result<()> {
|
fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
|
||||||
self.surface
|
self.surface
|
||||||
.remove_connector(connector)
|
.remove_connector(connector)
|
||||||
.chain_err(|| ErrorKind::UnderlyingBackendError)
|
.map_err(Error::Underlying)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_mode(&self) -> Option<Mode> {
|
fn current_mode(&self) -> Option<Mode> {
|
||||||
|
@ -64,10 +62,8 @@ where
|
||||||
self.surface.pending_mode()
|
self.surface.pending_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<()> {
|
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
|
||||||
self.surface
|
self.surface.use_mode(mode).map_err(Error::Underlying)
|
||||||
.use_mode(mode)
|
|
||||||
.chain_err(|| ErrorKind::UnderlyingBackendError)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,13 @@
|
||||||
//! [`GbmDevice`](GbmDevice) and [`GbmSurface`](GbmSurface).
|
//! [`GbmDevice`](GbmDevice) and [`GbmSurface`](GbmSurface).
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::backend::drm::{Device, RawDevice};
|
use crate::backend::drm::{Device, RawDevice, Surface};
|
||||||
use crate::backend::egl::error::Result as EglResult;
|
|
||||||
use crate::backend::egl::ffi;
|
use crate::backend::egl::ffi;
|
||||||
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
|
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
|
||||||
|
use crate::backend::egl::Error as EglError;
|
||||||
use crate::backend::graphics::SwapBuffersError;
|
use crate::backend::graphics::SwapBuffersError;
|
||||||
|
|
||||||
use super::error::{Error, Result};
|
use super::{Error, GbmDevice, GbmSurface};
|
||||||
use super::{GbmDevice, GbmSurface};
|
|
||||||
|
|
||||||
use drm::control::{crtc, Device as ControlDevice};
|
use drm::control::{crtc, Device as ControlDevice};
|
||||||
use gbm::AsRaw;
|
use gbm::AsRaw;
|
||||||
|
@ -54,17 +53,17 @@ impl<D: RawDevice + 'static> Backend for Gbm<D> {
|
||||||
|
|
||||||
unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for GbmDevice<D> {
|
unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for GbmDevice<D> {
|
||||||
type Arguments = crtc::Handle;
|
type Arguments = crtc::Handle;
|
||||||
type Error = Error;
|
type Error = Error<<<D as Device>::Surface as Surface>::Error>;
|
||||||
|
|
||||||
fn is_backend(&self) -> bool {
|
fn is_backend(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ptr(&self) -> EglResult<ffi::NativeDisplayType> {
|
fn ptr(&self) -> Result<ffi::NativeDisplayType, EglError> {
|
||||||
Ok(self.dev.borrow().as_raw() as *const _)
|
Ok(self.dev.borrow().as_raw() as *const _)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<GbmSurface<D>> {
|
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<GbmSurface<D>, Self::Error> {
|
||||||
Device::create_surface(self, crtc)
|
Device::create_surface(self, crtc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +79,7 @@ unsafe impl<D: RawDevice + 'static> NativeSurface for GbmSurface<D> {
|
||||||
|
|
||||||
fn recreate(&self) -> bool {
|
fn recreate(&self) -> bool {
|
||||||
if let Err(err) = GbmSurface::recreate(self) {
|
if let Err(err) = GbmSurface::recreate(self) {
|
||||||
error!(self.0.logger, "Failure recreating internal resources: {:?}", err);
|
error!(self.0.logger, "Failure recreating internal resources: {}", err);
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
|
|
|
@ -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"];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,18 +13,45 @@ use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface};
|
||||||
|
|
||||||
use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice};
|
use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice};
|
||||||
use drm::SystemError as DrmError;
|
use drm::SystemError as DrmError;
|
||||||
use failure::ResultExt as FailureResultExt;
|
|
||||||
use gbm::{self, BufferObjectFlags, Format as GbmFormat};
|
use gbm::{self, BufferObjectFlags, Format as GbmFormat};
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::io;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
pub mod error;
|
/// Errors thrown by the [`GbmDevice`](::backend::drm::gbm::GbmDevice)
|
||||||
use self::error::*;
|
/// and [`GbmSurface`](::backend::drm::gbm::GbmSurface).
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error<U: std::error::Error + std::fmt::Debug + std::fmt::Display + 'static> {
|
||||||
|
/// Creation of GBM device failed
|
||||||
|
#[error("Creation of GBM device failed")]
|
||||||
|
InitFailed(#[source] io::Error),
|
||||||
|
/// Creation of GBM surface failed
|
||||||
|
#[error("Creation of GBM surface failed")]
|
||||||
|
SurfaceCreationFailed(#[source] io::Error),
|
||||||
|
/// No mode is set, blocking the current operation
|
||||||
|
#[error("No mode is currently set")]
|
||||||
|
NoModeSet,
|
||||||
|
/// Creation of GBM buffer object failed
|
||||||
|
#[error("Creation of GBM buffer object failed")]
|
||||||
|
BufferCreationFailed(#[source] io::Error),
|
||||||
|
/// Writing to GBM buffer failed
|
||||||
|
#[error("Writing to GBM buffer failed")]
|
||||||
|
BufferWriteFailed(#[source] io::Error),
|
||||||
|
/// Lock of GBM surface front buffer failed
|
||||||
|
#[error("Lock of GBM surface font buffer failed")]
|
||||||
|
FrontBufferLockFailed,
|
||||||
|
/// The GBM device was destroyed
|
||||||
|
#[error("The GBM device was destroyed")]
|
||||||
|
DeviceDestroyed,
|
||||||
|
/// Underlying backend error
|
||||||
|
#[error("Underlying error: {0}")]
|
||||||
|
Underlying(#[source] U),
|
||||||
|
}
|
||||||
|
|
||||||
mod surface;
|
mod surface;
|
||||||
pub use self::surface::GbmSurface;
|
pub use self::surface::GbmSurface;
|
||||||
|
@ -50,7 +77,7 @@ impl<D: RawDevice + ControlDevice + 'static> GbmDevice<D> {
|
||||||
///
|
///
|
||||||
/// Returns an error if the file is no valid drm node or context creation was not
|
/// Returns an error if the file is no valid drm node or context creation was not
|
||||||
/// successful.
|
/// successful.
|
||||||
pub fn new<L>(mut dev: D, logger: L) -> Result<Self>
|
pub fn new<L>(mut dev: D, logger: L) -> Result<Self, Error<<<D as Device>::Surface as Surface>::Error>>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -74,9 +101,7 @@ impl<D: RawDevice + ControlDevice + 'static> GbmDevice<D> {
|
||||||
debug!(log, "Creating gbm device");
|
debug!(log, "Creating gbm device");
|
||||||
Ok(GbmDevice {
|
Ok(GbmDevice {
|
||||||
// Open the gbm device from the drm device
|
// Open the gbm device from the drm device
|
||||||
dev: Rc::new(RefCell::new(
|
dev: Rc::new(RefCell::new(gbm::Device::new(dev).map_err(Error::InitFailed)?)),
|
||||||
gbm::Device::new(dev).chain_err(|| ErrorKind::InitFailed)?,
|
|
||||||
)),
|
|
||||||
backends: Rc::new(RefCell::new(HashMap::new())),
|
backends: Rc::new(RefCell::new(HashMap::new())),
|
||||||
logger: log,
|
logger: log,
|
||||||
})
|
})
|
||||||
|
@ -108,8 +133,7 @@ impl<D: RawDevice + ControlDevice + 'static> DeviceHandler for InternalDeviceHan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) {
|
fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) {
|
||||||
self.handler
|
self.handler.error(Error::Underlying(error))
|
||||||
.error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,11 +156,14 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
|
||||||
self.dev.borrow_mut().clear_handler();
|
self.dev.borrow_mut().clear_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<GbmSurface<D>> {
|
fn create_surface(
|
||||||
|
&mut self,
|
||||||
|
crtc: crtc::Handle,
|
||||||
|
) -> Result<GbmSurface<D>, Error<<<D as Device>::Surface as Surface>::Error>> {
|
||||||
info!(self.logger, "Initializing GbmSurface");
|
info!(self.logger, "Initializing GbmSurface");
|
||||||
|
|
||||||
let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc)
|
let drm_surface =
|
||||||
.chain_err(|| ErrorKind::UnderlyingBackendError)?;
|
Device::create_surface(&mut **self.dev.borrow_mut(), crtc).map_err(Error::Underlying)?;
|
||||||
|
|
||||||
// initialize the surface
|
// initialize the surface
|
||||||
let (w, h) = drm_surface
|
let (w, h) = drm_surface
|
||||||
|
@ -152,7 +179,7 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
|
||||||
GbmFormat::XRGB8888,
|
GbmFormat::XRGB8888,
|
||||||
BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
|
BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
|
||||||
)
|
)
|
||||||
.chain_err(|| ErrorKind::SurfaceCreationFailed)?;
|
.map_err(Error::SurfaceCreationFailed)?;
|
||||||
|
|
||||||
// initialize a buffer for the cursor image
|
// initialize a buffer for the cursor image
|
||||||
let cursor = Cell::new((
|
let cursor = Cell::new((
|
||||||
|
@ -164,7 +191,7 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
|
||||||
GbmFormat::ARGB8888,
|
GbmFormat::ARGB8888,
|
||||||
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
|
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
|
||||||
)
|
)
|
||||||
.chain_err(|| ErrorKind::BufferCreationFailed)?,
|
.map_err(Error::BufferCreationFailed)?,
|
||||||
(0, 0),
|
(0, 0),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -187,12 +214,8 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
|
||||||
self.dev.borrow_mut().process_events()
|
self.dev.borrow_mut().process_events()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resource_handles(&self) -> Result<ResourceHandles> {
|
fn resource_handles(&self) -> Result<ResourceHandles, Error<<<D as Device>::Surface as Surface>::Error>> {
|
||||||
self.dev
|
Device::resource_handles(&**self.dev.borrow()).map_err(Error::Underlying)
|
||||||
.borrow()
|
|
||||||
.resource_handles()
|
|
||||||
.compat()
|
|
||||||
.chain_err(|| ErrorKind::UnderlyingBackendError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {
|
fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::super::{Device, RawDevice, RawSurface, Surface};
|
use super::super::{Device, RawDevice, RawSurface, Surface};
|
||||||
use super::error::*;
|
use super::Error;
|
||||||
|
|
||||||
use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode};
|
use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode};
|
||||||
use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle};
|
use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle};
|
||||||
|
@ -90,8 +90,8 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recreate(&self) -> Result<()> {
|
pub fn recreate(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
|
||||||
let (w, h) = self.pending_mode().chain_err(|| ErrorKind::NoModeSet)?.size();
|
let (w, h) = self.pending_mode().ok_or(Error::NoModeSet)?.size();
|
||||||
|
|
||||||
// Recreate the surface and the related resources to match the new
|
// Recreate the surface and the related resources to match the new
|
||||||
// resolution.
|
// resolution.
|
||||||
|
@ -105,7 +105,7 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
|
||||||
GbmFormat::XRGB8888,
|
GbmFormat::XRGB8888,
|
||||||
BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
|
BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
|
||||||
)
|
)
|
||||||
.chain_err(|| ErrorKind::SurfaceCreationFailed)?;
|
.map_err(Error::SurfaceCreationFailed)?;
|
||||||
|
|
||||||
// Clean up buffers
|
// Clean up buffers
|
||||||
if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) {
|
if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) {
|
||||||
|
@ -137,7 +137,7 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
|
||||||
|
|
||||||
impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
|
impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
|
||||||
type Connectors = <<D as Device>::Surface as Surface>::Connectors;
|
type Connectors = <<D as Device>::Surface as Surface>::Connectors;
|
||||||
type Error = Error;
|
type Error = Error<<<D as Device>::Surface as Surface>::Error>;
|
||||||
|
|
||||||
fn crtc(&self) -> crtc::Handle {
|
fn crtc(&self) -> crtc::Handle {
|
||||||
self.crtc.crtc()
|
self.crtc.crtc()
|
||||||
|
@ -151,16 +151,12 @@ impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
|
||||||
self.crtc.pending_connectors()
|
self.crtc.pending_connectors()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_connector(&self, connector: connector::Handle) -> Result<()> {
|
fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
|
||||||
self.crtc
|
self.crtc.add_connector(connector).map_err(Error::Underlying)
|
||||||
.add_connector(connector)
|
|
||||||
.chain_err(|| ErrorKind::UnderlyingBackendError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_connector(&self, connector: connector::Handle) -> Result<()> {
|
fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
|
||||||
self.crtc
|
self.crtc.remove_connector(connector).map_err(Error::Underlying)
|
||||||
.remove_connector(connector)
|
|
||||||
.chain_err(|| ErrorKind::UnderlyingBackendError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_mode(&self) -> Option<Mode> {
|
fn current_mode(&self) -> Option<Mode> {
|
||||||
|
@ -171,10 +167,8 @@ impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
|
||||||
self.crtc.pending_mode()
|
self.crtc.pending_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<()> {
|
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
|
||||||
self.crtc
|
self.crtc.use_mode(mode).map_err(Error::Underlying)
|
||||||
.use_mode(mode)
|
|
||||||
.chain_err(|| ErrorKind::UnderlyingBackendError)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,19 +199,17 @@ where
|
||||||
#[cfg(feature = "backend_drm_legacy")]
|
#[cfg(feature = "backend_drm_legacy")]
|
||||||
impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal<LegacyDrmDevice<A>> {
|
impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal<LegacyDrmDevice<A>> {
|
||||||
type CursorFormat = &'a ImageBuffer<Rgba<u8>, Vec<u8>>;
|
type CursorFormat = &'a ImageBuffer<Rgba<u8>, Vec<u8>>;
|
||||||
type Error = Error;
|
type Error = Error<<<LegacyDrmDevice<A> as Device>::Surface as Surface>::Error>;
|
||||||
|
|
||||||
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> {
|
fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error> {
|
||||||
ResultExt::chain_err(self.crtc.set_cursor_position(x, y), || {
|
self.crtc.set_cursor_position(x, y).map_err(Error::Underlying)
|
||||||
ErrorKind::UnderlyingBackendError
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_cursor_representation<'b>(
|
fn set_cursor_representation<'b>(
|
||||||
&'b self,
|
&'b self,
|
||||||
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
|
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
|
||||||
hotspot: (u32, u32),
|
hotspot: (u32, u32),
|
||||||
) -> Result<()>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where
|
||||||
'a: 'b,
|
'a: 'b,
|
||||||
{
|
{
|
||||||
|
@ -234,18 +226,18 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal<LegacyDr
|
||||||
GbmFormat::ARGB8888,
|
GbmFormat::ARGB8888,
|
||||||
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
|
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
|
||||||
)
|
)
|
||||||
.chain_err(|| ErrorKind::BufferCreationFailed)?;
|
.map_err(Error::BufferCreationFailed)?;
|
||||||
|
|
||||||
cursor
|
cursor
|
||||||
.write(&**buffer)
|
.write(&**buffer)
|
||||||
.chain_err(|| ErrorKind::BufferWriteFailed)?
|
.map_err(|_| Error::DeviceDestroyed)?
|
||||||
.chain_err(|| ErrorKind::BufferWriteFailed)?;
|
.map_err(Error::BufferWriteFailed)?;
|
||||||
|
|
||||||
trace!(self.logger, "Setting the new imported cursor");
|
trace!(self.logger, "Setting the new imported cursor");
|
||||||
|
|
||||||
ResultExt::chain_err(self.crtc.set_cursor_representation(&cursor, hotspot), || {
|
self.crtc
|
||||||
ErrorKind::UnderlyingBackendError
|
.set_cursor_representation(&cursor, hotspot)
|
||||||
})?;
|
.map_err(Error::Underlying)?;
|
||||||
|
|
||||||
// and store it
|
// and store it
|
||||||
self.cursor.set((cursor, hotspot));
|
self.cursor.set((cursor, hotspot));
|
||||||
|
@ -305,7 +297,7 @@ impl<D: RawDevice + 'static> GbmSurface<D> {
|
||||||
/// calling [`Surface::use_mode`](Surface::use_mode).
|
/// calling [`Surface::use_mode`](Surface::use_mode).
|
||||||
/// You may check if your [`GbmSurface`] needs recreation through
|
/// You may check if your [`GbmSurface`] needs recreation through
|
||||||
/// [`needs_recreation`](GbmSurface::needs_recreation).
|
/// [`needs_recreation`](GbmSurface::needs_recreation).
|
||||||
pub fn recreate(&self) -> Result<()> {
|
pub fn recreate(&self) -> Result<(), <Self as Surface>::Error> {
|
||||||
self.0.recreate()
|
self.0.recreate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +309,7 @@ impl<D: RawDevice + 'static> GbmSurface<D> {
|
||||||
|
|
||||||
impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
|
impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
|
||||||
type Connectors = <<D as Device>::Surface as Surface>::Connectors;
|
type Connectors = <<D as Device>::Surface as Surface>::Connectors;
|
||||||
type Error = Error;
|
type Error = Error<<<D as Device>::Surface as Surface>::Error>;
|
||||||
|
|
||||||
fn crtc(&self) -> crtc::Handle {
|
fn crtc(&self) -> crtc::Handle {
|
||||||
self.0.crtc()
|
self.0.crtc()
|
||||||
|
@ -331,11 +323,11 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
|
||||||
self.0.pending_connectors()
|
self.0.pending_connectors()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_connector(&self, connector: connector::Handle) -> Result<()> {
|
fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
|
||||||
self.0.add_connector(connector)
|
self.0.add_connector(connector)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_connector(&self, connector: connector::Handle) -> Result<()> {
|
fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
|
||||||
self.0.remove_connector(connector)
|
self.0.remove_connector(connector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +339,7 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
|
||||||
self.0.pending_mode()
|
self.0.pending_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<()> {
|
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
|
||||||
self.0.use_mode(mode)
|
self.0.use_mode(mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,9 +347,9 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
|
||||||
#[cfg(feature = "backend_drm_legacy")]
|
#[cfg(feature = "backend_drm_legacy")]
|
||||||
impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface<LegacyDrmDevice<A>> {
|
impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface<LegacyDrmDevice<A>> {
|
||||||
type CursorFormat = &'a ImageBuffer<Rgba<u8>, Vec<u8>>;
|
type CursorFormat = &'a ImageBuffer<Rgba<u8>, Vec<u8>>;
|
||||||
type Error = Error;
|
type Error = <Self as Surface>::Error;
|
||||||
|
|
||||||
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> {
|
fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error> {
|
||||||
self.0.set_cursor_position(x, y)
|
self.0.set_cursor_position(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +357,7 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface<LegacyDrmDevice<
|
||||||
&'b self,
|
&'b self,
|
||||||
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
|
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
|
||||||
hotspot: (u32, u32),
|
hotspot: (u32, u32),
|
||||||
) -> Result<()>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where
|
||||||
'a: 'b,
|
'a: 'b,
|
||||||
{
|
{
|
||||||
|
|
|
@ -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"];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,30 +11,68 @@
|
||||||
use super::{DevPath, Device, DeviceHandler, RawDevice};
|
use super::{DevPath, Device, DeviceHandler, RawDevice};
|
||||||
|
|
||||||
use drm::control::{
|
use drm::control::{
|
||||||
connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, ResourceHandles,
|
connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, Mode, ResourceHandles,
|
||||||
};
|
};
|
||||||
use drm::{Device as BasicDevice, SystemError as DrmError};
|
use drm::{Device as BasicDevice, SystemError as DrmError};
|
||||||
use failure::ResultExt as FailureResultExt;
|
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
use nix::sys::stat::fstat;
|
use nix::sys::stat::fstat;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
|
use failure::{Fail, ResultExt};
|
||||||
|
|
||||||
mod surface;
|
mod surface;
|
||||||
pub use self::surface::LegacyDrmSurface;
|
pub use self::surface::LegacyDrmSurface;
|
||||||
use self::surface::{LegacyDrmSurfaceInternal, State};
|
use self::surface::{LegacyDrmSurfaceInternal, State};
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
use self::error::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "backend_session")]
|
#[cfg(feature = "backend_session")]
|
||||||
pub mod session;
|
pub mod session;
|
||||||
|
|
||||||
|
/// Errors thrown by the [`LegacyDrmDevice`](::backend::drm::legacy::LegacyDrmDevice)
|
||||||
|
/// and [`LegacyDrmSurface`](::backend::drm::legacy::LegacyDrmSurface).
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Unable to acquire DRM master
|
||||||
|
#[error("Failed to aquire DRM master")]
|
||||||
|
DrmMasterFailed,
|
||||||
|
/// The `DrmDevice` encountered an access error
|
||||||
|
#[error("DRM access error: {errmsg} on device `{dev:?}`")]
|
||||||
|
Access {
|
||||||
|
/// Error message associated to the access error
|
||||||
|
errmsg: &'static str,
|
||||||
|
/// Device on which the error was generated
|
||||||
|
dev: Option<PathBuf>,
|
||||||
|
/// Underlying device error
|
||||||
|
source: failure::Compat<drm::SystemError>,
|
||||||
|
},
|
||||||
|
/// Unable to determine device id of drm device
|
||||||
|
#[error("Unable to determine device id of drm device")]
|
||||||
|
UnableToGetDeviceId(#[source] nix::Error),
|
||||||
|
/// Device is currently paused
|
||||||
|
#[error("Device is currently paused, operation rejected")]
|
||||||
|
DeviceInactive,
|
||||||
|
/// Mode is not compatible with all given connectors
|
||||||
|
#[error("Mode `{0:?}` is not compatible with all given connectors")]
|
||||||
|
ModeNotSuitable(Mode),
|
||||||
|
/// The given crtc is already in use by another backend
|
||||||
|
#[error("Crtc `{0:?}` is already in use by another backend")]
|
||||||
|
CrtcAlreadyInUse(crtc::Handle),
|
||||||
|
/// No encoder was found for a given connector on the set crtc
|
||||||
|
#[error("No encoder found for the given connector '{connector:?}' on crtc `{crtc:?}`")]
|
||||||
|
NoSuitableEncoder {
|
||||||
|
/// Connector info
|
||||||
|
connector: connector::Info,
|
||||||
|
/// CRTC
|
||||||
|
crtc: crtc::Handle,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
/// Open raw drm device utilizing legacy mode-setting
|
/// Open raw drm device utilizing legacy mode-setting
|
||||||
pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
|
pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
|
||||||
dev: Rc<Dev<A>>,
|
dev: Rc<Dev<A>>,
|
||||||
|
@ -92,7 +130,7 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
||||||
///
|
///
|
||||||
/// Returns an error if the file is no valid drm node or context creation was not
|
/// Returns an error if the file is no valid drm node or context creation was not
|
||||||
/// successful.
|
/// successful.
|
||||||
pub fn new<L>(dev: A, logger: L) -> Result<Self>
|
pub fn new<L>(dev: A, logger: L) -> Result<Self, Error>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -100,7 +138,7 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
||||||
info!(log, "DrmDevice initializing");
|
info!(log, "DrmDevice initializing");
|
||||||
|
|
||||||
let dev_id = fstat(dev.as_raw_fd())
|
let dev_id = fstat(dev.as_raw_fd())
|
||||||
.chain_err(|| ErrorKind::UnableToGetDeviceId)?
|
.map_err(Error::UnableToGetDeviceId)?
|
||||||
.st_rdev;
|
.st_rdev;
|
||||||
|
|
||||||
let active = Arc::new(AtomicBool::new(true));
|
let active = Arc::new(AtomicBool::new(true));
|
||||||
|
@ -119,20 +157,30 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// enumerate (and save) the current device state
|
// enumerate (and save) the current device state
|
||||||
let res_handles = ControlDevice::resource_handles(&dev).compat().chain_err(|| {
|
let res_handles = ControlDevice::resource_handles(&dev)
|
||||||
ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", dev.dev_path()))
|
.compat()
|
||||||
})?;
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Error loading drm resources",
|
||||||
|
dev: dev.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
for &con in res_handles.connectors() {
|
for &con in res_handles.connectors() {
|
||||||
let con_info = dev.get_connector(con).compat().chain_err(|| {
|
let con_info = dev.get_connector(con).compat().map_err(|source| Error::Access {
|
||||||
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", dev.dev_path()))
|
errmsg: "Error loading connector info",
|
||||||
|
dev: dev.dev_path(),
|
||||||
|
source,
|
||||||
})?;
|
})?;
|
||||||
if let Some(enc) = con_info.current_encoder() {
|
if let Some(enc) = con_info.current_encoder() {
|
||||||
let enc_info = dev.get_encoder(enc).compat().chain_err(|| {
|
let enc_info = dev.get_encoder(enc).compat().map_err(|source| Error::Access {
|
||||||
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", dev.dev_path()))
|
errmsg: "Error loading encoder info",
|
||||||
|
dev: dev.dev_path(),
|
||||||
|
source,
|
||||||
})?;
|
})?;
|
||||||
if let Some(crtc) = enc_info.crtc() {
|
if let Some(crtc) = enc_info.crtc() {
|
||||||
let info = dev.get_crtc(crtc).compat().chain_err(|| {
|
let info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
|
||||||
ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", dev.dev_path()))
|
errmsg: "Error loading crtc info",
|
||||||
|
dev: dev.dev_path(),
|
||||||
|
source,
|
||||||
})?;
|
})?;
|
||||||
dev.old_state
|
dev.old_state
|
||||||
.entry(crtc)
|
.entry(crtc)
|
||||||
|
@ -178,35 +226,44 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
|
||||||
let _ = self.handler.take();
|
let _ = self.handler.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<LegacyDrmSurface<A>> {
|
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<LegacyDrmSurface<A>, Error> {
|
||||||
if self.backends.borrow().contains_key(&crtc) {
|
if self.backends.borrow().contains_key(&crtc) {
|
||||||
bail!(ErrorKind::CrtcAlreadyInUse(crtc));
|
return Err(Error::CrtcAlreadyInUse(crtc));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.active.load(Ordering::SeqCst) {
|
if !self.active.load(Ordering::SeqCst) {
|
||||||
bail!(ErrorKind::DeviceInactive);
|
return Err(Error::DeviceInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to enumarate the current state to set the initial state variable correctly
|
// Try to enumarate the current state to set the initial state variable correctly
|
||||||
|
|
||||||
let crtc_info = self
|
let crtc_info = self.get_crtc(crtc).compat().map_err(|source| Error::Access {
|
||||||
.get_crtc(crtc)
|
errmsg: "Error loading crtc info",
|
||||||
.compat()
|
dev: self.dev_path(),
|
||||||
.chain_err(|| ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", self.dev_path())))?;
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
let mode = crtc_info.mode();
|
let mode = crtc_info.mode();
|
||||||
|
|
||||||
let mut connectors = HashSet::new();
|
let mut connectors = HashSet::new();
|
||||||
let res_handles = ControlDevice::resource_handles(self).compat().chain_err(|| {
|
let res_handles = ControlDevice::resource_handles(self)
|
||||||
ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path()))
|
.compat()
|
||||||
})?;
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Error loading drm resources",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
for &con in res_handles.connectors() {
|
for &con in res_handles.connectors() {
|
||||||
let con_info = self.get_connector(con).compat().chain_err(|| {
|
let con_info = self.get_connector(con).compat().map_err(|source| Error::Access {
|
||||||
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path()))
|
errmsg: "Error loading connector info",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
})?;
|
})?;
|
||||||
if let Some(enc) = con_info.current_encoder() {
|
if let Some(enc) = con_info.current_encoder() {
|
||||||
let enc_info = self.get_encoder(enc).compat().chain_err(|| {
|
let enc_info = self.get_encoder(enc).compat().map_err(|source| Error::Access {
|
||||||
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path()))
|
errmsg: "Error loading encoder info",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
})?;
|
})?;
|
||||||
if let Some(current_crtc) = enc_info.crtc() {
|
if let Some(current_crtc) = enc_info.crtc() {
|
||||||
if crtc == current_crtc {
|
if crtc == current_crtc {
|
||||||
|
@ -255,23 +312,26 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(source) => {
|
||||||
if let Some(handler) = self.handler.as_ref() {
|
if let Some(handler) = self.handler.as_ref() {
|
||||||
handler.borrow_mut().error(
|
handler.borrow_mut().error(Error::Access {
|
||||||
ResultExt::<()>::chain_err(Err(err).compat(), || {
|
errmsg: "Error processing drm events",
|
||||||
ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path()))
|
dev: self.dev_path(),
|
||||||
})
|
source: source.compat(),
|
||||||
.unwrap_err(),
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resource_handles(&self) -> Result<ResourceHandles> {
|
fn resource_handles(&self) -> Result<ResourceHandles, Error> {
|
||||||
ControlDevice::resource_handles(self)
|
ControlDevice::resource_handles(self)
|
||||||
.compat()
|
.compat()
|
||||||
.chain_err(|| ErrorKind::DrmDev(format!("Error loading resource info on {:?}", self.dev_path())))
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Error loading resource info",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {
|
fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {
|
||||||
|
|
|
@ -4,7 +4,6 @@ use drm::control::{
|
||||||
PageFlipFlags,
|
PageFlipFlags,
|
||||||
};
|
};
|
||||||
use drm::Device as BasicDevice;
|
use drm::Device as BasicDevice;
|
||||||
use failure::ResultExt as FailureResultExt;
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
@ -15,7 +14,9 @@ use crate::backend::drm::{DevPath, RawSurface, Surface};
|
||||||
use crate::backend::graphics::CursorBackend;
|
use crate::backend::graphics::CursorBackend;
|
||||||
use crate::backend::graphics::SwapBuffersError;
|
use crate::backend::graphics::SwapBuffersError;
|
||||||
|
|
||||||
use super::{error::*, Dev};
|
use super::{Dev, Error};
|
||||||
|
|
||||||
|
use failure::ResultExt;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
|
@ -44,14 +45,22 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurfaceInternal<A>
|
||||||
type CursorFormat = &'a dyn Buffer;
|
type CursorFormat = &'a dyn Buffer;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> {
|
fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Error> {
|
||||||
trace!(self.logger, "Move the cursor to {},{}", x, y);
|
trace!(self.logger, "Move the cursor to {},{}", x, y);
|
||||||
self.move_cursor(self.crtc, (x as i32, y as i32))
|
self.move_cursor(self.crtc, (x as i32, y as i32))
|
||||||
.compat()
|
.compat()
|
||||||
.chain_err(|| ErrorKind::DrmDev(format!("Error moving cursor on {:?}", self.dev_path())))
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Error moving cursor",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_cursor_representation<'b>(&'b self, buffer: Self::CursorFormat, hotspot: (u32, u32)) -> Result<()>
|
fn set_cursor_representation<'b>(
|
||||||
|
&'b self,
|
||||||
|
buffer: Self::CursorFormat,
|
||||||
|
hotspot: (u32, u32),
|
||||||
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
'a: 'b,
|
'a: 'b,
|
||||||
{
|
{
|
||||||
|
@ -63,7 +72,11 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurfaceInternal<A>
|
||||||
{
|
{
|
||||||
self.set_cursor(self.crtc, Some(buffer))
|
self.set_cursor(self.crtc, Some(buffer))
|
||||||
.compat()
|
.compat()
|
||||||
.chain_err(|| ErrorKind::DrmDev(format!("Failed to set cursor on {:?}", self.dev_path())))?;
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Failed to set cursor",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -94,10 +107,15 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
|
||||||
self.pending.read().unwrap().mode
|
self.pending.read().unwrap().mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_connector(&self, conn: connector::Handle) -> Result<()> {
|
fn add_connector(&self, conn: connector::Handle) -> Result<(), Error> {
|
||||||
let info = self.get_connector(conn).compat().chain_err(|| {
|
let info = self
|
||||||
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path()))
|
.get_connector(conn)
|
||||||
})?;
|
.compat()
|
||||||
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Error loading connector info",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut pending = self.pending.write().unwrap();
|
let mut pending = self.pending.write().unwrap();
|
||||||
|
|
||||||
|
@ -110,37 +128,46 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
|
||||||
.filter(|enc| enc.is_some())
|
.filter(|enc| enc.is_some())
|
||||||
.map(|enc| enc.unwrap())
|
.map(|enc| enc.unwrap())
|
||||||
.map(|encoder| {
|
.map(|encoder| {
|
||||||
self.get_encoder(encoder).compat().chain_err(|| {
|
self.get_encoder(encoder)
|
||||||
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path()))
|
.compat()
|
||||||
})
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Error loading encoder info",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<encoder::Info>>>()?;
|
.collect::<Result<Vec<encoder::Info>, _>>()?;
|
||||||
|
|
||||||
// and if any encoder supports the selected crtc
|
// and if any encoder supports the selected crtc
|
||||||
let resource_handles = self.resource_handles().compat().chain_err(|| {
|
let resource_handles = self.resource_handles().compat().map_err(|source| Error::Access {
|
||||||
ErrorKind::DrmDev(format!("Error loading resources on {:?}", self.dev_path()))
|
errmsg: "Error loading resources",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
})?;
|
})?;
|
||||||
if !encoders
|
if !encoders
|
||||||
.iter()
|
.iter()
|
||||||
.map(|encoder| encoder.possible_crtcs())
|
.map(|encoder| encoder.possible_crtcs())
|
||||||
.all(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&self.crtc))
|
.all(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&self.crtc))
|
||||||
{
|
{
|
||||||
bail!(ErrorKind::NoSuitableEncoder(info, self.crtc));
|
return Err(Error::NoSuitableEncoder {
|
||||||
|
connector: info,
|
||||||
|
crtc: self.crtc,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pending.connectors.insert(conn);
|
pending.connectors.insert(conn);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::ModeNotSuitable(pending.mode.unwrap()));
|
return Err(Error::ModeNotSuitable(pending.mode.unwrap()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_connector(&self, connector: connector::Handle) -> Result<()> {
|
fn remove_connector(&self, connector: connector::Handle) -> Result<(), Error> {
|
||||||
self.pending.write().unwrap().connectors.remove(&connector);
|
self.pending.write().unwrap().connectors.remove(&connector);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<()> {
|
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
|
||||||
let mut pending = self.pending.write().unwrap();
|
let mut pending = self.pending.write().unwrap();
|
||||||
|
|
||||||
// check the connectors to see if this mode is supported
|
// check the connectors to see if this mode is supported
|
||||||
|
@ -149,13 +176,15 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
|
||||||
if !self
|
if !self
|
||||||
.get_connector(*connector)
|
.get_connector(*connector)
|
||||||
.compat()
|
.compat()
|
||||||
.chain_err(|| {
|
.map_err(|source| Error::Access {
|
||||||
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path()))
|
errmsg: "Error loading connector info",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
})?
|
})?
|
||||||
.modes()
|
.modes()
|
||||||
.contains(&mode)
|
.contains(&mode)
|
||||||
{
|
{
|
||||||
bail!(ErrorKind::ModeNotSuitable(mode));
|
return Err(Error::ModeNotSuitable(mode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +200,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
|
||||||
*self.pending.read().unwrap() != *self.state.read().unwrap()
|
*self.pending.read().unwrap() != *self.state.read().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit(&self, framebuffer: framebuffer::Handle) -> Result<()> {
|
fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
|
||||||
let mut current = self.state.write().unwrap();
|
let mut current = self.state.write().unwrap();
|
||||||
let pending = self.pending.read().unwrap();
|
let pending = self.pending.read().unwrap();
|
||||||
|
|
||||||
|
@ -217,12 +246,10 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
|
||||||
pending.mode,
|
pending.mode,
|
||||||
)
|
)
|
||||||
.compat()
|
.compat()
|
||||||
.chain_err(|| {
|
.map_err(|source| Error::Access {
|
||||||
ErrorKind::DrmDev(format!(
|
errmsg: "Error setting crtc",
|
||||||
"Error setting crtc {:?} on {:?}",
|
dev: self.dev_path(),
|
||||||
self.crtc,
|
source,
|
||||||
self.dev_path()
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
*current = pending.clone();
|
*current = pending.clone();
|
||||||
|
@ -268,11 +295,15 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface<A> {
|
||||||
type CursorFormat = &'a dyn Buffer;
|
type CursorFormat = &'a dyn Buffer;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> {
|
fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Error> {
|
||||||
self.0.set_cursor_position(x, y)
|
self.0.set_cursor_position(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_cursor_representation<'b>(&'b self, buffer: Self::CursorFormat, hotspot: (u32, u32)) -> Result<()>
|
fn set_cursor_representation<'b>(
|
||||||
|
&'b self,
|
||||||
|
buffer: Self::CursorFormat,
|
||||||
|
hotspot: (u32, u32),
|
||||||
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
'a: 'b,
|
'a: 'b,
|
||||||
{
|
{
|
||||||
|
@ -304,15 +335,15 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurface<A> {
|
||||||
self.0.pending_mode()
|
self.0.pending_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_connector(&self, connector: connector::Handle) -> Result<()> {
|
fn add_connector(&self, connector: connector::Handle) -> Result<(), Error> {
|
||||||
self.0.add_connector(connector)
|
self.0.add_connector(connector)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_connector(&self, connector: connector::Handle) -> Result<()> {
|
fn remove_connector(&self, connector: connector::Handle) -> Result<(), Error> {
|
||||||
self.0.remove_connector(connector)
|
self.0.remove_connector(connector)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<()> {
|
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
|
||||||
self.0.use_mode(mode)
|
self.0.use_mode(mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,7 +353,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurface<A> {
|
||||||
self.0.commit_pending()
|
self.0.commit_pending()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit(&self, framebuffer: framebuffer::Handle) -> Result<()> {
|
fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
|
||||||
self.0.commit(framebuffer)
|
self.0.commit(framebuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,7 @@ pub trait Surface {
|
||||||
/// [`pending_connectors`](Surface::pending_connectors)
|
/// [`pending_connectors`](Surface::pending_connectors)
|
||||||
type Connectors: IntoIterator<Item = connector::Handle>;
|
type Connectors: IntoIterator<Item = connector::Handle>;
|
||||||
/// Error type returned by methods of this trait
|
/// Error type returned by methods of this trait
|
||||||
type Error: Error + Send;
|
type Error: Error + Send + 'static;
|
||||||
|
|
||||||
/// Returns the underlying [`crtc`](drm::control::crtc) of this surface
|
/// Returns the underlying [`crtc`](drm::control::crtc) of this surface
|
||||||
fn crtc(&self) -> crtc::Handle;
|
fn crtc(&self) -> crtc::Handle;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! EGL context related structs
|
//! EGL context related structs
|
||||||
|
|
||||||
use super::{error::*, ffi, native, EGLSurface};
|
use super::{ffi, native, EGLSurface, Error};
|
||||||
use crate::backend::graphics::PixelFormat;
|
use crate::backend::graphics::PixelFormat;
|
||||||
use nix::libc::{c_int, c_void};
|
use nix::libc::{c_int, c_void};
|
||||||
use slog;
|
use slog;
|
||||||
|
@ -33,7 +33,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
attributes: GlAttributes,
|
attributes: GlAttributes,
|
||||||
reqs: PixelFormatRequirements,
|
reqs: PixelFormatRequirements,
|
||||||
logger: L,
|
logger: L,
|
||||||
) -> Result<EGLContext<B, N>>
|
) -> Result<EGLContext<B, N>, Error>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -60,14 +60,17 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
mut attributes: GlAttributes,
|
mut attributes: GlAttributes,
|
||||||
reqs: PixelFormatRequirements,
|
reqs: PixelFormatRequirements,
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
) -> Result<(
|
) -> Result<
|
||||||
Rc<ffi::egl::types::EGLContext>,
|
(
|
||||||
Rc<ffi::egl::types::EGLDisplay>,
|
Rc<ffi::egl::types::EGLContext>,
|
||||||
ffi::egl::types::EGLConfig,
|
Rc<ffi::egl::types::EGLDisplay>,
|
||||||
Vec<c_int>,
|
ffi::egl::types::EGLConfig,
|
||||||
PixelFormat,
|
Vec<c_int>,
|
||||||
bool,
|
PixelFormat,
|
||||||
)> {
|
bool,
|
||||||
|
),
|
||||||
|
Error,
|
||||||
|
> {
|
||||||
// If no version is given, try OpenGLES 3.0, if available,
|
// If no version is given, try OpenGLES 3.0, if available,
|
||||||
// fallback to 2.0 otherwise
|
// fallback to 2.0 otherwise
|
||||||
let version = match attributes.version {
|
let version = match attributes.version {
|
||||||
|
@ -88,14 +91,14 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
}
|
}
|
||||||
Some((1, x)) => {
|
Some((1, x)) => {
|
||||||
error!(log, "OpenGLES 1.* is not supported by the EGL renderer backend");
|
error!(log, "OpenGLES 1.* is not supported by the EGL renderer backend");
|
||||||
bail!(ErrorKind::OpenGlVersionNotSupported((1, x)));
|
return Err(Error::OpenGlVersionNotSupported((1, x)));
|
||||||
}
|
}
|
||||||
Some(version) => {
|
Some(version) => {
|
||||||
error!(
|
error!(
|
||||||
log,
|
log,
|
||||||
"OpenGLES {:?} is unknown and not supported by the EGL renderer backend", version
|
"OpenGLES {:?} is unknown and not supported by the EGL renderer backend", version
|
||||||
);
|
);
|
||||||
bail!(ErrorKind::OpenGlVersionNotSupported(version));
|
return Err(Error::OpenGlVersionNotSupported(version));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,7 +149,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
let display = B::get_display(ptr, |e: &str| dp_extensions.iter().any(|s| s == e), log.clone());
|
let display = B::get_display(ptr, |e: &str| dp_extensions.iter().any(|s| s == e), log.clone());
|
||||||
if display == ffi::egl::NO_DISPLAY {
|
if display == ffi::egl::NO_DISPLAY {
|
||||||
error!(log, "EGL Display is not valid");
|
error!(log, "EGL Display is not valid");
|
||||||
bail!(ErrorKind::DisplayNotSupported);
|
return Err(Error::DisplayNotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
let egl_version = {
|
let egl_version = {
|
||||||
|
@ -154,7 +157,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
let mut minor: MaybeUninit<ffi::egl::types::EGLint> = MaybeUninit::uninit();
|
let mut minor: MaybeUninit<ffi::egl::types::EGLint> = MaybeUninit::uninit();
|
||||||
|
|
||||||
if ffi::egl::Initialize(display, major.as_mut_ptr(), minor.as_mut_ptr()) == 0 {
|
if ffi::egl::Initialize(display, major.as_mut_ptr(), minor.as_mut_ptr()) == 0 {
|
||||||
bail!(ErrorKind::InitFailed);
|
return Err(Error::InitFailed);
|
||||||
}
|
}
|
||||||
let major = major.assume_init();
|
let major = major.assume_init();
|
||||||
let minor = minor.assume_init();
|
let minor = minor.assume_init();
|
||||||
|
@ -179,7 +182,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
|
|
||||||
if egl_version >= (1, 2) && ffi::egl::BindAPI(ffi::egl::OPENGL_ES_API) == 0 {
|
if egl_version >= (1, 2) && ffi::egl::BindAPI(ffi::egl::OPENGL_ES_API) == 0 {
|
||||||
error!(log, "OpenGLES not supported by the underlying EGL implementation");
|
error!(log, "OpenGLES not supported by the underlying EGL implementation");
|
||||||
bail!(ErrorKind::OpenGlesNotSupported);
|
return Err(Error::OpenGlesNotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
let descriptor = {
|
let descriptor = {
|
||||||
|
@ -205,7 +208,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
log,
|
log,
|
||||||
"OpenglES 3.* is not supported on EGL Versions lower then 1.3"
|
"OpenglES 3.* is not supported on EGL Versions lower then 1.3"
|
||||||
);
|
);
|
||||||
bail!(ErrorKind::NoAvailablePixelFormat);
|
return Err(Error::NoAvailablePixelFormat);
|
||||||
}
|
}
|
||||||
trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES3");
|
trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES3");
|
||||||
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
||||||
|
@ -220,7 +223,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
log,
|
log,
|
||||||
"OpenglES 2.* is not supported on EGL Versions lower then 1.3"
|
"OpenglES 2.* is not supported on EGL Versions lower then 1.3"
|
||||||
);
|
);
|
||||||
bail!(ErrorKind::NoAvailablePixelFormat);
|
return Err(Error::NoAvailablePixelFormat);
|
||||||
}
|
}
|
||||||
trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES2");
|
trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES2");
|
||||||
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
||||||
|
@ -289,7 +292,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
|
|
||||||
if reqs.stereoscopy {
|
if reqs.stereoscopy {
|
||||||
error!(log, "Stereoscopy is currently unsupported (sorry!)");
|
error!(log, "Stereoscopy is currently unsupported (sorry!)");
|
||||||
bail!(ErrorKind::NoAvailablePixelFormat);
|
return Err(Error::NoAvailablePixelFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
out.push(ffi::egl::NONE as c_int);
|
out.push(ffi::egl::NONE as c_int);
|
||||||
|
@ -307,7 +310,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
num_configs.as_mut_ptr(),
|
num_configs.as_mut_ptr(),
|
||||||
) == 0
|
) == 0
|
||||||
{
|
{
|
||||||
bail!(ErrorKind::ConfigFailed);
|
return Err(Error::ConfigFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
let config_id = config_id.assume_init();
|
let config_id = config_id.assume_init();
|
||||||
|
@ -315,7 +318,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
|
|
||||||
if num_configs == 0 {
|
if num_configs == 0 {
|
||||||
error!(log, "No matching color format found");
|
error!(log, "No matching color format found");
|
||||||
bail!(ErrorKind::NoAvailablePixelFormat);
|
return Err(Error::NoAvailablePixelFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// analyzing each config
|
// analyzing each config
|
||||||
|
@ -329,7 +332,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
value.as_mut_ptr(),
|
value.as_mut_ptr(),
|
||||||
);
|
);
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
bail!(ErrorKind::ConfigFailed);
|
return Err(Error::ConfigFailed);
|
||||||
}
|
}
|
||||||
value.assume_init()
|
value.assume_init()
|
||||||
}};
|
}};
|
||||||
|
@ -386,8 +389,8 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
|
|
||||||
if context.is_null() {
|
if context.is_null() {
|
||||||
match ffi::egl::GetError() as u32 {
|
match ffi::egl::GetError() as u32 {
|
||||||
ffi::egl::BAD_ATTRIBUTE => bail!(ErrorKind::CreationFailed),
|
ffi::egl::BAD_ATTRIBUTE => return Err(Error::CreationFailed),
|
||||||
err_no => bail!(ErrorKind::Unknown(err_no)),
|
err_no => return Err(Error::Unknown(err_no)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!(log, "EGL context successfully created");
|
debug!(log, "EGL context successfully created");
|
||||||
|
@ -429,13 +432,12 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a surface for rendering
|
/// Creates a surface for rendering
|
||||||
pub fn create_surface(&self, args: N::Arguments) -> Result<EGLSurface<B::Surface>> {
|
pub fn create_surface(&self, args: N::Arguments) -> Result<EGLSurface<B::Surface>, Error> {
|
||||||
trace!(self.logger, "Creating EGL window surface.");
|
trace!(self.logger, "Creating EGL window surface.");
|
||||||
let surface = self
|
let surface = self.native.borrow_mut().create_surface(args).map_err(|e| {
|
||||||
.native
|
error!(self.logger, "EGL surface creation failed: {}", e);
|
||||||
.borrow_mut()
|
Error::SurfaceCreationFailed
|
||||||
.create_surface(args)
|
})?;
|
||||||
.chain_err(|| ErrorKind::SurfaceCreationFailed)?;
|
|
||||||
EGLSurface::new(self, surface).map(|x| {
|
EGLSurface::new(self, surface).map(|x| {
|
||||||
debug!(self.logger, "EGL surface successfully created");
|
debug!(self.logger, "EGL surface successfully created");
|
||||||
x
|
x
|
||||||
|
|
|
@ -1,82 +1,49 @@
|
||||||
//! EGL error types
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
/// EGL errors
|
||||||
error_chain! {
|
pub enum Error {
|
||||||
errors {
|
/// The requested OpenGL version is not supported
|
||||||
#[doc = "The requested OpenGL version is not supported"]
|
#[error("The requested OpenGL version {0:?} is not supported")]
|
||||||
OpenGlVersionNotSupported(version: (u8, u8)) {
|
OpenGlVersionNotSupported((u8, u8)),
|
||||||
description("The requested OpenGL version is not supported."),
|
/// The EGL implementation does not support creating OpenGL ES contexts
|
||||||
display("The requested OpenGL version {:?} is not supported.", version),
|
#[error("The EGL implementation does not support creating OpenGL ES contexts")]
|
||||||
}
|
OpenGlesNotSupported,
|
||||||
|
/// No available pixel format matched the criteria
|
||||||
#[doc = "The EGL implementation does not support creating OpenGL ES contexts"]
|
#[error("No available pixel format matched the criteria")]
|
||||||
OpenGlesNotSupported {
|
NoAvailablePixelFormat,
|
||||||
description("The EGL implementation does not support creating OpenGL ES contexts")
|
/// Backend does not match the context type
|
||||||
}
|
#[error("The expected backend '{0:?}' does not match the runtime")]
|
||||||
|
NonMatchingBackend(&'static str),
|
||||||
#[doc = "No available pixel format matched the criteria"]
|
/// Unable to obtain a valid EGL Display
|
||||||
NoAvailablePixelFormat {
|
#[error("Unable to obtain a valid EGL Display")]
|
||||||
description("No available pixel format matched the criteria.")
|
DisplayNotSupported,
|
||||||
}
|
/// `eglInitialize` returned an error
|
||||||
|
#[error("Failed to initialize EGL")]
|
||||||
#[doc = "Backend does not match the context type"]
|
InitFailed,
|
||||||
NonMatchingBackend(expected: &'static str) {
|
/// Failed to configure the EGL context
|
||||||
description("The expected backend did not match the runtime."),
|
#[error("Failed to configure the EGL context")]
|
||||||
display("The expected backend '{:?}' does not match the runtime.", expected),
|
ConfigFailed,
|
||||||
}
|
/// Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements
|
||||||
|
#[error("Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements")]
|
||||||
#[doc = "EGL was unable to obtain a valid EGL Display"]
|
CreationFailed,
|
||||||
DisplayNotSupported {
|
/// `eglCreateWindowSurface` failed
|
||||||
description("EGL was unable to obtain a valid EGL Display")
|
#[error("`eglCreateWindowSurface` failed")]
|
||||||
}
|
SurfaceCreationFailed,
|
||||||
|
/// The required EGL extension is not supported by the underlying EGL implementation
|
||||||
#[doc = "`eglInitialize` returned an error"]
|
#[error("None of the following EGL extensions is supported by the underlying EGL implementation, at least one is required: {0:?}")]
|
||||||
InitFailed {
|
EglExtensionNotSupported(&'static [&'static str]),
|
||||||
description("Failed to initialize EGL")
|
/// Only one EGLDisplay may be bound to a given `WlDisplay` at any time
|
||||||
}
|
#[error("Only one EGLDisplay may be bound to a given `WlDisplay` at any time")]
|
||||||
|
OtherEGLDisplayAlreadyBound,
|
||||||
#[doc = "Failed to configure the EGL context"]
|
/// No EGLDisplay is currently bound to this `WlDisplay`
|
||||||
ConfigFailed {
|
#[error("No EGLDisplay is currently bound to this `WlDisplay`")]
|
||||||
description("Failed to configure the EGL context")
|
NoEGLDisplayBound,
|
||||||
}
|
/// Index of plane is out of bounds for `EGLImages`
|
||||||
|
#[error("Index of plane is out of bounds for `EGLImages`")]
|
||||||
#[doc = "Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements"]
|
PlaneIndexOutOfBounds,
|
||||||
CreationFailed {
|
/// Failed to create `EGLImages` from the buffer
|
||||||
description("Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements")
|
#[error("Failed to create `EGLImages` from the buffer")]
|
||||||
}
|
EGLImageCreationFailed,
|
||||||
|
/// The reason of failure could not be determined
|
||||||
#[doc = "`eglCreateWindowSurface` failed"]
|
#[error("Unknown error: {0}")]
|
||||||
SurfaceCreationFailed {
|
Unknown(u32),
|
||||||
description("Failed to create a new EGLSurface")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "The required EGL extension is not supported by the underlying EGL implementation"]
|
|
||||||
EglExtensionNotSupported(extensions: &'static [&'static str]) {
|
|
||||||
description("The required EGL extension is not supported by the underlying EGL implementation"),
|
|
||||||
display("None of the following EGL extensions is supported by the underlying EGL implementation,
|
|
||||||
at least one is required: {:?}", extensions)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "Only one EGLDisplay may be bound to a given `WlDisplay` at any time"]
|
|
||||||
OtherEGLDisplayAlreadyBound {
|
|
||||||
description("Only one EGLDisplay may be bound to a given WlDisplay at any time")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "No EGLDisplay is currently bound to this `WlDisplay`"]
|
|
||||||
NoEGLDisplayBound {
|
|
||||||
description("No EGLDisplay is currently bound to this WlDisplay")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "Index of plane is out of bounds for `EGLImages`"]
|
|
||||||
PlaneIndexOutOfBounds {
|
|
||||||
description("Index of plane is out of bounds for EGLImages")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "Failed to create `EGLImages` from the buffer"]
|
|
||||||
EGLImageCreationFailed {
|
|
||||||
description("Failed to create EGLImages from the buffer")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "The reason of failure could not be determined"]
|
|
||||||
Unknown(err_no: u32)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,8 @@ use wayland_sys::server::wl_display;
|
||||||
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub use self::context::EGLContext;
|
pub use self::context::EGLContext;
|
||||||
pub mod error;
|
mod error;
|
||||||
use self::error::*;
|
pub use self::error::Error;
|
||||||
|
|
||||||
#[allow(non_camel_case_types, dead_code, unused_mut, non_upper_case_globals)]
|
#[allow(non_camel_case_types, dead_code, unused_mut, non_upper_case_globals)]
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
|
@ -59,27 +59,24 @@ impl fmt::Display for EglExtensionNotSupportedError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::error::Error for EglExtensionNotSupportedError {
|
impl ::std::error::Error for EglExtensionNotSupportedError {}
|
||||||
fn description(&self) -> &str {
|
|
||||||
"The required EGL extension is not supported by the underlying EGL implementation"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&dyn ::std::error::Error> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error that can occur when accessing an EGL buffer
|
/// Error that can occur when accessing an EGL buffer
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
|
#[derive(thiserror::Error)]
|
||||||
pub enum BufferAccessError {
|
pub enum BufferAccessError {
|
||||||
/// The corresponding Context is not alive anymore
|
/// The corresponding Context is not alive anymore
|
||||||
|
#[error("The corresponding context was lost")]
|
||||||
ContextLost,
|
ContextLost,
|
||||||
/// This buffer is not managed by the EGL buffer
|
/// This buffer is not managed by the EGL buffer
|
||||||
|
#[error("This buffer is not managed by EGL")]
|
||||||
NotManaged(WlBuffer),
|
NotManaged(WlBuffer),
|
||||||
/// Failed to create `EGLImages` from the buffer
|
/// Failed to create `EGLImages` from the buffer
|
||||||
|
#[error("Failed to create EGLImages from the buffer")]
|
||||||
EGLImageCreationFailed,
|
EGLImageCreationFailed,
|
||||||
/// The required EGL extension is not supported by the underlying EGL implementation
|
/// The required EGL extension is not supported by the underlying EGL implementation
|
||||||
EglExtensionNotSupported(EglExtensionNotSupportedError),
|
#[error("{0}")]
|
||||||
|
EglExtensionNotSupported(#[from] EglExtensionNotSupportedError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
|
@ -96,49 +93,11 @@ impl fmt::Debug for BufferAccessError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
|
||||||
impl fmt::Display for BufferAccessError {
|
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> ::std::result::Result<(), fmt::Error> {
|
|
||||||
use std::error::Error;
|
|
||||||
match *self {
|
|
||||||
BufferAccessError::ContextLost
|
|
||||||
| BufferAccessError::NotManaged(_)
|
|
||||||
| BufferAccessError::EGLImageCreationFailed => write!(formatter, "{}", self.description()),
|
|
||||||
BufferAccessError::EglExtensionNotSupported(ref err) => err.fmt(formatter),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
|
||||||
impl ::std::error::Error for BufferAccessError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
BufferAccessError::ContextLost => "The corresponding context was lost",
|
|
||||||
BufferAccessError::NotManaged(_) => "This buffer is not managed by EGL",
|
|
||||||
BufferAccessError::EGLImageCreationFailed => "Failed to create EGLImages from the buffer",
|
|
||||||
BufferAccessError::EglExtensionNotSupported(ref err) => err.description(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&dyn ::std::error::Error> {
|
|
||||||
match *self {
|
|
||||||
BufferAccessError::EglExtensionNotSupported(ref err) => Some(err),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
|
||||||
impl From<EglExtensionNotSupportedError> for BufferAccessError {
|
|
||||||
fn from(error: EglExtensionNotSupportedError) -> Self {
|
|
||||||
BufferAccessError::EglExtensionNotSupported(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error that might happen when binding an `EGLImage` to a GL texture
|
/// Error that might happen when binding an `EGLImage` to a GL texture
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
|
||||||
pub enum TextureCreationError {
|
pub enum TextureCreationError {
|
||||||
/// The given plane index is out of bounds
|
/// The given plane index is out of bounds
|
||||||
|
#[error("This buffer is not managed by EGL")]
|
||||||
PlaneIndexOutOfBounds,
|
PlaneIndexOutOfBounds,
|
||||||
/// The OpenGL context has been lost and needs to be recreated.
|
/// The OpenGL context has been lost and needs to be recreated.
|
||||||
///
|
///
|
||||||
|
@ -151,48 +110,18 @@ pub enum TextureCreationError {
|
||||||
/// A context loss usually happens on mobile devices when the user puts the
|
/// A context loss usually happens on mobile devices when the user puts the
|
||||||
/// application on sleep and wakes it up later. However any OpenGL implementation
|
/// application on sleep and wakes it up later. However any OpenGL implementation
|
||||||
/// can theoretically lose the context at any time.
|
/// can theoretically lose the context at any time.
|
||||||
|
#[error("The context has been lost, it needs to be recreated")]
|
||||||
ContextLost,
|
ContextLost,
|
||||||
/// Required OpenGL Extension for texture creation is missing
|
/// Required OpenGL Extension for texture creation is missing
|
||||||
|
#[error("Required OpenGL Extension for texture creation is missing: {0}")]
|
||||||
GLExtensionNotSupported(&'static str),
|
GLExtensionNotSupported(&'static str),
|
||||||
/// Failed to bind the `EGLImage` to the given texture
|
/// Failed to bind the `EGLImage` to the given texture
|
||||||
///
|
///
|
||||||
/// The given argument is the GL error code
|
/// The given argument is the GL error code
|
||||||
|
#[error("Failed to create EGLImages from the buffer (GL error code {0:x}")]
|
||||||
TextureBindingFailed(u32),
|
TextureBindingFailed(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TextureCreationError {
|
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> ::std::result::Result<(), fmt::Error> {
|
|
||||||
use std::error::Error;
|
|
||||||
match *self {
|
|
||||||
TextureCreationError::ContextLost => write!(formatter, "{}", self.description()),
|
|
||||||
TextureCreationError::PlaneIndexOutOfBounds => write!(formatter, "{}", self.description()),
|
|
||||||
TextureCreationError::GLExtensionNotSupported(ext) => {
|
|
||||||
write!(formatter, "{}: {:}", self.description(), ext)
|
|
||||||
}
|
|
||||||
TextureCreationError::TextureBindingFailed(code) => {
|
|
||||||
write!(formatter, "{}. Gl error code: {:?}", self.description(), code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::error::Error for TextureCreationError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
TextureCreationError::ContextLost => "The context has been lost, it needs to be recreated",
|
|
||||||
TextureCreationError::PlaneIndexOutOfBounds => "This buffer is not managed by EGL",
|
|
||||||
TextureCreationError::GLExtensionNotSupported(_) => {
|
|
||||||
"Required OpenGL Extension for texture creation is missing"
|
|
||||||
}
|
|
||||||
TextureCreationError::TextureBindingFailed(_) => "Failed to create EGLImages from the buffer",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&dyn ::std::error::Error> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Texture format types
|
/// Texture format types
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
@ -320,7 +249,7 @@ pub trait EGLGraphicsBackend {
|
||||||
///
|
///
|
||||||
/// This might return [`OtherEGLDisplayAlreadyBound`](ErrorKind::OtherEGLDisplayAlreadyBound)
|
/// This might return [`OtherEGLDisplayAlreadyBound`](ErrorKind::OtherEGLDisplayAlreadyBound)
|
||||||
/// if called for the same [`Display`] multiple times, as only one context may be bound at any given time.
|
/// if called for the same [`Display`] multiple times, as only one context may be bound at any given time.
|
||||||
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay>;
|
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type to receive [`EGLImages`] for EGL-based [`WlBuffer`]s.
|
/// Type to receive [`EGLImages`] for EGL-based [`WlBuffer`]s.
|
||||||
|
@ -525,22 +454,20 @@ impl Drop for EGLDisplay {
|
||||||
|
|
||||||
#[cfg(feature = "use_system_lib")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
impl<E: EGLGraphicsBackend> EGLGraphicsBackend for Rc<E> {
|
impl<E: EGLGraphicsBackend> EGLGraphicsBackend for Rc<E> {
|
||||||
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> {
|
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, Error> {
|
||||||
(**self).bind_wl_display(display)
|
(**self).bind_wl_display(display)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "use_system_lib")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGLContext<B, N> {
|
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGLContext<B, N> {
|
||||||
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> {
|
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, Error> {
|
||||||
if !self.wl_drm_support {
|
if !self.wl_drm_support {
|
||||||
bail!(ErrorKind::EglExtensionNotSupported(&[
|
return Err(Error::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"]));
|
||||||
"EGL_WL_bind_wayland_display"
|
|
||||||
]));
|
|
||||||
}
|
}
|
||||||
let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.c_ptr() as *mut _) };
|
let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.c_ptr() as *mut _) };
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
bail!(ErrorKind::OtherEGLDisplayAlreadyBound);
|
return Err(Error::OtherEGLDisplayAlreadyBound);
|
||||||
}
|
}
|
||||||
Ok(EGLDisplay::new(self, display.c_ptr()))
|
Ok(EGLDisplay::new(self, display.c_ptr()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Type safe native types for safe context/surface creation
|
//! Type safe native types for safe context/surface creation
|
||||||
|
|
||||||
use super::{error::*, ffi};
|
use super::{ffi, Error};
|
||||||
use crate::backend::graphics::SwapBuffersError;
|
use crate::backend::graphics::SwapBuffersError;
|
||||||
|
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
|
@ -105,7 +105,7 @@ pub unsafe trait NativeDisplay<B: Backend> {
|
||||||
/// if the expected [`Backend`] is used at runtime.
|
/// if the expected [`Backend`] is used at runtime.
|
||||||
fn is_backend(&self) -> bool;
|
fn is_backend(&self) -> bool;
|
||||||
/// Return a raw pointer EGL will accept for context creation.
|
/// Return a raw pointer EGL will accept for context creation.
|
||||||
fn ptr(&self) -> Result<ffi::NativeDisplayType>;
|
fn ptr(&self) -> Result<ffi::NativeDisplayType, Error>;
|
||||||
/// Create a surface
|
/// Create a surface
|
||||||
fn create_surface(&mut self, args: Self::Arguments) -> ::std::result::Result<B::Surface, Self::Error>;
|
fn create_surface(&mut self, args: Self::Arguments) -> ::std::result::Result<B::Surface, Self::Error>;
|
||||||
}
|
}
|
||||||
|
@ -119,16 +119,16 @@ unsafe impl NativeDisplay<X11> for WinitWindow {
|
||||||
self.xlib_display().is_some()
|
self.xlib_display().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ptr(&self) -> Result<ffi::NativeDisplayType> {
|
fn ptr(&self) -> Result<ffi::NativeDisplayType, Error> {
|
||||||
self.xlib_display()
|
self.xlib_display()
|
||||||
.map(|ptr| ptr as *const _)
|
.map(|ptr| ptr as *const _)
|
||||||
.ok_or_else(|| ErrorKind::NonMatchingBackend("X11").into())
|
.ok_or_else(|| Error::NonMatchingBackend("X11"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(&mut self, _args: ()) -> Result<XlibWindow> {
|
fn create_surface(&mut self, _args: ()) -> Result<XlibWindow, Error> {
|
||||||
self.xlib_window()
|
self.xlib_window()
|
||||||
.map(XlibWindow)
|
.map(XlibWindow)
|
||||||
.ok_or_else(|| ErrorKind::NonMatchingBackend("X11").into())
|
.ok_or_else(|| Error::NonMatchingBackend("X11"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,20 +141,20 @@ unsafe impl NativeDisplay<Wayland> for WinitWindow {
|
||||||
self.wayland_display().is_some()
|
self.wayland_display().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ptr(&self) -> Result<ffi::NativeDisplayType> {
|
fn ptr(&self) -> Result<ffi::NativeDisplayType, Error> {
|
||||||
self.wayland_display()
|
self.wayland_display()
|
||||||
.map(|ptr| ptr as *const _)
|
.map(|ptr| ptr as *const _)
|
||||||
.ok_or_else(|| ErrorKind::NonMatchingBackend("Wayland").into())
|
.ok_or_else(|| Error::NonMatchingBackend("Wayland"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(&mut self, _args: ()) -> Result<wegl::WlEglSurface> {
|
fn create_surface(&mut self, _args: ()) -> Result<wegl::WlEglSurface, Error> {
|
||||||
if let Some(surface) = self.wayland_surface() {
|
if let Some(surface) = self.wayland_surface() {
|
||||||
let size = self.inner_size();
|
let size = self.inner_size();
|
||||||
Ok(unsafe {
|
Ok(unsafe {
|
||||||
wegl::WlEglSurface::new_from_raw(surface as *mut _, size.width as i32, size.height as i32)
|
wegl::WlEglSurface::new_from_raw(surface as *mut _, size.width as i32, size.height as i32)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::NonMatchingBackend("Wayland"))
|
return Err(Error::NonMatchingBackend("Wayland"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! EGL surface related structs
|
//! EGL surface related structs
|
||||||
|
|
||||||
use super::{error::*, ffi, native, EGLContext};
|
use super::{ffi, native, EGLContext, Error};
|
||||||
use crate::backend::graphics::SwapBuffersError;
|
use crate::backend::graphics::SwapBuffersError;
|
||||||
use nix::libc::c_int;
|
use nix::libc::c_int;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -36,7 +36,7 @@ impl<N: native::NativeSurface> EGLSurface<N> {
|
||||||
pub(crate) fn new<B: native::Backend<Surface = N>, D: native::NativeDisplay<B>>(
|
pub(crate) fn new<B: native::Backend<Surface = N>, D: native::NativeDisplay<B>>(
|
||||||
context: &EGLContext<B, D>,
|
context: &EGLContext<B, D>,
|
||||||
native: N,
|
native: N,
|
||||||
) -> Result<EGLSurface<N>> {
|
) -> Result<EGLSurface<N>, Error> {
|
||||||
let surface = unsafe {
|
let surface = unsafe {
|
||||||
ffi::egl::CreateWindowSurface(
|
ffi::egl::CreateWindowSurface(
|
||||||
*context.display,
|
*context.display,
|
||||||
|
@ -47,7 +47,7 @@ impl<N: native::NativeSurface> EGLSurface<N> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if surface.is_null() {
|
if surface.is_null() {
|
||||||
bail!(ErrorKind::SurfaceCreationFailed);
|
return Err(Error::SurfaceCreationFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(EGLSurface {
|
Ok(EGLSurface {
|
||||||
|
|
|
@ -162,14 +162,14 @@ pub fn auto_session_bind<Data: 'static>(
|
||||||
impl Session for AutoSession {
|
impl Session for AutoSession {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd> {
|
fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd, Error> {
|
||||||
match *self {
|
match *self {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
AutoSession::Logind(ref mut logind) => logind.open(path, flags).map_err(|e| e.into()),
|
AutoSession::Logind(ref mut logind) => logind.open(path, flags).map_err(|e| e.into()),
|
||||||
AutoSession::Direct(ref mut direct) => direct.open(path, flags).map_err(|e| e.into()),
|
AutoSession::Direct(ref mut direct) => direct.open(path, flags).map_err(|e| e.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn close(&mut self, fd: RawFd) -> Result<()> {
|
fn close(&mut self, fd: RawFd) -> Result<(), Error> {
|
||||||
match *self {
|
match *self {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
AutoSession::Logind(ref mut logind) => logind.close(fd).map_err(|e| e.into()),
|
AutoSession::Logind(ref mut logind) => logind.close(fd).map_err(|e| e.into()),
|
||||||
|
@ -177,7 +177,7 @@ impl Session for AutoSession {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_vt(&mut self, vt: i32) -> Result<()> {
|
fn change_vt(&mut self, vt: i32) -> Result<(), Error> {
|
||||||
match *self {
|
match *self {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
AutoSession::Logind(ref mut logind) => logind.change_vt(vt).map_err(|e| e.into()),
|
AutoSession::Logind(ref mut logind) => logind.change_vt(vt).map_err(|e| e.into()),
|
||||||
|
@ -244,21 +244,19 @@ impl BoundAutoSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors related to auto sessions
|
/// Errors related to auto sessions
|
||||||
pub mod errors {
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
use super::logind::errors as logind;
|
/// Logind session error
|
||||||
|
#[error("Logind session error: {0}")]
|
||||||
error_chain! {
|
Logind(#[from] logind::Error),
|
||||||
links {
|
/// Direct session error
|
||||||
Logind(logind::Error, logind::ErrorKind) #[cfg(feature = "backend_session_logind")] #[doc = "Underlying logind session error"];
|
#[error("Direct session error: {0}")]
|
||||||
}
|
Direct(#[from] direct::Error),
|
||||||
|
/// Nix error
|
||||||
foreign_links {
|
#[error("Nix error: {0}")]
|
||||||
Direct(::nix::Error) #[doc = "Underlying direct tty session error"];
|
Nix(#[from] nix::Error),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
use self::errors::*;
|
|
||||||
|
|
||||||
impl AsErrno for Error {
|
impl AsErrno for Error {
|
||||||
fn as_errno(&self) -> Option<i32> {
|
fn as_errno(&self) -> Option<i32> {
|
||||||
|
|
|
@ -83,7 +83,7 @@ pub struct LogindSessionNotifier {
|
||||||
|
|
||||||
impl LogindSession {
|
impl LogindSession {
|
||||||
/// Tries to create a new session via the logind dbus interface.
|
/// Tries to create a new session via the logind dbus interface.
|
||||||
pub fn new<L>(logger: L) -> Result<(LogindSession, LogindSessionNotifier)>
|
pub fn new<L>(logger: L) -> Result<(LogindSession, LogindSessionNotifier), Error>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -91,12 +91,12 @@ impl LogindSession {
|
||||||
.new(o!("smithay_module" => "backend_session", "session_type" => "logind"));
|
.new(o!("smithay_module" => "backend_session", "session_type" => "logind"));
|
||||||
|
|
||||||
// Acquire session_id, seat and vt (if any) via libsystemd
|
// Acquire session_id, seat and vt (if any) via libsystemd
|
||||||
let session_id = login::get_session(None).chain_err(|| ErrorKind::FailedToGetSession)?;
|
let session_id = login::get_session(None).map_err(Error::FailedToGetSession)?;
|
||||||
let seat = login::get_seat(session_id.clone()).chain_err(|| ErrorKind::FailedToGetSeat)?;
|
let seat = login::get_seat(session_id.clone()).map_err(Error::FailedToGetSeat)?;
|
||||||
let vt = login::get_vt(session_id.clone()).ok();
|
let vt = login::get_vt(session_id.clone()).ok();
|
||||||
|
|
||||||
// Create dbus connection
|
// Create dbus connection
|
||||||
let conn = Connection::get_private(BusType::System).chain_err(|| ErrorKind::FailedDbusConnection)?;
|
let conn = Connection::get_private(BusType::System).map_err(Error::FailedDbusConnection)?;
|
||||||
// and get the session path
|
// and get the session path
|
||||||
let session_path = LogindSessionImpl::blocking_call(
|
let session_path = LogindSessionImpl::blocking_call(
|
||||||
&conn,
|
&conn,
|
||||||
|
@ -107,7 +107,7 @@ impl LogindSession {
|
||||||
Some(vec![session_id.clone().into()]),
|
Some(vec![session_id.clone().into()]),
|
||||||
)?
|
)?
|
||||||
.get1::<DbusPath<'static>>()
|
.get1::<DbusPath<'static>>()
|
||||||
.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
.ok_or(Error::UnexpectedMethodReturn)?;
|
||||||
|
|
||||||
// Match all signals that we want to receive and handle
|
// Match all signals that we want to receive and handle
|
||||||
let match1 = String::from(
|
let match1 = String::from(
|
||||||
|
@ -118,7 +118,7 @@ impl LogindSession {
|
||||||
path='/org/freedesktop/login1'",
|
path='/org/freedesktop/login1'",
|
||||||
);
|
);
|
||||||
conn.add_match(&match1)
|
conn.add_match(&match1)
|
||||||
.chain_err(|| ErrorKind::DbusMatchFailed(match1))?;
|
.map_err(|source| Error::DbusMatchFailed(match1, source))?;
|
||||||
let match2 = format!(
|
let match2 = format!(
|
||||||
"type='signal',\
|
"type='signal',\
|
||||||
sender='org.freedesktop.login1',\
|
sender='org.freedesktop.login1',\
|
||||||
|
@ -128,7 +128,7 @@ impl LogindSession {
|
||||||
&session_path
|
&session_path
|
||||||
);
|
);
|
||||||
conn.add_match(&match2)
|
conn.add_match(&match2)
|
||||||
.chain_err(|| ErrorKind::DbusMatchFailed(match2))?;
|
.map_err(|source| Error::DbusMatchFailed(match2, source))?;
|
||||||
let match3 = format!(
|
let match3 = format!(
|
||||||
"type='signal',\
|
"type='signal',\
|
||||||
sender='org.freedesktop.login1',\
|
sender='org.freedesktop.login1',\
|
||||||
|
@ -138,7 +138,7 @@ impl LogindSession {
|
||||||
&session_path
|
&session_path
|
||||||
);
|
);
|
||||||
conn.add_match(&match3)
|
conn.add_match(&match3)
|
||||||
.chain_err(|| ErrorKind::DbusMatchFailed(match3))?;
|
.map_err(|source| Error::DbusMatchFailed(match3, source))?;
|
||||||
let match4 = format!(
|
let match4 = format!(
|
||||||
"type='signal',\
|
"type='signal',\
|
||||||
sender='org.freedesktop.login1',\
|
sender='org.freedesktop.login1',\
|
||||||
|
@ -148,7 +148,7 @@ impl LogindSession {
|
||||||
&session_path
|
&session_path
|
||||||
);
|
);
|
||||||
conn.add_match(&match4)
|
conn.add_match(&match4)
|
||||||
.chain_err(|| ErrorKind::DbusMatchFailed(match4))?;
|
.map_err(|source| Error::DbusMatchFailed(match4, source))?;
|
||||||
|
|
||||||
// Activate (switch to) the session and take control
|
// Activate (switch to) the session and take control
|
||||||
LogindSessionImpl::blocking_call(
|
LogindSessionImpl::blocking_call(
|
||||||
|
@ -209,7 +209,7 @@ impl LogindSessionImpl {
|
||||||
interface: I,
|
interface: I,
|
||||||
method: M,
|
method: M,
|
||||||
arguments: Option<Vec<MessageItem>>,
|
arguments: Option<Vec<MessageItem>>,
|
||||||
) -> Result<Message>
|
) -> Result<Message, Error>
|
||||||
where
|
where
|
||||||
D: Into<BusName<'d>>,
|
D: Into<BusName<'d>>,
|
||||||
P: Into<DbusPath<'p>>,
|
P: Into<DbusPath<'p>>,
|
||||||
|
@ -227,30 +227,29 @@ impl LogindSessionImpl {
|
||||||
message.append_items(&arguments)
|
message.append_items(&arguments)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut message = conn.send_with_reply_and_block(message, 1000).chain_err(|| {
|
let mut message =
|
||||||
ErrorKind::FailedToSendDbusCall(
|
conn.send_with_reply_and_block(message, 1000)
|
||||||
destination.clone(),
|
.map_err(|source| Error::FailedToSendDbusCall {
|
||||||
path.clone(),
|
bus: destination.clone(),
|
||||||
interface.clone(),
|
path: path.clone(),
|
||||||
method.clone(),
|
interface: interface.clone(),
|
||||||
)
|
member: method.clone(),
|
||||||
})?;
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
match message.as_result() {
|
match message.as_result() {
|
||||||
Ok(_) => Ok(message),
|
Ok(_) => Ok(message),
|
||||||
Err(err) => Err(Error::with_chain(
|
Err(err) => Err(Error::DbusCallFailed {
|
||||||
err,
|
bus: destination.clone(),
|
||||||
ErrorKind::DbusCallFailed(
|
path: path.clone(),
|
||||||
destination.clone(),
|
interface: interface.clone(),
|
||||||
path.clone(),
|
member: method.clone(),
|
||||||
interface.clone(),
|
source: err,
|
||||||
method.clone(),
|
}),
|
||||||
),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_signals<I>(&self, signals: I) -> Result<()>
|
fn handle_signals<I>(&self, signals: I) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = ConnectionItem>,
|
I: IntoIterator<Item = ConnectionItem>,
|
||||||
{
|
{
|
||||||
|
@ -278,9 +277,9 @@ impl LogindSessionImpl {
|
||||||
} else if &*message.interface().unwrap() == "org.freedesktop.login1.Session" {
|
} else if &*message.interface().unwrap() == "org.freedesktop.login1.Session" {
|
||||||
if &*message.member().unwrap() == "PauseDevice" {
|
if &*message.member().unwrap() == "PauseDevice" {
|
||||||
let (major, minor, pause_type) = message.get3::<u32, u32, String>();
|
let (major, minor, pause_type) = message.get3::<u32, u32, String>();
|
||||||
let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
let major = major.ok_or(Error::UnexpectedMethodReturn)?;
|
||||||
let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
let minor = minor.ok_or(Error::UnexpectedMethodReturn)?;
|
||||||
let pause_type = pause_type.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
let pause_type = pause_type.ok_or(Error::UnexpectedMethodReturn)?;
|
||||||
debug!(
|
debug!(
|
||||||
self.logger,
|
self.logger,
|
||||||
"Request of type \"{}\" to close device ({},{})", pause_type, major, minor
|
"Request of type \"{}\" to close device ({},{})", pause_type, major, minor
|
||||||
|
@ -306,9 +305,9 @@ impl LogindSessionImpl {
|
||||||
}
|
}
|
||||||
} else if &*message.member().unwrap() == "ResumeDevice" {
|
} else if &*message.member().unwrap() == "ResumeDevice" {
|
||||||
let (major, minor, fd) = message.get3::<u32, u32, OwnedFd>();
|
let (major, minor, fd) = message.get3::<u32, u32, OwnedFd>();
|
||||||
let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
let major = major.ok_or(Error::UnexpectedMethodReturn)?;
|
||||||
let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
let minor = minor.ok_or(Error::UnexpectedMethodReturn)?;
|
||||||
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd();
|
let fd = fd.ok_or(Error::UnexpectedMethodReturn)?.into_fd();
|
||||||
debug!(self.logger, "Reactivating device ({},{})", major, minor);
|
debug!(self.logger, "Reactivating device ({},{})", major, minor);
|
||||||
for signal in &mut *self.signals.borrow_mut() {
|
for signal in &mut *self.signals.borrow_mut() {
|
||||||
if let &mut Some(ref mut signal) = signal {
|
if let &mut Some(ref mut signal) = signal {
|
||||||
|
@ -323,7 +322,7 @@ impl LogindSessionImpl {
|
||||||
|
|
||||||
let (_, changed, _) =
|
let (_, changed, _) =
|
||||||
message.get3::<String, Dict<'_, String, Variant<Iter<'_>>, Iter<'_>>, Array<'_, String, Iter<'_>>>();
|
message.get3::<String, Dict<'_, String, Variant<Iter<'_>>, Iter<'_>>, Array<'_, String, Iter<'_>>>();
|
||||||
let mut changed = changed.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
let mut changed = changed.ok_or(Error::UnexpectedMethodReturn)?;
|
||||||
if let Some((_, mut value)) = changed.find(|&(ref key, _)| &*key == "Active") {
|
if let Some((_, mut value)) = changed.find(|&(ref key, _)| &*key == "Active") {
|
||||||
if let Some(active) = Get::get(&mut value.0) {
|
if let Some(active) = Get::get(&mut value.0) {
|
||||||
self.active.store(active, Ordering::SeqCst);
|
self.active.store(active, Ordering::SeqCst);
|
||||||
|
@ -338,9 +337,9 @@ impl LogindSessionImpl {
|
||||||
impl Session for LogindSession {
|
impl Session for LogindSession {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd> {
|
fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd, Error> {
|
||||||
if let Some(session) = self.internal.upgrade() {
|
if let Some(session) = self.internal.upgrade() {
|
||||||
let stat = stat(path).chain_err(|| ErrorKind::FailedToStatDevice)?;
|
let stat = stat(path).map_err(Error::FailedToStatDevice)?;
|
||||||
// TODO handle paused
|
// TODO handle paused
|
||||||
let (fd, _paused) = LogindSessionImpl::blocking_call(
|
let (fd, _paused) = LogindSessionImpl::blocking_call(
|
||||||
&*session.conn.borrow(),
|
&*session.conn.borrow(),
|
||||||
|
@ -354,16 +353,16 @@ impl Session for LogindSession {
|
||||||
]),
|
]),
|
||||||
)?
|
)?
|
||||||
.get2::<OwnedFd, bool>();
|
.get2::<OwnedFd, bool>();
|
||||||
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd();
|
let fd = fd.ok_or(Error::UnexpectedMethodReturn)?.into_fd();
|
||||||
Ok(fd)
|
Ok(fd)
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::SessionLost)
|
return Err(Error::SessionLost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(&mut self, fd: RawFd) -> Result<()> {
|
fn close(&mut self, fd: RawFd) -> Result<(), Error> {
|
||||||
if let Some(session) = self.internal.upgrade() {
|
if let Some(session) = self.internal.upgrade() {
|
||||||
let stat = fstat(fd).chain_err(|| ErrorKind::FailedToStatDevice)?;
|
let stat = fstat(fd).map_err(Error::FailedToStatDevice)?;
|
||||||
LogindSessionImpl::blocking_call(
|
LogindSessionImpl::blocking_call(
|
||||||
&*session.conn.borrow(),
|
&*session.conn.borrow(),
|
||||||
"org.freedesktop.login1",
|
"org.freedesktop.login1",
|
||||||
|
@ -377,7 +376,7 @@ impl Session for LogindSession {
|
||||||
)
|
)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::SessionLost)
|
return Err(Error::SessionLost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +392,7 @@ impl Session for LogindSession {
|
||||||
self.seat.clone()
|
self.seat.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_vt(&mut self, vt_num: i32) -> Result<()> {
|
fn change_vt(&mut self, vt_num: i32) -> Result<(), Error> {
|
||||||
if let Some(session) = self.internal.upgrade() {
|
if let Some(session) = self.internal.upgrade() {
|
||||||
LogindSessionImpl::blocking_call(
|
LogindSessionImpl::blocking_call(
|
||||||
&*session.conn.borrow_mut(),
|
&*session.conn.borrow_mut(),
|
||||||
|
@ -405,7 +404,7 @@ impl Session for LogindSession {
|
||||||
)
|
)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::SessionLost)
|
return Err(Error::SessionLost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -532,67 +531,53 @@ impl LogindSessionNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors related to logind sessions
|
/// Errors related to logind sessions
|
||||||
pub mod errors {
|
#[derive(thiserror::Error, Debug)]
|
||||||
use dbus::strings::{BusName, Interface, Member, Path as DbusPath};
|
pub enum Error {
|
||||||
|
/// Failed to connect to dbus system socket
|
||||||
error_chain! {
|
#[error("Failed to connect to dbus system socket")]
|
||||||
errors {
|
FailedDbusConnection(#[source] dbus::Error),
|
||||||
#[doc = "Failed to connect to dbus system socket"]
|
/// Failed to get session from logind
|
||||||
FailedDbusConnection {
|
#[error("Failed to get session from logind")]
|
||||||
description("Failed to connect to dbus system socket"),
|
FailedToGetSession(#[source] IoError),
|
||||||
}
|
/// Failed to get seat from logind
|
||||||
|
#[error("Failed to get seat from logind")]
|
||||||
#[doc = "Failed to get session from logind"]
|
FailedToGetSeat(#[source] IoError),
|
||||||
FailedToGetSession {
|
/// Failed to get vt from logind
|
||||||
description("Failed to get session from logind")
|
#[error("Failed to get vt from logind")]
|
||||||
}
|
FailedToGetVT,
|
||||||
|
/// Failed call to a dbus method
|
||||||
#[doc = "Failed to get seat from logind"]
|
#[error("Failed to call dbus method for service: {bus:?}, path: {path:?}, interface: {interface:?}, member: {member:?}")]
|
||||||
FailedToGetSeat {
|
FailedToSendDbusCall {
|
||||||
description("Failed to get seat from logind")
|
bus: BusName<'static>,
|
||||||
}
|
path: DbusPath<'static>,
|
||||||
|
interface: Interface<'static>,
|
||||||
#[doc = "Failed to get vt from logind"]
|
member: Member<'static>,
|
||||||
FailedToGetVT {
|
#[source]
|
||||||
description("Failed to get vt from logind")
|
source: dbus::Error,
|
||||||
}
|
},
|
||||||
|
/// DBus method call failed
|
||||||
#[doc = "Failed to call dbus method"]
|
#[error("Dbus message call failed for service: {bus:?}, path: {path:?}, interface: {interface:?}, member: {member:?}")]
|
||||||
FailedToSendDbusCall(bus: BusName<'static>, path: DbusPath<'static>, interface: Interface<'static>, member: Member<'static>) {
|
DbusCallFailed {
|
||||||
description("Failed to call dbus method")
|
bus: BusName<'static>,
|
||||||
display("Failed to call dbus method for service: {:?}, path: {:?}, interface: {:?}, member: {:?}", bus, path, interface, member),
|
path: DbusPath<'static>,
|
||||||
}
|
interface: Interface<'static>,
|
||||||
|
member: Member<'static>,
|
||||||
#[doc = "Dbus method call failed"]
|
#[source]
|
||||||
DbusCallFailed(bus: BusName<'static>, path: DbusPath<'static>, interface: Interface<'static>, member: Member<'static>) {
|
source: dbus::Error,
|
||||||
description("Dbus method call failed")
|
},
|
||||||
display("Dbus message call failed for service: {:?}, path: {:?}, interface: {:?}, member: {:?}", bus, path, interface, member),
|
/// Dbus method return had unexpected format
|
||||||
}
|
#[error("Dbus method return had unexpected format")]
|
||||||
|
UnexpectedMethodReturn,
|
||||||
#[doc = "Dbus method return had unexpected format"]
|
/// Failed to setup dbus match rule
|
||||||
UnexpectedMethodReturn {
|
#[error("Failed to setup dbus match rule {0}")]
|
||||||
description("Dbus method return returned unexpected format")
|
DbusMatchFailed(String, #[source] dbus::Error),
|
||||||
}
|
/// Failed to stat device
|
||||||
|
#[error("Failed to stat device")]
|
||||||
#[doc = "Failed to setup dbus match rule"]
|
FailedToStatDevice(#[source] nix::Error),
|
||||||
DbusMatchFailed(rule: String) {
|
/// Session is already closed,
|
||||||
description("Failed to setup dbus match rule"),
|
#[error("Session is already closed")]
|
||||||
display("Failed to setup dbus match rule {}", rule),
|
SessionLost,
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "Failed to stat device"]
|
|
||||||
FailedToStatDevice {
|
|
||||||
description("Failed to stat device")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "Session is already closed"]
|
|
||||||
SessionLost {
|
|
||||||
description("Session is already closed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
use self::errors::*;
|
|
||||||
|
|
||||||
impl AsErrno for Error {
|
impl AsErrno for Error {
|
||||||
fn as_errno(&self) -> Option<i32> {
|
fn as_errno(&self) -> Option<i32> {
|
||||||
|
|
|
@ -169,7 +169,7 @@ impl DirectSession {
|
||||||
/// Tries to create a new session via the legacy virtual terminal interface.
|
/// Tries to create a new session via the legacy virtual terminal interface.
|
||||||
///
|
///
|
||||||
/// If you do not provide a tty device path, it will try to open the currently active tty if any.
|
/// If you do not provide a tty device path, it will try to open the currently active tty if any.
|
||||||
pub fn new<L>(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier)>
|
pub fn new<L>(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier), Error>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -183,10 +183,10 @@ impl DirectSession {
|
||||||
fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC,
|
fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC,
|
||||||
Mode::empty(),
|
Mode::empty(),
|
||||||
)
|
)
|
||||||
.chain_err(|| ErrorKind::FailedToOpenTTY(String::from(path.to_string_lossy())))
|
.map_err(|source| Error::FailedToOpenTTY(String::from(path.to_string_lossy()), source))
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
dup(0 /*stdin*/).chain_err(|| ErrorKind::FailedToOpenTTY(String::from("<stdin>")))
|
dup(0 /*stdin*/).map_err(|source| Error::FailedToOpenTTY(String::from("<stdin>"), source))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let active = Arc::new(AtomicBool::new(true));
|
let active = Arc::new(AtomicBool::new(true));
|
||||||
|
@ -215,10 +215,14 @@ impl DirectSession {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_tty(path: Option<&Path>, tty: RawFd, logger: ::slog::Logger) -> Result<(i32, i32, Signal)> {
|
fn setup_tty(
|
||||||
let stat = fstat(tty).chain_err(|| ErrorKind::NotRunningFromTTY)?;
|
path: Option<&Path>,
|
||||||
|
tty: RawFd,
|
||||||
|
logger: ::slog::Logger,
|
||||||
|
) -> Result<(i32, i32, Signal), Error> {
|
||||||
|
let stat = fstat(tty).map_err(|_| Error::NotRunningFromTTY)?;
|
||||||
if !is_tty_device(stat.st_dev, path) {
|
if !is_tty_device(stat.st_dev, path) {
|
||||||
bail!(ErrorKind::NotRunningFromTTY);
|
return Err(Error::NotRunningFromTTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
let vt_num = minor(stat.st_rdev) as i32;
|
let vt_num = minor(stat.st_rdev) as i32;
|
||||||
|
@ -226,24 +230,27 @@ impl DirectSession {
|
||||||
|
|
||||||
let mut mode = 0;
|
let mut mode = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
tty::kd_get_mode(tty, &mut mode).chain_err(|| ErrorKind::NotRunningFromTTY)?;
|
tty::kd_get_mode(tty, &mut mode).map_err(|_| Error::NotRunningFromTTY)?;
|
||||||
}
|
}
|
||||||
if mode != tty::KD_TEXT {
|
if mode != tty::KD_TEXT {
|
||||||
bail!(ErrorKind::TTYAlreadyInGraphicsMode);
|
return Err(Error::TTYAlreadyInGraphicsMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
tty::vt_activate(tty, vt_num as c_int).chain_err(|| ErrorKind::FailedToActivateTTY(vt_num))?;
|
tty::vt_activate(tty, vt_num as c_int)
|
||||||
tty::vt_wait_active(tty, vt_num as c_int).chain_err(|| ErrorKind::FailedToWaitForTTY(vt_num))?;
|
.map_err(|source| Error::FailedToActivateTTY(vt_num, source))?;
|
||||||
|
tty::vt_wait_active(tty, vt_num as c_int)
|
||||||
|
.map_err(|source| Error::FailedToWaitForTTY(vt_num, source))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut old_keyboard_mode = 0;
|
let mut old_keyboard_mode = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
tty::kd_get_kb_mode(tty, &mut old_keyboard_mode)
|
tty::kd_get_kb_mode(tty, &mut old_keyboard_mode)
|
||||||
.chain_err(|| ErrorKind::FailedToSaveTTYState(vt_num))?;
|
.map_err(|source| Error::FailedToSaveTTYState(vt_num, source))?;
|
||||||
tty::kd_set_kb_mode(tty, tty::K_OFF).chain_err(|| ErrorKind::FailedToSetTTYKbMode(vt_num))?;
|
tty::kd_set_kb_mode(tty, tty::K_OFF)
|
||||||
|
.map_err(|source| Error::FailedToSetTTYKbMode(vt_num, source))?;
|
||||||
tty::kd_set_mode(tty, tty::KD_GRAPHICS as i32)
|
tty::kd_set_mode(tty, tty::KD_GRAPHICS as i32)
|
||||||
.chain_err(|| ErrorKind::FailedToSetTTYMode(vt_num))?;
|
.map_err(|source| Error::FailedToSetTTYMode(vt_num, source))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Support realtime signals
|
// TODO: Support realtime signals
|
||||||
|
@ -265,7 +272,7 @@ impl DirectSession {
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
tty::vt_set_mode(tty, &mode).chain_err(|| ErrorKind::FailedToTakeControlOfTTY(vt_num))?;
|
tty::vt_set_mode(tty, &mode).map_err(|source| Error::FailedToTakeControlOfTTY(vt_num, source))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((vt_num, old_keyboard_mode, Signal::SIGUSR2))
|
Ok((vt_num, old_keyboard_mode, Signal::SIGUSR2))
|
||||||
|
@ -440,62 +447,33 @@ pub fn direct_session_bind<Data: 'static>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors related to direct/tty sessions
|
/// Errors related to direct/tty sessions
|
||||||
pub mod errors {
|
#[derive(thiserror::Error, Debug)]
|
||||||
error_chain! {
|
pub enum Error {
|
||||||
errors {
|
/// Failed to open TTY
|
||||||
#[doc = "Failed to open tty"]
|
#[error("Failed to open TTY `{0}`")]
|
||||||
FailedToOpenTTY(path: String) {
|
FailedToOpenTTY(String, #[source] nix::Error),
|
||||||
description("Failed to open tty"),
|
/// Not running from a TTY
|
||||||
display("Failed to open tty ({:?})", path),
|
#[error("Not running from a TTY")]
|
||||||
}
|
NotRunningFromTTY,
|
||||||
|
/// TTY is already in KB_GRAPHICS mode
|
||||||
#[doc = "Not running from a tty"]
|
#[error("The tty is already in graphics mode, is already a compositor running?")]
|
||||||
NotRunningFromTTY {
|
TTYAlreadyInGraphicsMode,
|
||||||
description("Not running from a tty"),
|
/// Failed to activate open tty
|
||||||
}
|
#[error("Failed to activate open tty ({0})")]
|
||||||
|
FailedToActivateTTY(i32, #[source] nix::Error),
|
||||||
#[doc = "tty is already in KB_GRAPHICS mode"]
|
/// Failed to wait for tty to become active
|
||||||
TTYAlreadyInGraphicsMode {
|
#[error("Failed to wait for tty {0} to become active")]
|
||||||
description("The tty is already in KB_GRAPHICS mode"),
|
FailedToWaitForTTY(i32, #[source] nix::Error),
|
||||||
display("The tty is already in graphics mode, is already a compositor running?"),
|
/// Failed to save old tty state
|
||||||
}
|
#[error("Failed to save old tty ({0}) state")]
|
||||||
|
FailedToSaveTTYState(i32, #[source] nix::Error),
|
||||||
#[doc = "Failed to activate open tty"]
|
/// Failed to set tty kb mode
|
||||||
FailedToActivateTTY(num: i32) {
|
#[error("Failed to set tty {0} kb mode to K_OFF")]
|
||||||
description("Failed to activate open tty"),
|
FailedToSetTTYKbMode(i32, #[source] nix::Error),
|
||||||
display("Failed to activate open tty ({:?})", num),
|
/// Failed to set tty mode
|
||||||
}
|
#[error("Failed to set tty {0} mode into graphics mode")]
|
||||||
|
FailedToSetTTYMode(i32, #[source] nix::Error),
|
||||||
#[doc = "Failed to wait for tty to become active"]
|
/// Failed to set tty in process mode
|
||||||
FailedToWaitForTTY(num: i32) {
|
#[error("Failed to take control of tty {0}")]
|
||||||
description("Failed to wait for tty to become active"),
|
FailedToTakeControlOfTTY(i32, #[source] nix::Error),
|
||||||
display("Failed to wait for tty ({:?}) to become active", num),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "Failed to save old tty state"]
|
|
||||||
FailedToSaveTTYState(num: i32) {
|
|
||||||
description("Failed to save old tty state"),
|
|
||||||
display("Failed to save old tty ({:?}) state", num),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "Failed to set tty kb mode"]
|
|
||||||
FailedToSetTTYKbMode(num: i32) {
|
|
||||||
description("Failed to set tty kb mode to K_OFF"),
|
|
||||||
display("Failed to set tty ({:?}) kb mode to K_OFF", num),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "Failed to set tty mode"]
|
|
||||||
FailedToSetTTYMode(num: i32) {
|
|
||||||
description("Failed to set tty mode to KD_GRAPHICS"),
|
|
||||||
display("Failed to set tty ({:?}) mode into graphics mode", num),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = "Failed to set tty in process mode"]
|
|
||||||
FailedToTakeControlOfTTY(num: i32) {
|
|
||||||
description("Failed to set tty mode to VT_PROCESS"),
|
|
||||||
display("Failed to take control of tty ({:?})", num),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
use self::errors::*;
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
use crate::backend::{
|
use crate::backend::{
|
||||||
egl::{
|
egl::{
|
||||||
context::GlAttributes, error::Result as EGLResult, native, EGLContext, EGLDisplay,
|
context::GlAttributes, native, EGLContext, EGLDisplay, EGLGraphicsBackend, EGLSurface,
|
||||||
EGLGraphicsBackend, EGLSurface,
|
Error as EGLError,
|
||||||
},
|
},
|
||||||
graphics::{gl::GLGraphicsBackend, CursorBackend, PixelFormat, SwapBuffersError},
|
graphics::{gl::GLGraphicsBackend, CursorBackend, PixelFormat, SwapBuffersError},
|
||||||
input::{
|
input::{
|
||||||
|
@ -16,7 +16,7 @@ use crate::backend::{
|
||||||
use nix::libc::c_void;
|
use nix::libc::c_void;
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell},
|
cell::{Ref, RefCell},
|
||||||
cmp, fmt,
|
cmp,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
@ -34,28 +34,18 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Errors thrown by the `winit` backends
|
/// Errors thrown by the `winit` backends
|
||||||
pub mod errors {
|
#[derive(thiserror::Error, Debug)]
|
||||||
use crate::backend::egl::error as egl_error;
|
pub enum Error {
|
||||||
|
/// Failed to initialize a window
|
||||||
error_chain! {
|
#[error("Failed to initialize a window")]
|
||||||
errors {
|
InitFailed(#[from] winit::error::OsError),
|
||||||
#[doc = "Failed to initialize a window"]
|
/// Context creation is not supported on the current window system
|
||||||
InitFailed {
|
#[error("Context creation is not supported on the current window system")]
|
||||||
description("Failed to initialize a window")
|
NotSupported,
|
||||||
}
|
/// EGL error
|
||||||
|
#[error("EGL error: {0}")]
|
||||||
#[doc = "Context creation is not supported on the current window system"]
|
EGL(#[from] EGLError),
|
||||||
NotSupported {
|
|
||||||
description("Context creation is not supported on the current window system.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
links {
|
|
||||||
EGL(egl_error::Error, egl_error::ErrorKind) #[doc = "EGL error"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
use self::errors::*;
|
|
||||||
|
|
||||||
enum Window {
|
enum Window {
|
||||||
Wayland {
|
Wayland {
|
||||||
|
@ -110,7 +100,7 @@ pub struct WinitInputBackend {
|
||||||
/// Create a new [`WinitGraphicsBackend`], which implements the [`EGLGraphicsBackend`]
|
/// Create a new [`WinitGraphicsBackend`], which implements the [`EGLGraphicsBackend`]
|
||||||
/// and [`GLGraphicsBackend`] graphics backend trait and a corresponding [`WinitInputBackend`],
|
/// and [`GLGraphicsBackend`] graphics backend trait and a corresponding [`WinitInputBackend`],
|
||||||
/// which implements the [`InputBackend`] trait
|
/// which implements the [`InputBackend`] trait
|
||||||
pub fn init<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend)>
|
pub fn init<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -129,7 +119,7 @@ where
|
||||||
pub fn init_from_builder<L>(
|
pub fn init_from_builder<L>(
|
||||||
builder: WindowBuilder,
|
builder: WindowBuilder,
|
||||||
logger: L,
|
logger: L,
|
||||||
) -> Result<(WinitGraphicsBackend, WinitInputBackend)>
|
) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -153,7 +143,7 @@ pub fn init_from_builder_with_gl_attr<L>(
|
||||||
builder: WindowBuilder,
|
builder: WindowBuilder,
|
||||||
attributes: GlAttributes,
|
attributes: GlAttributes,
|
||||||
logger: L,
|
logger: L,
|
||||||
) -> Result<(WinitGraphicsBackend, WinitInputBackend)>
|
) -> Result<(WinitGraphicsBackend, WinitInputBackend), Error>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -161,7 +151,7 @@ where
|
||||||
info!(log, "Initializing a winit backend");
|
info!(log, "Initializing a winit backend");
|
||||||
|
|
||||||
let events_loop = EventLoop::new();
|
let events_loop = EventLoop::new();
|
||||||
let winit_window = builder.build(&events_loop).chain_err(|| ErrorKind::InitFailed)?;
|
let winit_window = builder.build(&events_loop).map_err(Error::InitFailed)?;
|
||||||
|
|
||||||
debug!(log, "Window created");
|
debug!(log, "Window created");
|
||||||
|
|
||||||
|
@ -178,7 +168,7 @@ where
|
||||||
let surface = context.create_surface(())?;
|
let surface = context.create_surface(())?;
|
||||||
Window::X11 { context, surface }
|
Window::X11 { context, surface }
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::NotSupported);
|
return Err(Error::NotSupported);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -316,7 +306,7 @@ impl GLGraphicsBackend for WinitGraphicsBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EGLGraphicsBackend for WinitGraphicsBackend {
|
impl EGLGraphicsBackend for WinitGraphicsBackend {
|
||||||
fn bind_wl_display(&self, display: &Display) -> EGLResult<EGLDisplay> {
|
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay, EGLError> {
|
||||||
match *self.window {
|
match *self.window {
|
||||||
Window::Wayland { ref context, .. } => context.bind_wl_display(display),
|
Window::Wayland { ref context, .. } => context.bind_wl_display(display),
|
||||||
Window::X11 { ref context, .. } => context.bind_wl_display(display),
|
Window::X11 { ref context, .. } => context.bind_wl_display(display),
|
||||||
|
@ -325,28 +315,15 @@ impl EGLGraphicsBackend for WinitGraphicsBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors that may happen when driving the event loop of [`WinitInputBackend`]
|
/// Errors that may happen when driving the event loop of [`WinitInputBackend`]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
|
||||||
pub enum WinitInputError {
|
pub enum WinitInputError {
|
||||||
/// The underlying [`WinitWindow`] was closed. No further events can be processed.
|
/// The underlying [`WinitWindow`] was closed. No further events can be processed.
|
||||||
///
|
///
|
||||||
/// See `dispatch_new_events`.
|
/// See `dispatch_new_events`.
|
||||||
|
#[error("Winit window was closed")]
|
||||||
WindowClosed,
|
WindowClosed,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::error::Error for WinitInputError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
WinitInputError::WindowClosed => "Glutin Window was closed",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for WinitInputError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
use std::error::Error;
|
|
||||||
write!(f, "{}", self.description())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
/// Winit-Backend internal event wrapping `winit`'s types into a [`KeyboardKeyEvent`]
|
/// Winit-Backend internal event wrapping `winit`'s types into a [`KeyboardKeyEvent`]
|
||||||
pub struct WinitKeyboardInputEvent {
|
pub struct WinitKeyboardInputEvent {
|
||||||
|
|
|
@ -13,8 +13,6 @@ pub extern crate nix;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate slog;
|
extern crate slog;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate error_chain;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
|
Loading…
Reference in New Issue