Merge branch 'Smithay:master' into master

This commit is contained in:
Victor Timofei 2022-01-05 20:59:38 +02:00 committed by GitHub
commit 77fdd1883e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 464 additions and 360 deletions

View File

@ -73,6 +73,7 @@
- EGLBufferReader now checks if buffers are alive before using them. - EGLBufferReader now checks if buffers are alive before using them.
- LibSeat no longer panics on seat disable event. - LibSeat no longer panics on seat disable event.
- X11 backend will report an error when trying to present a dmabuf fails.
### Anvil ### Anvil

View File

@ -166,13 +166,13 @@ pub fn run_x11(log: Logger) {
event_loop event_loop
.handle() .handle()
.insert_source(backend, |event, _window, state| match event { .insert_source(backend, |event, _, state| match event {
X11Event::CloseRequested => { X11Event::CloseRequested { .. } => {
state.running.store(false, Ordering::SeqCst); state.running.store(false, Ordering::SeqCst);
} }
X11Event::Resized(size) => { X11Event::Resized { new_size, .. } => {
let size = { (size.w as i32, size.h as i32).into() }; let size = { (new_size.w as i32, new_size.h as i32).into() };
state.backend_data.mode = Mode { state.backend_data.mode = Mode {
size, size,
@ -193,7 +193,7 @@ pub fn run_x11(log: Logger) {
state.backend_data.render = true; state.backend_data.render = true;
} }
X11Event::PresentCompleted | X11Event::Refresh => { X11Event::PresentCompleted { .. } | X11Event::Refresh { .. } => {
state.backend_data.render = true; state.backend_data.render = true;
} }

View File

@ -354,7 +354,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
source, source,
})?; })?;
let test_fb = self.create_test_buffer(pending.mode.size())?; let test_fb = self.create_test_buffer(mode.size())?;
let req = self.build_request( let req = self.build_request(
&mut pending.connectors.iter(), &mut pending.connectors.iter(),
&mut [].iter(), &mut [].iter(),

View File

@ -309,8 +309,11 @@ where
/// Fails if the mode is not compatible with the underlying /// Fails if the mode is not compatible with the underlying
/// [`crtc`](drm::control::crtc) or any of the /// [`crtc`](drm::control::crtc) or any of the
/// pending [`connector`](drm::control::connector)s. /// pending [`connector`](drm::control::connector)s.
pub fn use_mode(&self, mode: Mode) -> Result<(), Error> { pub fn use_mode(&mut self, mode: Mode) -> Result<(), Error> {
self.drm.use_mode(mode).map_err(Error::DrmError) self.drm.use_mode(mode).map_err(Error::DrmError)?;
let (w, h) = mode.size();
self.swapchain.resize(w as _, h as _);
Ok(())
} }
} }

View File

@ -115,7 +115,7 @@ pub enum SwapBuffersError {
/// Operations will have no effect. Functions that read textures, buffers, etc. /// Operations will have no effect. Functions that read textures, buffers, etc.
/// will return uninitialized data instead. /// will return uninitialized data instead.
#[error("The context has been lost, it needs to be recreated: {0}")] #[error("The context has been lost, it needs to be recreated: {0}")]
ContextLost(Box<dyn std::error::Error>), ContextLost(Box<dyn std::error::Error + Send + Sync>),
/// A temporary condition caused to rendering to fail. /// A temporary condition caused to rendering to fail.
/// ///
/// Depending on the underlying error this *might* require fixing internal state of the rendering backend, /// Depending on the underlying error this *might* require fixing internal state of the rendering backend,
@ -126,5 +126,5 @@ pub enum SwapBuffersError {
/// If the root cause cannot be discovered and subsequent renderings also fail, it is advised to fallback to /// If the root cause cannot be discovered and subsequent renderings also fail, it is advised to fallback to
/// recreation. /// recreation.
#[error("A temporary condition caused the page flip to fail: {0}")] #[error("A temporary condition caused the page flip to fail: {0}")]
TemporaryFailure(Box<dyn std::error::Error>), TemporaryFailure(Box<dyn std::error::Error + Send + Sync>),
} }

View File

@ -29,54 +29,23 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use super::{Window, X11Error}; use super::{PresentError, Window, X11Error};
use drm_fourcc::DrmFourcc; use drm_fourcc::DrmFourcc;
use nix::fcntl; use nix::fcntl;
use x11rb::connection::Connection; use x11rb::{
use x11rb::protocol::dri3::ConnectionExt as _; connection::Connection,
use x11rb::protocol::present::{self, ConnectionExt}; protocol::{
use x11rb::protocol::xproto::PixmapWrapper; dri3::ConnectionExt as _,
use x11rb::rust_connection::{ConnectionError, ReplyOrIdError}; present::{self, ConnectionExt},
use x11rb::utils::RawFdContainer; xproto::PixmapWrapper,
},
utils::RawFdContainer,
};
use crate::backend::allocator::dmabuf::Dmabuf; use crate::backend::allocator::{dmabuf::Dmabuf, Buffer};
use crate::backend::allocator::Buffer;
// Shm can be easily supported in the future using, xcb_shm_create_pixmap. // Shm can be easily supported in the future using, xcb_shm_create_pixmap.
#[derive(Debug, thiserror::Error)]
pub enum CreatePixmapError {
#[error("An x11 protocol error occured")]
Protocol(X11Error),
#[error("The Dmabuf had too many planes")]
TooManyPlanes,
#[error("Duplicating the file descriptors for the dmabuf handles failed")]
DupFailed(String),
#[error("Buffer had incorrect format, expected: {0}")]
IncorrectFormat(DrmFourcc),
}
impl From<X11Error> for CreatePixmapError {
fn from(e: X11Error) -> Self {
CreatePixmapError::Protocol(e)
}
}
impl From<ReplyOrIdError> for CreatePixmapError {
fn from(e: ReplyOrIdError) -> Self {
X11Error::from(e).into()
}
}
impl From<ConnectionError> for CreatePixmapError {
fn from(e: ConnectionError) -> Self {
X11Error::from(e).into()
}
}
pub trait PixmapWrapperExt<'c, C> pub trait PixmapWrapperExt<'c, C>
where where
C: Connection, C: Connection,
@ -88,7 +57,7 @@ where
connection: &'c C, connection: &'c C,
window: &Window, window: &Window,
dmabuf: &Dmabuf, dmabuf: &Dmabuf,
) -> Result<PixmapWrapper<'c, C>, CreatePixmapError>; ) -> Result<PixmapWrapper<'c, C>, X11Error>;
/// Presents the pixmap to the window. /// Presents the pixmap to the window.
/// ///
@ -108,9 +77,9 @@ where
connection: &'c C, connection: &'c C,
window: &Window, window: &Window,
dmabuf: &Dmabuf, dmabuf: &Dmabuf,
) -> Result<PixmapWrapper<'c, C>, CreatePixmapError> { ) -> Result<PixmapWrapper<'c, C>, X11Error> {
if dmabuf.format().code != window.format() { if dmabuf.format().code != window.format() {
return Err(CreatePixmapError::IncorrectFormat(window.format())); return Err(PresentError::IncorrectFormat(window.format()).into());
} }
let mut fds = Vec::new(); let mut fds = Vec::new();
@ -121,7 +90,7 @@ where
handle, handle,
fcntl::FcntlArg::F_DUPFD_CLOEXEC(3), // Set to 3 so the fd cannot become stdin, stdout or stderr fcntl::FcntlArg::F_DUPFD_CLOEXEC(3), // Set to 3 so the fd cannot become stdin, stdout or stderr
) )
.map_err(|e| CreatePixmapError::DupFailed(e.to_string()))?; .map_err(|e| PresentError::DupFailed(e.to_string()))?;
fds.push(RawFdContainer::new(fd)) fds.push(RawFdContainer::new(fd))
} }
@ -129,7 +98,7 @@ where
// We need dri3 >= 1.2 in order to use the enhanced dri3_pixmap_from_buffers function. // We need dri3 >= 1.2 in order to use the enhanced dri3_pixmap_from_buffers function.
let xid = if window.0.extensions.dri3 >= Some((1, 2)) { let xid = if window.0.extensions.dri3 >= Some((1, 2)) {
if dmabuf.num_planes() > 4 { if dmabuf.num_planes() > 4 {
return Err(CreatePixmapError::TooManyPlanes); return Err(PresentError::TooManyPlanes.into());
} }
let xid = connection.generate_id()?; let xid = connection.generate_id()?;
@ -165,7 +134,7 @@ where
} else { } else {
// Old codepath can only create a pixmap using one plane from a dmabuf. // Old codepath can only create a pixmap using one plane from a dmabuf.
if dmabuf.num_planes() != 1 { if dmabuf.num_planes() != 1 {
return Err(CreatePixmapError::TooManyPlanes); return Err(PresentError::TooManyPlanes.into());
} }
let xid = connection.generate_id()?; let xid = connection.generate_id()?;

View File

@ -6,24 +6,26 @@ use x11rb::rust_connection::{ConnectError, ConnectionError, ReplyError, ReplyOrI
use crate::backend::{allocator::gbm::GbmConvertError, drm::CreateDrmNodeError}; use crate::backend::{allocator::gbm::GbmConvertError, drm::CreateDrmNodeError};
use super::PresentError;
/// An error emitted by the X11 backend during setup. /// An error emitted by the X11 backend during setup.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum X11Error { pub enum X11Error {
/// Connecting to the X server failed. /// Connecting to the X server failed.
#[error("Connecting to the X server failed")] #[error("Connecting to the X server failed")]
ConnectionFailed(ConnectError), ConnectionFailed(#[from] ConnectError),
/// A required X11 extension was not present or has the right version. /// A required X11 extension was not present or has the right version.
#[error("{0}")] #[error("{0}")]
MissingExtension(MissingExtensionError), MissingExtension(#[from] MissingExtensionError),
/// Some protocol error occurred during setup. /// Some protocol error occurred during setup.
#[error("Some protocol error occurred during setup")] #[error("Some protocol error occurred during setup")]
Protocol(ReplyOrIdError), Protocol(#[from] ReplyOrIdError),
/// Creating the window failed. /// Creating the window failed.
#[error("Creating the window failed")] #[error("Creating the window failed")]
CreateWindow(CreateWindowError), CreateWindow(#[from] CreateWindowError),
/// An X11 surface already exists for this window. /// An X11 surface already exists for this window.
#[error("An X11 surface already exists for this window")] #[error("An X11 surface already exists for this window")]
@ -42,13 +44,11 @@ pub enum X11Error {
/// Failed to allocate buffers needed to present to the window. /// Failed to allocate buffers needed to present to the window.
#[error("Failed to allocate buffers needed to present to the window")] #[error("Failed to allocate buffers needed to present to the window")]
Allocation(AllocateBuffersError), Allocation(#[from] AllocateBuffersError),
}
impl From<ConnectError> for X11Error { /// Error while presenting to a window.
fn from(err: ConnectError) -> Self { #[error(transparent)]
Self::ConnectionFailed(err) Present(#[from] PresentError),
}
} }
impl From<ReplyError> for X11Error { impl From<ReplyError> for X11Error {
@ -63,12 +63,6 @@ impl From<ConnectionError> for X11Error {
} }
} }
impl From<ReplyOrIdError> for X11Error {
fn from(err: ReplyOrIdError) -> Self {
Self::Protocol(err)
}
}
/// An error that occurs when a required X11 extension is not present. /// An error that occurs when a required X11 extension is not present.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum MissingExtensionError { pub enum MissingExtensionError {
@ -99,12 +93,6 @@ pub enum MissingExtensionError {
}, },
} }
impl From<MissingExtensionError> for X11Error {
fn from(err: MissingExtensionError) -> Self {
Self::MissingExtension(err)
}
}
/// An error which may occur when creating an X11 window. /// An error which may occur when creating an X11 window.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum CreateWindowError { pub enum CreateWindowError {
@ -117,12 +105,6 @@ pub enum CreateWindowError {
NoVisual, NoVisual,
} }
impl From<CreateWindowError> for X11Error {
fn from(err: CreateWindowError) -> Self {
Self::CreateWindow(err)
}
}
/// An error which may occur when allocating buffers for presentation to the window. /// An error which may occur when allocating buffers for presentation to the window.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum AllocateBuffersError { pub enum AllocateBuffersError {
@ -165,9 +147,3 @@ impl From<CreateDrmNodeError> for AllocateBuffersError {
} }
} }
} }
impl From<AllocateBuffersError> for X11Error {
fn from(err: AllocateBuffersError) -> Self {
Self::Allocation(err)
}
}

View File

@ -1,5 +1,6 @@
//! Input backend implementation for the X11 backend. //! Input backend implementation for the X11 backend.
use super::{window_inner::WindowInner, Window, WindowTemporary};
use crate::{ use crate::{
backend::input::{ backend::input::{
self, Axis, AxisSource, ButtonState, Device, DeviceCapability, InputBackend, KeyState, self, Axis, AxisSource, ButtonState, Device, DeviceCapability, InputBackend, KeyState,
@ -7,6 +8,7 @@ use crate::{
}, },
utils::{Logical, Size}, utils::{Logical, Size},
}; };
use std::sync::Weak;
/// Marker used to define the `InputBackend` types for the X11 backend. /// Marker used to define the `InputBackend` types for the X11 backend.
#[derive(Debug)] #[derive(Debug)]
@ -43,12 +45,22 @@ impl Device for X11VirtualDevice {
/// X11-Backend internal event wrapping `X11`'s types into a [`KeyboardKeyEvent`]. /// X11-Backend internal event wrapping `X11`'s types into a [`KeyboardKeyEvent`].
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone)]
pub struct X11KeyboardInputEvent { pub struct X11KeyboardInputEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) key: u32, pub(crate) key: u32,
pub(crate) count: u32, pub(crate) count: u32,
pub(crate) state: KeyState, pub(crate) state: KeyState,
pub(crate) window: Weak<WindowInner>,
}
impl X11KeyboardInputEvent {
/// Returns a temporary reference to the window belonging to this event.
///
/// Returns None if the window is not alive anymore.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
self.window.upgrade().map(Window).map(WindowTemporary)
}
} }
impl input::Event<X11Input> for X11KeyboardInputEvent { impl input::Event<X11Input> for X11KeyboardInputEvent {
@ -77,11 +89,21 @@ impl KeyboardKeyEvent<X11Input> for X11KeyboardInputEvent {
/// X11-Backend internal event wrapping `X11`'s types into a [`PointerAxisEvent`] /// X11-Backend internal event wrapping `X11`'s types into a [`PointerAxisEvent`]
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone)]
pub struct X11MouseWheelEvent { pub struct X11MouseWheelEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) axis: Axis, pub(crate) axis: Axis,
pub(crate) amount: f64, pub(crate) amount: f64,
pub(crate) window: Weak<WindowInner>,
}
impl X11MouseWheelEvent {
/// Returns a temporary reference to the window belonging to this event.
///
/// Returns None if the window is not alive anymore.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
self.window.upgrade().map(Window).map(WindowTemporary)
}
} }
impl input::Event<X11Input> for X11MouseWheelEvent { impl input::Event<X11Input> for X11MouseWheelEvent {
@ -115,11 +137,21 @@ impl PointerAxisEvent<X11Input> for X11MouseWheelEvent {
/// X11-Backend internal event wrapping `X11`'s types into a [`PointerButtonEvent`] /// X11-Backend internal event wrapping `X11`'s types into a [`PointerButtonEvent`]
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone)]
pub struct X11MouseInputEvent { pub struct X11MouseInputEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) raw: u32, pub(crate) raw: u32,
pub(crate) state: ButtonState, pub(crate) state: ButtonState,
pub(crate) window: Weak<WindowInner>,
}
impl X11MouseInputEvent {
/// Returns a temporary reference to the window belonging to this event.
///
/// Returns None if the window is not alive anymore.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
self.window.upgrade().map(Window).map(WindowTemporary)
}
} }
impl input::Event<X11Input> for X11MouseInputEvent { impl input::Event<X11Input> for X11MouseInputEvent {
@ -144,12 +176,22 @@ impl PointerButtonEvent<X11Input> for X11MouseInputEvent {
/// X11-Backend internal event wrapping `X11`'s types into a [`PointerMotionAbsoluteEvent`] /// X11-Backend internal event wrapping `X11`'s types into a [`PointerMotionAbsoluteEvent`]
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone)]
pub struct X11MouseMovedEvent { pub struct X11MouseMovedEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) x: f64, pub(crate) x: f64,
pub(crate) y: f64, pub(crate) y: f64,
pub(crate) size: Size<u16, Logical>, pub(crate) size: Size<u16, Logical>,
pub(crate) window: Weak<WindowInner>,
}
impl X11MouseMovedEvent {
/// Returns a temporary reference to the window belonging to this event.
///
/// Returns None if the window is not alive anymore.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
self.window.upgrade().map(Window).map(WindowTemporary)
}
} }
impl input::Event<X11Input> for X11MouseMovedEvent { impl input::Event<X11Input> for X11MouseMovedEvent {

View File

@ -79,15 +79,12 @@ mod error;
#[macro_use] #[macro_use]
mod extension; mod extension;
mod input; mod input;
mod surface;
mod window_inner; mod window_inner;
use self::{buffer::PixmapWrapperExt, window_inner::WindowInner};
use crate::{ use crate::{
backend::{ backend::{
allocator::{ allocator::Swapchain,
dmabuf::{AsDmabuf, Dmabuf},
Slot, Swapchain,
},
drm::{node::path_to_type, CreateDrmNodeError, DrmNode, NodeType}, drm::{node::path_to_type, CreateDrmNodeError, DrmNode, NodeType},
egl::{native::X11DefaultDisplay, EGLDevice, EGLDisplay, Error as EGLError}, egl::{native::X11DefaultDisplay, EGLDevice, EGLDisplay, Error as EGLError},
input::{Axis, ButtonState, InputEvent, KeyState}, input::{Axis, ButtonState, InputEvent, KeyState},
@ -96,7 +93,6 @@ use crate::{
}; };
use calloop::{EventSource, Poll, PostAction, Readiness, Token, TokenFactory}; use calloop::{EventSource, Poll, PostAction, Readiness, Token, TokenFactory};
use drm_fourcc::{DrmFourcc, DrmModifier}; use drm_fourcc::{DrmFourcc, DrmModifier};
use gbm::BufferObject;
use nix::{ use nix::{
fcntl::{self, OFlag}, fcntl::{self, OFlag},
sys::stat::Mode, sys::stat::Mode,
@ -104,12 +100,11 @@ use nix::{
use slog::{error, info, o, Logger}; use slog::{error, info, o, Logger};
use std::{ use std::{
collections::HashMap, collections::HashMap,
io, mem, io,
os::unix::prelude::AsRawFd, os::unix::prelude::AsRawFd,
sync::{ sync::{
atomic::{AtomicU32, Ordering}, atomic::{AtomicU32, Ordering},
mpsc::{self, Receiver}, mpsc, Arc, Mutex, Weak,
Arc, Mutex, MutexGuard, Weak,
}, },
}; };
use x11rb::{ use x11rb::{
@ -118,38 +113,51 @@ use x11rb::{
protocol::{ protocol::{
self as x11, self as x11,
dri3::ConnectionExt as _, dri3::ConnectionExt as _,
xproto::{ xproto::{ColormapAlloc, ConnectionExt, CreateWindowAux, VisualClass, WindowClass, WindowWrapper},
ColormapAlloc, ConnectionExt, CreateWindowAux, PixmapWrapper, VisualClass, WindowClass,
WindowWrapper,
},
ErrorKind, ErrorKind,
}, },
rust_connection::{ReplyError, RustConnection}, rust_connection::{ReplyError, RustConnection},
}; };
use self::{extension::Extensions, window_inner::WindowInner};
pub use self::error::*; pub use self::error::*;
use self::extension::Extensions;
pub use self::input::*; pub use self::input::*;
pub use self::surface::*;
/// An event emitted by the X11 backend. /// An event emitted by the X11 backend.
#[derive(Debug)] #[derive(Debug)]
pub enum X11Event { pub enum X11Event {
/// The X server has required the compositor to redraw the contents of window. /// The X server has required the compositor to redraw the contents of window.
Refresh, Refresh {
/// XID of the window
window_id: u32,
},
/// An input event occurred. /// An input event occurred.
Input(InputEvent<X11Input>), Input(InputEvent<X11Input>),
/// The window was resized. /// The window was resized.
Resized(Size<u16, Logical>), Resized {
/// The new size of the window
new_size: Size<u16, Logical>,
/// XID of the window
window_id: u32,
},
/// The last buffer presented to the window has been displayed. /// The last buffer presented to the window has been displayed.
/// ///
/// When this event is scheduled, the next frame may be rendered. /// When this event is scheduled, the next frame may be rendered.
PresentCompleted, PresentCompleted {
/// XID of the window
window_id: u32,
},
/// The window has received a request to be closed. /// The window has received a request to be closed.
CloseRequested, CloseRequested {
/// XID of the window
window_id: u32,
},
} }
/// Represents an active connection to the X to manage events on the Window provided by the backend. /// Represents an active connection to the X to manage events on the Window provided by the backend.
@ -161,16 +169,6 @@ pub struct X11Backend {
inner: Arc<Mutex<X11Inner>>, inner: Arc<Mutex<X11Inner>>,
} }
atom_manager! {
pub(crate) Atoms: AtomCollectionCookie {
WM_PROTOCOLS,
WM_DELETE_WINDOW,
_NET_WM_NAME,
UTF8_STRING,
_SMITHAY_X11_BACKEND_CLOSE,
}
}
impl X11Backend { impl X11Backend {
/// Initializes the X11 backend by connecting to the X server. /// Initializes the X11 backend by connecting to the X server.
pub fn new<L>(logger: L) -> Result<X11Backend, X11Error> pub fn new<L>(logger: L) -> Result<X11Backend, X11Error>
@ -257,6 +255,7 @@ impl X11Backend {
atoms, atoms,
depth, depth,
visual_id, visual_id,
devices: false,
}; };
Ok(X11Backend { Ok(X11Backend {
@ -277,19 +276,6 @@ impl X11Backend {
} }
} }
/// An X11 surface which uses GBM to allocate and present buffers.
#[derive(Debug)]
pub struct X11Surface {
connection: Weak<RustConnection>,
window: Weak<WindowInner>,
resize: Receiver<Size<u16, Logical>>,
swapchain: Swapchain<Arc<Mutex<gbm::Device<DrmNode>>>, BufferObject<()>>,
format: DrmFourcc,
width: u16,
height: u16,
buffer: Option<Slot<BufferObject<()>>>,
}
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
enum EGLInitError { enum EGLInitError {
#[error(transparent)] #[error(transparent)]
@ -298,81 +284,6 @@ enum EGLInitError {
IO(#[from] io::Error), IO(#[from] io::Error),
} }
fn egl_init(_: &X11Inner) -> Result<DrmNode, EGLInitError> {
let display = EGLDisplay::new(&X11DefaultDisplay, None)?;
let device = EGLDevice::device_for_display(&display)?;
let path = path_to_type(device.drm_device_path()?, NodeType::Render)?;
fcntl::open(&path, OFlag::O_RDWR | OFlag::O_CLOEXEC, Mode::empty())
.map_err(Into::<io::Error>::into)
.and_then(|fd| {
DrmNode::from_fd(fd).map_err(|err| match err {
CreateDrmNodeError::Io(err) => err,
_ => unreachable!(),
})
})
.map_err(EGLInitError::IO)
}
fn dri3_init(x11: &X11Inner) -> Result<DrmNode, X11Error> {
let connection = &x11.connection;
// Determine which drm-device the Display is using.
let screen = &connection.setup().roots[x11.screen_number];
// provider being NONE tells the X server to use the RandR provider.
let dri3 = match connection.dri3_open(screen.root, x11rb::NONE)?.reply() {
Ok(reply) => reply,
Err(err) => {
return Err(if let ReplyError::X11Error(ref protocol_error) = err {
match protocol_error.error_kind {
// Implementation is risen when the renderer is not capable of X server is not capable
// of rendering at all.
ErrorKind::Implementation => X11Error::CannotDirectRender,
// Match may occur when the node cannot be authenticated for the client.
ErrorKind::Match => X11Error::CannotDirectRender,
_ => err.into(),
}
} else {
err.into()
});
}
};
// Take ownership of the container's inner value so we do not need to duplicate the fd.
// This is fine because the X server will always open a new file descriptor.
let drm_device_fd = dri3.device_fd.into_raw_fd();
let fd_flags =
fcntl::fcntl(drm_device_fd.as_raw_fd(), fcntl::F_GETFD).map_err(AllocateBuffersError::from)?;
// Enable the close-on-exec flag.
fcntl::fcntl(
drm_device_fd,
fcntl::F_SETFD(fcntl::FdFlag::from_bits_truncate(fd_flags) | fcntl::FdFlag::FD_CLOEXEC),
)
.map_err(AllocateBuffersError::from)?;
let drm_node = DrmNode::from_fd(drm_device_fd).map_err(Into::<AllocateBuffersError>::into)?;
if drm_node.ty() != NodeType::Render && drm_node.has_render() {
// Try to get the render node.
if let Some(path) = drm_node.dev_path_with_type(NodeType::Render) {
return Ok(fcntl::open(&path, OFlag::O_RDWR | OFlag::O_CLOEXEC, Mode::empty())
.map_err(Into::<std::io::Error>::into)
.map_err(CreateDrmNodeError::Io)
.and_then(DrmNode::from_fd)
.unwrap_or_else(|err| {
slog::warn!(&x11.log, "Could not create render node from existing DRM node ({}), falling back to primary node", err);
drm_node
}));
}
}
slog::warn!(
&x11.log,
"DRM Device does not have a render node, falling back to primary node"
);
Ok(drm_node)
}
/// A handle to the X11 backend. /// A handle to the X11 backend.
/// ///
/// This is the primary object used to interface with the backend. /// This is the primary object used to interface with the backend.
@ -456,7 +367,12 @@ impl X11Handle {
return Err(X11Error::InvalidWindow); return Err(X11Error::InvalidWindow);
} }
let modifiers = modifiers.collect::<Vec<_>>(); let mut modifiers = modifiers.collect::<Vec<_>>();
// older dri3 versions do only support buffers with one plane.
// we need to make sure, we don't accidently allocate buffers with more.
if window.0.extensions.dri3 < Some((1, 2)) {
modifiers.retain(|modi| modi == &DrmModifier::Invalid || modi == &DrmModifier::Linear);
}
let format = window.0.format; let format = window.0.format;
let size = window.size(); let size = window.size();
@ -480,114 +396,13 @@ impl X11Handle {
resize: recv, resize: recv,
}) })
} }
}
impl X11Surface { /// Get a temporary reference to a window by its XID
/// Returns the window the surface presents to. pub fn window_ref_from_id(&self, id: u32) -> Option<impl AsRef<Window> + '_> {
/// X11Inner::window_ref_from_id(&self.inner, &id)
/// This will return [`None`] if the window has been destroyed. .and_then(|w| w.upgrade())
pub fn window(&self) -> Option<impl AsRef<Window> + '_> { .map(Window)
let window = self.window.upgrade().map(Window).map(WindowTemporary); .map(WindowTemporary)
struct WindowTemporary(Window);
impl AsRef<Window> for WindowTemporary {
fn as_ref(&self) -> &Window {
&self.0
}
}
window
}
/// Returns a handle to the GBM device used to allocate buffers.
pub fn device(&self) -> MutexGuard<'_, gbm::Device<DrmNode>> {
self.swapchain.allocator.lock().unwrap()
}
/// Returns the format of the buffers the surface accepts.
pub fn format(&self) -> DrmFourcc {
self.format
}
/// Returns the next buffer that will be presented to the Window and its age.
///
/// You may bind this buffer to a renderer to render.
/// This function will return the same buffer until [`submit`](Self::submit) is called
/// or [`reset_buffers`](Self::reset_buffer) is used to reset the buffers.
pub fn buffer(&mut self) -> Result<(Dmabuf, u8), AllocateBuffersError> {
if let Some(new_size) = self.resize.try_iter().last() {
self.resize(new_size)?;
}
if self.buffer.is_none() {
self.buffer = Some(
self.swapchain
.acquire()
.map_err(Into::<AllocateBuffersError>::into)?
.ok_or(AllocateBuffersError::NoFreeSlots)?,
);
}
let slot = self.buffer.as_ref().unwrap();
let age = slot.age();
match slot.userdata().get::<Dmabuf>() {
Some(dmabuf) => Ok((dmabuf.clone(), age)),
None => {
let dmabuf = slot.export().map_err(Into::<AllocateBuffersError>::into)?;
slot.userdata().insert_if_missing(|| dmabuf.clone());
Ok((dmabuf, age))
}
}
}
/// Consume and submit the buffer to the window.
pub fn submit(&mut self) -> Result<(), AllocateBuffersError> {
if let Some(connection) = self.connection.upgrade() {
// Get a new buffer
let mut next = self
.swapchain
.acquire()
.map_err(Into::<AllocateBuffersError>::into)?
.ok_or(AllocateBuffersError::NoFreeSlots)?;
// Swap the buffers
if let Some(current) = self.buffer.as_mut() {
mem::swap(&mut next, current);
}
let window = self.window().ok_or(AllocateBuffersError::WindowDestroyed)?;
if let Ok(pixmap) = PixmapWrapper::with_dmabuf(
&*connection,
window.as_ref(),
next.userdata().get::<Dmabuf>().unwrap(),
) {
// Now present the current buffer
let _ = pixmap.present(&*connection, window.as_ref());
}
self.swapchain.submitted(next);
// Flush the connection after presenting to the window to ensure we don't run out of buffer space in the X11 connection.
let _ = connection.flush();
}
Ok(())
}
/// Resets the internal buffers, e.g. to reset age values
pub fn reset_buffers(&mut self) {
self.swapchain.reset_buffers();
self.buffer = None;
}
fn resize(&mut self, size: Size<u16, Logical>) -> Result<(), AllocateBuffersError> {
self.swapchain.resize(size.w as u32, size.h as u32);
self.buffer = None;
self.width = size.w;
self.height = size.h;
Ok(())
} }
} }
@ -711,11 +526,19 @@ impl PartialEq for Window {
} }
} }
struct WindowTemporary(Window);
impl AsRef<Window> for WindowTemporary {
fn as_ref(&self) -> &Window {
&self.0
}
}
impl EventSource for X11Backend { impl EventSource for X11Backend {
type Event = X11Event; type Event = X11Event;
/// The window the incoming events are applicable to. /// The window the incoming events are applicable to.
type Metadata = Window; type Metadata = ();
type Ret = (); type Ret = ();
@ -755,6 +578,16 @@ impl EventSource for X11Backend {
} }
} }
atom_manager! {
pub(crate) Atoms: AtomCollectionCookie {
WM_PROTOCOLS,
WM_DELETE_WINDOW,
_NET_WM_NAME,
UTF8_STRING,
_SMITHAY_X11_BACKEND_CLOSE,
}
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct X11Inner { pub(crate) struct X11Inner {
log: Logger, log: Logger,
@ -768,30 +601,48 @@ pub(crate) struct X11Inner {
atoms: Atoms, atoms: Atoms,
depth: x11::xproto::Depth, depth: x11::xproto::Depth,
visual_id: u32, visual_id: u32,
devices: bool,
} }
impl X11Inner { impl X11Inner {
fn window_ref_from_id(inner: &Arc<Mutex<X11Inner>>, id: &u32) -> Option<Weak<WindowInner>> {
let mut inner = inner.lock().unwrap();
inner.windows.retain(|_, weak| weak.upgrade().is_some());
inner.windows.get(id).cloned()
}
fn process_event<F>(inner: &Arc<Mutex<X11Inner>>, log: &Logger, event: x11::Event, callback: &mut F) fn process_event<F>(inner: &Arc<Mutex<X11Inner>>, log: &Logger, event: x11::Event, callback: &mut F)
where where
F: FnMut(X11Event, &mut Window), F: FnMut(X11Event, &mut ()),
{ {
use self::X11Event::Input; {
let mut inner = inner.lock().unwrap();
fn window_from_id(inner: &Arc<Mutex<X11Inner>>, id: &u32) -> Option<Arc<WindowInner>> { if !inner.windows.is_empty() && !inner.devices {
inner callback(
.lock() Input(InputEvent::DeviceAdded {
.unwrap() device: X11VirtualDevice,
.windows }),
.get(id) &mut (),
.cloned() );
.and_then(|weak| weak.upgrade()) inner.devices = true;
} else if inner.windows.is_empty() && inner.devices {
callback(
Input(InputEvent::DeviceRemoved {
device: X11VirtualDevice,
}),
&mut (),
);
inner.devices = false;
}
} }
use self::X11Event::Input;
// If X11 is deadlocking somewhere here, make sure you drop your mutex guards. // If X11 is deadlocking somewhere here, make sure you drop your mutex guards.
match event { match event {
x11::Event::ButtonPress(button_press) => { x11::Event::ButtonPress(button_press) => {
if let Some(window) = window_from_id(inner, &button_press.event) { if let Some(window) = X11Inner::window_ref_from_id(inner, &button_press.event) {
// X11 decided to associate scroll wheel with a button, 4, 5, 6 and 7 for // X11 decided to associate scroll wheel with a button, 4, 5, 6 and 7 for
// up, down, right and left. For scrolling, a press event is emitted and a // up, down, right and left. For scrolling, a press event is emitted and a
// release is them immediately followed for scrolling. This means we can // release is them immediately followed for scrolling. This means we can
@ -834,9 +685,10 @@ impl X11Inner {
_ => unreachable!(), _ => unreachable!(),
}, },
window,
}, },
}), }),
&mut Window(window), &mut (),
) )
} else { } else {
callback( callback(
@ -845,9 +697,10 @@ impl X11Inner {
time: button_press.time, time: button_press.time,
raw: button_press.detail as u32, raw: button_press.detail as u32,
state: ButtonState::Pressed, state: ButtonState::Pressed,
window,
}, },
}), }),
&mut Window(window), &mut (),
) )
} }
} }
@ -861,22 +714,23 @@ impl X11Inner {
return; return;
} }
if let Some(window) = window_from_id(inner, &button_release.event) { if let Some(window) = X11Inner::window_ref_from_id(inner, &button_release.event) {
callback( callback(
Input(InputEvent::PointerButton { Input(InputEvent::PointerButton {
event: X11MouseInputEvent { event: X11MouseInputEvent {
time: button_release.time, time: button_release.time,
raw: button_release.detail as u32, raw: button_release.detail as u32,
state: ButtonState::Released, state: ButtonState::Released,
window,
}, },
}), }),
&mut Window(window), &mut (),
); );
} }
} }
x11::Event::KeyPress(key_press) => { x11::Event::KeyPress(key_press) => {
if let Some(window) = window_from_id(inner, &key_press.event) { if let Some(window) = X11Inner::window_ref_from_id(inner, &key_press.event) {
// Do not hold the lock. // Do not hold the lock.
let count = { inner.lock().unwrap().key_counter.fetch_add(1, Ordering::SeqCst) + 1 }; let count = { inner.lock().unwrap().key_counter.fetch_add(1, Ordering::SeqCst) + 1 };
@ -892,15 +746,16 @@ impl X11Inner {
key: key_press.detail as u32 - 8, key: key_press.detail as u32 - 8,
count, count,
state: KeyState::Pressed, state: KeyState::Pressed,
window,
}, },
}), }),
&mut Window(window), &mut (),
) )
} }
} }
x11::Event::KeyRelease(key_release) => { x11::Event::KeyRelease(key_release) => {
if let Some(window) = window_from_id(inner, &key_release.event) { if let Some(window) = X11Inner::window_ref_from_id(inner, &key_release.event) {
let count = { let count = {
let key_counter = inner.lock().unwrap().key_counter.clone(); let key_counter = inner.lock().unwrap().key_counter.clone();
@ -924,15 +779,18 @@ impl X11Inner {
key: key_release.detail as u32 - 8, key: key_release.detail as u32 - 8,
count, count,
state: KeyState::Released, state: KeyState::Released,
window,
}, },
}), }),
&mut Window(window), &mut (),
); );
} }
} }
x11::Event::MotionNotify(motion_notify) => { x11::Event::MotionNotify(motion_notify) => {
if let Some(window) = window_from_id(inner, &motion_notify.event) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &motion_notify.event).and_then(|w| w.upgrade())
{
// Use event_x/y since those are relative the the window receiving events. // Use event_x/y since those are relative the the window receiving events.
let x = motion_notify.event_x as f64; let x = motion_notify.event_x as f64;
let y = motion_notify.event_y as f64; let y = motion_notify.event_y as f64;
@ -946,15 +804,18 @@ impl X11Inner {
x, x,
y, y,
size: window_size, size: window_size,
window: Arc::downgrade(&window),
}, },
}), }),
&mut Window(window), &mut (),
) )
} }
} }
x11::Event::ConfigureNotify(configure_notify) => { x11::Event::ConfigureNotify(configure_notify) => {
if let Some(window) = window_from_id(inner, &configure_notify.window) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &configure_notify.window).and_then(|w| w.upgrade())
{
let previous_size = { *window.size.lock().unwrap() }; let previous_size = { *window.size.lock().unwrap() };
// Did the size of the window change? // Did the size of the window change?
@ -971,8 +832,11 @@ impl X11Inner {
} }
(callback)( (callback)(
X11Event::Resized(configure_notify_size), X11Event::Resized {
&mut Window(window.clone()), new_size: configure_notify_size,
window_id: configure_notify.window,
},
&mut (),
); );
if let Some(resize_sender) = window.resize.lock().unwrap().as_ref() { if let Some(resize_sender) = window.resize.lock().unwrap().as_ref() {
@ -983,40 +847,61 @@ impl X11Inner {
} }
x11::Event::EnterNotify(enter_notify) => { x11::Event::EnterNotify(enter_notify) => {
if let Some(window) = window_from_id(inner, &enter_notify.event) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &enter_notify.event).and_then(|w| w.upgrade())
{
window.cursor_enter(); window.cursor_enter();
} }
} }
x11::Event::LeaveNotify(leave_notify) => { x11::Event::LeaveNotify(leave_notify) => {
if let Some(window) = window_from_id(inner, &leave_notify.event) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &leave_notify.event).and_then(|w| w.upgrade())
{
window.cursor_leave(); window.cursor_leave();
} }
} }
x11::Event::ClientMessage(client_message) => { x11::Event::ClientMessage(client_message) => {
if let Some(window) = window_from_id(inner, &client_message.window) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &client_message.window).and_then(|w| w.upgrade())
{
if client_message.data.as_data32()[0] == window.atoms.WM_DELETE_WINDOW if client_message.data.as_data32()[0] == window.atoms.WM_DELETE_WINDOW
// Destroy the window? // Destroy the window?
{ {
(callback)(X11Event::CloseRequested, &mut Window(window)); (callback)(
X11Event::CloseRequested {
window_id: client_message.window,
},
&mut (),
);
} }
} }
} }
x11::Event::Expose(expose) => { x11::Event::Expose(expose) => {
if let Some(window) = window_from_id(inner, &expose.window) { if expose.count == 0 {
if expose.count == 0 { (callback)(
(callback)(X11Event::Refresh, &mut Window(window)); X11Event::Refresh {
} window_id: expose.window,
},
&mut (),
);
} }
} }
x11::Event::PresentCompleteNotify(complete_notify) => { x11::Event::PresentCompleteNotify(complete_notify) => {
if let Some(window) = window_from_id(inner, &complete_notify.window) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &complete_notify.window).and_then(|w| w.upgrade())
{
window.last_msc.store(complete_notify.msc, Ordering::SeqCst); window.last_msc.store(complete_notify.msc, Ordering::SeqCst);
(callback)(X11Event::PresentCompleted, &mut Window(window)); (callback)(
X11Event::PresentCompleted {
window_id: complete_notify.window,
},
&mut (),
);
} }
} }
@ -1032,3 +917,78 @@ impl X11Inner {
} }
} }
} }
fn egl_init(_: &X11Inner) -> Result<DrmNode, EGLInitError> {
let display = EGLDisplay::new(&X11DefaultDisplay, None)?;
let device = EGLDevice::device_for_display(&display)?;
let path = path_to_type(device.drm_device_path()?, NodeType::Render)?;
fcntl::open(&path, OFlag::O_RDWR | OFlag::O_CLOEXEC, Mode::empty())
.map_err(Into::<io::Error>::into)
.and_then(|fd| {
DrmNode::from_fd(fd).map_err(|err| match err {
CreateDrmNodeError::Io(err) => err,
_ => unreachable!(),
})
})
.map_err(EGLInitError::IO)
}
fn dri3_init(x11: &X11Inner) -> Result<DrmNode, X11Error> {
let connection = &x11.connection;
// Determine which drm-device the Display is using.
let screen = &connection.setup().roots[x11.screen_number];
// provider being NONE tells the X server to use the RandR provider.
let dri3 = match connection.dri3_open(screen.root, x11rb::NONE)?.reply() {
Ok(reply) => reply,
Err(err) => {
return Err(if let ReplyError::X11Error(ref protocol_error) = err {
match protocol_error.error_kind {
// Implementation is risen when the renderer is not capable of X server is not capable
// of rendering at all.
ErrorKind::Implementation => X11Error::CannotDirectRender,
// Match may occur when the node cannot be authenticated for the client.
ErrorKind::Match => X11Error::CannotDirectRender,
_ => err.into(),
}
} else {
err.into()
});
}
};
// Take ownership of the container's inner value so we do not need to duplicate the fd.
// This is fine because the X server will always open a new file descriptor.
let drm_device_fd = dri3.device_fd.into_raw_fd();
let fd_flags =
fcntl::fcntl(drm_device_fd.as_raw_fd(), fcntl::F_GETFD).map_err(AllocateBuffersError::from)?;
// Enable the close-on-exec flag.
fcntl::fcntl(
drm_device_fd,
fcntl::F_SETFD(fcntl::FdFlag::from_bits_truncate(fd_flags) | fcntl::FdFlag::FD_CLOEXEC),
)
.map_err(AllocateBuffersError::from)?;
let drm_node = DrmNode::from_fd(drm_device_fd).map_err(Into::<AllocateBuffersError>::into)?;
if drm_node.ty() != NodeType::Render && drm_node.has_render() {
// Try to get the render node.
if let Some(path) = drm_node.dev_path_with_type(NodeType::Render) {
return Ok(fcntl::open(&path, OFlag::O_RDWR | OFlag::O_CLOEXEC, Mode::empty())
.map_err(Into::<std::io::Error>::into)
.map_err(CreateDrmNodeError::Io)
.and_then(DrmNode::from_fd)
.unwrap_or_else(|err| {
slog::warn!(&x11.log, "Could not create render node from existing DRM node ({}), falling back to primary node", err);
drm_node
}));
}
}
slog::warn!(
&x11.log,
"DRM Device does not have a render node, falling back to primary node"
);
Ok(drm_node)
}

147
src/backend/x11/surface.rs Normal file
View File

@ -0,0 +1,147 @@
use std::{
mem,
sync::{mpsc::Receiver, Arc, Mutex, MutexGuard, Weak},
};
use drm_fourcc::DrmFourcc;
use gbm::BufferObject;
use x11rb::{connection::Connection, protocol::xproto::PixmapWrapper, rust_connection::RustConnection};
use crate::{
backend::{
allocator::{
dmabuf::{AsDmabuf, Dmabuf},
Slot, Swapchain,
},
drm::DrmNode,
x11::{buffer::PixmapWrapperExt, window_inner::WindowInner, AllocateBuffersError, Window},
},
utils::{Logical, Size},
};
use super::{WindowTemporary, X11Error};
/// An error that may occur when presenting.
#[derive(Debug, thiserror::Error)]
pub enum PresentError {
/// The dmabuf being presented has too many planes.
#[error("The Dmabuf had too many planes")]
TooManyPlanes,
/// Duplicating the dmabuf handles failed.
#[error("Duplicating the file descriptors for the dmabuf handles failed")]
DupFailed(String),
/// The format dmabuf presented does not match the format of the window.
#[error("Buffer had incorrect format, expected: {0}")]
IncorrectFormat(DrmFourcc),
}
/// An X11 surface which uses GBM to allocate and present buffers.
#[derive(Debug)]
pub struct X11Surface {
pub(crate) connection: Weak<RustConnection>,
pub(crate) window: Weak<WindowInner>,
pub(crate) resize: Receiver<Size<u16, Logical>>,
pub(crate) swapchain: Swapchain<Arc<Mutex<gbm::Device<DrmNode>>>, BufferObject<()>>,
pub(crate) format: DrmFourcc,
pub(crate) width: u16,
pub(crate) height: u16,
pub(crate) buffer: Option<Slot<BufferObject<()>>>,
}
impl X11Surface {
/// Returns the window the surface presents to.
///
/// This will return [`None`] if the window has been destroyed.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
self.window.upgrade().map(Window).map(WindowTemporary)
}
/// Returns a handle to the GBM device used to allocate buffers.
pub fn device(&self) -> MutexGuard<'_, gbm::Device<DrmNode>> {
self.swapchain.allocator.lock().unwrap()
}
/// Returns the format of the buffers the surface accepts.
pub fn format(&self) -> DrmFourcc {
self.format
}
/// Returns the next buffer that will be presented to the Window and its age.
///
/// You may bind this buffer to a renderer to render.
/// This function will return the same buffer until [`submit`](Self::submit) is called
/// or [`reset_buffers`](Self::reset_buffer) is used to reset the buffers.
pub fn buffer(&mut self) -> Result<(Dmabuf, u8), AllocateBuffersError> {
if let Some(new_size) = self.resize.try_iter().last() {
self.resize(new_size);
}
if self.buffer.is_none() {
self.buffer = Some(
self.swapchain
.acquire()
.map_err(Into::<AllocateBuffersError>::into)?
.ok_or(AllocateBuffersError::NoFreeSlots)?,
);
}
let slot = self.buffer.as_ref().unwrap();
let age = slot.age();
match slot.userdata().get::<Dmabuf>() {
Some(dmabuf) => Ok((dmabuf.clone(), age)),
None => {
let dmabuf = slot.export().map_err(Into::<AllocateBuffersError>::into)?;
slot.userdata().insert_if_missing(|| dmabuf.clone());
Ok((dmabuf, age))
}
}
}
/// Consume and submit the buffer to the window.
pub fn submit(&mut self) -> Result<(), X11Error> {
if let Some(connection) = self.connection.upgrade() {
// Get a new buffer
let mut next = self
.swapchain
.acquire()
.map_err(Into::<AllocateBuffersError>::into)?
.ok_or(AllocateBuffersError::NoFreeSlots)?;
// Swap the buffers
if let Some(current) = self.buffer.as_mut() {
mem::swap(&mut next, current);
}
let window = self.window().ok_or(AllocateBuffersError::WindowDestroyed)?;
let pixmap = PixmapWrapper::with_dmabuf(
&*connection,
window.as_ref(),
next.userdata().get::<Dmabuf>().unwrap(),
)?;
// Now present the current buffer
let _ = pixmap.present(&*connection, window.as_ref())?;
self.swapchain.submitted(next);
// Flush the connection after presenting to the window to ensure we don't run out of buffer space in the X11 connection.
let _ = connection.flush();
}
Ok(())
}
/// Resets the internal buffers, e.g. to reset age values
pub fn reset_buffers(&mut self) {
self.swapchain.reset_buffers();
self.buffer = None;
}
fn resize(&mut self, size: Size<u16, Logical>) {
self.swapchain.resize(size.w as u32, size.h as u32);
self.buffer = None;
self.width = size.w;
self.height = size.h;
}
}

View File

@ -886,16 +886,21 @@ impl<N: Coordinate, Kind> Rectangle<N, Kind> {
} }
/// Clamp rectangle to min and max corners resulting in the overlapping area of two rectangles /// Clamp rectangle to min and max corners resulting in the overlapping area of two rectangles
///
/// Returns `None` if the two rectangles don't overlap
#[inline] #[inline]
pub fn intersection(self, other: impl Into<Rectangle<N, Kind>>) -> Self { pub fn intersection(self, other: impl Into<Rectangle<N, Kind>>) -> Option<Self> {
let other = other.into(); let other = other.into();
Rectangle::from_extemities( if !self.overlaps(other) {
return None;
}
Some(Rectangle::from_extemities(
(self.loc.x.max(other.loc.x), self.loc.y.max(other.loc.y)), (self.loc.x.max(other.loc.x), self.loc.y.max(other.loc.y)),
( (
(self.loc.x.saturating_add(self.size.w)).min(other.loc.x.saturating_add(other.size.w)), (self.loc.x.saturating_add(self.size.w)).min(other.loc.x.saturating_add(other.size.w)),
(self.loc.y.saturating_add(self.size.h)).min(other.loc.y.saturating_add(other.size.h)), (self.loc.y.saturating_add(self.size.h)).min(other.loc.y.saturating_add(other.size.h)),
), ),
) ))
} }
/// Compute the bounding box of a given set of points /// Compute the bounding box of a given set of points

View File

@ -41,7 +41,8 @@ mod pointer;
pub use self::{ pub use self::{
keyboard::{ keyboard::{
keysyms, Error as KeyboardError, FilterResult, KeyboardHandle, Keysym, ModifiersState, XkbConfig, keysyms, Error as KeyboardError, FilterResult, KeyboardHandle, Keysym, KeysymHandle, ModifiersState,
XkbConfig,
}, },
pointer::{ pointer::{
AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData, PointerGrab, PointerHandle, AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData, PointerGrab, PointerHandle,