Merge pull request #101 from Smithay/wayland-021
Update to wayland-rs 0.21
This commit is contained in:
commit
ae5b9e55f4
|
@ -53,7 +53,7 @@ env:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# special features for lint & fmt
|
# special features for lint & fmt
|
||||||
- rust: nightly
|
- rust: stable
|
||||||
env: FEATURES="cargo-fmt"
|
env: FEATURES="cargo-fmt"
|
||||||
- rust: nightly
|
- rust: nightly
|
||||||
env: FEATURES="cargo-clippy"
|
env: FEATURES="cargo-clippy"
|
||||||
|
@ -81,17 +81,16 @@ script:
|
||||||
vagga cargo-$TRAVIS_RUST_VERSION doc --no-deps
|
vagga cargo-$TRAVIS_RUST_VERSION doc --no-deps
|
||||||
;;
|
;;
|
||||||
"cargo-fmt")
|
"cargo-fmt")
|
||||||
vagga cargo-$TRAVIS_RUST_VERSION fmt -- --write-mode=diff
|
vagga cargo-$TRAVIS_RUST_VERSION fmt --all -- --check
|
||||||
;;
|
;;
|
||||||
"cargo-clippy")
|
"cargo-clippy")
|
||||||
vagga cargo-$TRAVIS_RUST_VERSION install -f clippy &&
|
|
||||||
vagga cargo-$TRAVIS_RUST_VERSION clippy --all-features -- -D warnings
|
vagga cargo-$TRAVIS_RUST_VERSION clippy --all-features -- -D warnings
|
||||||
;;
|
;;
|
||||||
"anvil")
|
"anvil")
|
||||||
vagga cargo-$TRAVIS_RUST_VERSION test -p anvil --all-features
|
vagga cargo-$TRAVIS_RUST_VERSION test -p anvil --all-features
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
vagga cargo-$TRAVIS_RUST_VERSION test --lib --doc --tests --no-default-features --features "$FEATURES" &&
|
vagga cargo-$TRAVIS_RUST_VERSION test --no-default-features --features "$FEATURES" &&
|
||||||
vagga cargo-$TRAVIS_RUST_VERSION doc --no-deps --no-default-features --features "$FEATURES"
|
vagga cargo-$TRAVIS_RUST_VERSION doc --no-deps --no-default-features --features "$FEATURES"
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -10,12 +10,12 @@ repository = "https://github.com/Smithay/smithay"
|
||||||
members = [ "anvil" ]
|
members = [ "anvil" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wayland-server = "0.20.5"
|
wayland-server = "0.21.1"
|
||||||
wayland-sys = "0.20.5"
|
wayland-sys = "0.21.1"
|
||||||
nix = "0.10.0"
|
nix = "0.11"
|
||||||
xkbcommon = "0.2.1"
|
xkbcommon = "0.2.1"
|
||||||
tempfile = "2.1.5"
|
tempfile = "2.1.5"
|
||||||
slog = { version = "2.1.1" }
|
slog = "2.1.1"
|
||||||
slog-stdlog = "3.0.2"
|
slog-stdlog = "3.0.2"
|
||||||
libloading = "0.4.0"
|
libloading = "0.4.0"
|
||||||
wayland-client = { version = "0.20.5", optional = true }
|
wayland-client = { version = "0.20.5", optional = true }
|
||||||
|
@ -27,7 +27,7 @@ input = { version = "0.4.0", optional = true }
|
||||||
udev = { version = "0.2.0", optional = true }
|
udev = { version = "0.2.0", optional = true }
|
||||||
dbus = { version = "0.6.1", optional = true }
|
dbus = { version = "0.6.1", optional = true }
|
||||||
systemd = { version = "^0.2.0", optional = true }
|
systemd = { version = "^0.2.0", optional = true }
|
||||||
wayland-protocols = { version = "0.20.5", features = ["unstable_protocols", "server"] }
|
wayland-protocols = { version = "0.21.1", features = ["unstable_protocols", "native_server"] }
|
||||||
image = "0.17.0"
|
image = "0.17.0"
|
||||||
error-chain = "0.11.0"
|
error-chain = "0.11.0"
|
||||||
lazy_static = "1.0.0"
|
lazy_static = "1.0.0"
|
||||||
|
|
|
@ -11,7 +11,7 @@ slog-term = "2.3"
|
||||||
slog-async = "2.2"
|
slog-async = "2.2"
|
||||||
rand = "0.3"
|
rand = "0.3"
|
||||||
glium = { version = "0.19.0", default-features = false }
|
glium = { version = "0.19.0", default-features = false }
|
||||||
wayland-server = "0.20"
|
wayland-server = "0.21"
|
||||||
xkbcommon = "0.2.1"
|
xkbcommon = "0.2.1"
|
||||||
|
|
||||||
[dependencies.smithay]
|
[dependencies.smithay]
|
||||||
|
@ -28,4 +28,3 @@ winit = [ "smithay/backend_winit" ]
|
||||||
tty_launch = [ "smithay/backend_libinput", "smithay/backend_drm" ]
|
tty_launch = [ "smithay/backend_libinput", "smithay/backend_drm" ]
|
||||||
udev = [ "tty_launch", "smithay/backend_udev" ]
|
udev = [ "tty_launch", "smithay/backend_udev" ]
|
||||||
logind = [ "smithay/backend_session_logind" ]
|
logind = [ "smithay/backend_session_logind" ]
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,11 @@ use glium;
|
||||||
use glium::index::PrimitiveType;
|
use glium::index::PrimitiveType;
|
||||||
use glium::texture::{MipmapsOption, Texture2d, UncompressedFloatFormat};
|
use glium::texture::{MipmapsOption, Texture2d, UncompressedFloatFormat};
|
||||||
use glium::{Frame, GlObject, Surface};
|
use glium::{Frame, GlObject, Surface};
|
||||||
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
|
||||||
use smithay::backend::graphics::egl::error::Result as EGLResult;
|
use smithay::backend::graphics::egl::error::Result as EGLResult;
|
||||||
use smithay::backend::graphics::egl::wayland::{BufferAccessError, EGLDisplay, EGLImages,
|
use smithay::backend::graphics::egl::wayland::{
|
||||||
EGLWaylandExtensions, Format};
|
BufferAccessError, EGLDisplay, EGLImages, EGLWaylandExtensions, Format,
|
||||||
|
};
|
||||||
|
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
||||||
use smithay::backend::graphics::glium::GliumGraphicsBackend;
|
use smithay::backend::graphics::glium::GliumGraphicsBackend;
|
||||||
use smithay::wayland::compositor::roles::Role;
|
use smithay::wayland::compositor::roles::Role;
|
||||||
use smithay::wayland::compositor::{SubsurfaceRole, TraversalAction};
|
use smithay::wayland::compositor::{SubsurfaceRole, TraversalAction};
|
||||||
|
@ -199,8 +200,7 @@ impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
|
||||||
blend: blending,
|
blend: blending,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)
|
).unwrap();
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -282,8 +282,7 @@ impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
|
||||||
TraversalAction::SkipChildren
|
TraversalAction::SkipChildren
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
).unwrap();
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
|
use smithay::backend::input::{
|
||||||
|
self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent,
|
||||||
|
PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent,
|
||||||
|
};
|
||||||
#[cfg(feature = "udev")]
|
#[cfg(feature = "udev")]
|
||||||
use smithay::backend::session::auto::AutoSession;
|
use smithay::backend::session::auto::AutoSession;
|
||||||
use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent,
|
|
||||||
PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent,
|
|
||||||
PointerMotionEvent};
|
|
||||||
use smithay::wayland::seat::{keysyms as xkb, KeyboardHandle, Keysym, ModifiersState, PointerHandle};
|
use smithay::wayland::seat::{keysyms as xkb, KeyboardHandle, Keysym, ModifiersState, PointerHandle};
|
||||||
use smithay::wayland_server::protocol::wl_pointer;
|
use smithay::wayland_server::protocol::wl_pointer;
|
||||||
|
|
||||||
|
@ -160,7 +161,8 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
||||||
// this event is never generated by winit so self.screen_size is relevant
|
// this event is never generated by winit so self.screen_size is relevant
|
||||||
location.0 = (location.0).max(0.0).min(self.screen_size.0 as f64);
|
location.0 = (location.0).max(0.0).min(self.screen_size.0 as f64);
|
||||||
location.1 = (location.1).max(0.0).min(self.screen_size.1 as f64);
|
location.1 = (location.1).max(0.0).min(self.screen_size.1 as f64);
|
||||||
let under = self.window_map
|
let under = self
|
||||||
|
.window_map
|
||||||
.borrow()
|
.borrow()
|
||||||
.get_surface_under((location.0, location.1));
|
.get_surface_under((location.0, location.1));
|
||||||
self.pointer.motion(
|
self.pointer.motion(
|
||||||
|
@ -191,9 +193,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
||||||
};
|
};
|
||||||
*self.pointer_location.borrow_mut() = (x, y);
|
*self.pointer_location.borrow_mut() = (x, y);
|
||||||
let serial = self.next_serial();
|
let serial = self.next_serial();
|
||||||
let under = self.window_map
|
let under = self.window_map.borrow().get_surface_under((x as f64, y as f64));
|
||||||
.borrow()
|
|
||||||
.get_surface_under((x as f64, y as f64));
|
|
||||||
self.pointer.motion(
|
self.pointer.motion(
|
||||||
under.as_ref().map(|&(ref s, (x, y))| (s, x, y)),
|
under.as_ref().map(|&(ref s, (x, y))| (s, x, y)),
|
||||||
serial,
|
serial,
|
||||||
|
@ -212,7 +212,8 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
||||||
let state = match evt.state() {
|
let state = match evt.state() {
|
||||||
input::MouseButtonState::Pressed => {
|
input::MouseButtonState::Pressed => {
|
||||||
// change the keyboard focus
|
// change the keyboard focus
|
||||||
let under = self.window_map
|
let under = self
|
||||||
|
.window_map
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.get_surface_and_bring_to_top(*self.pointer_location.borrow());
|
.get_surface_and_bring_to_top(*self.pointer_location.borrow());
|
||||||
self.keyboard
|
self.keyboard
|
||||||
|
@ -230,9 +231,11 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
||||||
input::AxisSource::Finger => wl_pointer::AxisSource::Finger,
|
input::AxisSource::Finger => wl_pointer::AxisSource::Finger,
|
||||||
input::AxisSource::Wheel | input::AxisSource::WheelTilt => wl_pointer::AxisSource::Wheel,
|
input::AxisSource::Wheel | input::AxisSource::WheelTilt => wl_pointer::AxisSource::Wheel,
|
||||||
};
|
};
|
||||||
let horizontal_amount = evt.amount(&input::Axis::Horizontal)
|
let horizontal_amount = evt
|
||||||
|
.amount(&input::Axis::Horizontal)
|
||||||
.unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0);
|
.unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0);
|
||||||
let vertical_amount = evt.amount(&input::Axis::Vertical)
|
let vertical_amount = evt
|
||||||
|
.amount(&input::Axis::Vertical)
|
||||||
.unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0);
|
.unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0);
|
||||||
let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal);
|
let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal);
|
||||||
let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical);
|
let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical);
|
||||||
|
@ -241,11 +244,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
||||||
let mut event = self.pointer.axis();
|
let mut event = self.pointer.axis();
|
||||||
event.source(source);
|
event.source(source);
|
||||||
if horizontal_amount != 0.0 {
|
if horizontal_amount != 0.0 {
|
||||||
event.value(
|
event.value(wl_pointer::Axis::HorizontalScroll, horizontal_amount, evt.time());
|
||||||
wl_pointer::Axis::HorizontalScroll,
|
|
||||||
horizontal_amount,
|
|
||||||
evt.time(),
|
|
||||||
);
|
|
||||||
if let Some(discrete) = horizontal_amount_discrete {
|
if let Some(discrete) = horizontal_amount_discrete {
|
||||||
event.discrete(wl_pointer::Axis::HorizontalScroll, discrete as i32);
|
event.discrete(wl_pointer::Axis::HorizontalScroll, discrete as i32);
|
||||||
}
|
}
|
||||||
|
@ -253,11 +252,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
||||||
event.stop(wl_pointer::Axis::HorizontalScroll, evt.time());
|
event.stop(wl_pointer::Axis::HorizontalScroll, evt.time());
|
||||||
}
|
}
|
||||||
if vertical_amount != 0.0 {
|
if vertical_amount != 0.0 {
|
||||||
event.value(
|
event.value(wl_pointer::Axis::VerticalScroll, vertical_amount, evt.time());
|
||||||
wl_pointer::Axis::VerticalScroll,
|
|
||||||
vertical_amount,
|
|
||||||
evt.time(),
|
|
||||||
);
|
|
||||||
if let Some(discrete) = vertical_amount_discrete {
|
if let Some(discrete) = vertical_amount_discrete {
|
||||||
event.discrete(wl_pointer::Axis::VerticalScroll, discrete as i32);
|
event.discrete(wl_pointer::Axis::VerticalScroll, discrete as i32);
|
||||||
}
|
}
|
||||||
|
@ -304,7 +299,8 @@ enum KeyAction {
|
||||||
|
|
||||||
fn process_keyboard_shortcut(modifiers: &ModifiersState, keysym: Keysym) -> KeyAction {
|
fn process_keyboard_shortcut(modifiers: &ModifiersState, keysym: Keysym) -> KeyAction {
|
||||||
if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace
|
if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace
|
||||||
|| modifiers.logo && keysym == xkb::KEY_q {
|
|| modifiers.logo && keysym == xkb::KEY_q
|
||||||
|
{
|
||||||
// ctrl+alt+backspace = quit
|
// ctrl+alt+backspace = quit
|
||||||
// logo + q = quit
|
// logo + q = quit
|
||||||
KeyAction::Quit
|
KeyAction::Quit
|
||||||
|
|
|
@ -10,6 +10,7 @@ extern crate smithay;
|
||||||
extern crate xkbcommon;
|
extern crate xkbcommon;
|
||||||
|
|
||||||
use slog::Drain;
|
use slog::Drain;
|
||||||
|
use smithay::wayland_server::calloop::EventLoop;
|
||||||
use smithay::wayland_server::Display;
|
use smithay::wayland_server::Display;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -42,7 +43,8 @@ fn main() {
|
||||||
o!(),
|
o!(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let (mut display, mut event_loop) = Display::new();
|
let mut event_loop = EventLoop::<()>::new().unwrap();
|
||||||
|
let mut display = Display::new(event_loop.handle());
|
||||||
|
|
||||||
let arg = ::std::env::args().nth(1);
|
let arg = ::std::env::args().nth(1);
|
||||||
match arg.as_ref().map(|s| &s[..]) {
|
match arg.as_ref().map(|s| &s[..]) {
|
||||||
|
|
|
@ -5,17 +5,18 @@ use std::os::unix::io::RawFd;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use smithay::drm::Device as BasicDevice;
|
use smithay::backend::drm::{drm_device_bind, DrmBackend, DrmDevice, DrmHandler};
|
||||||
use smithay::drm::control::{Device as ControlDevice, ResourceInfo};
|
use smithay::backend::graphics::egl::wayland::EGLWaylandExtensions;
|
||||||
use smithay::drm::control::connector::{Info as ConnectorInfo, State as ConnectorState};
|
use smithay::drm::control::connector::{Info as ConnectorInfo, State as ConnectorState};
|
||||||
use smithay::drm::control::crtc;
|
use smithay::drm::control::crtc;
|
||||||
use smithay::drm::control::encoder::Info as EncoderInfo;
|
use smithay::drm::control::encoder::Info as EncoderInfo;
|
||||||
|
use smithay::drm::control::{Device as ControlDevice, ResourceInfo};
|
||||||
use smithay::drm::result::Error as DrmError;
|
use smithay::drm::result::Error as DrmError;
|
||||||
use smithay::backend::drm::{drm_device_bind, DrmBackend, DrmDevice, DrmHandler};
|
use smithay::drm::Device as BasicDevice;
|
||||||
use smithay::backend::graphics::egl::wayland::EGLWaylandExtensions;
|
|
||||||
use smithay::wayland::compositor::CompositorToken;
|
use smithay::wayland::compositor::CompositorToken;
|
||||||
use smithay::wayland::shm::init_shm_global;
|
use smithay::wayland::shm::init_shm_global;
|
||||||
use smithay::wayland_server::{Display, EventLoop};
|
use smithay::wayland_server::calloop::EventLoop;
|
||||||
|
use smithay::wayland_server::Display;
|
||||||
|
|
||||||
use glium::Surface;
|
use glium::Surface;
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
@ -35,7 +36,7 @@ impl AsRawFd for Card {
|
||||||
impl BasicDevice for Card {}
|
impl BasicDevice for Card {}
|
||||||
impl ControlDevice for Card {}
|
impl ControlDevice for Card {}
|
||||||
|
|
||||||
pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger) -> Result<(), ()> {
|
pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop<()>, log: Logger) -> Result<(), ()> {
|
||||||
/*
|
/*
|
||||||
* Initialize the drm backend
|
* Initialize the drm backend
|
||||||
*/
|
*/
|
||||||
|
@ -43,10 +44,8 @@ pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger)
|
||||||
let mut options = OpenOptions::new();
|
let mut options = OpenOptions::new();
|
||||||
options.read(true);
|
options.read(true);
|
||||||
options.write(true);
|
options.write(true);
|
||||||
let mut device = DrmDevice::new(
|
let mut device =
|
||||||
Card(options.clone().open("/dev/dri/card0").unwrap()),
|
DrmDevice::new(Card(options.clone().open("/dev/dri/card0").unwrap()), log.clone()).unwrap();
|
||||||
log.clone(),
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
// Get a set of all modesetting resource handles (excluding planes):
|
// Get a set of all modesetting resource handles (excluding planes):
|
||||||
let res_handles = device.resource_handles().unwrap();
|
let res_handles = device.resource_handles().unwrap();
|
||||||
|
@ -100,9 +99,9 @@ pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger)
|
||||||
* Initialize the globals
|
* Initialize the globals
|
||||||
*/
|
*/
|
||||||
|
|
||||||
init_shm_global(&mut display, event_loop.token(), vec![], log.clone());
|
init_shm_global(&mut display, vec![], log.clone());
|
||||||
|
|
||||||
let (compositor_token, _, _, window_map) = init_shell(&mut display, event_loop.token(), log.clone());
|
let (compositor_token, _, _, window_map) = init_shell(&mut display, log.clone());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a listening socket:
|
* Add a listening socket:
|
||||||
|
@ -114,7 +113,7 @@ pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger)
|
||||||
* Register the DrmDevice on the EventLoop
|
* Register the DrmDevice on the EventLoop
|
||||||
*/
|
*/
|
||||||
let _source = drm_device_bind(
|
let _source = drm_device_bind(
|
||||||
&event_loop.token(),
|
&event_loop.handle(),
|
||||||
device,
|
device,
|
||||||
DrmHandlerImpl {
|
DrmHandlerImpl {
|
||||||
compositor_token,
|
compositor_token,
|
||||||
|
@ -126,7 +125,9 @@ pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
event_loop.dispatch(Some(16)).unwrap();
|
event_loop
|
||||||
|
.dispatch(Some(::std::time::Duration::from_millis(16)), &mut ())
|
||||||
|
.unwrap();
|
||||||
display.flush_clients();
|
display.flush_clients();
|
||||||
|
|
||||||
window_map.borrow_mut().refresh();
|
window_map.borrow_mut().refresh();
|
||||||
|
@ -148,11 +149,8 @@ impl DrmHandler<Card> for DrmHandlerImpl {
|
||||||
_frame: u32,
|
_frame: u32,
|
||||||
_duration: Duration,
|
_duration: Duration,
|
||||||
) {
|
) {
|
||||||
self.drawer.draw_windows(
|
self.drawer
|
||||||
&*self.window_map.borrow(),
|
.draw_windows(&*self.window_map.borrow(), self.compositor_token, &self.logger);
|
||||||
self.compositor_token,
|
|
||||||
&self.logger,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&mut self, _device: &mut DrmDevice<Card>, error: DrmError) {
|
fn error(&mut self, _device: &mut DrmDevice<Card>, error: DrmError) {
|
||||||
|
|
|
@ -5,12 +5,15 @@ use std::sync::{Arc, Mutex};
|
||||||
use rand;
|
use rand;
|
||||||
|
|
||||||
use smithay::wayland::compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceEvent};
|
use smithay::wayland::compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceEvent};
|
||||||
use smithay::wayland::shell::legacy::{wl_shell_init, ShellRequest, ShellState as WlShellState,
|
use smithay::wayland::shell::legacy::{
|
||||||
ShellSurfaceKind, ShellSurfaceRole};
|
wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind, ShellSurfaceRole,
|
||||||
use smithay::wayland::shell::xdg::{xdg_shell_init, PopupConfigure, ShellState as XdgShellState,
|
};
|
||||||
ToplevelConfigure, XdgRequest, XdgSurfaceRole};
|
use smithay::wayland::shell::xdg::{
|
||||||
|
xdg_shell_init, PopupConfigure, ShellState as XdgShellState, ToplevelConfigure, XdgRequest,
|
||||||
|
XdgSurfaceRole,
|
||||||
|
};
|
||||||
use smithay::wayland_server::protocol::{wl_buffer, wl_callback, wl_shell_surface, wl_surface};
|
use smithay::wayland_server::protocol::{wl_buffer, wl_callback, wl_shell_surface, wl_surface};
|
||||||
use smithay::wayland_server::{Display, LoopToken, Resource};
|
use smithay::wayland_server::{Display, Resource};
|
||||||
|
|
||||||
use window_map::{Kind as SurfaceKind, WindowMap};
|
use window_map::{Kind as SurfaceKind, WindowMap};
|
||||||
|
|
||||||
|
@ -23,7 +26,6 @@ pub type MyCompositorToken = CompositorToken<SurfaceData, Roles>;
|
||||||
|
|
||||||
pub fn init_shell(
|
pub fn init_shell(
|
||||||
display: &mut Display,
|
display: &mut Display,
|
||||||
looptoken: LoopToken,
|
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
) -> (
|
) -> (
|
||||||
CompositorToken<SurfaceData, Roles>,
|
CompositorToken<SurfaceData, Roles>,
|
||||||
|
@ -34,11 +36,10 @@ pub fn init_shell(
|
||||||
// Create the compositor
|
// Create the compositor
|
||||||
let (compositor_token, _, _) = compositor_init(
|
let (compositor_token, _, _) = compositor_init(
|
||||||
display,
|
display,
|
||||||
looptoken.clone(),
|
move |request, surface, ctoken| match request {
|
||||||
move |request, (surface, ctoken)| match request {
|
|
||||||
SurfaceEvent::Commit => surface_commit(&surface, ctoken),
|
SurfaceEvent::Commit => surface_commit(&surface, ctoken),
|
||||||
SurfaceEvent::Frame { callback } => callback
|
SurfaceEvent::Frame { callback } => callback
|
||||||
.implement(|e, _| match e {}, None::<fn(_, _)>)
|
.implement(|e, _| match e {}, None::<fn(_)>, ())
|
||||||
.send(wl_callback::Event::Done { callback_data: 0 }),
|
.send(wl_callback::Event::Done { callback_data: 0 }),
|
||||||
},
|
},
|
||||||
log.clone(),
|
log.clone(),
|
||||||
|
@ -54,9 +55,8 @@ pub fn init_shell(
|
||||||
let xdg_window_map = window_map.clone();
|
let xdg_window_map = window_map.clone();
|
||||||
let (xdg_shell_state, _, _) = xdg_shell_init(
|
let (xdg_shell_state, _, _) = xdg_shell_init(
|
||||||
display,
|
display,
|
||||||
looptoken.clone(),
|
|
||||||
compositor_token,
|
compositor_token,
|
||||||
move |shell_event, ()| match shell_event {
|
move |shell_event| match shell_event {
|
||||||
XdgRequest::NewToplevel { surface } => {
|
XdgRequest::NewToplevel { surface } => {
|
||||||
// place the window at a random location in the [0;300]x[0;300] square
|
// place the window at a random location in the [0;300]x[0;300] square
|
||||||
use rand::distributions::{IndependentSample, Range};
|
use rand::distributions::{IndependentSample, Range};
|
||||||
|
@ -87,13 +87,13 @@ pub fn init_shell(
|
||||||
let shell_window_map = window_map.clone();
|
let shell_window_map = window_map.clone();
|
||||||
let (wl_shell_state, _) = wl_shell_init(
|
let (wl_shell_state, _) = wl_shell_init(
|
||||||
display,
|
display,
|
||||||
looptoken,
|
|
||||||
compositor_token,
|
compositor_token,
|
||||||
move |req: ShellRequest<_, _, ()>, ()|
|
move |req: ShellRequest<_, _, ()>| {
|
||||||
if let ShellRequest::SetKind {
|
if let ShellRequest::SetKind {
|
||||||
surface,
|
surface,
|
||||||
kind: ShellSurfaceKind::Toplevel,
|
kind: ShellSurfaceKind::Toplevel,
|
||||||
} = req {
|
} = req
|
||||||
|
{
|
||||||
// place the window at a random location in the [0;300]x[0;300] square
|
// place the window at a random location in the [0;300]x[0;300] square
|
||||||
use rand::distributions::{IndependentSample, Range};
|
use rand::distributions::{IndependentSample, Range};
|
||||||
let range = Range::new(0, 300);
|
let range = Range::new(0, 300);
|
||||||
|
@ -104,6 +104,7 @@ pub fn init_shell(
|
||||||
shell_window_map
|
shell_window_map
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(SurfaceKind::Wl(surface), (x, y));
|
.insert(SurfaceKind::Wl(surface), (x, y));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
log.clone(),
|
log.clone(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,8 +3,8 @@ use std::collections::HashMap;
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use glium::Surface;
|
use glium::Surface;
|
||||||
|
@ -13,33 +13,33 @@ use smithay::image::{ImageBuffer, Rgba};
|
||||||
|
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
use smithay::drm::control::{Device as ControlDevice, ResourceInfo};
|
use smithay::backend::drm::{DevPath, DrmBackend, DrmDevice, DrmHandler};
|
||||||
|
use smithay::backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
||||||
|
use smithay::backend::graphics::GraphicsBackend;
|
||||||
|
use smithay::backend::input::InputBackend;
|
||||||
|
use smithay::backend::libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface};
|
||||||
|
use smithay::backend::session::auto::{auto_session_bind, AutoSession};
|
||||||
|
use smithay::backend::session::{Session, SessionNotifier};
|
||||||
|
use smithay::backend::udev::{primary_gpu, udev_backend_bind, SessionFdDrmDevice, UdevBackend, UdevHandler};
|
||||||
use smithay::drm::control::connector::{Info as ConnectorInfo, State as ConnectorState};
|
use smithay::drm::control::connector::{Info as ConnectorInfo, State as ConnectorState};
|
||||||
use smithay::drm::control::crtc;
|
use smithay::drm::control::crtc;
|
||||||
use smithay::drm::control::encoder::Info as EncoderInfo;
|
use smithay::drm::control::encoder::Info as EncoderInfo;
|
||||||
|
use smithay::drm::control::{Device as ControlDevice, ResourceInfo};
|
||||||
use smithay::drm::result::Error as DrmError;
|
use smithay::drm::result::Error as DrmError;
|
||||||
use smithay::backend::drm::{DevPath, DrmBackend, DrmDevice, DrmHandler};
|
use smithay::input::Libinput;
|
||||||
use smithay::backend::graphics::GraphicsBackend;
|
|
||||||
use smithay::backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
|
||||||
use smithay::backend::input::InputBackend;
|
|
||||||
use smithay::backend::libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface};
|
|
||||||
use smithay::backend::session::{Session, SessionNotifier};
|
|
||||||
use smithay::backend::session::auto::{auto_session_bind, AutoSession};
|
|
||||||
use smithay::backend::udev::{primary_gpu, udev_backend_bind, SessionFdDrmDevice, UdevBackend, UdevHandler};
|
|
||||||
use smithay::wayland::compositor::CompositorToken;
|
use smithay::wayland::compositor::CompositorToken;
|
||||||
use smithay::wayland::output::{Mode, Output, PhysicalProperties};
|
use smithay::wayland::output::{Mode, Output, PhysicalProperties};
|
||||||
use smithay::wayland::seat::Seat;
|
use smithay::wayland::seat::Seat;
|
||||||
use smithay::wayland::shm::init_shm_global;
|
use smithay::wayland::shm::init_shm_global;
|
||||||
use smithay::wayland_server::{Display, EventLoop};
|
use smithay::wayland_server::calloop::EventLoop;
|
||||||
use smithay::wayland_server::commons::downcast_impl;
|
|
||||||
use smithay::wayland_server::protocol::wl_output;
|
use smithay::wayland_server::protocol::wl_output;
|
||||||
use smithay::input::Libinput;
|
use smithay::wayland_server::Display;
|
||||||
|
|
||||||
use glium_drawer::GliumDrawer;
|
use glium_drawer::GliumDrawer;
|
||||||
use shell::{init_shell, MyWindowMap, Roles, SurfaceData};
|
|
||||||
use input_handler::AnvilInputHandler;
|
use input_handler::AnvilInputHandler;
|
||||||
|
use shell::{init_shell, MyWindowMap, Roles, SurfaceData};
|
||||||
|
|
||||||
pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> Result<(), ()> {
|
pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger) -> Result<(), ()> {
|
||||||
let name = display.add_socket_auto().unwrap().into_string().unwrap();
|
let name = display.add_socket_auto().unwrap().into_string().unwrap();
|
||||||
info!(log, "Listening on wayland socket"; "name" => name.clone());
|
info!(log, "Listening on wayland socket"; "name" => name.clone());
|
||||||
::std::env::set_var("WAYLAND_DISPLAY", name);
|
::std::env::set_var("WAYLAND_DISPLAY", name);
|
||||||
|
@ -51,18 +51,9 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) ->
|
||||||
/*
|
/*
|
||||||
* Initialize the compositor
|
* Initialize the compositor
|
||||||
*/
|
*/
|
||||||
init_shm_global(
|
init_shm_global(&mut display.borrow_mut(), vec![], log.clone());
|
||||||
&mut display.borrow_mut(),
|
|
||||||
event_loop.token(),
|
|
||||||
vec![],
|
|
||||||
log.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let (compositor_token, _, _, window_map) = init_shell(
|
let (compositor_token, _, _, window_map) = init_shell(&mut display.borrow_mut(), log.clone());
|
||||||
&mut display.borrow_mut(),
|
|
||||||
event_loop.token(),
|
|
||||||
log.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize session
|
* Initialize session
|
||||||
|
@ -83,7 +74,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) ->
|
||||||
|
|
||||||
let bytes = include_bytes!("../resources/cursor2.rgba");
|
let bytes = include_bytes!("../resources/cursor2.rgba");
|
||||||
let mut udev_backend = UdevBackend::new(
|
let mut udev_backend = UdevBackend::new(
|
||||||
event_loop.token(),
|
event_loop.handle(),
|
||||||
&context,
|
&context,
|
||||||
session.clone(),
|
session.clone(),
|
||||||
UdevHandlerImpl {
|
UdevHandlerImpl {
|
||||||
|
@ -102,12 +93,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) ->
|
||||||
|
|
||||||
let udev_session_id = notifier.register(&mut udev_backend);
|
let udev_session_id = notifier.register(&mut udev_backend);
|
||||||
|
|
||||||
let (mut w_seat, _) = Seat::new(
|
let (mut w_seat, _) = Seat::new(&mut display.borrow_mut(), session.seat(), log.clone());
|
||||||
&mut display.borrow_mut(),
|
|
||||||
event_loop.token(),
|
|
||||||
session.seat(),
|
|
||||||
log.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let pointer = w_seat.add_pointer();
|
let pointer = w_seat.add_pointer();
|
||||||
let keyboard = w_seat
|
let keyboard = w_seat
|
||||||
|
@ -116,13 +102,12 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) ->
|
||||||
|
|
||||||
let (output, _output_global) = Output::new(
|
let (output, _output_global) = Output::new(
|
||||||
&mut display.borrow_mut(),
|
&mut display.borrow_mut(),
|
||||||
event_loop.token(),
|
|
||||||
"Drm".into(),
|
"Drm".into(),
|
||||||
PhysicalProperties {
|
PhysicalProperties {
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
subpixel: wl_output::Subpixel::Unknown,
|
subpixel: wl_output::Subpixel::Unknown,
|
||||||
maker: "Smithay".into(),
|
make: "Smithay".into(),
|
||||||
model: "Generic DRM".into(),
|
model: "Generic DRM".into(),
|
||||||
},
|
},
|
||||||
log.clone(),
|
log.clone(),
|
||||||
|
@ -162,19 +147,20 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) ->
|
||||||
pointer_location,
|
pointer_location,
|
||||||
session,
|
session,
|
||||||
));
|
));
|
||||||
let libinput_event_source = libinput_bind(libinput_backend, event_loop.token())
|
let libinput_event_source = libinput_bind(libinput_backend, event_loop.handle())
|
||||||
.map_err(|(err, _)| err)
|
.map_err(|(e, _)| e)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let session_event_source = auto_session_bind(notifier, &event_loop.token())
|
let session_event_source = auto_session_bind(notifier, &event_loop.handle())
|
||||||
.map_err(|(err, _)| err)
|
.map_err(|(e, _)| e)
|
||||||
.unwrap();
|
|
||||||
let udev_event_source = udev_backend_bind(&event_loop.token(), udev_backend)
|
|
||||||
.map_err(|(err, _)| err)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let udev_event_source = udev_backend_bind(udev_backend).unwrap();
|
||||||
|
|
||||||
while running.load(Ordering::SeqCst) {
|
while running.load(Ordering::SeqCst) {
|
||||||
if event_loop.dispatch(Some(16)).is_err() {
|
if event_loop
|
||||||
|
.dispatch(Some(::std::time::Duration::from_millis(16)), &mut ())
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
running.store(false, Ordering::SeqCst);
|
running.store(false, Ordering::SeqCst);
|
||||||
} else {
|
} else {
|
||||||
display.borrow_mut().flush_clients();
|
display.borrow_mut().flush_clients();
|
||||||
|
@ -187,14 +173,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) ->
|
||||||
notifier.unregister(libinput_session_id);
|
notifier.unregister(libinput_session_id);
|
||||||
|
|
||||||
libinput_event_source.remove();
|
libinput_event_source.remove();
|
||||||
|
udev_event_source.remove();
|
||||||
|
|
||||||
// destroy the udev backend freeing the drm devices
|
|
||||||
//
|
|
||||||
// udev_event_source.remove() returns a Box<Implementation<..>>, downcast_impl
|
|
||||||
// allows us to cast it back to its original type, storing it back into its original
|
|
||||||
// variable to simplify type inference.
|
|
||||||
udev_backend = *(downcast_impl(udev_event_source.remove()).unwrap_or_else(|_| unreachable!()));
|
|
||||||
udev_backend.close();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,10 +261,9 @@ impl UdevHandler<DrmHandlerImpl> for UdevHandlerImpl {
|
||||||
*self.active_egl_context.borrow_mut() = device.bind_wl_display(&*self.display.borrow()).ok();
|
*self.active_egl_context.borrow_mut() = device.bind_wl_display(&*self.display.borrow()).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let backends = Rc::new(RefCell::new(self.scan_connectors(
|
let backends = Rc::new(RefCell::new(
|
||||||
device,
|
self.scan_connectors(device, self.active_egl_context.clone()),
|
||||||
self.active_egl_context.clone(),
|
));
|
||||||
)));
|
|
||||||
self.backends.insert(device.device_id(), backends.clone());
|
self.backends.insert(device.device_id(), backends.clone());
|
||||||
|
|
||||||
Some(DrmHandlerImpl {
|
Some(DrmHandlerImpl {
|
||||||
|
@ -341,11 +320,7 @@ impl DrmHandler<SessionFdDrmDevice> for DrmHandlerImpl {
|
||||||
.set_cursor_position(x.trunc().abs() as u32, y.trunc().abs() as u32);
|
.set_cursor_position(x.trunc().abs() as u32, y.trunc().abs() as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawer.draw_windows(
|
drawer.draw_windows(&*self.window_map.borrow(), self.compositor_token, &self.logger);
|
||||||
&*self.window_map.borrow(),
|
|
||||||
self.compositor_token,
|
|
||||||
&self.logger,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use smithay::utils::Rectangle;
|
use smithay::utils::Rectangle;
|
||||||
use smithay::wayland::compositor::{CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction};
|
|
||||||
use smithay::wayland::compositor::roles::Role;
|
use smithay::wayland::compositor::roles::Role;
|
||||||
use smithay::wayland::shell::xdg::{ToplevelSurface, XdgSurfaceRole};
|
use smithay::wayland::compositor::{CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction};
|
||||||
use smithay::wayland::shell::legacy::{ShellSurface, ShellSurfaceRole};
|
use smithay::wayland::shell::legacy::{ShellSurface, ShellSurfaceRole};
|
||||||
use smithay::wayland_server::Resource;
|
use smithay::wayland::shell::xdg::{ToplevelSurface, XdgSurfaceRole};
|
||||||
use smithay::wayland_server::protocol::wl_surface;
|
use smithay::wayland_server::protocol::wl_surface;
|
||||||
|
use smithay::wayland_server::Resource;
|
||||||
|
|
||||||
pub enum Kind<U, R, SD, D> {
|
pub enum Kind<U, R, SD, D> {
|
||||||
Xdg(ToplevelSurface<U, R, SD>),
|
Xdg(ToplevelSurface<U, R, SD>),
|
||||||
|
|
|
@ -1,25 +1,26 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use smithay::wayland::shm::init_shm_global;
|
use smithay::backend::graphics::egl::wayland::EGLWaylandExtensions;
|
||||||
use smithay::wayland::seat::Seat;
|
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
||||||
use smithay::wayland::output::{Mode, Output, PhysicalProperties};
|
|
||||||
use smithay::backend::input::InputBackend;
|
use smithay::backend::input::InputBackend;
|
||||||
use smithay::backend::winit;
|
use smithay::backend::winit;
|
||||||
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
use smithay::wayland::output::{Mode, Output, PhysicalProperties};
|
||||||
use smithay::backend::graphics::egl::wayland::EGLWaylandExtensions;
|
use smithay::wayland::seat::Seat;
|
||||||
use smithay::wayland_server::{Display, EventLoop};
|
use smithay::wayland::shm::init_shm_global;
|
||||||
|
use smithay::wayland_server::calloop::EventLoop;
|
||||||
use smithay::wayland_server::protocol::wl_output;
|
use smithay::wayland_server::protocol::wl_output;
|
||||||
|
use smithay::wayland_server::Display;
|
||||||
|
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
use glium_drawer::GliumDrawer;
|
use glium_drawer::GliumDrawer;
|
||||||
use shell::init_shell;
|
|
||||||
use input_handler::AnvilInputHandler;
|
use input_handler::AnvilInputHandler;
|
||||||
|
use shell::init_shell;
|
||||||
|
|
||||||
pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger) -> Result<(), ()> {
|
pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Logger) -> Result<(), ()> {
|
||||||
let (renderer, mut input) = winit::init(log.clone()).map_err(|_| ())?;
|
let (renderer, mut input) = winit::init(log.clone()).map_err(|_| ())?;
|
||||||
|
|
||||||
let egl_display = Rc::new(RefCell::new(
|
let egl_display = Rc::new(RefCell::new(
|
||||||
|
@ -44,25 +45,25 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger)
|
||||||
* Initialize the globals
|
* Initialize the globals
|
||||||
*/
|
*/
|
||||||
|
|
||||||
init_shm_global(display, event_loop.token(), vec![], log.clone());
|
init_shm_global(display, vec![], log.clone());
|
||||||
|
|
||||||
let (compositor_token, _, _, window_map) = init_shell(display, event_loop.token(), log.clone());
|
let (compositor_token, _, _, window_map) = init_shell(display, log.clone());
|
||||||
|
|
||||||
let (mut seat, _) = Seat::new(display, event_loop.token(), "winit".into(), log.clone());
|
let (mut seat, _) = Seat::new(display, "winit".into(), log.clone());
|
||||||
|
|
||||||
let pointer = seat.add_pointer();
|
let pointer = seat.add_pointer();
|
||||||
let keyboard = seat.add_keyboard("", "fr", "oss", None, 1000, 500)
|
let keyboard = seat
|
||||||
|
.add_keyboard("", "fr", "oss", None, 1000, 500)
|
||||||
.expect("Failed to initialize the keyboard");
|
.expect("Failed to initialize the keyboard");
|
||||||
|
|
||||||
let (output, _) = Output::new(
|
let (output, _) = Output::new(
|
||||||
display,
|
display,
|
||||||
event_loop.token(),
|
|
||||||
"Winit".into(),
|
"Winit".into(),
|
||||||
PhysicalProperties {
|
PhysicalProperties {
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
subpixel: wl_output::Subpixel::Unknown,
|
subpixel: wl_output::Subpixel::Unknown,
|
||||||
maker: "Smithay".into(),
|
make: "Smithay".into(),
|
||||||
model: "Winit".into(),
|
model: "Winit".into(),
|
||||||
},
|
},
|
||||||
log.clone(),
|
log.clone(),
|
||||||
|
@ -100,7 +101,9 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger)
|
||||||
|
|
||||||
drawer.draw_windows(&*window_map.borrow(), compositor_token, &log);
|
drawer.draw_windows(&*window_map.borrow(), compositor_token, &log);
|
||||||
|
|
||||||
event_loop.dispatch(Some(16)).unwrap();
|
event_loop
|
||||||
|
.dispatch(Some(::std::time::Duration::from_millis(16)), &mut ())
|
||||||
|
.unwrap();
|
||||||
display.flush_clients();
|
display.flush_clients();
|
||||||
|
|
||||||
window_map.borrow_mut().refresh();
|
window_map.borrow_mut().refresh();
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
use super::DevPath;
|
|
||||||
use super::error::*;
|
use super::error::*;
|
||||||
use backend::graphics::GraphicsBackend;
|
use super::DevPath;
|
||||||
use backend::graphics::egl::{EGLContext, EGLGraphicsBackend, EGLSurface, PixelFormat, SwapBuffersError};
|
|
||||||
use backend::graphics::egl::error::Result as EGLResult;
|
use backend::graphics::egl::error::Result as EGLResult;
|
||||||
use backend::graphics::egl::native::{Gbm, GbmSurfaceArguments};
|
use backend::graphics::egl::native::{Gbm, GbmSurfaceArguments};
|
||||||
use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
||||||
use drm::Device as BasicDevice;
|
use backend::graphics::egl::{EGLContext, EGLGraphicsBackend, EGLSurface, PixelFormat, SwapBuffersError};
|
||||||
use drm::control::{Device, ResourceInfo};
|
use backend::graphics::GraphicsBackend;
|
||||||
use drm::control::{connector, crtc, encoder, framebuffer, Mode};
|
use drm::control::{connector, crtc, encoder, framebuffer, Mode};
|
||||||
use gbm::{BufferObject, BufferObjectFlags, Device as GbmDevice, Format as GbmFormat, Surface as GbmSurface,
|
use drm::control::{Device, ResourceInfo};
|
||||||
SurfaceBufferHandle};
|
use drm::Device as BasicDevice;
|
||||||
|
use gbm::{
|
||||||
|
BufferObject, BufferObjectFlags, Device as GbmDevice, Format as GbmFormat, Surface as GbmSurface,
|
||||||
|
SurfaceBufferHandle,
|
||||||
|
};
|
||||||
use image::{ImageBuffer, Rgba};
|
use image::{ImageBuffer, Rgba};
|
||||||
use nix::libc::c_void;
|
use nix::libc::c_void;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -54,19 +56,12 @@ impl<A: Device + 'static> DrmBackend<A> {
|
||||||
size: (w as u32, h as u32),
|
size: (w as u32, h as u32),
|
||||||
format: GbmFormat::XRGB8888,
|
format: GbmFormat::XRGB8888,
|
||||||
flags: BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
|
flags: BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
|
||||||
})
|
}).chain_err(|| ErrorKind::GbmInitFailed)?;
|
||||||
.chain_err(|| ErrorKind::GbmInitFailed)?;
|
|
||||||
|
|
||||||
// make it active for the first `crtc::set`
|
// make it active for the first `crtc::set`
|
||||||
// (which is needed before the first page_flip)
|
// (which is needed before the first page_flip)
|
||||||
unsafe {
|
unsafe { surface.make_current().chain_err(|| ErrorKind::FailedToSwap)? };
|
||||||
surface
|
surface.swap_buffers().chain_err(|| ErrorKind::FailedToSwap)?;
|
||||||
.make_current()
|
|
||||||
.chain_err(|| ErrorKind::FailedToSwap)?
|
|
||||||
};
|
|
||||||
surface
|
|
||||||
.swap_buffers()
|
|
||||||
.chain_err(|| ErrorKind::FailedToSwap)?;
|
|
||||||
|
|
||||||
// init the first screen
|
// init the first screen
|
||||||
// (must be done before calling page_flip for the first time)
|
// (must be done before calling page_flip for the first time)
|
||||||
|
@ -78,21 +73,11 @@ impl<A: Device + 'static> DrmBackend<A> {
|
||||||
|
|
||||||
// we need a framebuffer for the front buffer
|
// we need a framebuffer for the front buffer
|
||||||
let fb = framebuffer::create(&*context, &*front_bo).chain_err(|| {
|
let fb = framebuffer::create(&*context, &*front_bo).chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("Error creating framebuffer on {:?}", context.dev_path()))
|
||||||
"Error creating framebuffer on {:?}",
|
|
||||||
context.dev_path()
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
debug!(log, "Initialize screen");
|
debug!(log, "Initialize screen");
|
||||||
crtc::set(
|
crtc::set(&*context, crtc, fb.handle(), &connectors, (0, 0), Some(mode)).chain_err(|| {
|
||||||
&*context,
|
|
||||||
crtc,
|
|
||||||
fb.handle(),
|
|
||||||
&connectors,
|
|
||||||
(0, 0),
|
|
||||||
Some(mode),
|
|
||||||
).chain_err(|| {
|
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!(
|
||||||
"Error setting crtc {:?} on {:?}",
|
"Error setting crtc {:?} on {:?}",
|
||||||
crtc,
|
crtc,
|
||||||
|
@ -108,8 +93,7 @@ impl<A: Device + 'static> DrmBackend<A> {
|
||||||
1,
|
1,
|
||||||
GbmFormat::ARGB8888,
|
GbmFormat::ARGB8888,
|
||||||
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
|
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
|
||||||
)
|
).chain_err(|| ErrorKind::GbmInitFailed)?,
|
||||||
.chain_err(|| ErrorKind::GbmInitFailed)?,
|
|
||||||
(0, 0),
|
(0, 0),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -149,7 +133,8 @@ impl<A: Device + 'static> DrmBackend<A> {
|
||||||
// check if the connector can handle the current mode
|
// check if the connector can handle the current mode
|
||||||
if info.modes().contains(&self.mode) {
|
if info.modes().contains(&self.mode) {
|
||||||
// check if there is a valid encoder
|
// check if there is a valid encoder
|
||||||
let encoders = info.encoders()
|
let encoders = info
|
||||||
|
.encoders()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|encoder| {
|
.map(|encoder| {
|
||||||
encoder::Info::load_from_device(&*self.backend.context, *encoder).chain_err(|| {
|
encoder::Info::load_from_device(&*self.backend.context, *encoder).chain_err(|| {
|
||||||
|
@ -158,8 +143,7 @@ impl<A: Device + 'static> DrmBackend<A> {
|
||||||
self.backend.context.dev_path()
|
self.backend.context.dev_path()
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
})
|
}).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.backend.context.resource_handles().chain_err(|| {
|
let resource_handles = self.backend.context.resource_handles().chain_err(|| {
|
||||||
|
@ -171,11 +155,11 @@ impl<A: Device + 'static> DrmBackend<A> {
|
||||||
if !encoders
|
if !encoders
|
||||||
.iter()
|
.iter()
|
||||||
.map(|encoder| encoder.possible_crtcs())
|
.map(|encoder| encoder.possible_crtcs())
|
||||||
.all(|crtc_list|
|
.all(|crtc_list| {
|
||||||
resource_handles
|
resource_handles
|
||||||
.filter_crtcs(crtc_list)
|
.filter_crtcs(crtc_list)
|
||||||
.contains(&self.backend.crtc)
|
.contains(&self.backend.crtc)
|
||||||
) {
|
}) {
|
||||||
bail!(ErrorKind::NoSuitableEncoder(info, self.backend.crtc));
|
bail!(ErrorKind::NoSuitableEncoder(info, self.backend.crtc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,8 +216,7 @@ impl<A: Device + 'static> DrmBackend<A> {
|
||||||
"Error loading connector info on {:?}",
|
"Error loading connector info on {:?}",
|
||||||
self.backend.context.dev_path()
|
self.backend.context.dev_path()
|
||||||
))
|
))
|
||||||
})?
|
})?.modes()
|
||||||
.modes()
|
|
||||||
.contains(&mode)
|
.contains(&mode)
|
||||||
{
|
{
|
||||||
bail!(ErrorKind::ModeNotSuitable(mode));
|
bail!(ErrorKind::ModeNotSuitable(mode));
|
||||||
|
@ -249,25 +232,19 @@ impl<A: Device + 'static> DrmBackend<A> {
|
||||||
self.backend.logger,
|
self.backend.logger,
|
||||||
"Reinitializing surface for new mode: {}:{}", w, h
|
"Reinitializing surface for new mode: {}:{}", w, h
|
||||||
);
|
);
|
||||||
let surface = self.backend
|
let surface = self
|
||||||
|
.backend
|
||||||
.context
|
.context
|
||||||
.create_surface(GbmSurfaceArguments {
|
.create_surface(GbmSurfaceArguments {
|
||||||
size: (w as u32, h as u32),
|
size: (w as u32, h as u32),
|
||||||
format: GbmFormat::XRGB8888,
|
format: GbmFormat::XRGB8888,
|
||||||
flags: BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
|
flags: BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
|
||||||
})
|
}).chain_err(|| ErrorKind::GbmInitFailed)?;
|
||||||
.chain_err(|| ErrorKind::GbmInitFailed)?;
|
|
||||||
|
|
||||||
// make it active for the first `crtc::set`
|
// make it active for the first `crtc::set`
|
||||||
// (which is needed before the first page_flip)
|
// (which is needed before the first page_flip)
|
||||||
unsafe {
|
unsafe { surface.make_current().chain_err(|| ErrorKind::FailedToSwap)? };
|
||||||
surface
|
surface.swap_buffers().chain_err(|| ErrorKind::FailedToSwap)?;
|
||||||
.make_current()
|
|
||||||
.chain_err(|| ErrorKind::FailedToSwap)?
|
|
||||||
};
|
|
||||||
surface
|
|
||||||
.swap_buffers()
|
|
||||||
.chain_err(|| ErrorKind::FailedToSwap)?;
|
|
||||||
|
|
||||||
// Clean up next_buffer
|
// Clean up next_buffer
|
||||||
{
|
{
|
||||||
|
@ -412,11 +389,7 @@ impl<A: Device + 'static> GraphicsBackend for DrmBackend<A> {
|
||||||
|
|
||||||
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> {
|
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> {
|
||||||
trace!(self.backend.logger, "Move the cursor to {},{}", x, y);
|
trace!(self.backend.logger, "Move the cursor to {},{}", x, y);
|
||||||
crtc::move_cursor(
|
crtc::move_cursor(&*self.backend.context, self.backend.crtc, (x as i32, y as i32)).chain_err(|| {
|
||||||
&*self.backend.context,
|
|
||||||
self.backend.crtc,
|
|
||||||
(x as i32, y as i32),
|
|
||||||
).chain_err(|| {
|
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!(
|
||||||
"Error moving cursor on {:?}",
|
"Error moving cursor on {:?}",
|
||||||
self.backend.context.dev_path()
|
self.backend.context.dev_path()
|
||||||
|
@ -433,15 +406,15 @@ impl<A: Device + 'static> GraphicsBackend for DrmBackend<A> {
|
||||||
debug!(self.backend.logger, "Importing cursor");
|
debug!(self.backend.logger, "Importing cursor");
|
||||||
|
|
||||||
// import the cursor into a buffer we can render
|
// import the cursor into a buffer we can render
|
||||||
let mut cursor = self.backend
|
let mut cursor = self
|
||||||
|
.backend
|
||||||
.context
|
.context
|
||||||
.create_buffer_object(
|
.create_buffer_object(
|
||||||
w,
|
w,
|
||||||
h,
|
h,
|
||||||
GbmFormat::ARGB8888,
|
GbmFormat::ARGB8888,
|
||||||
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
|
BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
|
||||||
)
|
).chain_err(|| ErrorKind::GbmInitFailed)?;
|
||||||
.chain_err(|| ErrorKind::GbmInitFailed)?;
|
|
||||||
cursor
|
cursor
|
||||||
.write(&**buffer)
|
.write(&**buffer)
|
||||||
.chain_err(|| ErrorKind::GbmInitFailed)?
|
.chain_err(|| ErrorKind::GbmInitFailed)?
|
||||||
|
@ -495,7 +468,8 @@ impl<A: Device + 'static> EGLGraphicsBackend for DrmBackend<A> {
|
||||||
// would most likely result in a lot of flickering.
|
// would most likely result in a lot of flickering.
|
||||||
// neither weston, wlc or wlroots bother with that as well.
|
// neither weston, wlc or wlroots bother with that as well.
|
||||||
// so we just assume we got at least two buffers to do flipping.
|
// so we just assume we got at least two buffers to do flipping.
|
||||||
let mut next_bo = self.surface
|
let mut next_bo = self
|
||||||
|
.surface
|
||||||
.lock_front_buffer()
|
.lock_front_buffer()
|
||||||
.expect("Surface only has one front buffer. Not supported by smithay");
|
.expect("Surface only has one front buffer. Not supported by smithay");
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,8 @@
|
||||||
//! #
|
//! #
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! #
|
//! #
|
||||||
//! # let (_display, mut event_loop) = wayland_server::Display::new();
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
//! #
|
//! #
|
||||||
//! # let mut options = OpenOptions::new();
|
//! # let mut options = OpenOptions::new();
|
||||||
//! # options.read(true);
|
//! # options.read(true);
|
||||||
|
@ -199,12 +200,12 @@
|
||||||
//! backend.swap_buffers().unwrap();
|
//! backend.swap_buffers().unwrap();
|
||||||
//!
|
//!
|
||||||
//! let (_source, _device_rc) = drm_device_bind(
|
//! let (_source, _device_rc) = drm_device_bind(
|
||||||
//! &event_loop.token(),
|
//! &event_loop.handle(),
|
||||||
//! device,
|
//! device,
|
||||||
//! MyDrmHandler(backend)
|
//! MyDrmHandler(backend)
|
||||||
//! ).map_err(|(err, _)| err).unwrap();
|
//! ).map_err(|(err, _)| err).unwrap();
|
||||||
//!
|
//!
|
||||||
//! event_loop.run().unwrap();
|
//! /* And then run the event loop once all your setup is done */
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
@ -214,11 +215,11 @@ use backend::graphics::egl::native::Gbm;
|
||||||
use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
||||||
#[cfg(feature = "backend_session")]
|
#[cfg(feature = "backend_session")]
|
||||||
use backend::session::{AsSessionObserver, SessionObserver};
|
use backend::session::{AsSessionObserver, SessionObserver};
|
||||||
use drm::Device as BasicDevice;
|
|
||||||
use drm::control::{connector, crtc, encoder, Mode, ResourceInfo};
|
|
||||||
use drm::control::Device as ControlDevice;
|
|
||||||
use drm::control::framebuffer;
|
use drm::control::framebuffer;
|
||||||
|
use drm::control::Device as ControlDevice;
|
||||||
|
use drm::control::{connector, crtc, encoder, Mode, ResourceInfo};
|
||||||
use drm::result::Error as DrmError;
|
use drm::result::Error as DrmError;
|
||||||
|
use drm::Device as BasicDevice;
|
||||||
use gbm::{BufferObject, Device as GbmDevice};
|
use gbm::{BufferObject, Device as GbmDevice};
|
||||||
use nix;
|
use nix;
|
||||||
use nix::sys::stat::{self, dev_t, fstat};
|
use nix::sys::stat::{self, dev_t, fstat};
|
||||||
|
@ -229,12 +230,13 @@ use std::io::Error as IoError;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::{Arc, Once, ONCE_INIT};
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::{Arc, Once, ONCE_INIT};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wayland_server::{Display, LoopToken};
|
|
||||||
use wayland_server::commons::Implementation;
|
use wayland_server::calloop::generic::{EventedRawFd, Generic};
|
||||||
use wayland_server::sources::{FdEvent, FdInterest, Source};
|
use wayland_server::calloop::{LoopHandle, Ready, Source};
|
||||||
|
use wayland_server::Display;
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
@ -306,7 +308,8 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
|
||||||
|
|
||||||
let mut drm = DrmDevice {
|
let mut drm = DrmDevice {
|
||||||
// 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
|
||||||
context: Rc::new(EGLContext::new(
|
context: Rc::new(
|
||||||
|
EGLContext::new(
|
||||||
{
|
{
|
||||||
debug!(log, "Creating gbm device");
|
debug!(log, "Creating gbm device");
|
||||||
let gbm = GbmDevice::new(dev).chain_err(|| ErrorKind::GbmInitFailed)?;
|
let gbm = GbmDevice::new(dev).chain_err(|| ErrorKind::GbmInitFailed)?;
|
||||||
|
@ -316,7 +319,8 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
|
||||||
attributes,
|
attributes,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
log.clone(),
|
log.clone(),
|
||||||
).map_err(Error::from)?),
|
).map_err(Error::from)?,
|
||||||
|
),
|
||||||
backends: Rc::new(RefCell::new(HashMap::new())),
|
backends: Rc::new(RefCell::new(HashMap::new())),
|
||||||
device_id,
|
device_id,
|
||||||
old_state: HashMap::new(),
|
old_state: HashMap::new(),
|
||||||
|
@ -329,32 +333,20 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
|
||||||
|
|
||||||
// we want to mode-set, so we better be the master, if we run via a tty session
|
// we want to mode-set, so we better be the master, if we run via a tty session
|
||||||
if drm.set_master().is_err() {
|
if drm.set_master().is_err() {
|
||||||
warn!(
|
warn!(log, "Unable to become drm master, assuming unpriviledged mode");
|
||||||
log,
|
|
||||||
"Unable to become drm master, assuming unpriviledged mode"
|
|
||||||
);
|
|
||||||
drm.priviledged = false;
|
drm.priviledged = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
let res_handles = drm.resource_handles().chain_err(|| {
|
let res_handles = drm.resource_handles().chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", drm.dev_path()))
|
||||||
"Error loading drm resources on {:?}",
|
|
||||||
drm.dev_path()
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
for &con in res_handles.connectors() {
|
for &con in res_handles.connectors() {
|
||||||
let con_info = connector::Info::load_from_device(&drm, con).chain_err(|| {
|
let con_info = connector::Info::load_from_device(&drm, con).chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", drm.dev_path()))
|
||||||
"Error loading connector info on {:?}",
|
|
||||||
drm.dev_path()
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
if let Some(enc) = con_info.current_encoder() {
|
if let Some(enc) = con_info.current_encoder() {
|
||||||
let enc_info = encoder::Info::load_from_device(&drm, enc).chain_err(|| {
|
let enc_info = encoder::Info::load_from_device(&drm, enc).chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", drm.dev_path()))
|
||||||
"Error loading encoder info on {:?}",
|
|
||||||
drm.dev_path()
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
if let Some(crtc) = enc_info.current_crtc() {
|
if let Some(crtc) = enc_info.current_crtc() {
|
||||||
let info = crtc::Info::load_from_device(&drm, crtc).chain_err(|| {
|
let info = crtc::Info::load_from_device(&drm, crtc).chain_err(|| {
|
||||||
|
@ -400,10 +392,7 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
|
||||||
// check if we have an encoder for every connector and the mode mode
|
// check if we have an encoder for every connector and the mode mode
|
||||||
for connector in &connectors {
|
for connector in &connectors {
|
||||||
let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| {
|
let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path()))
|
||||||
"Error loading connector info on {:?}",
|
|
||||||
self.dev_path()
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// check the mode
|
// check the mode
|
||||||
|
@ -417,20 +406,13 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|encoder| {
|
.map(|encoder| {
|
||||||
encoder::Info::load_from_device(self, *encoder).chain_err(|| {
|
encoder::Info::load_from_device(self, *encoder).chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path()))
|
||||||
"Error loading encoder info on {:?}",
|
|
||||||
self.dev_path()
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
})
|
}).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().chain_err(|| {
|
let resource_handles = self.resource_handles().chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path()))
|
||||||
"Error loading drm resources on {:?}",
|
|
||||||
self.dev_path()
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
if !encoders
|
if !encoders
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -512,18 +494,12 @@ impl<A: ControlDevice + 'static> Drop for DrmDevice<A> {
|
||||||
info.position(),
|
info.position(),
|
||||||
info.mode(),
|
info.mode(),
|
||||||
) {
|
) {
|
||||||
error!(
|
error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err);
|
||||||
self.logger,
|
|
||||||
"Failed to reset crtc ({:?}). Error: {}", handle, err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.priviledged {
|
if self.priviledged {
|
||||||
if let Err(err) = self.drop_master() {
|
if let Err(err) = self.drop_master() {
|
||||||
error!(
|
error!(self.logger, "Failed to drop drm master state. Error: {}", err);
|
||||||
self.logger,
|
|
||||||
"Failed to drop drm master state. Error: {}", err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -546,84 +522,59 @@ pub trait DrmHandler<A: ControlDevice + 'static> {
|
||||||
/// Bind a `DrmDevice` to an `EventLoop`,
|
/// Bind a `DrmDevice` to an `EventLoop`,
|
||||||
///
|
///
|
||||||
/// This will cause it to recieve events and feed them into an `DrmHandler`
|
/// This will cause it to recieve events and feed them into an `DrmHandler`
|
||||||
pub fn drm_device_bind<A, H>(
|
pub fn drm_device_bind<A, H, Data: 'static>(
|
||||||
token: &LoopToken,
|
handle: &LoopHandle<Data>,
|
||||||
device: DrmDevice<A>,
|
device: DrmDevice<A>,
|
||||||
handler: H,
|
mut handler: H,
|
||||||
) -> ::std::result::Result<(Source<FdEvent>, Rc<RefCell<DrmDevice<A>>>), (IoError, (DrmDevice<A>, H))>
|
) -> ::std::result::Result<(Source<Generic<EventedRawFd>>, Rc<RefCell<DrmDevice<A>>>), (IoError, DrmDevice<A>)>
|
||||||
where
|
where
|
||||||
A: ControlDevice + 'static,
|
A: ControlDevice + 'static,
|
||||||
H: DrmHandler<A> + 'static,
|
H: DrmHandler<A> + 'static,
|
||||||
{
|
{
|
||||||
let fd = device.as_raw_fd();
|
let fd = device.as_raw_fd();
|
||||||
let device = Rc::new(RefCell::new(device));
|
let device = Rc::new(RefCell::new(device));
|
||||||
match token.add_fd_event_source(
|
|
||||||
fd,
|
let mut source = Generic::from_raw_fd(fd);
|
||||||
FdInterest::READ,
|
source.set_interest(Ready::readable());
|
||||||
DrmFdImpl {
|
|
||||||
device: device.clone(),
|
match handle.insert_source(source, {
|
||||||
handler,
|
let device = device.clone();
|
||||||
},
|
move |_evt, _| {
|
||||||
) {
|
let mut device = device.borrow_mut();
|
||||||
|
process_events(&mut *device, &mut handler);
|
||||||
|
}
|
||||||
|
}) {
|
||||||
Ok(source) => Ok((source, device)),
|
Ok(source) => Ok((source, device)),
|
||||||
Err((
|
Err(e) => {
|
||||||
ioerror,
|
|
||||||
DrmFdImpl {
|
|
||||||
device: device2,
|
|
||||||
handler,
|
|
||||||
},
|
|
||||||
)) => {
|
|
||||||
// make the Rc unique again
|
|
||||||
::std::mem::drop(device2);
|
|
||||||
let device = Rc::try_unwrap(device).unwrap_or_else(|_| unreachable!());
|
let device = Rc::try_unwrap(device).unwrap_or_else(|_| unreachable!());
|
||||||
Err((ioerror, (device.into_inner(), handler)))
|
Err((e, device.into_inner()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DrmFdImpl<A: ControlDevice + 'static, H> {
|
fn process_events<A, H>(device: &mut DrmDevice<A>, handler: &mut H)
|
||||||
device: Rc<RefCell<DrmDevice<A>>>,
|
|
||||||
handler: H,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, H> Implementation<(), FdEvent> for DrmFdImpl<A, H>
|
|
||||||
where
|
where
|
||||||
A: ControlDevice + 'static,
|
A: ControlDevice + 'static,
|
||||||
H: DrmHandler<A> + 'static,
|
H: DrmHandler<A> + 'static,
|
||||||
{
|
{
|
||||||
fn receive(&mut self, event: FdEvent, (): ()) {
|
match crtc::receive_events(&*device) {
|
||||||
let mut device = self.device.borrow_mut();
|
|
||||||
match event {
|
|
||||||
FdEvent::Ready { .. } => match crtc::receive_events(&*device) {
|
|
||||||
Ok(events) => for event in events {
|
Ok(events) => for event in events {
|
||||||
if let crtc::Event::PageFlip(event) = event {
|
if let crtc::Event::PageFlip(event) = event {
|
||||||
if device.active.load(Ordering::SeqCst) {
|
if device.active.load(Ordering::SeqCst) {
|
||||||
let backends = device.backends.borrow().clone();
|
let backends = device.backends.borrow().clone();
|
||||||
if let Some(backend) = backends
|
if let Some(backend) = backends.get(&event.crtc).iter().flat_map(|x| x.upgrade()).next() {
|
||||||
.get(&event.crtc)
|
|
||||||
.iter()
|
|
||||||
.flat_map(|x| x.upgrade())
|
|
||||||
.next()
|
|
||||||
{
|
|
||||||
// we can now unlock the buffer
|
// we can now unlock the buffer
|
||||||
backend.unlock_buffer();
|
backend.unlock_buffer();
|
||||||
trace!(device.logger, "Handling event for backend {:?}", event.crtc);
|
trace!(device.logger, "Handling event for backend {:?}", event.crtc);
|
||||||
// and then call the user to render the next frame
|
// and then call the user to render the next frame
|
||||||
self.handler
|
handler.ready(device, event.crtc, event.frame, event.duration);
|
||||||
.ready(&mut device, event.crtc, event.frame, event.duration);
|
|
||||||
} else {
|
} else {
|
||||||
device.backends.borrow_mut().remove(&event.crtc);
|
device.backends.borrow_mut().remove(&event.crtc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(err) => self.handler.error(&mut device, err),
|
Err(err) => handler.error(device, err),
|
||||||
},
|
|
||||||
FdEvent::Error { error, .. } => {
|
|
||||||
warn!(device.logger, "DrmDevice errored: {}", error);
|
|
||||||
self.handler.error(&mut device, error.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,10 +622,7 @@ impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
|
||||||
info.position(),
|
info.position(),
|
||||||
info.mode(),
|
info.mode(),
|
||||||
) {
|
) {
|
||||||
error!(
|
error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err);
|
||||||
self.logger,
|
|
||||||
"Failed to reset crtc ({:?}). Error: {}", handle, err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -682,10 +630,7 @@ impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
|
||||||
if self.priviledged {
|
if self.priviledged {
|
||||||
if let Some(device) = self.context.upgrade() {
|
if let Some(device) = self.context.upgrade() {
|
||||||
if let Err(err) = device.drop_master() {
|
if let Err(err) = device.drop_master() {
|
||||||
error!(
|
error!(self.logger, "Failed to drop drm master state. Error: {}", err);
|
||||||
self.logger,
|
|
||||||
"Failed to drop drm master state. Error: {}", err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -707,11 +652,7 @@ impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
|
||||||
if self.priviledged {
|
if self.priviledged {
|
||||||
if let Some(device) = self.context.upgrade() {
|
if let Some(device) = self.context.upgrade() {
|
||||||
if let Err(err) = device.set_master() {
|
if let Err(err) = device.set_master() {
|
||||||
crit!(
|
crit!(self.logger, "Failed to acquire drm master again. Error: {}", err);
|
||||||
self.logger,
|
|
||||||
"Failed to acquire drm master again. Error: {}",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
//! EGL context related structs
|
//! EGL context related structs
|
||||||
|
|
||||||
use super::{ffi, EGLSurface, PixelFormat};
|
|
||||||
use super::error::*;
|
use super::error::*;
|
||||||
use super::native;
|
use super::native;
|
||||||
#[cfg(feature = "backend_drm")]
|
use super::{ffi, EGLSurface, PixelFormat};
|
||||||
use drm::Device as BasicDevice;
|
|
||||||
#[cfg(feature = "backend_drm")]
|
#[cfg(feature = "backend_drm")]
|
||||||
use drm::control::Device as ControlDevice;
|
use drm::control::Device as ControlDevice;
|
||||||
#[cfg(feature = "backend_drm")]
|
#[cfg(feature = "backend_drm")]
|
||||||
|
use drm::Device as BasicDevice;
|
||||||
|
#[cfg(feature = "backend_drm")]
|
||||||
use gbm::Device as GbmDevice;
|
use gbm::Device as GbmDevice;
|
||||||
use nix::libc::{c_int, c_void};
|
use nix::libc::{c_int, c_void};
|
||||||
use slog;
|
use slog;
|
||||||
|
@ -89,8 +89,7 @@ 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::EGLContext>,
|
||||||
Rc<ffi::egl::types::EGLDisplay>,
|
Rc<ffi::egl::types::EGLDisplay>,
|
||||||
ffi::egl::types::EGLConfig,
|
ffi::egl::types::EGLConfig,
|
||||||
|
@ -98,8 +97,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
PixelFormat,
|
PixelFormat,
|
||||||
bool,
|
bool,
|
||||||
bool,
|
bool,
|
||||||
),
|
)> {
|
||||||
> {
|
|
||||||
// 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 {
|
||||||
|
@ -119,10 +117,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some((1, x)) => {
|
Some((1, x)) => {
|
||||||
error!(
|
error!(log, "OpenGLES 1.* is not supported by the EGL renderer backend");
|
||||||
log,
|
|
||||||
"OpenGLES 1.* is not supported by the EGL renderer backend"
|
|
||||||
);
|
|
||||||
bail!(ErrorKind::OpenGlVersionNotSupported((1, x)));
|
bail!(ErrorKind::OpenGlVersionNotSupported((1, x)));
|
||||||
}
|
}
|
||||||
Some(version) => {
|
Some(version) => {
|
||||||
|
@ -178,11 +173,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
|
|
||||||
debug!(log, "EGL No-Display Extensions: {:?}", dp_extensions);
|
debug!(log, "EGL No-Display Extensions: {:?}", dp_extensions);
|
||||||
|
|
||||||
let display = B::get_display(
|
let display = B::get_display(ptr, |e: &str| dp_extensions.iter().any(|s| s == e), log.clone());
|
||||||
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);
|
bail!(ErrorKind::DisplayNotSupported);
|
||||||
|
@ -215,10 +206,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
info!(log, "EGL Extensions: {:?}", extensions);
|
info!(log, "EGL Extensions: {:?}", extensions);
|
||||||
|
|
||||||
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!(
|
error!(log, "OpenGLES not supported by the underlying EGL implementation");
|
||||||
log,
|
|
||||||
"OpenGLES not supported by the underlying EGL implementation"
|
|
||||||
);
|
|
||||||
bail!(ErrorKind::OpenGlesNotSupported);
|
bail!(ErrorKind::OpenGlesNotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,14 +327,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
// calling `eglChooseConfig`
|
// calling `eglChooseConfig`
|
||||||
let mut config_id = mem::uninitialized();
|
let mut config_id = mem::uninitialized();
|
||||||
let mut num_configs = mem::uninitialized();
|
let mut num_configs = mem::uninitialized();
|
||||||
if ffi::egl::ChooseConfig(
|
if ffi::egl::ChooseConfig(display, descriptor.as_ptr(), &mut config_id, 1, &mut num_configs) == 0 {
|
||||||
display,
|
|
||||||
descriptor.as_ptr(),
|
|
||||||
&mut config_id,
|
|
||||||
1,
|
|
||||||
&mut num_configs,
|
|
||||||
) == 0
|
|
||||||
{
|
|
||||||
bail!(ErrorKind::ConfigFailed);
|
bail!(ErrorKind::ConfigFailed);
|
||||||
}
|
}
|
||||||
if num_configs == 0 {
|
if num_configs == 0 {
|
||||||
|
@ -356,17 +337,14 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
|
|
||||||
// analyzing each config
|
// analyzing each config
|
||||||
macro_rules! attrib {
|
macro_rules! attrib {
|
||||||
($display:expr, $config:expr, $attr:expr) => (
|
($display:expr, $config:expr, $attr:expr) => {{
|
||||||
{
|
|
||||||
let mut value = mem::uninitialized();
|
let mut value = mem::uninitialized();
|
||||||
let res = ffi::egl::GetConfigAttrib($display, $config,
|
let res = ffi::egl::GetConfigAttrib($display, $config, $attr as ffi::egl::types::EGLint, &mut value);
|
||||||
$attr as ffi::egl::types::EGLint, &mut value);
|
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
bail!(ErrorKind::ConfigFailed);
|
bail!(ErrorKind::ConfigFailed);
|
||||||
}
|
}
|
||||||
value
|
value
|
||||||
}
|
}};
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let desc = PixelFormat {
|
let desc = PixelFormat {
|
||||||
|
@ -450,12 +428,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
info!(log, "EGL context created");
|
info!(log, "EGL context created");
|
||||||
|
|
||||||
// make current and get list of gl extensions
|
// make current and get list of gl extensions
|
||||||
ffi::egl::MakeCurrent(
|
ffi::egl::MakeCurrent(display as *const _, ptr::null(), ptr::null(), context as *const _);
|
||||||
display as *const _,
|
|
||||||
ptr::null(),
|
|
||||||
ptr::null(),
|
|
||||||
context as *const _,
|
|
||||||
);
|
|
||||||
|
|
||||||
// the list of gl extensions supported by the context
|
// the list of gl extensions supported by the context
|
||||||
let gl_extensions = {
|
let gl_extensions = {
|
||||||
|
@ -474,9 +447,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||||
config_id,
|
config_id,
|
||||||
surface_attributes,
|
surface_attributes,
|
||||||
desc,
|
desc,
|
||||||
extensions
|
extensions.iter().any(|s| *s == "EGL_WL_bind_wayland_display"),
|
||||||
.iter()
|
|
||||||
.any(|s| *s == "EGL_WL_bind_wayland_display"),
|
|
||||||
gl_extensions
|
gl_extensions
|
||||||
.iter()
|
.iter()
|
||||||
.any(|s| *s == "GL_OES_EGL_image" || *s == "GL_OES_EGL_image_base"),
|
.any(|s| *s == "GL_OES_EGL_image" || *s == "GL_OES_EGL_image_base"),
|
||||||
|
|
|
@ -25,9 +25,7 @@ pub mod egl {
|
||||||
use std::sync::{Once, ONCE_INIT};
|
use std::sync::{Once, ONCE_INIT};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref LIB: Library = {
|
pub static ref LIB: Library = { Library::new("libEGL.so.1").expect("Failed to load LibEGL") };
|
||||||
Library::new("libEGL.so.1").expect("Failed to load LibEGL")
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static LOAD: Once = ONCE_INIT;
|
pub static LOAD: Once = ONCE_INIT;
|
||||||
|
@ -101,9 +99,9 @@ pub mod egl {
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub mod BindWaylandDisplayWL {
|
pub mod BindWaylandDisplayWL {
|
||||||
use super::{metaloadfn, wayland_storage};
|
|
||||||
use super::FnPtr;
|
use super::FnPtr;
|
||||||
use super::__gl_imports::raw;
|
use super::__gl_imports::raw;
|
||||||
|
use super::{metaloadfn, wayland_storage};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -125,9 +123,9 @@ pub mod egl {
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub mod UnbindWaylandDisplayWL {
|
pub mod UnbindWaylandDisplayWL {
|
||||||
use super::{metaloadfn, wayland_storage};
|
|
||||||
use super::FnPtr;
|
use super::FnPtr;
|
||||||
use super::__gl_imports::raw;
|
use super::__gl_imports::raw;
|
||||||
|
use super::{metaloadfn, wayland_storage};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -149,9 +147,9 @@ pub mod egl {
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub mod QueryWaylandBufferWL {
|
pub mod QueryWaylandBufferWL {
|
||||||
use super::{metaloadfn, wayland_storage};
|
|
||||||
use super::FnPtr;
|
use super::FnPtr;
|
||||||
use super::__gl_imports::raw;
|
use super::__gl_imports::raw;
|
||||||
|
use super::{metaloadfn, wayland_storage};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -13,7 +13,12 @@ use std::fmt;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub use self::context::EGLContext;
|
pub use self::context::EGLContext;
|
||||||
pub mod error;
|
pub mod 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;
|
||||||
pub mod native;
|
pub mod native;
|
||||||
pub mod surface;
|
pub mod surface;
|
||||||
|
|
|
@ -15,9 +15,9 @@ use std::ptr;
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
use wayland_client::egl as wegl;
|
use wayland_client::egl as wegl;
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
use winit::Window as WinitWindow;
|
|
||||||
#[cfg(feature = "backend_winit")]
|
|
||||||
use winit::os::unix::WindowExt;
|
use winit::os::unix::WindowExt;
|
||||||
|
#[cfg(feature = "backend_winit")]
|
||||||
|
use winit::Window as WinitWindow;
|
||||||
|
|
||||||
/// Trait for typed backend variants (X11/Wayland/GBM)
|
/// Trait for typed backend variants (X11/Wayland/GBM)
|
||||||
pub trait Backend {
|
pub trait Backend {
|
||||||
|
@ -53,26 +53,12 @@ impl Backend for Wayland {
|
||||||
F: Fn(&str) -> bool,
|
F: Fn(&str) -> bool,
|
||||||
{
|
{
|
||||||
if has_dp_extension("EGL_KHR_platform_wayland") && ffi::egl::GetPlatformDisplay::is_loaded() {
|
if has_dp_extension("EGL_KHR_platform_wayland") && ffi::egl::GetPlatformDisplay::is_loaded() {
|
||||||
trace!(
|
trace!(log, "EGL Display Initialization via EGL_KHR_platform_wayland");
|
||||||
log,
|
ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_WAYLAND_KHR, display as *mut _, ptr::null())
|
||||||
"EGL Display Initialization via EGL_KHR_platform_wayland"
|
|
||||||
);
|
|
||||||
ffi::egl::GetPlatformDisplay(
|
|
||||||
ffi::egl::PLATFORM_WAYLAND_KHR,
|
|
||||||
display as *mut _,
|
|
||||||
ptr::null(),
|
|
||||||
)
|
|
||||||
} else if has_dp_extension("EGL_EXT_platform_wayland") && ffi::egl::GetPlatformDisplayEXT::is_loaded()
|
} else if has_dp_extension("EGL_EXT_platform_wayland") && ffi::egl::GetPlatformDisplayEXT::is_loaded()
|
||||||
{
|
{
|
||||||
trace!(
|
trace!(log, "EGL Display Initialization via EGL_EXT_platform_wayland");
|
||||||
log,
|
ffi::egl::GetPlatformDisplayEXT(ffi::egl::PLATFORM_WAYLAND_EXT, display as *mut _, ptr::null())
|
||||||
"EGL Display Initialization via EGL_EXT_platform_wayland"
|
|
||||||
);
|
|
||||||
ffi::egl::GetPlatformDisplayEXT(
|
|
||||||
ffi::egl::PLATFORM_WAYLAND_EXT,
|
|
||||||
display as *mut _,
|
|
||||||
ptr::null(),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
trace!(log, "Default EGL Display Initialization via GetDisplay");
|
trace!(log, "Default EGL Display Initialization via GetDisplay");
|
||||||
ffi::egl::GetDisplay(display as *mut _)
|
ffi::egl::GetDisplay(display as *mut _)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! EGL surface related structs
|
//! EGL surface related structs
|
||||||
|
|
||||||
use super::{EGLContext, SwapBuffersError};
|
|
||||||
use super::error::*;
|
use super::error::*;
|
||||||
use super::ffi;
|
use super::ffi;
|
||||||
use super::native;
|
use super::native;
|
||||||
|
use super::{EGLContext, SwapBuffersError};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,14 @@
|
||||||
//! You may then use the resulting `EGLDisplay` to recieve `EGLImages` of an egl-based `WlBuffer`
|
//! You may then use the resulting `EGLDisplay` to recieve `EGLImages` of an egl-based `WlBuffer`
|
||||||
//! for rendering.
|
//! for rendering.
|
||||||
|
|
||||||
use backend::graphics::egl::{ffi, native, EGLContext, EglExtensionNotSupportedError};
|
|
||||||
use backend::graphics::egl::error::*;
|
use backend::graphics::egl::error::*;
|
||||||
use backend::graphics::egl::ffi::egl::types::EGLImage;
|
use backend::graphics::egl::ffi::egl::types::EGLImage;
|
||||||
|
use backend::graphics::egl::{ffi, native, EGLContext, EglExtensionNotSupportedError};
|
||||||
use nix::libc::c_uint;
|
use nix::libc::c_uint;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use wayland_server::{Display, Resource};
|
|
||||||
use wayland_server::protocol::wl_buffer::{self, WlBuffer};
|
use wayland_server::protocol::wl_buffer::{self, WlBuffer};
|
||||||
|
use wayland_server::{Display, Resource};
|
||||||
use wayland_sys::server::wl_display;
|
use wayland_sys::server::wl_display;
|
||||||
|
|
||||||
/// Error that can occur when accessing an EGL buffer
|
/// Error that can occur when accessing an EGL buffer
|
||||||
|
@ -110,12 +110,9 @@ impl fmt::Display for TextureCreationError {
|
||||||
match *self {
|
match *self {
|
||||||
TextureCreationError::ContextLost => write!(formatter, "{}", self.description()),
|
TextureCreationError::ContextLost => write!(formatter, "{}", self.description()),
|
||||||
TextureCreationError::PlaneIndexOutOfBounds => write!(formatter, "{}", self.description()),
|
TextureCreationError::PlaneIndexOutOfBounds => write!(formatter, "{}", self.description()),
|
||||||
TextureCreationError::TextureBindingFailed(code) => write!(
|
TextureCreationError::TextureBindingFailed(code) => {
|
||||||
formatter,
|
write!(formatter, "{}. Gl error code: {:?}", self.description(), code)
|
||||||
"{}. Gl error code: {:?}",
|
}
|
||||||
self.description(),
|
|
||||||
code
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +200,8 @@ impl EGLImages {
|
||||||
ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, tex_id);
|
ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, tex_id);
|
||||||
ffi::gl::EGLImageTargetTexture2DOES(
|
ffi::gl::EGLImageTargetTexture2DOES(
|
||||||
ffi::gl::TEXTURE_2D,
|
ffi::gl::TEXTURE_2D,
|
||||||
*self.images
|
*self
|
||||||
|
.images
|
||||||
.get(plane)
|
.get(plane)
|
||||||
.ok_or(TextureCreationError::PlaneIndexOutOfBounds)?,
|
.ok_or(TextureCreationError::PlaneIndexOutOfBounds)?,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
//! Glium compatibility module
|
//! Glium compatibility module
|
||||||
|
|
||||||
use backend::graphics::egl::{EGLGraphicsBackend, SwapBuffersError};
|
|
||||||
use backend::graphics::egl::error::Result as EGLResult;
|
use backend::graphics::egl::error::Result as EGLResult;
|
||||||
use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
||||||
use glium::Frame;
|
use backend::graphics::egl::{EGLGraphicsBackend, SwapBuffersError};
|
||||||
use glium::SwapBuffersError as GliumSwapBuffersError;
|
|
||||||
use glium::backend::{Backend, Context, Facade};
|
use glium::backend::{Backend, Context, Facade};
|
||||||
use glium::debug::DebugCallbackBehavior;
|
use glium::debug::DebugCallbackBehavior;
|
||||||
|
use glium::Frame;
|
||||||
|
use glium::SwapBuffersError as GliumSwapBuffersError;
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -51,10 +51,7 @@ impl<T: EGLGraphicsBackend + 'static> GliumGraphicsBackend<T> {
|
||||||
/// Note that destroying a `Frame` is immediate, even if vsync is enabled.
|
/// Note that destroying a `Frame` is immediate, even if vsync is enabled.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn draw(&self) -> Frame {
|
pub fn draw(&self) -> Frame {
|
||||||
Frame::new(
|
Frame::new(self.context.clone(), self.backend.get_framebuffer_dimensions())
|
||||||
self.context.clone(),
|
|
||||||
self.backend.get_framebuffer_dimensions(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrow the underlying backend.
|
/// Borrow the underlying backend.
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub trait GraphicsBackend {
|
||||||
) -> Result<(), Self::Error>;
|
) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod software;
|
|
||||||
pub mod egl;
|
pub mod egl;
|
||||||
#[cfg(feature = "renderer_glium")]
|
#[cfg(feature = "renderer_glium")]
|
||||||
pub mod glium;
|
pub mod glium;
|
||||||
|
pub mod software;
|
||||||
|
|
|
@ -6,14 +6,17 @@ use backend::input::Axis;
|
||||||
use backend::session::{AsErrno, Session, SessionObserver};
|
use backend::session::{AsErrno, Session, SessionObserver};
|
||||||
use input as libinput;
|
use input as libinput;
|
||||||
use input::event;
|
use input::event;
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
|
use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use wayland_server::LoopToken;
|
use std::rc::Rc;
|
||||||
use wayland_server::commons::Implementation;
|
|
||||||
use wayland_server::sources::{FdEvent, FdInterest, Source};
|
use wayland_server::calloop::generic::{EventedRawFd, Generic};
|
||||||
|
use wayland_server::calloop::{LoopHandle, Ready, Source};
|
||||||
|
|
||||||
// No idea if this is the same across unix platforms
|
// No idea if this is the same across unix platforms
|
||||||
// Lets make this linux exclusive for now, once someone tries to build it for
|
// Lets make this linux exclusive for now, once someone tries to build it for
|
||||||
|
@ -355,15 +358,18 @@ impl backend::InputBackend for LibinputInputBackend {
|
||||||
// update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`.
|
// update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`.
|
||||||
if let Some(seat) = self.seats.get_mut(&device_seat) {
|
if let Some(seat) = self.seats.get_mut(&device_seat) {
|
||||||
let caps = seat.capabilities_mut();
|
let caps = seat.capabilities_mut();
|
||||||
caps.pointer = self.devices
|
caps.pointer = self
|
||||||
|
.devices
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|x| x.seat() == device_seat)
|
.filter(|x| x.seat() == device_seat)
|
||||||
.any(|x| x.has_capability(libinput::DeviceCapability::Pointer));
|
.any(|x| x.has_capability(libinput::DeviceCapability::Pointer));
|
||||||
caps.keyboard = self.devices
|
caps.keyboard = self
|
||||||
|
.devices
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|x| x.seat() == device_seat)
|
.filter(|x| x.seat() == device_seat)
|
||||||
.any(|x| x.has_capability(libinput::DeviceCapability::Keyboard));
|
.any(|x| x.has_capability(libinput::DeviceCapability::Keyboard));
|
||||||
caps.touch = self.devices
|
caps.touch = self
|
||||||
|
.devices
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|x| x.seat() == device_seat)
|
.filter(|x| x.seat() == device_seat)
|
||||||
.any(|x| x.has_capability(libinput::DeviceCapability::Touch));
|
.any(|x| x.has_capability(libinput::DeviceCapability::Touch));
|
||||||
|
@ -411,11 +417,7 @@ impl backend::InputBackend for LibinputInputBackend {
|
||||||
handler.on_touch_down(seat, down_event)
|
handler.on_touch_down(seat, down_event)
|
||||||
}
|
}
|
||||||
TouchEvent::Motion(motion_event) => {
|
TouchEvent::Motion(motion_event) => {
|
||||||
trace!(
|
trace!(self.logger, "Calling on_touch_motion with {:?}", motion_event);
|
||||||
self.logger,
|
|
||||||
"Calling on_touch_motion with {:?}",
|
|
||||||
motion_event
|
|
||||||
);
|
|
||||||
handler.on_touch_motion(seat, motion_event)
|
handler.on_touch_motion(seat, motion_event)
|
||||||
}
|
}
|
||||||
TouchEvent::Up(up_event) => {
|
TouchEvent::Up(up_event) => {
|
||||||
|
@ -423,11 +425,7 @@ impl backend::InputBackend for LibinputInputBackend {
|
||||||
handler.on_touch_up(seat, up_event)
|
handler.on_touch_up(seat, up_event)
|
||||||
}
|
}
|
||||||
TouchEvent::Cancel(cancel_event) => {
|
TouchEvent::Cancel(cancel_event) => {
|
||||||
trace!(
|
trace!(self.logger, "Calling on_touch_cancel with {:?}", cancel_event);
|
||||||
self.logger,
|
|
||||||
"Calling on_touch_cancel with {:?}",
|
|
||||||
cancel_event
|
|
||||||
);
|
|
||||||
handler.on_touch_cancel(seat, cancel_event)
|
handler.on_touch_cancel(seat, cancel_event)
|
||||||
}
|
}
|
||||||
TouchEvent::Frame(frame_event) => {
|
TouchEvent::Frame(frame_event) => {
|
||||||
|
@ -463,11 +461,7 @@ impl backend::InputBackend for LibinputInputBackend {
|
||||||
if let Some(ref seat) = self.seats.get(&device_seat) {
|
if let Some(ref seat) = self.seats.get(&device_seat) {
|
||||||
match pointer_event {
|
match pointer_event {
|
||||||
PointerEvent::Motion(motion_event) => {
|
PointerEvent::Motion(motion_event) => {
|
||||||
trace!(
|
trace!(self.logger, "Calling on_pointer_move with {:?}", motion_event);
|
||||||
self.logger,
|
|
||||||
"Calling on_pointer_move with {:?}",
|
|
||||||
motion_event
|
|
||||||
);
|
|
||||||
handler.on_pointer_move(seat, motion_event);
|
handler.on_pointer_move(seat, motion_event);
|
||||||
}
|
}
|
||||||
PointerEvent::MotionAbsolute(motion_abs_event) => {
|
PointerEvent::MotionAbsolute(motion_abs_event) => {
|
||||||
|
@ -483,11 +477,7 @@ impl backend::InputBackend for LibinputInputBackend {
|
||||||
handler.on_pointer_axis(seat, axis_event);
|
handler.on_pointer_axis(seat, axis_event);
|
||||||
}
|
}
|
||||||
PointerEvent::Button(button_event) => {
|
PointerEvent::Button(button_event) => {
|
||||||
trace!(
|
trace!(self.logger, "Calling on_pointer_button with {:?}", button_event);
|
||||||
self.logger,
|
|
||||||
"Calling on_pointer_button with {:?}",
|
|
||||||
button_event
|
|
||||||
);
|
|
||||||
handler.on_pointer_button(seat, button_event);
|
handler.on_pointer_button(seat, button_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -600,26 +590,25 @@ impl<S: Session> libinput::LibinputInterface for LibinputSessionInterface<S> {
|
||||||
///
|
///
|
||||||
/// Automatically feeds the backend with incoming events without any manual calls to
|
/// Automatically feeds the backend with incoming events without any manual calls to
|
||||||
/// `dispatch_new_events`. Should be used to achieve the smallest possible latency.
|
/// `dispatch_new_events`. Should be used to achieve the smallest possible latency.
|
||||||
pub fn libinput_bind(
|
pub fn libinput_bind<Data: 'static>(
|
||||||
backend: LibinputInputBackend,
|
backend: LibinputInputBackend,
|
||||||
token: LoopToken,
|
handle: LoopHandle<Data>,
|
||||||
) -> ::std::result::Result<Source<FdEvent>, (IoError, LibinputInputBackend)> {
|
) -> ::std::result::Result<Source<Generic<EventedRawFd>>, (IoError, LibinputInputBackend)> {
|
||||||
let fd = unsafe { backend.context.fd() };
|
let mut source = Generic::from_raw_fd(unsafe { backend.context.fd() });
|
||||||
token.add_fd_event_source(fd, FdInterest::READ, backend)
|
source.set_interest(Ready::readable());
|
||||||
}
|
let backend = Rc::new(RefCell::new(backend));
|
||||||
|
let fail_backend = backend.clone();
|
||||||
impl Implementation<(), FdEvent> for LibinputInputBackend {
|
handle
|
||||||
fn receive(&mut self, event: FdEvent, (): ()) {
|
.insert_source(source, move |_, _| {
|
||||||
match event {
|
|
||||||
FdEvent::Ready { .. } => {
|
|
||||||
use backend::input::InputBackend;
|
use backend::input::InputBackend;
|
||||||
if let Err(error) = self.dispatch_new_events() {
|
if let Err(error) = backend.borrow_mut().dispatch_new_events() {
|
||||||
warn!(self.logger, "Libinput errored: {}", error);
|
warn!(backend.borrow().logger, "Libinput errored: {}", error);
|
||||||
}
|
|
||||||
}
|
|
||||||
FdEvent::Error { error, .. } => {
|
|
||||||
warn!(self.logger, "Libinput fd errored: {}", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}).map_err(move |e| {
|
||||||
|
// the backend in the closure should already have been dropped
|
||||||
|
let backend = Rc::try_unwrap(fail_backend)
|
||||||
|
.unwrap_or_else(|_| unreachable!())
|
||||||
|
.into_inner();
|
||||||
|
(e, backend)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,9 @@
|
||||||
//! - winit
|
//! - winit
|
||||||
//! - libinput
|
//! - libinput
|
||||||
|
|
||||||
pub mod input;
|
|
||||||
pub mod graphics;
|
pub mod graphics;
|
||||||
|
pub mod input;
|
||||||
|
|
||||||
#[cfg(feature = "backend_winit")]
|
|
||||||
pub mod winit;
|
|
||||||
#[cfg(feature = "backend_drm")]
|
#[cfg(feature = "backend_drm")]
|
||||||
pub mod drm;
|
pub mod drm;
|
||||||
#[cfg(feature = "backend_libinput")]
|
#[cfg(feature = "backend_libinput")]
|
||||||
|
@ -27,3 +25,5 @@ pub mod libinput;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
#[cfg(feature = "backend_udev")]
|
#[cfg(feature = "backend_udev")]
|
||||||
pub mod udev;
|
pub mod udev;
|
||||||
|
#[cfg(feature = "backend_winit")]
|
||||||
|
pub mod winit;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
//!
|
|
||||||
//! Implementation of the `Session` trait through various implementations
|
//! Implementation of the `Session` trait through various implementations
|
||||||
//! automatically choosing the best available interface.
|
//! automatically choosing the best available interface.
|
||||||
//!
|
//!
|
||||||
|
@ -29,19 +28,18 @@
|
||||||
//! automatically by the `UdevBackend`, if not done manually).
|
//! automatically by the `UdevBackend`, if not done manually).
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver};
|
use super::direct::{self, direct_session_bind, BoundDirectSession, DirectSession, DirectSessionNotifier};
|
||||||
use super::direct::{self, direct_session_bind, DirectSession, DirectSessionNotifier};
|
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier};
|
use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier};
|
||||||
|
use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver};
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wayland_server::LoopToken;
|
|
||||||
use wayland_server::commons::downcast_impl;
|
use wayland_server::calloop::LoopHandle;
|
||||||
use wayland_server::sources::{SignalEvent, Source};
|
|
||||||
|
|
||||||
/// `Session` using the best available inteface
|
/// `Session` using the best available inteface
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -62,7 +60,7 @@ pub enum AutoSessionNotifier {
|
||||||
Direct(DirectSessionNotifier),
|
Direct(DirectSessionNotifier),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bound session that is driven by the `wayland_server::EventLoop`.
|
/// Bound session that is driven by the `calloop::EventLoop`.
|
||||||
///
|
///
|
||||||
/// See `auto_session_bind` for details.
|
/// See `auto_session_bind` for details.
|
||||||
///
|
///
|
||||||
|
@ -72,7 +70,7 @@ pub enum BoundAutoSession {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
Logind(BoundLogindSession),
|
Logind(BoundLogindSession),
|
||||||
/// Bound direct / tty session
|
/// Bound direct / tty session
|
||||||
Direct(Source<SignalEvent>),
|
Direct(BoundDirectSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Id's used by the `AutoSessionNotifier` internally.
|
/// Id's used by the `AutoSessionNotifier` internally.
|
||||||
|
@ -111,10 +109,7 @@ impl AutoSession {
|
||||||
)),
|
)),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(logger, "Failed to create direct session: {}", err);
|
warn!(logger, "Failed to create direct session: {}", err);
|
||||||
error!(
|
error!(logger, "Could not create any session, possibilities exhausted");
|
||||||
logger,
|
|
||||||
"Could not create any session, possibilities exhausted"
|
|
||||||
);
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,10 +133,7 @@ impl AutoSession {
|
||||||
)),
|
)),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(logger, "Failed to create direct session: {}", err);
|
warn!(logger, "Failed to create direct session: {}", err);
|
||||||
error!(
|
error!(logger, "Could not create any session, possibilities exhausted");
|
||||||
logger,
|
|
||||||
"Could not create any session, possibilities exhausted"
|
|
||||||
);
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,16 +145,18 @@ impl AutoSession {
|
||||||
/// Allows the `AutoSessionNotifier` to listen for incoming signals signalling the session state.
|
/// Allows the `AutoSessionNotifier` to listen for incoming signals signalling the session state.
|
||||||
/// If you don't use this function `AutoSessionNotifier` will not correctly tell you the
|
/// If you don't use this function `AutoSessionNotifier` will not correctly tell you the
|
||||||
/// session state and call it's `SessionObservers`.
|
/// session state and call it's `SessionObservers`.
|
||||||
pub fn auto_session_bind(
|
pub fn auto_session_bind<Data: 'static>(
|
||||||
notifier: AutoSessionNotifier,
|
notifier: AutoSessionNotifier,
|
||||||
token: &LoopToken,
|
handle: &LoopHandle<Data>,
|
||||||
) -> ::std::result::Result<BoundAutoSession, (IoError, AutoSessionNotifier)> {
|
) -> ::std::result::Result<BoundAutoSession, (IoError, AutoSessionNotifier)> {
|
||||||
Ok(match notifier {
|
Ok(match notifier {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(logind_session_bind(logind, token)
|
AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(
|
||||||
.map_err(|(error, notifier)| (error, AutoSessionNotifier::Logind(notifier)))?),
|
logind_session_bind(logind, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Logind(n)))?,
|
||||||
AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(direct_session_bind(direct, token)
|
),
|
||||||
.map_err(|(error, notifier)| (error, AutoSessionNotifier::Direct(notifier)))?),
|
AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(
|
||||||
|
direct_session_bind(direct, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Direct(n)))?,
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +219,9 @@ impl SessionNotifier for AutoSessionNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unregister(&mut self, signal: Self::Id) {
|
fn unregister(&mut self, signal: Self::Id) {
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
match (self, signal) {
|
match (self, signal) {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
(&mut AutoSessionNotifier::Logind(ref mut logind), AutoId(AutoIdInternal::Logind(signal))) => {
|
(&mut AutoSessionNotifier::Logind(ref mut logind), AutoId(AutoIdInternal::Logind(signal))) => {
|
||||||
|
@ -234,6 +230,7 @@ impl SessionNotifier for AutoSessionNotifier {
|
||||||
(&mut AutoSessionNotifier::Direct(ref mut direct), AutoId(AutoIdInternal::Direct(signal))) => {
|
(&mut AutoSessionNotifier::Direct(ref mut direct), AutoId(AutoIdInternal::Direct(signal))) => {
|
||||||
direct.unregister(signal)
|
direct.unregister(signal)
|
||||||
}
|
}
|
||||||
|
// this pattern is needed when the logind backend is activated
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,9 +257,7 @@ impl BoundAutoSession {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
BoundAutoSession::Logind(logind) => AutoSessionNotifier::Logind(logind.unbind()),
|
BoundAutoSession::Logind(logind) => AutoSessionNotifier::Logind(logind.unbind()),
|
||||||
BoundAutoSession::Direct(source) => {
|
BoundAutoSession::Direct(direct) => AutoSessionNotifier::Direct(direct.unbind()),
|
||||||
AutoSessionNotifier::Direct(*downcast_impl(source.remove()).unwrap_or_else(|_| unreachable!()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,10 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use backend::session::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver};
|
use backend::session::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver};
|
||||||
use dbus::{BusName, BusType, Connection, ConnectionItem, ConnectionItems, Interface, Member, Message,
|
use dbus::{
|
||||||
MessageItem, OwnedFd, Path as DbusPath, Watch, WatchEvent};
|
BusName, BusType, Connection, ConnectionItem, ConnectionItems, Interface, Member, Message, MessageItem,
|
||||||
|
OwnedFd, Path as DbusPath, Watch, WatchEvent,
|
||||||
|
};
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use nix::sys::stat::{fstat, major, minor, stat};
|
use nix::sys::stat::{fstat, major, minor, stat};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
@ -42,9 +44,9 @@ use std::path::Path;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use systemd::login;
|
use systemd::login;
|
||||||
use wayland_server::LoopToken;
|
|
||||||
use wayland_server::commons::Implementation;
|
use wayland_server::calloop::generic::{Event, EventedRawFd, Generic};
|
||||||
use wayland_server::sources::{FdEvent, FdInterest, Source};
|
use wayland_server::calloop::{LoopHandle, Ready, Source};
|
||||||
|
|
||||||
struct LogindSessionImpl {
|
struct LogindSessionImpl {
|
||||||
conn: RefCell<Connection>,
|
conn: RefCell<Connection>,
|
||||||
|
@ -212,8 +214,7 @@ impl LogindSessionImpl {
|
||||||
message.append_items(&arguments)
|
message.append_items(&arguments)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut message = conn.send_with_reply_and_block(message, 1000)
|
let mut message = conn.send_with_reply_and_block(message, 1000).chain_err(|| {
|
||||||
.chain_err(|| {
|
|
||||||
ErrorKind::FailedToSendDbusCall(
|
ErrorKind::FailedToSendDbusCall(
|
||||||
destination.clone(),
|
destination.clone(),
|
||||||
path.clone(),
|
path.clone(),
|
||||||
|
@ -290,8 +291,7 @@ impl LogindSessionImpl {
|
||||||
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.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
||||||
let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
||||||
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?
|
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd();
|
||||||
.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 {
|
||||||
|
@ -336,8 +336,7 @@ impl Session for LogindSession {
|
||||||
(minor(stat.st_rdev) as u32).into(),
|
(minor(stat.st_rdev) as u32).into(),
|
||||||
]),
|
]),
|
||||||
)?.get2::<OwnedFd, bool>();
|
)?.get2::<OwnedFd, bool>();
|
||||||
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?
|
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd();
|
||||||
.into_fd();
|
|
||||||
Ok(fd)
|
Ok(fd)
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::SessionLost)
|
bail!(ErrorKind::SessionLost)
|
||||||
|
@ -429,7 +428,7 @@ impl SessionNotifier for LogindSessionNotifier {
|
||||||
pub struct BoundLogindSession {
|
pub struct BoundLogindSession {
|
||||||
notifier: LogindSessionNotifier,
|
notifier: LogindSessionNotifier,
|
||||||
_watches: Vec<Watch>,
|
_watches: Vec<Watch>,
|
||||||
sources: Vec<Source<FdEvent>>,
|
sources: Vec<Source<Generic<EventedRawFd>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bind a `LogindSessionNotifier` to an `EventLoop`.
|
/// Bind a `LogindSessionNotifier` to an `EventLoop`.
|
||||||
|
@ -437,9 +436,9 @@ pub struct BoundLogindSession {
|
||||||
/// Allows the `LogindSessionNotifier` to listen for incoming signals signalling the session state.
|
/// Allows the `LogindSessionNotifier` to listen for incoming signals signalling the session state.
|
||||||
/// If you don't use this function `LogindSessionNotifier` will not correctly tell you the logind
|
/// If you don't use this function `LogindSessionNotifier` will not correctly tell you the logind
|
||||||
/// session state and call it's `SessionObservers`.
|
/// session state and call it's `SessionObservers`.
|
||||||
pub fn logind_session_bind(
|
pub fn logind_session_bind<Data: 'static>(
|
||||||
notifier: LogindSessionNotifier,
|
notifier: LogindSessionNotifier,
|
||||||
token: &LoopToken,
|
handle: &LoopHandle<Data>,
|
||||||
) -> ::std::result::Result<BoundLogindSession, (IoError, LogindSessionNotifier)> {
|
) -> ::std::result::Result<BoundLogindSession, (IoError, LogindSessionNotifier)> {
|
||||||
let watches = notifier.internal.conn.borrow().watch_fds();
|
let watches = notifier.internal.conn.borrow().watch_fds();
|
||||||
|
|
||||||
|
@ -448,13 +447,14 @@ pub fn logind_session_bind(
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|watch| {
|
.map(|watch| {
|
||||||
let mut interest = FdInterest::empty();
|
let mut source = Generic::from_raw_fd(watch.fd());
|
||||||
interest.set(FdInterest::READ, watch.readable());
|
source.set_interest(Ready::readable() | Ready::writable());
|
||||||
interest.set(FdInterest::WRITE, watch.writable());
|
handle.insert_source(source, {
|
||||||
token.add_fd_event_source(watch.fd(), interest, notifier.clone())
|
let mut notifier = notifier.clone();
|
||||||
|
move |evt, _| notifier.event(evt)
|
||||||
})
|
})
|
||||||
.collect::<::std::result::Result<Vec<Source<FdEvent>>, (IoError, _)>>()
|
}).collect::<::std::result::Result<Vec<Source<Generic<EventedRawFd>>>, IoError>>()
|
||||||
.map_err(|(err, _)| {
|
.map_err(|err| {
|
||||||
(
|
(
|
||||||
err,
|
err,
|
||||||
LogindSessionNotifier {
|
LogindSessionNotifier {
|
||||||
|
@ -495,41 +495,27 @@ impl Drop for LogindSessionNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Implementation<(), FdEvent> for LogindSessionNotifier {
|
impl LogindSessionNotifier {
|
||||||
fn receive(&mut self, event: FdEvent, (): ()) {
|
fn event(&mut self, event: Event<EventedRawFd>) {
|
||||||
match event {
|
let fd = event.source.borrow().0;
|
||||||
FdEvent::Ready { fd, mask } => {
|
let readiness = event.readiness;
|
||||||
let conn = self.internal.conn.borrow();
|
let conn = self.internal.conn.borrow();
|
||||||
let items = conn.watch_handle(
|
let items = conn.watch_handle(
|
||||||
fd,
|
fd,
|
||||||
match mask {
|
if readiness.is_readable() && readiness.is_writable() {
|
||||||
x if x.contains(FdInterest::READ) && x.contains(FdInterest::WRITE) => {
|
|
||||||
WatchEvent::Readable as u32 | WatchEvent::Writable as u32
|
WatchEvent::Readable as u32 | WatchEvent::Writable as u32
|
||||||
}
|
} else if readiness.is_readable() {
|
||||||
x if x.contains(FdInterest::READ) => WatchEvent::Readable as u32,
|
WatchEvent::Readable as u32
|
||||||
x if x.contains(FdInterest::WRITE) => WatchEvent::Writable as u32,
|
} else if readiness.is_writable() {
|
||||||
_ => return,
|
WatchEvent::Writable as u32
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if let Err(err) = self.internal.handle_signals(items) {
|
if let Err(err) = self.internal.handle_signals(items) {
|
||||||
error!(self.internal.logger, "Error handling dbus signals: {}", err);
|
error!(self.internal.logger, "Error handling dbus signals: {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FdEvent::Error { fd, error } => {
|
|
||||||
warn!(
|
|
||||||
self.internal.logger,
|
|
||||||
"Error on dbus connection: {:?}", error
|
|
||||||
);
|
|
||||||
// handle the remaining messages, they might contain the SessionRemoved event
|
|
||||||
// in case the server did close the connection.
|
|
||||||
let conn = self.internal.conn.borrow();
|
|
||||||
let items = conn.watch_handle(fd, WatchEvent::Error as u32);
|
|
||||||
if let Err(err) = self.internal.handle_signals(items) {
|
|
||||||
error!(self.internal.logger, "Error handling dbus signals: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
|
|
|
@ -46,42 +46,43 @@
|
||||||
//! automatically by the `UdevBackend`, if not done manually).
|
//! automatically by the `UdevBackend`, if not done manually).
|
||||||
|
|
||||||
use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver};
|
use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver};
|
||||||
use nix::{Error as NixError, Result as NixResult};
|
|
||||||
use nix::fcntl::{self, open, OFlag};
|
use nix::fcntl::{self, open, OFlag};
|
||||||
use nix::libc::c_int;
|
use nix::libc::c_int;
|
||||||
use nix::sys::signal::{self, Signal};
|
use nix::sys::signal::{self, Signal};
|
||||||
use nix::sys::stat::{dev_t, fstat, major, minor, Mode};
|
use nix::sys::stat::{dev_t, fstat, major, minor, Mode};
|
||||||
use nix::unistd::{close, dup};
|
use nix::unistd::{close, dup};
|
||||||
|
use nix::{Error as NixError, Result as NixResult};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
#[cfg(feature = "backend_session_udev")]
|
#[cfg(feature = "backend_session_udev")]
|
||||||
use udev::Context;
|
use udev::Context;
|
||||||
use wayland_server::LoopToken;
|
use wayland_server::calloop::signals::Signals;
|
||||||
use wayland_server::commons::Implementation;
|
use wayland_server::calloop::{LoopHandle, Source};
|
||||||
use wayland_server::sources::{SignalEvent, Source};
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod tty {
|
mod tty {
|
||||||
ioctl!(bad read kd_get_mode with 0x4B3B; i16);
|
ioctl_read_bad!(kd_get_mode, 0x4B3B, i16);
|
||||||
ioctl!(bad write_int kd_set_mode with 0x4B3A);
|
ioctl_write_int_bad!(kd_set_mode, 0x4B3A);
|
||||||
pub const KD_TEXT: i16 = 0x00;
|
pub const KD_TEXT: i16 = 0x00;
|
||||||
pub const KD_GRAPHICS: i16 = 0x00;
|
pub const KD_GRAPHICS: i16 = 0x00;
|
||||||
|
|
||||||
ioctl!(bad read kd_get_kb_mode with 0x4B44; i32);
|
ioctl_read_bad!(kd_get_kb_mode, 0x4B44, i32);
|
||||||
ioctl!(bad write_int kd_set_kb_mode with 0x4B45);
|
ioctl_write_int_bad!(kd_set_kb_mode, 0x4B45);
|
||||||
pub const K_RAW: i32 = 0x00;
|
pub const K_RAW: i32 = 0x00;
|
||||||
pub const K_XLATE: i32 = 0x01;
|
pub const K_XLATE: i32 = 0x01;
|
||||||
pub const K_MEDIUMRAW: i32 = 0x02;
|
pub const K_MEDIUMRAW: i32 = 0x02;
|
||||||
pub const K_UNICODE: i32 = 0x03;
|
pub const K_UNICODE: i32 = 0x03;
|
||||||
pub const K_OFF: i32 = 0x04;
|
pub const K_OFF: i32 = 0x04;
|
||||||
|
|
||||||
ioctl!(bad write_int vt_activate with 0x5606);
|
ioctl_write_int_bad!(vt_activate, 0x5606);
|
||||||
ioctl!(bad write_int vt_wait_active with 0x5607);
|
ioctl_write_int_bad!(vt_wait_active, 0x5607);
|
||||||
ioctl!(bad write_ptr vt_set_mode with 0x5602; VtMode);
|
ioctl_write_ptr_bad!(vt_set_mode, 0x5602, VtMode);
|
||||||
ioctl!(bad write_int vt_rel_disp with 0x5605);
|
ioctl_write_int_bad!(vt_rel_disp, 0x5605);
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
pub struct VtMode {
|
pub struct VtMode {
|
||||||
|
@ -171,13 +172,16 @@ impl DirectSession {
|
||||||
let logger = ::slog_or_stdlog(logger)
|
let logger = ::slog_or_stdlog(logger)
|
||||||
.new(o!("smithay_module" => "backend_session", "session_type" => "direct/vt"));
|
.new(o!("smithay_module" => "backend_session", "session_type" => "direct/vt"));
|
||||||
|
|
||||||
let fd = tty.map(|path| {
|
let fd = tty
|
||||||
|
.map(|path| {
|
||||||
open(
|
open(
|
||||||
path,
|
path,
|
||||||
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())))
|
).chain_err(|| ErrorKind::FailedToOpenTTY(String::from(path.to_string_lossy())))
|
||||||
}).unwrap_or_else(|| dup(0 /*stdin*/).chain_err(|| ErrorKind::FailedToOpenTTY(String::from("<stdin>"))))?;
|
}).unwrap_or_else(|| {
|
||||||
|
dup(0 /*stdin*/).chain_err(|| ErrorKind::FailedToOpenTTY(String::from("<stdin>")))
|
||||||
|
})?;
|
||||||
|
|
||||||
let active = Arc::new(AtomicBool::new(true));
|
let active = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
|
@ -310,16 +314,10 @@ impl Drop for DirectSession {
|
||||||
info!(self.logger, "Deallocating tty {}", self.tty);
|
info!(self.logger, "Deallocating tty {}", self.tty);
|
||||||
|
|
||||||
if let Err(err) = unsafe { tty::kd_set_kb_mode(self.tty, self.old_keyboard_mode) } {
|
if let Err(err) = unsafe { tty::kd_set_kb_mode(self.tty, self.old_keyboard_mode) } {
|
||||||
warn!(
|
warn!(self.logger, "Unable to restore vt keyboard mode. Error: {}", err);
|
||||||
self.logger,
|
|
||||||
"Unable to restore vt keyboard mode. Error: {}", err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if let Err(err) = unsafe { tty::kd_set_mode(self.tty, tty::KD_TEXT as i32) } {
|
if let Err(err) = unsafe { tty::kd_set_mode(self.tty, tty::KD_TEXT as i32) } {
|
||||||
warn!(
|
warn!(self.logger, "Unable to restore vt text mode. Error: {}", err);
|
||||||
self.logger,
|
|
||||||
"Unable to restore vt text mode. Error: {}", err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if let Err(err) = unsafe {
|
if let Err(err) = unsafe {
|
||||||
tty::vt_set_mode(
|
tty::vt_set_mode(
|
||||||
|
@ -333,10 +331,7 @@ impl Drop for DirectSession {
|
||||||
error!(self.logger, "Failed to reset vt handling. Error: {}", err);
|
error!(self.logger, "Failed to reset vt handling. Error: {}", err);
|
||||||
}
|
}
|
||||||
if let Err(err) = close(self.tty) {
|
if let Err(err) = close(self.tty) {
|
||||||
error!(
|
error!(self.logger, "Failed to close tty file descriptor. Error: {}", err);
|
||||||
self.logger,
|
|
||||||
"Failed to close tty file descriptor. Error: {}", err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,8 +362,8 @@ impl SessionNotifier for DirectSessionNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Implementation<(), SignalEvent> for DirectSessionNotifier {
|
impl DirectSessionNotifier {
|
||||||
fn receive(&mut self, _signal: SignalEvent, (): ()) {
|
fn signal_received(&mut self) {
|
||||||
if self.is_active() {
|
if self.is_active() {
|
||||||
info!(self.logger, "Session shall become inactive.");
|
info!(self.logger, "Session shall become inactive.");
|
||||||
for signal in &mut self.signals {
|
for signal in &mut self.signals {
|
||||||
|
@ -397,18 +392,54 @@ impl Implementation<(), SignalEvent> for DirectSessionNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bound logind session that is driven by the `wayland_server::EventLoop`.
|
||||||
|
///
|
||||||
|
/// See `direct_session_bind` for details.
|
||||||
|
pub struct BoundDirectSession {
|
||||||
|
source: Source<Signals>,
|
||||||
|
notifier: Rc<RefCell<DirectSessionNotifier>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoundDirectSession {
|
||||||
|
/// Unbind the direct session from the `EventLoop`
|
||||||
|
pub fn unbind(self) -> DirectSessionNotifier {
|
||||||
|
let BoundDirectSession { source, notifier } = self;
|
||||||
|
source.remove();
|
||||||
|
match Rc::try_unwrap(notifier) {
|
||||||
|
Ok(notifier) => notifier.into_inner(),
|
||||||
|
Err(_) => panic!("Notifier should have been freed from the event loop!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Bind a `DirectSessionNotifier` to an `EventLoop`.
|
/// Bind a `DirectSessionNotifier` to an `EventLoop`.
|
||||||
///
|
///
|
||||||
/// Allows the `DirectSessionNotifier` to listen for incoming signals signalling the session state.
|
/// Allows the `DirectSessionNotifier` to listen for incoming signals signalling the session state.
|
||||||
/// If you don't use this function `DirectSessionNotifier` will not correctly tell you the current
|
/// If you don't use this function `DirectSessionNotifier` will not correctly tell you the current
|
||||||
/// session state and call it's `SessionObservers`.
|
/// session state and call it's `SessionObservers`.
|
||||||
pub fn direct_session_bind(
|
pub fn direct_session_bind<Data: 'static>(
|
||||||
notifier: DirectSessionNotifier,
|
notifier: DirectSessionNotifier,
|
||||||
token: &LoopToken,
|
handle: &LoopHandle<Data>,
|
||||||
) -> ::std::result::Result<Source<SignalEvent>, (IoError, DirectSessionNotifier)> {
|
) -> ::std::result::Result<BoundDirectSession, (IoError, DirectSessionNotifier)> {
|
||||||
let signal = notifier.signal;
|
let signal = notifier.signal;
|
||||||
|
let source = match Signals::new(&[signal]) {
|
||||||
token.add_signal_event_source(signal, notifier)
|
Ok(s) => s,
|
||||||
|
Err(e) => return Err((e, notifier)),
|
||||||
|
};
|
||||||
|
let notifier = Rc::new(RefCell::new(notifier));
|
||||||
|
let fail_notifier = notifier.clone();
|
||||||
|
let source = handle
|
||||||
|
.insert_source(source, {
|
||||||
|
let notifier = notifier.clone();
|
||||||
|
move |_, _| notifier.borrow_mut().signal_received()
|
||||||
|
}).map_err(move |e| {
|
||||||
|
// the backend in the closure should already have been dropped
|
||||||
|
let notifier = Rc::try_unwrap(fail_notifier)
|
||||||
|
.unwrap_or_else(|_| unreachable!())
|
||||||
|
.into_inner();
|
||||||
|
(e, notifier)
|
||||||
|
})?;
|
||||||
|
Ok(BoundDirectSession { source, notifier })
|
||||||
}
|
}
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
|
|
|
@ -181,6 +181,6 @@ impl AsErrno for () {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod auto;
|
pub mod auto;
|
||||||
pub mod direct;
|
|
||||||
mod dbus;
|
mod dbus;
|
||||||
|
pub mod direct;
|
||||||
pub use self::dbus::*;
|
pub use self::dbus::*;
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
|
|
||||||
use backend::drm::{drm_device_bind, DrmDevice, DrmHandler};
|
use backend::drm::{drm_device_bind, DrmDevice, DrmHandler};
|
||||||
use backend::session::{AsSessionObserver, Session, SessionObserver};
|
use backend::session::{AsSessionObserver, Session, SessionObserver};
|
||||||
use drm::Device as BasicDevice;
|
|
||||||
use drm::control::Device as ControlDevice;
|
use drm::control::Device as ControlDevice;
|
||||||
|
use drm::Device as BasicDevice;
|
||||||
use nix::fcntl;
|
use nix::fcntl;
|
||||||
use nix::sys::stat::dev_t;
|
use nix::sys::stat::dev_t;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
@ -24,9 +24,9 @@ use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult};
|
use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult};
|
||||||
use wayland_server::LoopToken;
|
|
||||||
use wayland_server::commons::Implementation;
|
use wayland_server::calloop::generic::{EventedRawFd, Generic};
|
||||||
use wayland_server::sources::{FdEvent, FdInterest, Source};
|
use wayland_server::calloop::{LoopHandle, Ready, Source};
|
||||||
|
|
||||||
/// Udev's `DrmDevice` type based on the underlying session
|
/// Udev's `DrmDevice` type based on the underlying session
|
||||||
pub struct SessionFdDrmDevice(RawFd);
|
pub struct SessionFdDrmDevice(RawFd);
|
||||||
|
@ -48,18 +48,33 @@ pub struct UdevBackend<
|
||||||
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
||||||
S: Session + 'static,
|
S: Session + 'static,
|
||||||
T: UdevHandler<H> + 'static,
|
T: UdevHandler<H> + 'static,
|
||||||
|
Data: 'static,
|
||||||
> {
|
> {
|
||||||
_handler: ::std::marker::PhantomData<H>,
|
_handler: ::std::marker::PhantomData<H>,
|
||||||
devices: Rc<RefCell<HashMap<dev_t, (Source<FdEvent>, Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>)>>>,
|
devices: Rc<
|
||||||
|
RefCell<
|
||||||
|
HashMap<
|
||||||
|
dev_t,
|
||||||
|
(
|
||||||
|
Source<Generic<EventedRawFd>>,
|
||||||
|
Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
monitor: MonitorSocket,
|
monitor: MonitorSocket,
|
||||||
session: S,
|
session: S,
|
||||||
handler: T,
|
handler: T,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
token: LoopToken,
|
handle: LoopHandle<Data>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevHandler<H> + 'static>
|
impl<
|
||||||
UdevBackend<H, S, T>
|
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
||||||
|
S: Session + 'static,
|
||||||
|
T: UdevHandler<H> + 'static,
|
||||||
|
Data: 'static,
|
||||||
|
> UdevBackend<H, S, T, Data>
|
||||||
{
|
{
|
||||||
/// Creates a new `UdevBackend` and adds it to the given `EventLoop`'s state.
|
/// Creates a new `UdevBackend` and adds it to the given `EventLoop`'s state.
|
||||||
///
|
///
|
||||||
|
@ -70,12 +85,12 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
||||||
/// `handler` - User-provided handler to respond to any detected changes
|
/// `handler` - User-provided handler to respond to any detected changes
|
||||||
/// `logger` - slog Logger to be used by the backend and its `DrmDevices`.
|
/// `logger` - slog Logger to be used by the backend and its `DrmDevices`.
|
||||||
pub fn new<L>(
|
pub fn new<L>(
|
||||||
token: LoopToken,
|
handle: LoopHandle<Data>,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
mut session: S,
|
mut session: S,
|
||||||
mut handler: T,
|
mut handler: T,
|
||||||
logger: L,
|
logger: L,
|
||||||
) -> Result<UdevBackend<H, S, T>>
|
) -> Result<UdevBackend<H, S, T, Data>>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -103,9 +118,9 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
||||||
let fd = device.as_raw_fd();
|
let fd = device.as_raw_fd();
|
||||||
match handler.device_added(&mut device) {
|
match handler.device_added(&mut device) {
|
||||||
Some(drm_handler) => {
|
Some(drm_handler) => {
|
||||||
match drm_device_bind(&token, device, drm_handler) {
|
match drm_device_bind(&handle, device, drm_handler) {
|
||||||
Ok((event_source, device)) => Some((devnum, (event_source, device))),
|
Ok((event_source, device)) => Some((devnum, (event_source, device))),
|
||||||
Err((err, (mut device, _))) => {
|
Err((err, mut device)) => {
|
||||||
warn!(logger, "Failed to bind device. Error: {:?}.", err);
|
warn!(logger, "Failed to bind device. Error: {:?}.", err);
|
||||||
handler.device_removed(&mut device);
|
handler.device_removed(&mut device);
|
||||||
drop(device);
|
drop(device);
|
||||||
|
@ -137,9 +152,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
||||||
builder
|
builder
|
||||||
.match_subsystem("drm")
|
.match_subsystem("drm")
|
||||||
.chain_err(|| ErrorKind::FailedToInitMonitor)?;
|
.chain_err(|| ErrorKind::FailedToInitMonitor)?;
|
||||||
let monitor = builder
|
let monitor = builder.listen().chain_err(|| ErrorKind::FailedToInitMonitor)?;
|
||||||
.listen()
|
|
||||||
.chain_err(|| ErrorKind::FailedToInitMonitor)?;
|
|
||||||
|
|
||||||
Ok(UdevBackend {
|
Ok(UdevBackend {
|
||||||
_handler: ::std::marker::PhantomData,
|
_handler: ::std::marker::PhantomData,
|
||||||
|
@ -148,7 +161,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
||||||
session,
|
session,
|
||||||
handler,
|
handler,
|
||||||
logger,
|
logger,
|
||||||
token,
|
handle,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,19 +177,38 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
||||||
let fd = device.as_raw_fd();
|
let fd = device.as_raw_fd();
|
||||||
drop(device);
|
drop(device);
|
||||||
if let Err(err) = self.session.close(fd) {
|
if let Err(err) = self.session.close(fd) {
|
||||||
warn!(
|
warn!(self.logger, "Failed to close device. Error: {:?}. Ignoring", err);
|
||||||
self.logger,
|
|
||||||
"Failed to close device. Error: {:?}. Ignoring", err
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
info!(self.logger, "All devices closed");
|
info!(self.logger, "All devices closed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
||||||
|
S: Session + 'static,
|
||||||
|
T: UdevHandler<H> + 'static,
|
||||||
|
Data: 'static,
|
||||||
|
> Drop for UdevBackend<H, S, T, Data>
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `SessionObserver` linked to the `UdevBackend` it was created from.
|
/// `SessionObserver` linked to the `UdevBackend` it was created from.
|
||||||
pub struct UdevBackendObserver {
|
pub struct UdevBackendObserver {
|
||||||
devices: Weak<RefCell<HashMap<dev_t, (Source<FdEvent>, Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>)>>>,
|
devices: Weak<
|
||||||
|
RefCell<
|
||||||
|
HashMap<
|
||||||
|
dev_t,
|
||||||
|
(
|
||||||
|
Source<Generic<EventedRawFd>>,
|
||||||
|
Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +216,8 @@ impl<
|
||||||
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
||||||
S: Session + 'static,
|
S: Session + 'static,
|
||||||
T: UdevHandler<H> + 'static,
|
T: UdevHandler<H> + 'static,
|
||||||
> AsSessionObserver<UdevBackendObserver> for UdevBackend<H, S, T>
|
Data: 'static,
|
||||||
|
> AsSessionObserver<UdevBackendObserver> for UdevBackend<H, S, T, Data>
|
||||||
{
|
{
|
||||||
fn observer(&mut self) -> UdevBackendObserver {
|
fn observer(&mut self) -> UdevBackendObserver {
|
||||||
UdevBackendObserver {
|
UdevBackendObserver {
|
||||||
|
@ -218,28 +251,31 @@ impl SessionObserver for UdevBackendObserver {
|
||||||
///
|
///
|
||||||
/// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`.
|
/// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`.
|
||||||
/// No runtime functionality can be provided without using this function.
|
/// No runtime functionality can be provided without using this function.
|
||||||
pub fn udev_backend_bind<H, S, T>(
|
pub fn udev_backend_bind<H, S, T, Data>(
|
||||||
token: &LoopToken,
|
mut udev: UdevBackend<H, S, T, Data>,
|
||||||
udev: UdevBackend<H, S, T>,
|
) -> ::std::result::Result<Source<Generic<EventedRawFd>>, IoError>
|
||||||
) -> ::std::result::Result<Source<FdEvent>, (IoError, UdevBackend<H, S, T>)>
|
|
||||||
where
|
where
|
||||||
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
||||||
T: UdevHandler<H> + 'static,
|
T: UdevHandler<H> + 'static,
|
||||||
S: Session + 'static,
|
S: Session + 'static,
|
||||||
{
|
{
|
||||||
let fd = udev.monitor.as_raw_fd();
|
let fd = udev.monitor.as_raw_fd();
|
||||||
token.add_fd_event_source(fd, FdInterest::READ, udev)
|
let handle = udev.handle.clone();
|
||||||
|
let mut source = Generic::from_raw_fd(fd);
|
||||||
|
source.set_interest(Ready::readable());
|
||||||
|
handle.insert_source(source, move |_, _| {
|
||||||
|
udev.process_events();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, S, T> Implementation<(), FdEvent> for UdevBackend<H, S, T>
|
impl<H, S, T, Data> UdevBackend<H, S, T, Data>
|
||||||
where
|
where
|
||||||
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
||||||
T: UdevHandler<H> + 'static,
|
T: UdevHandler<H> + 'static,
|
||||||
S: Session + 'static,
|
S: Session + 'static,
|
||||||
|
Data: 'static,
|
||||||
{
|
{
|
||||||
fn receive(&mut self, event: FdEvent, (): ()) {
|
fn process_events(&mut self) {
|
||||||
match event {
|
|
||||||
FdEvent::Ready { .. } => {
|
|
||||||
let events = self.monitor.clone().collect::<Vec<Event>>();
|
let events = self.monitor.clone().collect::<Vec<Event>>();
|
||||||
for event in events {
|
for event in events {
|
||||||
match event.event_type() {
|
match event.event_type() {
|
||||||
|
@ -253,7 +289,8 @@ where
|
||||||
let logger = self.logger.clone();
|
let logger = self.logger.clone();
|
||||||
match self.session.open(
|
match self.session.open(
|
||||||
path,
|
path,
|
||||||
fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC
|
fcntl::OFlag::O_RDWR
|
||||||
|
| fcntl::OFlag::O_CLOEXEC
|
||||||
| fcntl::OFlag::O_NOCTTY
|
| fcntl::OFlag::O_NOCTTY
|
||||||
| fcntl::OFlag::O_NONBLOCK,
|
| fcntl::OFlag::O_NONBLOCK,
|
||||||
) {
|
) {
|
||||||
|
@ -275,9 +312,7 @@ where
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(
|
warn!(
|
||||||
self.logger,
|
self.logger,
|
||||||
"Failed to initialize device {:?}. Error: {}. Skipping",
|
"Failed to initialize device {:?}. Error: {}. Skipping", path, err
|
||||||
path,
|
|
||||||
err
|
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -285,16 +320,12 @@ where
|
||||||
};
|
};
|
||||||
let fd = device.as_raw_fd();
|
let fd = device.as_raw_fd();
|
||||||
match self.handler.device_added(&mut device) {
|
match self.handler.device_added(&mut device) {
|
||||||
Some(drm_handler) => {
|
Some(drm_handler) => match drm_device_bind(&self.handle, device, drm_handler) {
|
||||||
match drm_device_bind(&self.token, device, drm_handler) {
|
|
||||||
Ok(fd_event_source) => {
|
Ok(fd_event_source) => {
|
||||||
self.devices.borrow_mut().insert(devnum, fd_event_source);
|
self.devices.borrow_mut().insert(devnum, fd_event_source);
|
||||||
}
|
}
|
||||||
Err((err, (mut device, _))) => {
|
Err((err, mut device)) => {
|
||||||
warn!(
|
warn!(self.logger, "Failed to bind device. Error: {:?}.", err);
|
||||||
self.logger,
|
|
||||||
"Failed to bind device. Error: {:?}.", err
|
|
||||||
);
|
|
||||||
self.handler.device_removed(&mut device);
|
self.handler.device_removed(&mut device);
|
||||||
drop(device);
|
drop(device);
|
||||||
if let Err(err) = self.session.close(fd) {
|
if let Err(err) = self.session.close(fd) {
|
||||||
|
@ -304,16 +335,12 @@ where
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
self.handler.device_removed(&mut device);
|
self.handler.device_removed(&mut device);
|
||||||
drop(device);
|
drop(device);
|
||||||
if let Err(err) = self.session.close(fd) {
|
if let Err(err) = self.session.close(fd) {
|
||||||
warn!(
|
warn!(self.logger, "Failed to close unused device. Error: {:?}", err);
|
||||||
self.logger,
|
|
||||||
"Failed to close unused device. Error: {:?}", err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -323,9 +350,7 @@ where
|
||||||
EventType::Remove => {
|
EventType::Remove => {
|
||||||
info!(self.logger, "Device Remove");
|
info!(self.logger, "Device Remove");
|
||||||
if let Some(devnum) = event.devnum() {
|
if let Some(devnum) = event.devnum() {
|
||||||
if let Some((fd_event_source, device)) =
|
if let Some((fd_event_source, device)) = self.devices.borrow_mut().remove(&devnum) {
|
||||||
self.devices.borrow_mut().remove(&devnum)
|
|
||||||
{
|
|
||||||
fd_event_source.remove();
|
fd_event_source.remove();
|
||||||
let mut device = Rc::try_unwrap(device)
|
let mut device = Rc::try_unwrap(device)
|
||||||
.unwrap_or_else(|_| unreachable!())
|
.unwrap_or_else(|_| unreachable!())
|
||||||
|
@ -363,9 +388,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FdEvent::Error { error, .. } => self.handler.error(error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handler for the `UdevBackend`, allows to open, close and update drm devices as they change during runtime.
|
/// Handler for the `UdevBackend`, allows to open, close and update drm devices as they change during runtime.
|
||||||
|
@ -413,7 +435,8 @@ pub fn primary_gpu<S: AsRef<str>>(context: &Context, seat: S) -> UdevResult<Opti
|
||||||
if device
|
if device
|
||||||
.property_value("ID_SEAT")
|
.property_value("ID_SEAT")
|
||||||
.map(|x| x.to_os_string())
|
.map(|x| x.to_os_string())
|
||||||
.unwrap_or(OsString::from("seat0")) == *seat.as_ref()
|
.unwrap_or(OsString::from("seat0"))
|
||||||
|
== *seat.as_ref()
|
||||||
{
|
{
|
||||||
if let Some(pci) = device.parent_with_subsystem(Path::new("pci"))? {
|
if let Some(pci) = device.parent_with_subsystem(Path::new("pci"))? {
|
||||||
if let Some(id) = pci.attribute_value("boot_vga") {
|
if let Some(id) = pci.attribute_value("boot_vga") {
|
||||||
|
@ -442,9 +465,9 @@ pub fn all_gpus<S: AsRef<str>>(context: &Context, seat: S) -> UdevResult<Vec<Pat
|
||||||
device
|
device
|
||||||
.property_value("ID_SEAT")
|
.property_value("ID_SEAT")
|
||||||
.map(|x| x.to_os_string())
|
.map(|x| x.to_os_string())
|
||||||
.unwrap_or(OsString::from("seat0")) == *seat.as_ref()
|
.unwrap_or(OsString::from("seat0"))
|
||||||
})
|
== *seat.as_ref()
|
||||||
.flat_map(|device| device.devnode().map(PathBuf::from))
|
}).flat_map(|device| device.devnode().map(PathBuf::from))
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
//! Implementation of backend traits for types provided by `winit`
|
//! Implementation of backend traits for types provided by `winit`
|
||||||
|
|
||||||
use backend::graphics::GraphicsBackend;
|
|
||||||
use backend::graphics::egl::{EGLContext, EGLGraphicsBackend, EGLSurface, PixelFormat, SwapBuffersError};
|
|
||||||
use backend::graphics::egl::context::GlAttributes;
|
use backend::graphics::egl::context::GlAttributes;
|
||||||
use backend::graphics::egl::error as egl_error;
|
use backend::graphics::egl::error as egl_error;
|
||||||
use backend::graphics::egl::error::Result as EGLResult;
|
use backend::graphics::egl::error::Result as EGLResult;
|
||||||
use backend::graphics::egl::native;
|
use backend::graphics::egl::native;
|
||||||
use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
|
||||||
use backend::input::{Axis, AxisSource, Event as BackendEvent, InputBackend, InputHandler, KeyState,
|
use backend::graphics::egl::{EGLContext, EGLGraphicsBackend, EGLSurface, PixelFormat, SwapBuffersError};
|
||||||
KeyboardKeyEvent, MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent,
|
use backend::graphics::GraphicsBackend;
|
||||||
PointerMotionAbsoluteEvent, Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent,
|
use backend::input::{
|
||||||
TouchMotionEvent, TouchSlot, TouchUpEvent, UnusedEvent};
|
Axis, AxisSource, Event as BackendEvent, InputBackend, InputHandler, KeyState, KeyboardKeyEvent,
|
||||||
|
MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, Seat,
|
||||||
|
SeatCapabilities, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent,
|
||||||
|
UnusedEvent,
|
||||||
|
};
|
||||||
use nix::libc::c_void;
|
use nix::libc::c_void;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::error;
|
use std::error;
|
||||||
|
@ -19,8 +21,10 @@ use std::rc::Rc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use wayland_client::egl as wegl;
|
use wayland_client::egl as wegl;
|
||||||
use wayland_server::Display;
|
use wayland_server::Display;
|
||||||
use winit::{ElementState, Event, EventsLoop, KeyboardInput, MouseButton as WinitMouseButton, MouseCursor,
|
use winit::{
|
||||||
MouseScrollDelta, Touch, TouchPhase, Window as WinitWindow, WindowBuilder, WindowEvent};
|
ElementState, Event, EventsLoop, KeyboardInput, MouseButton as WinitMouseButton, MouseCursor,
|
||||||
|
MouseScrollDelta, Touch, TouchPhase, Window as WinitWindow, WindowBuilder, WindowEvent,
|
||||||
|
};
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
errors {
|
errors {
|
||||||
|
@ -136,9 +140,7 @@ where
|
||||||
info!(log, "Initializing a winit backend");
|
info!(log, "Initializing a winit backend");
|
||||||
|
|
||||||
let events_loop = EventsLoop::new();
|
let events_loop = EventsLoop::new();
|
||||||
let winit_window = builder
|
let winit_window = builder.build(&events_loop).chain_err(|| ErrorKind::InitFailed)?;
|
||||||
.build(&events_loop)
|
|
||||||
.chain_err(|| ErrorKind::InitFailed)?;
|
|
||||||
debug!(log, "Window created");
|
debug!(log, "Window created");
|
||||||
|
|
||||||
let reqs = Default::default();
|
let reqs = Default::default();
|
||||||
|
@ -367,24 +369,16 @@ impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent {
|
||||||
|
|
||||||
fn x_transformed(&self, width: u32) -> u32 {
|
fn x_transformed(&self, width: u32) -> u32 {
|
||||||
cmp::max(
|
cmp::max(
|
||||||
(self.x * width as f64
|
(self.x * width as f64 / self.window.window().get_inner_size().unwrap_or((width, 0)).0 as f64)
|
||||||
/ self.window
|
as i32,
|
||||||
.window()
|
|
||||||
.get_inner_size()
|
|
||||||
.unwrap_or((width, 0))
|
|
||||||
.0 as f64) as i32,
|
|
||||||
0,
|
0,
|
||||||
) as u32
|
) as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn y_transformed(&self, height: u32) -> u32 {
|
fn y_transformed(&self, height: u32) -> u32 {
|
||||||
cmp::max(
|
cmp::max(
|
||||||
(self.y * height as f64
|
(self.y * height as f64 / self.window.window().get_inner_size().unwrap_or((0, height)).1 as f64)
|
||||||
/ self.window
|
as i32,
|
||||||
.window()
|
|
||||||
.get_inner_size()
|
|
||||||
.unwrap_or((0, height))
|
|
||||||
.1 as f64) as i32,
|
|
||||||
0,
|
0,
|
||||||
) as u32
|
) as u32
|
||||||
}
|
}
|
||||||
|
@ -483,11 +477,7 @@ impl TouchDownEvent for WinitTouchStartedEvent {
|
||||||
fn x_transformed(&self, width: u32) -> u32 {
|
fn x_transformed(&self, width: u32) -> u32 {
|
||||||
cmp::min(
|
cmp::min(
|
||||||
self.location.0 as i32 * width as i32
|
self.location.0 as i32 * width as i32
|
||||||
/ self.window
|
/ self.window.window().get_inner_size().unwrap_or((width, 0)).0 as i32,
|
||||||
.window()
|
|
||||||
.get_inner_size()
|
|
||||||
.unwrap_or((width, 0))
|
|
||||||
.0 as i32,
|
|
||||||
0,
|
0,
|
||||||
) as u32
|
) as u32
|
||||||
}
|
}
|
||||||
|
@ -495,11 +485,7 @@ impl TouchDownEvent for WinitTouchStartedEvent {
|
||||||
fn y_transformed(&self, height: u32) -> u32 {
|
fn y_transformed(&self, height: u32) -> u32 {
|
||||||
cmp::min(
|
cmp::min(
|
||||||
self.location.1 as i32 * height as i32
|
self.location.1 as i32 * height as i32
|
||||||
/ self.window
|
/ self.window.window().get_inner_size().unwrap_or((0, height)).1 as i32,
|
||||||
.window()
|
|
||||||
.get_inner_size()
|
|
||||||
.unwrap_or((0, height))
|
|
||||||
.1 as i32,
|
|
||||||
0,
|
0,
|
||||||
) as u32
|
) as u32
|
||||||
}
|
}
|
||||||
|
@ -534,21 +520,11 @@ impl TouchMotionEvent for WinitTouchMovedEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn x_transformed(&self, width: u32) -> u32 {
|
fn x_transformed(&self, width: u32) -> u32 {
|
||||||
self.location.0 as u32 * width
|
self.location.0 as u32 * width / self.window.window().get_inner_size().unwrap_or((width, 0)).0
|
||||||
/ self.window
|
|
||||||
.window()
|
|
||||||
.get_inner_size()
|
|
||||||
.unwrap_or((width, 0))
|
|
||||||
.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn y_transformed(&self, height: u32) -> u32 {
|
fn y_transformed(&self, height: u32) -> u32 {
|
||||||
self.location.1 as u32 * height
|
self.location.1 as u32 * height / self.window.window().get_inner_size().unwrap_or((0, height)).1
|
||||||
/ self.window
|
|
||||||
.window()
|
|
||||||
.get_inner_size()
|
|
||||||
.unwrap_or((0, height))
|
|
||||||
.1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,11 +620,7 @@ impl InputBackend for WinitInputBackend {
|
||||||
|
|
||||||
fn clear_handler(&mut self) {
|
fn clear_handler(&mut self) {
|
||||||
if let Some(mut handler) = self.handler.take() {
|
if let Some(mut handler) = self.handler.take() {
|
||||||
trace!(
|
trace!(self.logger, "Calling on_seat_destroyed with {:?}", self.seat);
|
||||||
self.logger,
|
|
||||||
"Calling on_seat_destroyed with {:?}",
|
|
||||||
self.seat
|
|
||||||
);
|
|
||||||
handler.on_seat_destroyed(&self.seat);
|
handler.on_seat_destroyed(&self.seat);
|
||||||
}
|
}
|
||||||
info!(self.logger, "Removing input handler");
|
info!(self.logger, "Removing input handler");
|
||||||
|
@ -714,10 +686,7 @@ impl InputBackend for WinitInputBackend {
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
WindowEvent::KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
input:
|
input: KeyboardInput { scancode, state, .. },
|
||||||
KeyboardInput {
|
|
||||||
scancode, state, ..
|
|
||||||
},
|
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
Some(handler),
|
Some(handler),
|
||||||
|
@ -729,11 +698,7 @@ impl InputBackend for WinitInputBackend {
|
||||||
*key_counter = key_counter.checked_sub(1).unwrap_or(0)
|
*key_counter = key_counter.checked_sub(1).unwrap_or(0)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
trace!(
|
trace!(logger, "Calling on_keyboard_key with {:?}", (scancode, state));
|
||||||
logger,
|
|
||||||
"Calling on_keyboard_key with {:?}",
|
|
||||||
(scancode, state)
|
|
||||||
);
|
|
||||||
handler.on_keyboard_key(
|
handler.on_keyboard_key(
|
||||||
seat,
|
seat,
|
||||||
WinitKeyboardInputEvent {
|
WinitKeyboardInputEvent {
|
||||||
|
@ -744,13 +709,7 @@ impl InputBackend for WinitInputBackend {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(
|
(WindowEvent::CursorMoved { position: (x, y), .. }, Some(handler), _) => {
|
||||||
WindowEvent::CursorMoved {
|
|
||||||
position: (x, y), ..
|
|
||||||
},
|
|
||||||
Some(handler),
|
|
||||||
_,
|
|
||||||
) => {
|
|
||||||
trace!(logger, "Calling on_pointer_move_absolute with {:?}", (x, y));
|
trace!(logger, "Calling on_pointer_move_absolute with {:?}", (x, y));
|
||||||
handler.on_pointer_move_absolute(
|
handler.on_pointer_move_absolute(
|
||||||
seat,
|
seat,
|
||||||
|
@ -768,19 +727,8 @@ impl InputBackend for WinitInputBackend {
|
||||||
handler.on_pointer_axis(seat, event);
|
handler.on_pointer_axis(seat, event);
|
||||||
}
|
}
|
||||||
(WindowEvent::MouseInput { state, button, .. }, Some(handler), _) => {
|
(WindowEvent::MouseInput { state, button, .. }, Some(handler), _) => {
|
||||||
trace!(
|
trace!(logger, "Calling on_pointer_button with {:?}", (button, state));
|
||||||
logger,
|
handler.on_pointer_button(seat, WinitMouseInputEvent { time, button, state })
|
||||||
"Calling on_pointer_button with {:?}",
|
|
||||||
(button, state)
|
|
||||||
);
|
|
||||||
handler.on_pointer_button(
|
|
||||||
seat,
|
|
||||||
WinitMouseInputEvent {
|
|
||||||
time,
|
|
||||||
button,
|
|
||||||
state,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
WindowEvent::Touch(Touch {
|
WindowEvent::Touch(Touch {
|
||||||
|
|
|
@ -49,8 +49,8 @@ extern crate error_chain;
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
pub mod wayland;
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod wayland;
|
||||||
|
|
||||||
#[cfg(feature = "xwayland")]
|
#[cfg(feature = "xwayland")]
|
||||||
pub mod xwayland;
|
pub mod xwayland;
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use super::{CompositorToken, Damage, Rectangle, RectangleKind, Role, RoleType, SubsurfaceRole, SurfaceEvent};
|
|
||||||
use super::region::RegionData;
|
|
||||||
use super::tree::{Location, SurfaceData};
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wayland_server::{LoopToken, NewResource, Resource};
|
use std::sync::Mutex;
|
||||||
use wayland_server::commons::Implementation;
|
|
||||||
use wayland_server::protocol::{wl_compositor, wl_region, wl_subcompositor, wl_subsurface, wl_surface};
|
use wayland_server::protocol::{wl_compositor, wl_region, wl_subcompositor, wl_subsurface, wl_surface};
|
||||||
|
use wayland_server::{DisplayToken, NewResource, Resource};
|
||||||
|
|
||||||
|
use super::tree::{Location, SurfaceData};
|
||||||
|
use super::{
|
||||||
|
CompositorToken, Damage, Rectangle, RectangleKind, RegionAttributes, Role, RoleType, SubsurfaceRole,
|
||||||
|
SurfaceEvent,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wl_compositor
|
* wl_compositor
|
||||||
|
@ -13,14 +17,14 @@ use wayland_server::protocol::{wl_compositor, wl_region, wl_subcompositor, wl_su
|
||||||
|
|
||||||
pub(crate) fn implement_compositor<U, R, Impl>(
|
pub(crate) fn implement_compositor<U, R, Impl>(
|
||||||
compositor: NewResource<wl_compositor::WlCompositor>,
|
compositor: NewResource<wl_compositor::WlCompositor>,
|
||||||
token: LoopToken,
|
token: DisplayToken,
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
implem: Rc<RefCell<Impl>>,
|
implem: Rc<RefCell<Impl>>,
|
||||||
) -> Resource<wl_compositor::WlCompositor>
|
) -> Resource<wl_compositor::WlCompositor>
|
||||||
where
|
where
|
||||||
U: Default + 'static,
|
U: Default + 'static,
|
||||||
R: Default + 'static,
|
R: Default + 'static,
|
||||||
Impl: Implementation<(Resource<wl_surface::WlSurface>, CompositorToken<U, R>), SurfaceEvent> + 'static,
|
Impl: FnMut(SurfaceEvent, Resource<wl_surface::WlSurface>, CompositorToken<U, R>) + 'static,
|
||||||
{
|
{
|
||||||
let my_token = token.clone();
|
let my_token = token.clone();
|
||||||
compositor.implement_nonsend(
|
compositor.implement_nonsend(
|
||||||
|
@ -34,7 +38,8 @@ where
|
||||||
implement_region(id, &token);
|
implement_region(id, &token);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None::<fn(_, _)>,
|
None::<fn(_)>,
|
||||||
|
(),
|
||||||
&my_token,
|
&my_token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -46,95 +51,74 @@ where
|
||||||
// Internal implementation data of surfaces
|
// Internal implementation data of surfaces
|
||||||
pub(crate) struct SurfaceImplem<U, R> {
|
pub(crate) struct SurfaceImplem<U, R> {
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
implem:
|
implem: Rc<RefCell<FnMut(SurfaceEvent, Resource<wl_surface::WlSurface>, CompositorToken<U, R>)>>,
|
||||||
Rc<RefCell<Implementation<(Resource<wl_surface::WlSurface>, CompositorToken<U, R>), SurfaceEvent>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R> SurfaceImplem<U, R> {
|
impl<U, R> SurfaceImplem<U, R> {
|
||||||
fn make<Impl>(log: ::slog::Logger, implem: Rc<RefCell<Impl>>) -> SurfaceImplem<U, R>
|
fn make<Impl>(log: ::slog::Logger, implem: Rc<RefCell<Impl>>) -> SurfaceImplem<U, R>
|
||||||
where
|
where
|
||||||
Impl: Implementation<(Resource<wl_surface::WlSurface>, CompositorToken<U, R>), SurfaceEvent>
|
Impl: FnMut(SurfaceEvent, Resource<wl_surface::WlSurface>, CompositorToken<U, R>) + 'static,
|
||||||
+ 'static,
|
|
||||||
{
|
{
|
||||||
SurfaceImplem {
|
SurfaceImplem { log, implem }
|
||||||
log,
|
|
||||||
implem,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R> Implementation<Resource<wl_surface::WlSurface>, wl_surface::Request> for SurfaceImplem<U, R>
|
impl<U, R> SurfaceImplem<U, R>
|
||||||
where
|
where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: 'static,
|
R: 'static,
|
||||||
{
|
{
|
||||||
fn receive(&mut self, req: wl_surface::Request, surface: Resource<wl_surface::WlSurface>) {
|
fn receive_surface_request(
|
||||||
|
&mut self,
|
||||||
|
req: wl_surface::Request,
|
||||||
|
surface: Resource<wl_surface::WlSurface>,
|
||||||
|
) {
|
||||||
match req {
|
match req {
|
||||||
wl_surface::Request::Attach { buffer, x, y } => unsafe {
|
wl_surface::Request::Attach { buffer, x, y } => {
|
||||||
SurfaceData::<U, R>::with_data(&surface, |d| {
|
SurfaceData::<U, R>::with_data(&surface, |d| {
|
||||||
d.buffer = Some(buffer.map(|b| (b.clone(), (x, y))))
|
d.buffer = Some(buffer.map(|b| (b.clone(), (x, y))))
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
wl_surface::Request::Damage {
|
wl_surface::Request::Damage { x, y, width, height } => {
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
} => unsafe {
|
|
||||||
SurfaceData::<U, R>::with_data(&surface, |d| {
|
SurfaceData::<U, R>::with_data(&surface, |d| {
|
||||||
d.damage = Damage::Surface(Rectangle {
|
d.damage = Damage::Surface(Rectangle { x, y, width, height })
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
wl_surface::Request::Frame { callback } => {
|
wl_surface::Request::Frame { callback } => {
|
||||||
let mut user_impl = self.implem.borrow_mut();
|
let mut user_impl = self.implem.borrow_mut();
|
||||||
trace!(self.log, "Calling user implementation for wl_surface.frame");
|
trace!(self.log, "Calling user implementation for wl_surface.frame");
|
||||||
user_impl.receive(
|
(&mut *user_impl)(SurfaceEvent::Frame { callback }, surface, CompositorToken::make());
|
||||||
SurfaceEvent::Frame { callback },
|
|
||||||
(surface, CompositorToken::make()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
wl_surface::Request::SetOpaqueRegion { region } => unsafe {
|
wl_surface::Request::SetOpaqueRegion { region } => {
|
||||||
let attributes = region.map(|r| RegionData::get_attributes(&r));
|
let attributes = region.map(|r| {
|
||||||
|
let attributes_mutex = r.user_data::<Mutex<RegionAttributes>>().unwrap();
|
||||||
|
attributes_mutex.lock().unwrap().clone()
|
||||||
|
});
|
||||||
SurfaceData::<U, R>::with_data(&surface, |d| d.opaque_region = attributes);
|
SurfaceData::<U, R>::with_data(&surface, |d| d.opaque_region = attributes);
|
||||||
},
|
}
|
||||||
wl_surface::Request::SetInputRegion { region } => unsafe {
|
wl_surface::Request::SetInputRegion { region } => {
|
||||||
let attributes = region.map(|r| RegionData::get_attributes(&r));
|
let attributes = region.map(|r| {
|
||||||
|
let attributes_mutex = r.user_data::<Mutex<RegionAttributes>>().unwrap();
|
||||||
|
attributes_mutex.lock().unwrap().clone()
|
||||||
|
});
|
||||||
SurfaceData::<U, R>::with_data(&surface, |d| d.input_region = attributes);
|
SurfaceData::<U, R>::with_data(&surface, |d| d.input_region = attributes);
|
||||||
},
|
}
|
||||||
wl_surface::Request::Commit => {
|
wl_surface::Request::Commit => {
|
||||||
let mut user_impl = self.implem.borrow_mut();
|
let mut user_impl = self.implem.borrow_mut();
|
||||||
trace!(
|
trace!(self.log, "Calling user implementation for wl_surface.commit");
|
||||||
self.log,
|
(&mut *user_impl)(SurfaceEvent::Commit, surface, CompositorToken::make());
|
||||||
"Calling user implementation for wl_surface.commit"
|
|
||||||
);
|
|
||||||
user_impl.receive(SurfaceEvent::Commit, (surface, CompositorToken::make()));
|
|
||||||
}
|
}
|
||||||
wl_surface::Request::SetBufferTransform { transform } => unsafe {
|
wl_surface::Request::SetBufferTransform { transform } => {
|
||||||
SurfaceData::<U, R>::with_data(&surface, |d| d.buffer_transform = transform);
|
SurfaceData::<U, R>::with_data(&surface, |d| d.buffer_transform = transform);
|
||||||
},
|
}
|
||||||
wl_surface::Request::SetBufferScale { scale } => unsafe {
|
wl_surface::Request::SetBufferScale { scale } => {
|
||||||
SurfaceData::<U, R>::with_data(&surface, |d| d.buffer_scale = scale);
|
SurfaceData::<U, R>::with_data(&surface, |d| d.buffer_scale = scale);
|
||||||
},
|
}
|
||||||
wl_surface::Request::DamageBuffer {
|
wl_surface::Request::DamageBuffer { x, y, width, height } => {
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
} => unsafe {
|
|
||||||
SurfaceData::<U, R>::with_data(&surface, |d| {
|
SurfaceData::<U, R>::with_data(&surface, |d| {
|
||||||
d.damage = Damage::Buffer(Rectangle {
|
d.damage = Damage::Buffer(Rectangle { x, y, width, height })
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
wl_surface::Request::Destroy => {
|
wl_surface::Request::Destroy => {
|
||||||
// All is already handled by our destructor
|
// All is already handled by our destructor
|
||||||
}
|
}
|
||||||
|
@ -144,25 +128,24 @@ where
|
||||||
|
|
||||||
fn implement_surface<U, R, Impl>(
|
fn implement_surface<U, R, Impl>(
|
||||||
surface: NewResource<wl_surface::WlSurface>,
|
surface: NewResource<wl_surface::WlSurface>,
|
||||||
token: &LoopToken,
|
token: &DisplayToken,
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
implem: Rc<RefCell<Impl>>,
|
implem: Rc<RefCell<Impl>>,
|
||||||
) -> Resource<wl_surface::WlSurface>
|
) -> Resource<wl_surface::WlSurface>
|
||||||
where
|
where
|
||||||
U: Default + 'static,
|
U: Default + 'static,
|
||||||
R: Default + 'static,
|
R: Default + 'static,
|
||||||
Impl: Implementation<(Resource<wl_surface::WlSurface>, CompositorToken<U, R>), SurfaceEvent> + 'static,
|
Impl: FnMut(SurfaceEvent, Resource<wl_surface::WlSurface>, CompositorToken<U, R>) + 'static,
|
||||||
{
|
{
|
||||||
let surface = surface.implement_nonsend(
|
let surface = surface.implement_nonsend(
|
||||||
SurfaceImplem::make(log, implem),
|
{
|
||||||
Some(|surface, _| unsafe {
|
let mut implem = SurfaceImplem::make(log, implem);
|
||||||
SurfaceData::<U, R>::cleanup(&surface);
|
move |req, surface| implem.receive_surface_request(req, surface)
|
||||||
}),
|
},
|
||||||
|
Some(|surface| SurfaceData::<U, R>::cleanup(&surface)),
|
||||||
|
SurfaceData::<U, R>::new(),
|
||||||
token,
|
token,
|
||||||
);
|
);
|
||||||
unsafe {
|
|
||||||
SurfaceData::<U, R>::init(&surface);
|
|
||||||
}
|
|
||||||
surface
|
surface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,63 +153,32 @@ where
|
||||||
* wl_region
|
* wl_region
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub(crate) struct RegionImplem;
|
fn region_implem(request: wl_region::Request, region: Resource<wl_region::WlRegion>) {
|
||||||
|
let attributes_mutex = region.user_data::<Mutex<RegionAttributes>>().unwrap();
|
||||||
impl Implementation<Resource<wl_region::WlRegion>, wl_region::Request> for RegionImplem {
|
let mut guard = attributes_mutex.lock().unwrap();
|
||||||
fn receive(&mut self, request: wl_region::Request, region: Resource<wl_region::WlRegion>) {
|
|
||||||
unsafe {
|
|
||||||
match request {
|
match request {
|
||||||
wl_region::Request::Add {
|
wl_region::Request::Add { x, y, width, height } => guard
|
||||||
x,
|
.rects
|
||||||
y,
|
.push((RectangleKind::Add, Rectangle { x, y, width, height })),
|
||||||
width,
|
wl_region::Request::Subtract { x, y, width, height } => guard
|
||||||
height,
|
.rects
|
||||||
} => RegionData::add_rectangle(
|
.push((RectangleKind::Subtract, Rectangle { x, y, width, height })),
|
||||||
®ion,
|
|
||||||
RectangleKind::Add,
|
|
||||||
Rectangle {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
wl_region::Request::Subtract {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
} => RegionData::add_rectangle(
|
|
||||||
®ion,
|
|
||||||
RectangleKind::Subtract,
|
|
||||||
Rectangle {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
wl_region::Request::Destroy => {
|
wl_region::Request::Destroy => {
|
||||||
// all is handled by our destructor
|
// all is handled by our destructor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implement_region(
|
fn implement_region(
|
||||||
region: NewResource<wl_region::WlRegion>,
|
region: NewResource<wl_region::WlRegion>,
|
||||||
token: &LoopToken,
|
token: &DisplayToken,
|
||||||
) -> Resource<wl_region::WlRegion> {
|
) -> Resource<wl_region::WlRegion> {
|
||||||
let region = region.implement_nonsend(
|
region.implement_nonsend(
|
||||||
RegionImplem,
|
region_implem,
|
||||||
Some(|region, _| unsafe { RegionData::cleanup(®ion) }),
|
None::<fn(_)>,
|
||||||
|
Mutex::new(RegionAttributes::default()),
|
||||||
token,
|
token,
|
||||||
);
|
)
|
||||||
unsafe {
|
|
||||||
RegionData::init(®ion);
|
|
||||||
}
|
|
||||||
region
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -235,7 +187,7 @@ fn implement_region(
|
||||||
|
|
||||||
pub(crate) fn implement_subcompositor<U, R>(
|
pub(crate) fn implement_subcompositor<U, R>(
|
||||||
subcompositor: NewResource<wl_subcompositor::WlSubcompositor>,
|
subcompositor: NewResource<wl_subcompositor::WlSubcompositor>,
|
||||||
token: LoopToken,
|
token: DisplayToken,
|
||||||
) -> Resource<wl_subcompositor::WlSubcompositor>
|
) -> Resource<wl_subcompositor::WlSubcompositor>
|
||||||
where
|
where
|
||||||
R: RoleType + Role<SubsurfaceRole> + 'static,
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
|
@ -244,24 +196,20 @@ where
|
||||||
let my_token = token.clone();
|
let my_token = token.clone();
|
||||||
subcompositor.implement_nonsend(
|
subcompositor.implement_nonsend(
|
||||||
move |request, subcompositor: Resource<_>| match request {
|
move |request, subcompositor: Resource<_>| match request {
|
||||||
wl_subcompositor::Request::GetSubsurface {
|
wl_subcompositor::Request::GetSubsurface { id, surface, parent } => {
|
||||||
id,
|
if let Err(()) = SurfaceData::<U, R>::set_parent(&surface, &parent) {
|
||||||
surface,
|
|
||||||
parent,
|
|
||||||
} => {
|
|
||||||
if let Err(()) = unsafe { SurfaceData::<U, R>::set_parent(&surface, &parent) } {
|
|
||||||
subcompositor.post_error(
|
subcompositor.post_error(
|
||||||
wl_subcompositor::Error::BadSurface as u32,
|
wl_subcompositor::Error::BadSurface as u32,
|
||||||
"Surface already has a role.".into(),
|
"Surface already has a role.".into(),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let subsurface = implement_subsurface::<U, R>(id, &token);
|
implement_subsurface::<U, R>(id, surface.clone(), &token);
|
||||||
subsurface.set_user_data(Box::into_raw(Box::new(surface.clone())) as *mut ());
|
|
||||||
}
|
}
|
||||||
wl_subcompositor::Request::Destroy => {}
|
wl_subcompositor::Request::Destroy => {}
|
||||||
},
|
},
|
||||||
None::<fn(_, _)>,
|
None::<fn(_)>,
|
||||||
|
(),
|
||||||
&my_token,
|
&my_token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -270,28 +218,28 @@ where
|
||||||
* wl_subsurface
|
* wl_subsurface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsafe fn with_subsurface_attributes<U, R, F>(subsurface: &Resource<wl_subsurface::WlSubsurface>, f: F)
|
fn with_subsurface_attributes<U, R, F>(subsurface: &Resource<wl_subsurface::WlSubsurface>, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut SubsurfaceRole),
|
F: FnOnce(&mut SubsurfaceRole),
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: RoleType + Role<SubsurfaceRole> + 'static,
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
{
|
{
|
||||||
let ptr = subsurface.get_user_data();
|
let surface = subsurface.user_data::<Resource<wl_surface::WlSurface>>().unwrap();
|
||||||
let surface = &*(ptr as *mut Resource<wl_surface::WlSurface>);
|
|
||||||
SurfaceData::<U, R>::with_role_data::<SubsurfaceRole, _, _>(surface, |d| f(d))
|
SurfaceData::<U, R>::with_role_data::<SubsurfaceRole, _, _>(surface, |d| f(d))
|
||||||
.expect("The surface does not have a subsurface role while it has a wl_subsurface?!");
|
.expect("The surface does not have a subsurface role while it has a wl_subsurface?!");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implement_subsurface<U, R>(
|
fn implement_subsurface<U, R>(
|
||||||
subsurface: NewResource<wl_subsurface::WlSubsurface>,
|
subsurface: NewResource<wl_subsurface::WlSubsurface>,
|
||||||
token: &LoopToken,
|
surface: Resource<wl_surface::WlSurface>,
|
||||||
|
token: &DisplayToken,
|
||||||
) -> Resource<wl_subsurface::WlSubsurface>
|
) -> Resource<wl_subsurface::WlSubsurface>
|
||||||
where
|
where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: RoleType + Role<SubsurfaceRole> + 'static,
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
{
|
{
|
||||||
subsurface.implement_nonsend(
|
subsurface.implement_nonsend(
|
||||||
|request, subsurface| unsafe {
|
|request, subsurface| {
|
||||||
match request {
|
match request {
|
||||||
wl_subsurface::Request::SetPosition { x, y } => {
|
wl_subsurface::Request::SetPosition { x, y } => {
|
||||||
with_subsurface_attributes::<U, R, _>(&subsurface, |attrs| {
|
with_subsurface_attributes::<U, R, _>(&subsurface, |attrs| {
|
||||||
|
@ -299,7 +247,7 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
wl_subsurface::Request::PlaceAbove { sibling } => {
|
wl_subsurface::Request::PlaceAbove { sibling } => {
|
||||||
let surface = &*(subsurface.get_user_data() as *mut Resource<wl_surface::WlSurface>);
|
let surface = subsurface.user_data::<Resource<wl_surface::WlSurface>>().unwrap();
|
||||||
if let Err(()) = SurfaceData::<U, R>::reorder(surface, Location::After, &sibling) {
|
if let Err(()) = SurfaceData::<U, R>::reorder(surface, Location::After, &sibling) {
|
||||||
subsurface.post_error(
|
subsurface.post_error(
|
||||||
wl_subsurface::Error::BadSurface as u32,
|
wl_subsurface::Error::BadSurface as u32,
|
||||||
|
@ -308,7 +256,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wl_subsurface::Request::PlaceBelow { sibling } => {
|
wl_subsurface::Request::PlaceBelow { sibling } => {
|
||||||
let surface = &*(subsurface.get_user_data() as *mut Resource<wl_surface::WlSurface>);
|
let surface = subsurface.user_data::<Resource<wl_surface::WlSurface>>().unwrap();
|
||||||
if let Err(()) = SurfaceData::<U, R>::reorder(surface, Location::Before, &sibling) {
|
if let Err(()) = SurfaceData::<U, R>::reorder(surface, Location::Before, &sibling) {
|
||||||
subsurface.post_error(
|
subsurface.post_error(
|
||||||
wl_subsurface::Error::BadSurface as u32,
|
wl_subsurface::Error::BadSurface as u32,
|
||||||
|
@ -331,21 +279,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(|subsurface, _| unsafe {
|
Some(|subsurface| destroy_subsurface::<U, R>(&subsurface)),
|
||||||
destroy_subsurface::<U, R>(&subsurface);
|
surface,
|
||||||
}),
|
|
||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn destroy_subsurface<U, R>(subsurface: &Resource<wl_subsurface::WlSubsurface>)
|
fn destroy_subsurface<U, R>(subsurface: &Resource<wl_subsurface::WlSubsurface>)
|
||||||
where
|
where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: RoleType + Role<SubsurfaceRole> + 'static,
|
R: RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
{
|
{
|
||||||
let ptr = subsurface.get_user_data();
|
let surface = subsurface.user_data::<Resource<wl_surface::WlSurface>>().unwrap();
|
||||||
subsurface.set_user_data(::std::ptr::null_mut());
|
|
||||||
let surface = Box::from_raw(ptr as *mut Resource<wl_surface::WlSurface>);
|
|
||||||
if surface.is_alive() {
|
if surface.is_alive() {
|
||||||
SurfaceData::<U, R>::unset_parent(&surface);
|
SurfaceData::<U, R>::unset_parent(&surface);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,15 +43,14 @@
|
||||||
//! define_roles!(MyRoles);
|
//! define_roles!(MyRoles);
|
||||||
//!
|
//!
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # let (mut display, event_loop) = wayland_server::Display::new();
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
//! // Call the init function:
|
//! // Call the init function:
|
||||||
//! let (token, _, _) = compositor_init::<MyData, MyRoles, _, _>(
|
//! let (token, _, _) = compositor_init::<MyData, MyRoles, _, _>(
|
||||||
//! &mut display,
|
//! &mut display,
|
||||||
//! event_loop.token(),
|
//! |request, surface, compositor_token| {
|
||||||
//! |request, (surface, compositor_token)| {
|
|
||||||
//! /*
|
//! /*
|
||||||
//! Your handling of the user requests. This closure can also
|
//! Your handling of the user requests.
|
||||||
//! be a struct implementing the appropriate Implementation trait.
|
|
||||||
//! */
|
//! */
|
||||||
//! },
|
//! },
|
||||||
//! None // put a logger here
|
//! None // put a logger here
|
||||||
|
@ -79,21 +78,21 @@
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
mod handlers;
|
mod handlers;
|
||||||
mod tree;
|
|
||||||
mod region;
|
|
||||||
pub mod roles;
|
pub mod roles;
|
||||||
|
mod tree;
|
||||||
|
|
||||||
use self::region::RegionData;
|
|
||||||
use self::roles::{Role, RoleType, WrongRole};
|
use self::roles::{Role, RoleType, WrongRole};
|
||||||
use self::tree::SurfaceData;
|
use self::tree::SurfaceData;
|
||||||
pub use self::tree::TraversalAction;
|
pub use self::tree::TraversalAction;
|
||||||
use utils::Rectangle;
|
use utils::Rectangle;
|
||||||
use wayland_server::{Display, Global, LoopToken, NewResource, Resource};
|
|
||||||
use wayland_server::commons::Implementation;
|
|
||||||
use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor};
|
|
||||||
use wayland_server::protocol::wl_surface::WlSurface;
|
use wayland_server::protocol::wl_surface::WlSurface;
|
||||||
|
use wayland_server::protocol::{
|
||||||
|
wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor,
|
||||||
|
};
|
||||||
|
use wayland_server::{Display, Global, NewResource, Resource};
|
||||||
|
|
||||||
/// Description of which part of a surface
|
/// Description of which part of a surface
|
||||||
/// should be considered damaged and needs to be redrawn
|
/// should be considered damaged and needs to be redrawn
|
||||||
|
@ -271,11 +270,7 @@ impl<U: 'static, R: 'static> CompositorToken<U, R> {
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut SurfaceAttributes<U>) -> T,
|
F: FnOnce(&mut SurfaceAttributes<U>) -> T,
|
||||||
{
|
{
|
||||||
assert!(
|
SurfaceData::<U, R>::with_data(surface, f)
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe { SurfaceData::<U, R>::with_data(surface, f) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,13 +304,7 @@ where
|
||||||
where
|
where
|
||||||
F: FnMut(&Resource<WlSurface>, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
F: FnMut(&Resource<WlSurface>, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
||||||
{
|
{
|
||||||
assert!(
|
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe {
|
|
||||||
SurfaceData::<U, R>::map_tree(surface, initial, f, false);
|
SurfaceData::<U, R>::map_tree(surface, initial, f, false);
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,13 +324,7 @@ where
|
||||||
where
|
where
|
||||||
F: FnMut(&Resource<WlSurface>, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
F: FnMut(&Resource<WlSurface>, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
||||||
{
|
{
|
||||||
assert!(
|
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe {
|
|
||||||
SurfaceData::<U, R>::map_tree(surface, initial, f, true);
|
SurfaceData::<U, R>::map_tree(surface, initial, f, true);
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,11 +335,7 @@ where
|
||||||
/// If the surface is not managed by the CompositorGlobal that provided this token, this
|
/// If the surface is not managed by the CompositorGlobal that provided this token, this
|
||||||
/// will panic (having more than one compositor is not supported).
|
/// will panic (having more than one compositor is not supported).
|
||||||
pub fn get_parent(&self, surface: &Resource<WlSurface>) -> Option<Resource<WlSurface>> {
|
pub fn get_parent(&self, surface: &Resource<WlSurface>) -> Option<Resource<WlSurface>> {
|
||||||
assert!(
|
SurfaceData::<U, R>::get_parent(surface)
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe { SurfaceData::<U, R>::get_parent(surface) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the children of this surface
|
/// Retrieve the children of this surface
|
||||||
|
@ -364,11 +343,7 @@ where
|
||||||
/// If the surface is not managed by the CompositorGlobal that provided this token, this
|
/// If the surface is not managed by the CompositorGlobal that provided this token, this
|
||||||
/// will panic (having more than one compositor is not supported).
|
/// will panic (having more than one compositor is not supported).
|
||||||
pub fn get_children(&self, surface: &Resource<WlSurface>) -> Vec<Resource<WlSurface>> {
|
pub fn get_children(&self, surface: &Resource<WlSurface>) -> Vec<Resource<WlSurface>> {
|
||||||
assert!(
|
SurfaceData::<U, R>::get_children(surface)
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe { SurfaceData::<U, R>::get_children(surface) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,11 +353,7 @@ impl<U: 'static, R: RoleType + 'static> CompositorToken<U, R> {
|
||||||
/// If the surface is not managed by the CompositorGlobal that provided this token, this
|
/// If the surface is not managed by the CompositorGlobal that provided this token, this
|
||||||
/// will panic (having more than one compositor is not supported).
|
/// will panic (having more than one compositor is not supported).
|
||||||
pub fn has_a_role(&self, surface: &Resource<WlSurface>) -> bool {
|
pub fn has_a_role(&self, surface: &Resource<WlSurface>) -> bool {
|
||||||
assert!(
|
SurfaceData::<U, R>::has_a_role(surface)
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe { SurfaceData::<U, R>::has_a_role(surface) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check wether this surface as a specific role
|
/// Check wether this surface as a specific role
|
||||||
|
@ -393,11 +364,7 @@ impl<U: 'static, R: RoleType + 'static> CompositorToken<U, R> {
|
||||||
where
|
where
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
{
|
{
|
||||||
assert!(
|
SurfaceData::<U, R>::has_role::<RoleData>(surface)
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe { SurfaceData::<U, R>::has_role::<RoleData>(surface) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register that this surface has given role with default data
|
/// Register that this surface has given role with default data
|
||||||
|
@ -411,11 +378,7 @@ impl<U: 'static, R: RoleType + 'static> CompositorToken<U, R> {
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
RoleData: Default,
|
RoleData: Default,
|
||||||
{
|
{
|
||||||
assert!(
|
SurfaceData::<U, R>::give_role::<RoleData>(surface)
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe { SurfaceData::<U, R>::give_role::<RoleData>(surface) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register that this surface has given role with given data
|
/// Register that this surface has given role with given data
|
||||||
|
@ -432,11 +395,7 @@ impl<U: 'static, R: RoleType + 'static> CompositorToken<U, R> {
|
||||||
where
|
where
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
{
|
{
|
||||||
assert!(
|
SurfaceData::<U, R>::give_role_with::<RoleData>(surface, data)
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe { SurfaceData::<U, R>::give_role_with::<RoleData>(surface, data) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the role data of a surface
|
/// Access the role data of a surface
|
||||||
|
@ -450,11 +409,7 @@ impl<U: 'static, R: RoleType + 'static> CompositorToken<U, R> {
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
F: FnOnce(&mut RoleData) -> T,
|
F: FnOnce(&mut RoleData) -> T,
|
||||||
{
|
{
|
||||||
assert!(
|
SurfaceData::<U, R>::with_role_data::<RoleData, _, _>(surface, f)
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe { SurfaceData::<U, R>::with_role_data::<RoleData, _, _>(surface, f) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register that this surface does not have a role any longer and retrieve the data
|
/// Register that this surface does not have a role any longer and retrieve the data
|
||||||
|
@ -467,11 +422,7 @@ impl<U: 'static, R: RoleType + 'static> CompositorToken<U, R> {
|
||||||
where
|
where
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
{
|
{
|
||||||
assert!(
|
SurfaceData::<U, R>::remove_role::<RoleData>(surface)
|
||||||
surface.is_implemented_with::<self::handlers::SurfaceImplem<U, R>>(),
|
|
||||||
"Accessing the data of foreign surfaces is not supported."
|
|
||||||
);
|
|
||||||
unsafe { SurfaceData::<U, R>::remove_role::<RoleData>(surface) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the metadata associated with a wl_region
|
/// Retrieve the metadata associated with a wl_region
|
||||||
|
@ -479,11 +430,10 @@ impl<U: 'static, R: RoleType + 'static> CompositorToken<U, R> {
|
||||||
/// If the region is not managed by the CompositorGlobal that provided this token, this
|
/// If the region is not managed by the CompositorGlobal that provided this token, this
|
||||||
/// will panic (having more than one compositor is not supported).
|
/// will panic (having more than one compositor is not supported).
|
||||||
pub fn get_region_attributes(&self, region: &Resource<wl_region::WlRegion>) -> RegionAttributes {
|
pub fn get_region_attributes(&self, region: &Resource<wl_region::WlRegion>) -> RegionAttributes {
|
||||||
assert!(
|
match region.user_data::<Mutex<RegionAttributes>>() {
|
||||||
region.is_implemented_with::<self::handlers::RegionImplem>(),
|
Some(mutex) => mutex.lock().unwrap().clone(),
|
||||||
"Accessing the data of foreign regions is not supported."
|
None => panic!("Accessing the data of foreign regions is not supported."),
|
||||||
);
|
}
|
||||||
unsafe { RegionData::get_attributes(region) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +447,6 @@ impl<U: 'static, R: RoleType + 'static> CompositorToken<U, R> {
|
||||||
/// globals from the event loop in the future.
|
/// globals from the event loop in the future.
|
||||||
pub fn compositor_init<U, R, Impl, L>(
|
pub fn compositor_init<U, R, Impl, L>(
|
||||||
display: &mut Display,
|
display: &mut Display,
|
||||||
token: LoopToken,
|
|
||||||
implem: Impl,
|
implem: Impl,
|
||||||
logger: L,
|
logger: L,
|
||||||
) -> (
|
) -> (
|
||||||
|
@ -509,15 +458,15 @@ where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
U: Default + 'static,
|
U: Default + 'static,
|
||||||
R: Default + RoleType + Role<SubsurfaceRole> + 'static,
|
R: Default + RoleType + Role<SubsurfaceRole> + 'static,
|
||||||
Impl: Implementation<(Resource<WlSurface>, CompositorToken<U, R>), SurfaceEvent> + 'static,
|
Impl: FnMut(SurfaceEvent, Resource<WlSurface>, CompositorToken<U, R>) + 'static,
|
||||||
{
|
{
|
||||||
let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "compositor_handler"));
|
let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "compositor_handler"));
|
||||||
let implem = Rc::new(RefCell::new(implem));
|
let implem = Rc::new(RefCell::new(implem));
|
||||||
|
|
||||||
let comp_token = token.clone();
|
let comp_token = display.get_token();
|
||||||
let sub_token = token.clone();
|
let sub_token = display.get_token();
|
||||||
|
|
||||||
let compositor = display.create_global(&token, 4, move |_version, new_compositor| {
|
let compositor = display.create_global(4, move |new_compositor, _version| {
|
||||||
self::handlers::implement_compositor::<U, R, Impl>(
|
self::handlers::implement_compositor::<U, R, Impl>(
|
||||||
new_compositor,
|
new_compositor,
|
||||||
comp_token.clone(),
|
comp_token.clone(),
|
||||||
|
@ -526,7 +475,7 @@ where
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let subcompositor = display.create_global(&token, 1, move |_version, new_subcompositor| {
|
let subcompositor = display.create_global(1, move |new_subcompositor, _version| {
|
||||||
self::handlers::implement_subcompositor::<U, R>(new_subcompositor, sub_token.clone());
|
self::handlers::implement_subcompositor::<U, R>(new_subcompositor, sub_token.clone());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
use super::{Rectangle, RectangleKind, RegionAttributes};
|
|
||||||
use std::sync::Mutex;
|
|
||||||
use wayland_server::Resource;
|
|
||||||
use wayland_server::protocol::wl_region;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct RegionData {
|
|
||||||
attributes: RegionAttributes,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegionData {
|
|
||||||
/// Initialize the user_data of a region, must be called right when the surface is created
|
|
||||||
pub unsafe fn init(region: &Resource<wl_region::WlRegion>) {
|
|
||||||
region.set_user_data(Box::into_raw(Box::new(Mutex::new(RegionData::default()))) as *mut _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cleans the user_data of that surface, must be called when it is destroyed
|
|
||||||
pub unsafe fn cleanup(region: &Resource<wl_region::WlRegion>) {
|
|
||||||
let ptr = region.get_user_data();
|
|
||||||
region.set_user_data(::std::ptr::null_mut());
|
|
||||||
let _my_data_mutex: Box<Mutex<RegionData>> = Box::from_raw(ptr as *mut _);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_data(region: &Resource<wl_region::WlRegion>) -> &Mutex<RegionData> {
|
|
||||||
let ptr = region.get_user_data();
|
|
||||||
&*(ptr as *mut _)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn get_attributes(region: &Resource<wl_region::WlRegion>) -> RegionAttributes {
|
|
||||||
let data_mutex = Self::get_data(region);
|
|
||||||
let data_guard = data_mutex.lock().unwrap();
|
|
||||||
data_guard.attributes.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn add_rectangle(
|
|
||||||
region: &Resource<wl_region::WlRegion>,
|
|
||||||
kind: RectangleKind,
|
|
||||||
rect: Rectangle,
|
|
||||||
) {
|
|
||||||
let data_mutex = Self::get_data(region);
|
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
|
||||||
data_guard.attributes.rects.push((kind, rect));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
use super::{SubsurfaceRole, SurfaceAttributes};
|
|
||||||
use super::roles::*;
|
use super::roles::*;
|
||||||
|
use super::{SubsurfaceRole, SurfaceAttributes};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use wayland_server::Resource;
|
|
||||||
use wayland_server::protocol::wl_surface::WlSurface;
|
use wayland_server::protocol::wl_surface::WlSurface;
|
||||||
|
use wayland_server::Resource;
|
||||||
|
|
||||||
/// Node of a subsurface tree, holding some user specified data type U
|
/// Node of a subsurface tree, holding some user specified data type U
|
||||||
/// at each node
|
/// at each node
|
||||||
|
@ -20,9 +20,6 @@ use wayland_server::protocol::wl_surface::WlSurface;
|
||||||
/// a tree, but with loops allowed. This is because the wayland protocol does not
|
/// a tree, but with loops allowed. This is because the wayland protocol does not
|
||||||
/// have a failure case to forbid this. Note that if any node in such a graph does not
|
/// have a failure case to forbid this. Note that if any node in such a graph does not
|
||||||
/// have a parent, then the graph is a tree and this node is its root.
|
/// have a parent, then the graph is a tree and this node is its root.
|
||||||
///
|
|
||||||
/// All the methods here are unsafe, because they assume the provided `wl_surface` object
|
|
||||||
/// is correctly initialized regarding its `user_data`.
|
|
||||||
pub struct SurfaceData<U, R> {
|
pub struct SurfaceData<U, R> {
|
||||||
parent: Option<Resource<WlSurface>>,
|
parent: Option<Resource<WlSurface>>,
|
||||||
children: Vec<Resource<WlSurface>>,
|
children: Vec<Resource<WlSurface>>,
|
||||||
|
@ -46,18 +43,13 @@ pub enum TraversalAction<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: Default, R: Default> SurfaceData<U, R> {
|
impl<U: Default, R: Default> SurfaceData<U, R> {
|
||||||
fn new() -> SurfaceData<U, R> {
|
pub fn new() -> Mutex<SurfaceData<U, R>> {
|
||||||
SurfaceData {
|
Mutex::new(SurfaceData {
|
||||||
parent: None,
|
parent: None,
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
role: Default::default(),
|
role: Default::default(),
|
||||||
attributes: Default::default(),
|
attributes: Default::default(),
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize the user_data of a surface, must be called right when the surface is created
|
|
||||||
pub unsafe fn init(surface: &Resource<WlSurface>) {
|
|
||||||
surface.set_user_data(Box::into_raw(Box::new(Mutex::new(SurfaceData::<U, R>::new()))) as *mut _)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,21 +58,14 @@ where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: 'static,
|
R: 'static,
|
||||||
{
|
{
|
||||||
unsafe fn get_data(surface: &Resource<WlSurface>) -> &Mutex<SurfaceData<U, R>> {
|
|
||||||
let ptr = surface.get_user_data();
|
|
||||||
&*(ptr as *mut _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cleans the user_data of that surface, must be called when it is destroyed
|
/// Cleans the user_data of that surface, must be called when it is destroyed
|
||||||
pub unsafe fn cleanup(surface: &Resource<WlSurface>) {
|
pub fn cleanup(surface: &Resource<WlSurface>) {
|
||||||
let ptr = surface.get_user_data();
|
let my_data_mutex = surface.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
surface.set_user_data(::std::ptr::null_mut());
|
let mut my_data = my_data_mutex.lock().unwrap();
|
||||||
let my_data_mutex: Box<Mutex<SurfaceData<U, R>>> = Box::from_raw(ptr as *mut _);
|
|
||||||
let mut my_data = my_data_mutex.into_inner().unwrap();
|
|
||||||
if let Some(old_parent) = my_data.parent.take() {
|
if let Some(old_parent) = my_data.parent.take() {
|
||||||
if !old_parent.equals(surface) {
|
if !old_parent.equals(surface) {
|
||||||
// We had a parent that is not ourselves, lets unregister ourselves from it
|
// We had a parent that is not ourselves, lets unregister ourselves from it
|
||||||
let old_parent_mutex = Self::get_data(&old_parent);
|
let old_parent_mutex = old_parent.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut old_parent_guard = old_parent_mutex.lock().unwrap();
|
let mut old_parent_guard = old_parent_mutex.lock().unwrap();
|
||||||
old_parent_guard.children.retain(|c| !c.equals(surface));
|
old_parent_guard.children.retain(|c| !c.equals(surface));
|
||||||
}
|
}
|
||||||
|
@ -91,7 +76,7 @@ where
|
||||||
if child.equals(surface) {
|
if child.equals(surface) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let child_mutex = Self::get_data(child);
|
let child_mutex = child.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut child_guard = child_mutex.lock().unwrap();
|
let mut child_guard = child_mutex.lock().unwrap();
|
||||||
child_guard.parent = None;
|
child_guard.parent = None;
|
||||||
}
|
}
|
||||||
|
@ -99,32 +84,32 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: 'static, R: RoleType + 'static> SurfaceData<U, R> {
|
impl<U: 'static, R: RoleType + 'static> SurfaceData<U, R> {
|
||||||
pub unsafe fn has_a_role(surface: &Resource<WlSurface>) -> bool {
|
pub fn has_a_role(surface: &Resource<WlSurface>) -> bool {
|
||||||
debug_assert!(surface.is_alive());
|
debug_assert!(surface.is_alive());
|
||||||
let data_mutex = Self::get_data(surface);
|
let data_mutex = surface.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let data_guard = data_mutex.lock().unwrap();
|
let data_guard = data_mutex.lock().unwrap();
|
||||||
<R as RoleType>::has_role(&data_guard.role)
|
<R as RoleType>::has_role(&data_guard.role)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check wether a surface has a given role
|
/// Check wether a surface has a given role
|
||||||
pub unsafe fn has_role<RoleData>(surface: &Resource<WlSurface>) -> bool
|
pub fn has_role<RoleData>(surface: &Resource<WlSurface>) -> bool
|
||||||
where
|
where
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
{
|
{
|
||||||
debug_assert!(surface.is_alive());
|
debug_assert!(surface.is_alive());
|
||||||
let data_mutex = Self::get_data(surface);
|
let data_mutex = surface.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let data_guard = data_mutex.lock().unwrap();
|
let data_guard = data_mutex.lock().unwrap();
|
||||||
<R as Role<RoleData>>::has(&data_guard.role)
|
<R as Role<RoleData>>::has(&data_guard.role)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register that this surface has a role, fails if it already has one
|
/// Register that this surface has a role, fails if it already has one
|
||||||
pub unsafe fn give_role<RoleData>(surface: &Resource<WlSurface>) -> Result<(), ()>
|
pub fn give_role<RoleData>(surface: &Resource<WlSurface>) -> Result<(), ()>
|
||||||
where
|
where
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
RoleData: Default,
|
RoleData: Default,
|
||||||
{
|
{
|
||||||
debug_assert!(surface.is_alive());
|
debug_assert!(surface.is_alive());
|
||||||
let data_mutex = Self::get_data(surface);
|
let data_mutex = surface.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
let mut data_guard = data_mutex.lock().unwrap();
|
||||||
<R as Role<RoleData>>::set(&mut data_guard.role)
|
<R as Role<RoleData>>::set(&mut data_guard.role)
|
||||||
}
|
}
|
||||||
|
@ -132,15 +117,12 @@ impl<U: 'static, R: RoleType + 'static> SurfaceData<U, R> {
|
||||||
/// Register that this surface has a role with given data
|
/// Register that this surface has a role with given data
|
||||||
///
|
///
|
||||||
/// Fails if it already has one and returns the data
|
/// Fails if it already has one and returns the data
|
||||||
pub unsafe fn give_role_with<RoleData>(
|
pub fn give_role_with<RoleData>(surface: &Resource<WlSurface>, data: RoleData) -> Result<(), RoleData>
|
||||||
surface: &Resource<WlSurface>,
|
|
||||||
data: RoleData,
|
|
||||||
) -> Result<(), RoleData>
|
|
||||||
where
|
where
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
{
|
{
|
||||||
debug_assert!(surface.is_alive());
|
debug_assert!(surface.is_alive());
|
||||||
let data_mutex = Self::get_data(surface);
|
let data_mutex = surface.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
let mut data_guard = data_mutex.lock().unwrap();
|
||||||
<R as Role<RoleData>>::set_with(&mut data_guard.role, data)
|
<R as Role<RoleData>>::set_with(&mut data_guard.role, data)
|
||||||
}
|
}
|
||||||
|
@ -149,24 +131,24 @@ impl<U: 'static, R: RoleType + 'static> SurfaceData<U, R> {
|
||||||
///
|
///
|
||||||
/// It is a noop if this surface already didn't have one, but fails if
|
/// It is a noop if this surface already didn't have one, but fails if
|
||||||
/// the role was "subsurface", it must be removed by the `unset_parent` method.
|
/// the role was "subsurface", it must be removed by the `unset_parent` method.
|
||||||
pub unsafe fn remove_role<RoleData>(surface: &Resource<WlSurface>) -> Result<RoleData, WrongRole>
|
pub fn remove_role<RoleData>(surface: &Resource<WlSurface>) -> Result<RoleData, WrongRole>
|
||||||
where
|
where
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
{
|
{
|
||||||
debug_assert!(surface.is_alive());
|
debug_assert!(surface.is_alive());
|
||||||
let data_mutex = Self::get_data(surface);
|
let data_mutex = surface.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
let mut data_guard = data_mutex.lock().unwrap();
|
||||||
<R as Role<RoleData>>::unset(&mut data_guard.role)
|
<R as Role<RoleData>>::unset(&mut data_guard.role)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access to the role data
|
/// Access to the role data
|
||||||
pub unsafe fn with_role_data<RoleData, F, T>(surface: &Resource<WlSurface>, f: F) -> Result<T, WrongRole>
|
pub fn with_role_data<RoleData, F, T>(surface: &Resource<WlSurface>, f: F) -> Result<T, WrongRole>
|
||||||
where
|
where
|
||||||
R: Role<RoleData>,
|
R: Role<RoleData>,
|
||||||
F: FnOnce(&mut RoleData) -> T,
|
F: FnOnce(&mut RoleData) -> T,
|
||||||
{
|
{
|
||||||
debug_assert!(surface.is_alive());
|
debug_assert!(surface.is_alive());
|
||||||
let data_mutex = Self::get_data(surface);
|
let data_mutex = surface.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
let mut data_guard = data_mutex.lock().unwrap();
|
||||||
let data = <R as Role<RoleData>>::data_mut(&mut data_guard.role)?;
|
let data = <R as Role<RoleData>>::data_mut(&mut data_guard.role)?;
|
||||||
Ok(f(data))
|
Ok(f(data))
|
||||||
|
@ -178,13 +160,13 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
///
|
///
|
||||||
/// if this surface already has a role, does nothing and fails, otherwise
|
/// if this surface already has a role, does nothing and fails, otherwise
|
||||||
/// its role is now to be a subsurface
|
/// its role is now to be a subsurface
|
||||||
pub unsafe fn set_parent(child: &Resource<WlSurface>, parent: &Resource<WlSurface>) -> Result<(), ()> {
|
pub fn set_parent(child: &Resource<WlSurface>, parent: &Resource<WlSurface>) -> Result<(), ()> {
|
||||||
debug_assert!(child.is_alive());
|
debug_assert!(child.is_alive());
|
||||||
debug_assert!(parent.is_alive());
|
debug_assert!(parent.is_alive());
|
||||||
|
|
||||||
// change child's parent
|
// change child's parent
|
||||||
{
|
{
|
||||||
let child_mutex = Self::get_data(child);
|
let child_mutex = child.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut child_guard = child_mutex.lock().unwrap();
|
let mut child_guard = child_mutex.lock().unwrap();
|
||||||
// if surface already has a role, it cannot become a subsurface
|
// if surface already has a role, it cannot become a subsurface
|
||||||
<R as Role<SubsurfaceRole>>::set(&mut child_guard.role)?;
|
<R as Role<SubsurfaceRole>>::set(&mut child_guard.role)?;
|
||||||
|
@ -194,7 +176,7 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
// register child to new parent
|
// register child to new parent
|
||||||
// double scoping is to be robust to have a child be its own parent
|
// double scoping is to be robust to have a child be its own parent
|
||||||
{
|
{
|
||||||
let parent_mutex = Self::get_data(parent);
|
let parent_mutex = parent.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut parent_guard = parent_mutex.lock().unwrap();
|
let mut parent_guard = parent_mutex.lock().unwrap();
|
||||||
parent_guard.children.push(child.clone())
|
parent_guard.children.push(child.clone())
|
||||||
}
|
}
|
||||||
|
@ -204,10 +186,10 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
/// Remove a pre-existing parent of this child
|
/// Remove a pre-existing parent of this child
|
||||||
///
|
///
|
||||||
/// Does nothing if it has no parent
|
/// Does nothing if it has no parent
|
||||||
pub unsafe fn unset_parent(child: &Resource<WlSurface>) {
|
pub fn unset_parent(child: &Resource<WlSurface>) {
|
||||||
debug_assert!(child.is_alive());
|
debug_assert!(child.is_alive());
|
||||||
let old_parent = {
|
let old_parent = {
|
||||||
let child_mutex = Self::get_data(child);
|
let child_mutex = child.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut child_guard = child_mutex.lock().unwrap();
|
let mut child_guard = child_mutex.lock().unwrap();
|
||||||
let old_parent = child_guard.parent.take();
|
let old_parent = child_guard.parent.take();
|
||||||
if old_parent.is_some() {
|
if old_parent.is_some() {
|
||||||
|
@ -219,22 +201,22 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
};
|
};
|
||||||
// unregister from our parent
|
// unregister from our parent
|
||||||
if let Some(old_parent) = old_parent {
|
if let Some(old_parent) = old_parent {
|
||||||
let parent_mutex = Self::get_data(&old_parent);
|
let parent_mutex = old_parent.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut parent_guard = parent_mutex.lock().unwrap();
|
let mut parent_guard = parent_mutex.lock().unwrap();
|
||||||
parent_guard.children.retain(|c| !c.equals(child));
|
parent_guard.children.retain(|c| !c.equals(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the parent surface (if any) of this surface
|
/// Retrieve the parent surface (if any) of this surface
|
||||||
pub unsafe fn get_parent(child: &Resource<WlSurface>) -> Option<Resource<WlSurface>> {
|
pub fn get_parent(child: &Resource<WlSurface>) -> Option<Resource<WlSurface>> {
|
||||||
let child_mutex = Self::get_data(child);
|
let child_mutex = child.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let child_guard = child_mutex.lock().unwrap();
|
let child_guard = child_mutex.lock().unwrap();
|
||||||
child_guard.parent.as_ref().cloned()
|
child_guard.parent.as_ref().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the parent surface (if any) of this surface
|
/// Retrieve the parent surface (if any) of this surface
|
||||||
pub unsafe fn get_children(child: &Resource<WlSurface>) -> Vec<Resource<WlSurface>> {
|
pub fn get_children(child: &Resource<WlSurface>) -> Vec<Resource<WlSurface>> {
|
||||||
let child_mutex = Self::get_data(child);
|
let child_mutex = child.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let child_guard = child_mutex.lock().unwrap();
|
let child_guard = child_mutex.lock().unwrap();
|
||||||
child_guard.children.to_vec()
|
child_guard.children.to_vec()
|
||||||
}
|
}
|
||||||
|
@ -242,13 +224,13 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
/// Reorders a surface relative to one of its sibling
|
/// Reorders a surface relative to one of its sibling
|
||||||
///
|
///
|
||||||
/// Fails if `relative_to` is not a sibling or parent of `surface`.
|
/// Fails if `relative_to` is not a sibling or parent of `surface`.
|
||||||
pub unsafe fn reorder(
|
pub fn reorder(
|
||||||
surface: &Resource<WlSurface>,
|
surface: &Resource<WlSurface>,
|
||||||
to: Location,
|
to: Location,
|
||||||
relative_to: &Resource<WlSurface>,
|
relative_to: &Resource<WlSurface>,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let parent = {
|
let parent = {
|
||||||
let data_mutex = Self::get_data(surface);
|
let data_mutex = surface.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let data_guard = data_mutex.lock().unwrap();
|
let data_guard = data_mutex.lock().unwrap();
|
||||||
data_guard.parent.as_ref().cloned().unwrap()
|
data_guard.parent.as_ref().cloned().unwrap()
|
||||||
};
|
};
|
||||||
|
@ -266,7 +248,7 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
let parent_mutex = Self::get_data(&parent);
|
let parent_mutex = parent.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut parent_guard = parent_mutex.lock().unwrap();
|
let mut parent_guard = parent_mutex.lock().unwrap();
|
||||||
let my_index = index_of(surface, &parent_guard.children).unwrap();
|
let my_index = index_of(surface, &parent_guard.children).unwrap();
|
||||||
let mut other_index = match index_of(surface, &parent_guard.children) {
|
let mut other_index = match index_of(surface, &parent_guard.children) {
|
||||||
|
@ -291,11 +273,13 @@ impl<U: 'static, R: 'static> SurfaceData<U, R> {
|
||||||
///
|
///
|
||||||
/// Note that an internal lock is taken during access of this data,
|
/// Note that an internal lock is taken during access of this data,
|
||||||
/// so the tree cannot be manipulated at the same time
|
/// so the tree cannot be manipulated at the same time
|
||||||
pub unsafe fn with_data<T, F>(surface: &Resource<WlSurface>, f: F) -> T
|
pub fn with_data<T, F>(surface: &Resource<WlSurface>, f: F) -> T
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut SurfaceAttributes<U>) -> T,
|
F: FnOnce(&mut SurfaceAttributes<U>) -> T,
|
||||||
{
|
{
|
||||||
let data_mutex = Self::get_data(surface);
|
let data_mutex = surface
|
||||||
|
.user_data::<Mutex<SurfaceData<U, R>>>()
|
||||||
|
.expect("Accessing the data of foreign surfaces is not supported.");
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
let mut data_guard = data_mutex.lock().unwrap();
|
||||||
f(&mut data_guard.attributes)
|
f(&mut data_guard.attributes)
|
||||||
}
|
}
|
||||||
|
@ -308,12 +292,12 @@ impl<U: 'static, R: 'static> SurfaceData<U, R> {
|
||||||
///
|
///
|
||||||
/// The callback returns wether the traversal should continue or not. Returning
|
/// The callback returns wether the traversal should continue or not. Returning
|
||||||
/// false will cause an early-stopping.
|
/// false will cause an early-stopping.
|
||||||
pub unsafe fn map_tree<F, T>(root: &Resource<WlSurface>, initial: T, mut f: F, reverse: bool)
|
pub fn map_tree<F, T>(root: &Resource<WlSurface>, initial: T, mut f: F, reverse: bool)
|
||||||
where
|
where
|
||||||
F: FnMut(&Resource<WlSurface>, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
F: FnMut(&Resource<WlSurface>, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
||||||
{
|
{
|
||||||
// helper function for recursion
|
// helper function for recursion
|
||||||
unsafe fn map<U: 'static, R: 'static, F, T>(
|
fn map<U: 'static, R: 'static, F, T>(
|
||||||
surface: &Resource<WlSurface>,
|
surface: &Resource<WlSurface>,
|
||||||
root: &Resource<WlSurface>,
|
root: &Resource<WlSurface>,
|
||||||
initial: &T,
|
initial: &T,
|
||||||
|
@ -328,16 +312,11 @@ impl<U: 'static, R: 'static> SurfaceData<U, R> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let data_mutex = SurfaceData::<U, R>::get_data(surface);
|
let data_mutex = surface.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
let mut data_guard = data_mutex.lock().unwrap();
|
||||||
let data_guard = &mut *data_guard;
|
let data_guard = &mut *data_guard;
|
||||||
// call the callback on ourselves
|
// call the callback on ourselves
|
||||||
match f(
|
match f(surface, &mut data_guard.attributes, &mut data_guard.role, initial) {
|
||||||
surface,
|
|
||||||
&mut data_guard.attributes,
|
|
||||||
&mut data_guard.role,
|
|
||||||
initial,
|
|
||||||
) {
|
|
||||||
TraversalAction::DoChildren(t) => {
|
TraversalAction::DoChildren(t) => {
|
||||||
// loop over children
|
// loop over children
|
||||||
if reverse {
|
if reverse {
|
||||||
|
@ -360,16 +339,13 @@ impl<U: 'static, R: 'static> SurfaceData<U, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let data_mutex = Self::get_data(root);
|
let data_mutex = root.user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
let mut data_guard = data_mutex.lock().unwrap();
|
||||||
let data_guard = &mut *data_guard;
|
let data_guard = &mut *data_guard;
|
||||||
// call the callback on ourselves
|
// call the callback on ourselves
|
||||||
if let TraversalAction::DoChildren(t) = f(
|
if let TraversalAction::DoChildren(t) =
|
||||||
root,
|
f(root, &mut data_guard.attributes, &mut data_guard.role, &initial)
|
||||||
&mut data_guard.attributes,
|
{
|
||||||
&mut data_guard.role,
|
|
||||||
&initial,
|
|
||||||
) {
|
|
||||||
// loop over children
|
// loop over children
|
||||||
if reverse {
|
if reverse {
|
||||||
for c in data_guard.children.iter().rev() {
|
for c in data_guard.children.iter().rev() {
|
||||||
|
|
|
@ -7,19 +7,13 @@
|
||||||
//!
|
//!
|
||||||
//! - An init function or method will take the event loop as argument and
|
//! - An init function or method will take the event loop as argument and
|
||||||
//! insert one or more globals into it.
|
//! insert one or more globals into it.
|
||||||
//! - These functions will return the `Global` handles and, if applicable,
|
|
||||||
//! a `StateToken` allowing you to access the associated state value in
|
|
||||||
//! this event loop.
|
|
||||||
//! - If you want to remove a previously inserted global, just call the
|
//! - If you want to remove a previously inserted global, just call the
|
||||||
//! `destroy()` method on the associated `Global`. If you don't plan to
|
//! `destroy()` method on the associated `Global`. If you don't plan to
|
||||||
//! destroy the global at all, you don't need to bother keeping the
|
//! destroy the global at all, you don't need to bother keeping the
|
||||||
//! `Global` around.
|
//! `Global` around.
|
||||||
//! - You should not remove a state value from the event loop if you have
|
|
||||||
//! not previously destroyed all the globals using it, otherwise you'll
|
|
||||||
//! quickly encounter a panic.
|
|
||||||
|
|
||||||
pub mod compositor;
|
pub mod compositor;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
pub mod seat;
|
pub mod seat;
|
||||||
pub mod shm;
|
|
||||||
pub mod shell;
|
pub mod shell;
|
||||||
|
pub mod shm;
|
||||||
|
|
|
@ -22,17 +22,17 @@
|
||||||
//! use wayland_server::protocol::wl_output;
|
//! use wayland_server::protocol::wl_output;
|
||||||
//!
|
//!
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # let (mut display, event_loop) = wayland_server::Display::new();
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
//! // Create the Output with given name and physical properties
|
//! // Create the Output with given name and physical properties
|
||||||
//! let (output, _output_global) = Output::new(
|
//! let (output, _output_global) = Output::new(
|
||||||
//! &mut display, // the display
|
//! &mut display, // the display
|
||||||
//! event_loop.token(), // the LoopToken
|
|
||||||
//! "output-0".into(), // the name of this output,
|
//! "output-0".into(), // the name of this output,
|
||||||
//! PhysicalProperties {
|
//! PhysicalProperties {
|
||||||
//! width: 200, // width in mm
|
//! width: 200, // width in mm
|
||||||
//! height: 150, // height in mm,
|
//! height: 150, // height in mm,
|
||||||
//! subpixel: wl_output::Subpixel::HorizontalRgb, // subpixel information
|
//! subpixel: wl_output::Subpixel::HorizontalRgb, // subpixel information
|
||||||
//! maker: "Screens Inc".into(), // manufacturer of the monitor
|
//! make: "Screens Inc".into(), // make of the monitor
|
||||||
//! model: "Monitor Ultra".into(), // model of the monitor
|
//! model: "Monitor Ultra".into(), // model of the monitor
|
||||||
//! },
|
//! },
|
||||||
//! None // insert a logger here
|
//! None // insert a logger here
|
||||||
|
@ -53,10 +53,9 @@
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use wayland_server::{Display, Global, LoopToken, NewResource, Resource};
|
|
||||||
use wayland_server::commons::{downcast_impl, Implementation};
|
|
||||||
use wayland_server::protocol::wl_output::{Event, Mode as WMode, Request, WlOutput};
|
use wayland_server::protocol::wl_output::{Event, Mode as WMode, Request, WlOutput};
|
||||||
pub use wayland_server::protocol::wl_output::{Subpixel, Transform};
|
pub use wayland_server::protocol::wl_output::{Subpixel, Transform};
|
||||||
|
use wayland_server::{Display, Global, NewResource, Resource};
|
||||||
|
|
||||||
/// An output mode
|
/// An output mode
|
||||||
///
|
///
|
||||||
|
@ -84,8 +83,8 @@ pub struct PhysicalProperties {
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
/// The subpixel geometry
|
/// The subpixel geometry
|
||||||
pub subpixel: Subpixel,
|
pub subpixel: Subpixel,
|
||||||
/// Textual representation of the manufacturer
|
/// Textual representation of the make
|
||||||
pub maker: String,
|
pub make: String,
|
||||||
/// Textual representation of the model
|
/// Textual representation of the model
|
||||||
pub model: String,
|
pub model: String,
|
||||||
}
|
}
|
||||||
|
@ -148,27 +147,13 @@ impl Inner {
|
||||||
physical_width: self.physical.width,
|
physical_width: self.physical.width,
|
||||||
physical_height: self.physical.height,
|
physical_height: self.physical.height,
|
||||||
subpixel: self.physical.subpixel,
|
subpixel: self.physical.subpixel,
|
||||||
make: self.physical.maker.clone(),
|
make: self.physical.make.clone(),
|
||||||
model: self.physical.model.clone(),
|
model: self.physical.model.clone(),
|
||||||
transform: self.transform,
|
transform: self.transform,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InnerWrapper {
|
|
||||||
inner: Arc<Mutex<Inner>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// This implementation does nothing, we just use it as a stable type to downcast the
|
|
||||||
// implementation in the destructor of wl_output, in order to retrieve the Arc to the
|
|
||||||
// inner and remove this output from the list
|
|
||||||
impl Implementation<Resource<WlOutput>, Request> for InnerWrapper {
|
|
||||||
fn receive(&mut self, req: Request, _res: Resource<WlOutput>) {
|
|
||||||
// this will break if new variants are added :)
|
|
||||||
let Request::Release = req;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An output as seen by the clients
|
/// An output as seen by the clients
|
||||||
///
|
///
|
||||||
/// This handle is stored in the events loop, and allows you to notify clients
|
/// This handle is stored in the events loop, and allows you to notify clients
|
||||||
|
@ -185,7 +170,6 @@ impl Output {
|
||||||
/// in case you whish to remove this global in the future.
|
/// in case you whish to remove this global in the future.
|
||||||
pub fn new<L>(
|
pub fn new<L>(
|
||||||
display: &mut Display,
|
display: &mut Display,
|
||||||
token: LoopToken,
|
|
||||||
name: String,
|
name: String,
|
||||||
physical: PhysicalProperties,
|
physical: PhysicalProperties,
|
||||||
logger: L,
|
logger: L,
|
||||||
|
@ -210,25 +194,19 @@ impl Output {
|
||||||
preferred_mode: None,
|
preferred_mode: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let output = Output {
|
let output = Output { inner: inner.clone() };
|
||||||
inner: inner.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let global = display.create_global(&token, 3, move |_version, new_output: NewResource<_>| {
|
let global = display.create_global(3, move |new_output: NewResource<_>, _version| {
|
||||||
let output = new_output.implement(
|
let output = new_output.implement(
|
||||||
InnerWrapper {
|
|req, _| {
|
||||||
inner: inner.clone(),
|
// this will break if new variants are added :)
|
||||||
|
let Request::Release = req;
|
||||||
},
|
},
|
||||||
Some(|output, boxed_impl| {
|
Some(|output: Resource<WlOutput>| {
|
||||||
let wrapper: Box<InnerWrapper> =
|
let inner = output.user_data::<Arc<Mutex<Inner>>>().unwrap();
|
||||||
downcast_impl(boxed_impl).unwrap_or_else(|_| unreachable!());
|
inner.lock().unwrap().instances.retain(|o| !o.equals(&output));
|
||||||
wrapper
|
|
||||||
.inner
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.instances
|
|
||||||
.retain(|o| !o.equals(&output));
|
|
||||||
}),
|
}),
|
||||||
|
inner.clone(),
|
||||||
);
|
);
|
||||||
inner.lock().unwrap().new_global(output);
|
inner.lock().unwrap().new_global(output);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,9 +3,11 @@ use std::io::{Error as IoError, Write};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use tempfile::tempfile;
|
use tempfile::tempfile;
|
||||||
use wayland_server::{NewResource, Resource};
|
use wayland_server::protocol::wl_keyboard::{
|
||||||
|
Event, KeyState as WlKeyState, KeymapFormat, Request, WlKeyboard,
|
||||||
|
};
|
||||||
use wayland_server::protocol::wl_surface::WlSurface;
|
use wayland_server::protocol::wl_surface::WlSurface;
|
||||||
use wayland_server::protocol::wl_keyboard::{Event, KeyState as WlKeyState, KeymapFormat, Request, WlKeyboard};
|
use wayland_server::{NewResource, Resource};
|
||||||
use xkbcommon::xkb;
|
use xkbcommon::xkb;
|
||||||
pub use xkbcommon::xkb::{keysyms, Keysym};
|
pub use xkbcommon::xkb::{keysyms, Keysym};
|
||||||
|
|
||||||
|
@ -194,15 +196,8 @@ pub(crate) fn create_keyboard_handler(
|
||||||
"rules" => rules, "model" => model, "layout" => layout, "variant" => variant,
|
"rules" => rules, "model" => model, "layout" => layout, "variant" => variant,
|
||||||
"options" => &options
|
"options" => &options
|
||||||
);
|
);
|
||||||
let internal = KbdInternal::new(
|
let internal = KbdInternal::new(rules, model, layout, variant, options, repeat_rate, repeat_delay)
|
||||||
rules,
|
.map_err(|_| {
|
||||||
model,
|
|
||||||
layout,
|
|
||||||
variant,
|
|
||||||
options,
|
|
||||||
repeat_rate,
|
|
||||||
repeat_delay,
|
|
||||||
).map_err(|_| {
|
|
||||||
debug!(log, "Loading keymap failed");
|
debug!(log, "Loading keymap failed");
|
||||||
Error::BadKeymap
|
Error::BadKeymap
|
||||||
})?;
|
})?;
|
||||||
|
@ -416,7 +411,7 @@ pub(crate) fn implement_keyboard(
|
||||||
let destructor = match handle {
|
let destructor = match handle {
|
||||||
Some(h) => {
|
Some(h) => {
|
||||||
let arc = h.arc.clone();
|
let arc = h.arc.clone();
|
||||||
Some(move |keyboard: Resource<_>, _| {
|
Some(move |keyboard: Resource<_>| {
|
||||||
arc.internal
|
arc.internal
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -435,5 +430,6 @@ pub(crate) fn implement_keyboard(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destructor,
|
destructor,
|
||||||
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
//! use smithay::wayland::seat::Seat;
|
//! use smithay::wayland::seat::Seat;
|
||||||
//!
|
//!
|
||||||
//! # fn main(){
|
//! # fn main(){
|
||||||
//! # let (mut display, event_loop) = wayland_server::Display::new();
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
//! // insert the seat:
|
//! // insert the seat:
|
||||||
//! let (seat, seat_global) = Seat::new(
|
//! let (seat, seat_global) = Seat::new(
|
||||||
//! &mut display, // the display
|
//! &mut display, // the display
|
||||||
//! event_loop.token(), // a LoopToken
|
//! "seat-0".into(), // the name of the seat, will be advertized to clients
|
||||||
//! "seat-0".into(), // the name of the seat, will be advertize to clients
|
//! None // insert a logger here
|
||||||
//! None /* insert a logger here*/
|
|
||||||
//! );
|
//! );
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
@ -40,12 +40,12 @@
|
||||||
//! # use smithay::wayland::seat::Seat;
|
//! # use smithay::wayland::seat::Seat;
|
||||||
//! #
|
//! #
|
||||||
//! # fn main(){
|
//! # fn main(){
|
||||||
//! # let (mut display, event_loop) = wayland_server::Display::new();
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
//! # let (mut seat, seat_global) = Seat::new(
|
//! # let (mut seat, seat_global) = Seat::new(
|
||||||
//! # &mut display,
|
//! # &mut display,
|
||||||
//! # event_loop.token(),
|
//! # "seat-0".into(),
|
||||||
//! # "seat-0".into(), // the name of the seat, will be advertize to clients
|
//! # None
|
||||||
//! # None /* insert a logger here*/
|
|
||||||
//! # );
|
//! # );
|
||||||
//! let pointer_handle = seat.add_pointer();
|
//! let pointer_handle = seat.add_pointer();
|
||||||
//! # }
|
//! # }
|
||||||
|
@ -61,8 +61,8 @@ mod pointer;
|
||||||
|
|
||||||
pub use self::keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState};
|
pub use self::keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState};
|
||||||
pub use self::pointer::{PointerAxisHandle, PointerHandle};
|
pub use self::pointer::{PointerAxisHandle, PointerHandle};
|
||||||
use wayland_server::{Display, Global, LoopToken, NewResource, Resource};
|
|
||||||
use wayland_server::protocol::wl_seat;
|
use wayland_server::protocol::wl_seat;
|
||||||
|
use wayland_server::{Display, Global, NewResource, Resource};
|
||||||
|
|
||||||
struct Inner {
|
struct Inner {
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
|
@ -113,12 +113,7 @@ impl Seat {
|
||||||
/// You are provided with the state token to retrieve it (allowing
|
/// You are provided with the state token to retrieve it (allowing
|
||||||
/// you to add or remove capabilities from it), and the global handle,
|
/// you to add or remove capabilities from it), and the global handle,
|
||||||
/// in case you want to remove it.
|
/// in case you want to remove it.
|
||||||
pub fn new<L>(
|
pub fn new<L>(display: &mut Display, name: String, logger: L) -> (Seat, Global<wl_seat::WlSeat>)
|
||||||
display: &mut Display,
|
|
||||||
token: LoopToken,
|
|
||||||
name: String,
|
|
||||||
logger: L,
|
|
||||||
) -> (Seat, Global<wl_seat::WlSeat>)
|
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -130,10 +125,8 @@ impl Seat {
|
||||||
keyboard: None,
|
keyboard: None,
|
||||||
known_seats: Vec::new(),
|
known_seats: Vec::new(),
|
||||||
}));
|
}));
|
||||||
let seat = Seat {
|
let seat = Seat { inner: inner.clone() };
|
||||||
inner: inner.clone(),
|
let global = display.create_global(5, move |new_seat, _version| {
|
||||||
};
|
|
||||||
let global = display.create_global(&token, 5, move |_version, new_seat| {
|
|
||||||
let seat = implement_seat(new_seat, inner.clone());
|
let seat = implement_seat(new_seat, inner.clone());
|
||||||
let mut inner = inner.lock().unwrap();
|
let mut inner = inner.lock().unwrap();
|
||||||
if seat.version() >= 2 {
|
if seat.version() >= 2 {
|
||||||
|
@ -277,12 +270,13 @@ fn implement_seat(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(move |seat, _| {
|
Some(move |seat| {
|
||||||
dest_inner
|
dest_inner
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.known_seats
|
.known_seats
|
||||||
.retain(|s| !s.equals(&seat));
|
.retain(|s| !s.equals(&seat));
|
||||||
}),
|
}),
|
||||||
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use wayland_server::{NewResource, Resource};
|
|
||||||
use wayland_server::protocol::wl_surface::WlSurface;
|
|
||||||
use wayland_server::protocol::wl_pointer::{Axis, AxisSource, ButtonState, Event, Request, WlPointer};
|
use wayland_server::protocol::wl_pointer::{Axis, AxisSource, ButtonState, Event, Request, WlPointer};
|
||||||
|
use wayland_server::protocol::wl_surface::WlSurface;
|
||||||
|
use wayland_server::{NewResource, Resource};
|
||||||
|
|
||||||
// TODO: handle pointer surface role
|
// TODO: handle pointer surface role
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ impl PointerHandle {
|
||||||
///
|
///
|
||||||
/// A single frame will group multiple scroll events as if they happended in the same instance.
|
/// A single frame will group multiple scroll events as if they happended in the same instance.
|
||||||
/// Dropping the returned `PointerAxisHandle` will group the events together.
|
/// Dropping the returned `PointerAxisHandle` will group the events together.
|
||||||
pub fn axis(& self) -> PointerAxisHandle {
|
pub fn axis(&self) -> PointerAxisHandle {
|
||||||
PointerAxisHandle {
|
PointerAxisHandle {
|
||||||
inner: self.inner.lock().unwrap(),
|
inner: self.inner.lock().unwrap(),
|
||||||
}
|
}
|
||||||
|
@ -171,9 +171,7 @@ impl<'a> PointerAxisHandle<'a> {
|
||||||
pub fn source(&mut self, source: AxisSource) -> &mut Self {
|
pub fn source(&mut self, source: AxisSource) -> &mut Self {
|
||||||
self.inner.with_focused_pointers(|pointer, _| {
|
self.inner.with_focused_pointers(|pointer, _| {
|
||||||
if pointer.version() >= 5 {
|
if pointer.version() >= 5 {
|
||||||
pointer.send(Event::AxisSource {
|
pointer.send(Event::AxisSource { axis_source: source });
|
||||||
axis_source: source,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
|
@ -245,7 +243,7 @@ pub(crate) fn implement_pointer(
|
||||||
let destructor = match handle {
|
let destructor = match handle {
|
||||||
Some(h) => {
|
Some(h) => {
|
||||||
let inner = h.inner.clone();
|
let inner = h.inner.clone();
|
||||||
Some(move |pointer: Resource<_>, _| {
|
Some(move |pointer: Resource<_>| {
|
||||||
inner
|
inner
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -267,5 +265,6 @@ pub(crate) fn implement_pointer(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destructor,
|
destructor,
|
||||||
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
//! use smithay::wayland::compositor::roles::*;
|
//! use smithay::wayland::compositor::roles::*;
|
||||||
//! use smithay::wayland::compositor::CompositorToken;
|
//! use smithay::wayland::compositor::CompositorToken;
|
||||||
//! use smithay::wayland::shell::legacy::{wl_shell_init, ShellSurfaceRole, ShellRequest};
|
//! use smithay::wayland::shell::legacy::{wl_shell_init, ShellSurfaceRole, ShellRequest};
|
||||||
//! use wayland_server::{EventLoop, LoopToken};
|
|
||||||
//! # use wayland_server::protocol::{wl_seat, wl_output};
|
//! # use wayland_server::protocol::{wl_seat, wl_output};
|
||||||
//! # #[derive(Default)] struct MySurfaceData;
|
//! # #[derive(Default)] struct MySurfaceData;
|
||||||
//!
|
//!
|
||||||
|
@ -51,21 +50,19 @@
|
||||||
//! );
|
//! );
|
||||||
//!
|
//!
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # let (mut display, event_loop) = wayland_server::Display::new();
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
//! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::<(), MyRoles, _, _>(
|
//! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::<(), MyRoles, _, _>(
|
||||||
//! # &mut display,
|
//! # &mut display,
|
||||||
//! # event_loop.token(),
|
//! # |_, _, _| {},
|
||||||
//! # |_, _| {},
|
|
||||||
//! # None
|
//! # None
|
||||||
//! # );
|
//! # );
|
||||||
//! let (shell_state, _) = wl_shell_init(
|
//! let (shell_state, _) = wl_shell_init(
|
||||||
//! &mut display,
|
//! &mut display,
|
||||||
//! event_loop.token(),
|
|
||||||
//! // token from the compositor implementation
|
//! // token from the compositor implementation
|
||||||
//! compositor_token,
|
//! compositor_token,
|
||||||
//! // your implementation, can also be a strucy implementing the
|
//! // your implementation
|
||||||
//! // appropriate Implementation<(), ShellRequest<_, _, _>> trait
|
//! |event: ShellRequest<_, _, MyShellSurfaceData>| { /* ... */ },
|
||||||
//! |event: ShellRequest<_, _, MyShellSurfaceData>, ()| { /* ... */ },
|
|
||||||
//! None // put a logger if you want
|
//! None // put a logger if you want
|
||||||
//! );
|
//! );
|
||||||
//!
|
//!
|
||||||
|
@ -73,16 +70,15 @@
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use wayland::compositor::CompositorToken;
|
|
||||||
use wayland::compositor::roles::Role;
|
use wayland::compositor::roles::Role;
|
||||||
|
use wayland::compositor::CompositorToken;
|
||||||
|
|
||||||
use wayland_server::{Display, Global, LoopToken, Resource};
|
|
||||||
use wayland_server::commons::Implementation;
|
|
||||||
use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface};
|
use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface};
|
||||||
|
use wayland_server::{Display, Global, Resource};
|
||||||
|
|
||||||
mod wl_handlers;
|
mod wl_handlers;
|
||||||
|
|
||||||
|
@ -154,8 +150,7 @@ where
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if let Ok(true) = ret {
|
if let Ok(true) = ret {
|
||||||
self.shell_surface
|
self.shell_surface.send(wl_shell_surface::Event::Ping { serial });
|
||||||
.send(wl_shell_surface::Event::Ping { serial });
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
|
@ -318,7 +313,6 @@ where
|
||||||
/// Create a new `wl_shell` global
|
/// Create a new `wl_shell` global
|
||||||
pub fn wl_shell_init<U, R, D, L, Impl>(
|
pub fn wl_shell_init<U, R, D, L, Impl>(
|
||||||
display: &mut Display,
|
display: &mut Display,
|
||||||
ltoken: LoopToken,
|
|
||||||
ctoken: CompositorToken<U, R>,
|
ctoken: CompositorToken<U, R>,
|
||||||
implementation: Impl,
|
implementation: Impl,
|
||||||
logger: L,
|
logger: L,
|
||||||
|
@ -328,23 +322,23 @@ where
|
||||||
D: Default + 'static,
|
D: Default + 'static,
|
||||||
R: Role<ShellSurfaceRole<D>> + 'static,
|
R: Role<ShellSurfaceRole<D>> + 'static,
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
Impl: Implementation<(), ShellRequest<U, R, D>>,
|
Impl: FnMut(ShellRequest<U, R, D>) + 'static,
|
||||||
{
|
{
|
||||||
let _log = ::slog_or_stdlog(logger);
|
let _log = ::slog_or_stdlog(logger);
|
||||||
|
|
||||||
let implementation = Rc::new(RefCell::new(implementation));
|
let implementation = Rc::new(RefCell::new(implementation));
|
||||||
|
|
||||||
let ltoken2 = ltoken.clone();
|
let dtoken = display.get_token();
|
||||||
|
|
||||||
let state = Arc::new(Mutex::new(ShellState {
|
let state = Arc::new(Mutex::new(ShellState {
|
||||||
known_surfaces: Vec::new(),
|
known_surfaces: Vec::new(),
|
||||||
}));
|
}));
|
||||||
let state2 = state.clone();
|
let state2 = state.clone();
|
||||||
|
|
||||||
let global = display.create_global(<oken2, 1, move |_version, shell| {
|
let global = display.create_global(1, move |shell, _version| {
|
||||||
self::wl_handlers::implement_shell(
|
self::wl_handlers::implement_shell(
|
||||||
shell,
|
shell,
|
||||||
ltoken.clone(),
|
dtoken.clone(),
|
||||||
ctoken,
|
ctoken,
|
||||||
implementation.clone(),
|
implementation.clone(),
|
||||||
state2.clone(),
|
state2.clone(),
|
||||||
|
|
|
@ -2,18 +2,17 @@ use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use wayland_server::{LoopToken, NewResource, Resource};
|
|
||||||
use wayland_server::commons::Implementation;
|
|
||||||
use wayland_server::protocol::{wl_shell, wl_shell_surface, wl_surface};
|
use wayland_server::protocol::{wl_shell, wl_shell_surface, wl_surface};
|
||||||
|
use wayland_server::{DisplayToken, NewResource, Resource};
|
||||||
|
|
||||||
use wayland::compositor::CompositorToken;
|
|
||||||
use wayland::compositor::roles::Role;
|
use wayland::compositor::roles::Role;
|
||||||
|
use wayland::compositor::CompositorToken;
|
||||||
|
|
||||||
use super::{ShellRequest, ShellState, ShellSurface, ShellSurfaceKind, ShellSurfaceRole};
|
use super::{ShellRequest, ShellState, ShellSurface, ShellSurfaceKind, ShellSurfaceRole};
|
||||||
|
|
||||||
pub(crate) fn implement_shell<U, R, D, Impl>(
|
pub(crate) fn implement_shell<U, R, D, Impl>(
|
||||||
shell: NewResource<wl_shell::WlShell>,
|
shell: NewResource<wl_shell::WlShell>,
|
||||||
ltoken: LoopToken,
|
dtoken: DisplayToken,
|
||||||
ctoken: CompositorToken<U, R>,
|
ctoken: CompositorToken<U, R>,
|
||||||
implementation: Rc<RefCell<Impl>>,
|
implementation: Rc<RefCell<Impl>>,
|
||||||
state: Arc<Mutex<ShellState<U, R, D>>>,
|
state: Arc<Mutex<ShellState<U, R, D>>>,
|
||||||
|
@ -21,9 +20,9 @@ pub(crate) fn implement_shell<U, R, D, Impl>(
|
||||||
U: 'static,
|
U: 'static,
|
||||||
D: Default + 'static,
|
D: Default + 'static,
|
||||||
R: Role<ShellSurfaceRole<D>> + 'static,
|
R: Role<ShellSurfaceRole<D>> + 'static,
|
||||||
Impl: Implementation<(), ShellRequest<U, R, D>> + 'static,
|
Impl: FnMut(ShellRequest<U, R, D>) + 'static,
|
||||||
{
|
{
|
||||||
let ltoken2 = ltoken.clone();
|
let dtoken2 = dtoken.clone();
|
||||||
shell.implement_nonsend(
|
shell.implement_nonsend(
|
||||||
move |req, shell: Resource<_>| {
|
move |req, shell: Resource<_>| {
|
||||||
let wl_shell::Request::GetShellSurface { id, surface } = req;
|
let wl_shell::Request::GetShellSurface { id, surface } = req;
|
||||||
|
@ -34,17 +33,14 @@ pub(crate) fn implement_shell<U, R, D, Impl>(
|
||||||
user_data: Default::default(),
|
user_data: Default::default(),
|
||||||
};
|
};
|
||||||
if ctoken.give_role_with(&surface, role_data).is_err() {
|
if ctoken.give_role_with(&surface, role_data).is_err() {
|
||||||
shell.post_error(
|
shell.post_error(wl_shell::Error::Role as u32, "Surface already has a role.".into());
|
||||||
wl_shell::Error::Role as u32,
|
|
||||||
"Surface already has a role.".into(),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let shell_surface = implement_shell_surface(
|
let shell_surface = implement_shell_surface(
|
||||||
id,
|
id,
|
||||||
surface,
|
surface,
|
||||||
implementation.clone(),
|
implementation.clone(),
|
||||||
ltoken.clone(),
|
dtoken.clone(),
|
||||||
ctoken,
|
ctoken,
|
||||||
state.clone(),
|
state.clone(),
|
||||||
);
|
);
|
||||||
|
@ -53,23 +49,29 @@ pub(crate) fn implement_shell<U, R, D, Impl>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.known_surfaces
|
.known_surfaces
|
||||||
.push(make_handle(&shell_surface, ctoken));
|
.push(make_handle(&shell_surface, ctoken));
|
||||||
implementation.borrow_mut().receive(
|
let mut imp = implementation.borrow_mut();
|
||||||
ShellRequest::NewShellSurface {
|
(&mut *imp)(ShellRequest::NewShellSurface {
|
||||||
surface: make_handle(&shell_surface, ctoken),
|
surface: make_handle(&shell_surface, ctoken),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
None::<fn(_)>,
|
||||||
(),
|
(),
|
||||||
);
|
&dtoken2,
|
||||||
},
|
|
||||||
None::<fn(_, _)>,
|
|
||||||
<oken2,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_handle<U, R, D>(
|
fn make_handle<U, R, SD>(
|
||||||
shell_surface: &Resource<wl_shell_surface::WlShellSurface>,
|
shell_surface: &Resource<wl_shell_surface::WlShellSurface>,
|
||||||
token: CompositorToken<U, R>,
|
token: CompositorToken<U, R>,
|
||||||
) -> ShellSurface<U, R, D> {
|
) -> ShellSurface<U, R, SD>
|
||||||
let data = unsafe { &*(shell_surface.get_user_data() as *mut ShellSurfaceUserData<U, R, D>) };
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<ShellSurfaceRole<SD>> + 'static,
|
||||||
|
SD: 'static,
|
||||||
|
{
|
||||||
|
let data = shell_surface
|
||||||
|
.user_data::<ShellSurfaceUserData<U, R, SD>>()
|
||||||
|
.unwrap();
|
||||||
ShellSurface {
|
ShellSurface {
|
||||||
wl_surface: data.surface.clone(),
|
wl_surface: data.surface.clone(),
|
||||||
shell_surface: shell_surface.clone(),
|
shell_surface: shell_surface.clone(),
|
||||||
|
@ -78,29 +80,31 @@ fn make_handle<U, R, D>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ShellSurfaceUserData<U, R, D> {
|
pub(crate) struct ShellSurfaceUserData<U, R, SD> {
|
||||||
surface: Resource<wl_surface::WlSurface>,
|
surface: Resource<wl_surface::WlSurface>,
|
||||||
state: Arc<Mutex<ShellState<U, R, D>>>,
|
state: Arc<Mutex<ShellState<U, R, SD>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implement_shell_surface<U, R, Impl, D>(
|
fn implement_shell_surface<U, R, Impl, SD>(
|
||||||
shell_surface: NewResource<wl_shell_surface::WlShellSurface>,
|
shell_surface: NewResource<wl_shell_surface::WlShellSurface>,
|
||||||
surface: Resource<wl_surface::WlSurface>,
|
surface: Resource<wl_surface::WlSurface>,
|
||||||
implementation: Rc<RefCell<Impl>>,
|
implementation: Rc<RefCell<Impl>>,
|
||||||
ltoken: LoopToken,
|
dtoken: DisplayToken,
|
||||||
ctoken: CompositorToken<U, R>,
|
ctoken: CompositorToken<U, R>,
|
||||||
state: Arc<Mutex<ShellState<U, R, D>>>,
|
state: Arc<Mutex<ShellState<U, R, SD>>>,
|
||||||
) -> Resource<wl_shell_surface::WlShellSurface>
|
) -> Resource<wl_shell_surface::WlShellSurface>
|
||||||
where
|
where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
D: 'static,
|
SD: 'static,
|
||||||
R: Role<ShellSurfaceRole<D>> + 'static,
|
R: Role<ShellSurfaceRole<SD>> + 'static,
|
||||||
Impl: Implementation<(), ShellRequest<U, R, D>> + 'static,
|
Impl: FnMut(ShellRequest<U, R, SD>) + 'static,
|
||||||
{
|
{
|
||||||
use self::wl_shell_surface::Request;
|
use self::wl_shell_surface::Request;
|
||||||
let shell_surface = shell_surface.implement_nonsend(
|
shell_surface.implement_nonsend(
|
||||||
move |req, shell_surface: Resource<_>| {
|
move |req, shell_surface: Resource<_>| {
|
||||||
let data = unsafe { &mut *(shell_surface.get_user_data() as *mut ShellSurfaceUserData<U, R, D>) };
|
let data = shell_surface
|
||||||
|
.user_data::<ShellSurfaceUserData<U, R, SD>>()
|
||||||
|
.unwrap();
|
||||||
let mut user_impl = implementation.borrow_mut();
|
let mut user_impl = implementation.borrow_mut();
|
||||||
match req {
|
match req {
|
||||||
Request::Pong { serial } => {
|
Request::Pong { serial } => {
|
||||||
|
@ -112,76 +116,48 @@ where
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
})
|
}).expect("wl_shell_surface exists but surface has not the right role?");
|
||||||
.expect("wl_shell_surface exists but surface has not the right role?");
|
|
||||||
if valid {
|
if valid {
|
||||||
user_impl.receive(
|
(&mut *user_impl)(ShellRequest::Pong {
|
||||||
ShellRequest::Pong {
|
|
||||||
surface: make_handle(&shell_surface, ctoken),
|
surface: make_handle(&shell_surface, ctoken),
|
||||||
},
|
});
|
||||||
(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Request::Move { seat, serial } => user_impl.receive(
|
Request::Move { seat, serial } => (&mut *user_impl)(ShellRequest::Move {
|
||||||
ShellRequest::Move {
|
|
||||||
surface: make_handle(&shell_surface, ctoken),
|
surface: make_handle(&shell_surface, ctoken),
|
||||||
serial,
|
serial,
|
||||||
seat,
|
seat,
|
||||||
},
|
}),
|
||||||
(),
|
Request::Resize { seat, serial, edges } => (&mut *user_impl)(ShellRequest::Resize {
|
||||||
),
|
|
||||||
Request::Resize {
|
|
||||||
seat,
|
|
||||||
serial,
|
|
||||||
edges,
|
|
||||||
} => user_impl.receive(
|
|
||||||
ShellRequest::Resize {
|
|
||||||
surface: make_handle(&shell_surface, ctoken),
|
surface: make_handle(&shell_surface, ctoken),
|
||||||
serial,
|
serial,
|
||||||
seat,
|
seat,
|
||||||
edges,
|
edges,
|
||||||
},
|
}),
|
||||||
(),
|
Request::SetToplevel => (&mut *user_impl)(ShellRequest::SetKind {
|
||||||
),
|
|
||||||
Request::SetToplevel => user_impl.receive(
|
|
||||||
ShellRequest::SetKind {
|
|
||||||
surface: make_handle(&shell_surface, ctoken),
|
surface: make_handle(&shell_surface, ctoken),
|
||||||
kind: ShellSurfaceKind::Toplevel,
|
kind: ShellSurfaceKind::Toplevel,
|
||||||
},
|
}),
|
||||||
(),
|
Request::SetTransient { parent, x, y, flags } => (&mut *user_impl)(ShellRequest::SetKind {
|
||||||
),
|
|
||||||
Request::SetTransient {
|
|
||||||
parent,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
flags,
|
|
||||||
} => user_impl.receive(
|
|
||||||
ShellRequest::SetKind {
|
|
||||||
surface: make_handle(&shell_surface, ctoken),
|
surface: make_handle(&shell_surface, ctoken),
|
||||||
kind: ShellSurfaceKind::Transient {
|
kind: ShellSurfaceKind::Transient {
|
||||||
parent,
|
parent,
|
||||||
location: (x, y),
|
location: (x, y),
|
||||||
inactive: flags.contains(wl_shell_surface::Transient::Inactive),
|
inactive: flags.contains(wl_shell_surface::Transient::Inactive),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
(),
|
|
||||||
),
|
|
||||||
Request::SetFullscreen {
|
Request::SetFullscreen {
|
||||||
method,
|
method,
|
||||||
framerate,
|
framerate,
|
||||||
output,
|
output,
|
||||||
} => user_impl.receive(
|
} => (&mut *user_impl)(ShellRequest::SetKind {
|
||||||
ShellRequest::SetKind {
|
|
||||||
surface: make_handle(&shell_surface, ctoken),
|
surface: make_handle(&shell_surface, ctoken),
|
||||||
kind: ShellSurfaceKind::Fullscreen {
|
kind: ShellSurfaceKind::Fullscreen {
|
||||||
method,
|
method,
|
||||||
framerate,
|
framerate,
|
||||||
output,
|
output,
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
(),
|
|
||||||
),
|
|
||||||
Request::SetPopup {
|
Request::SetPopup {
|
||||||
seat,
|
seat,
|
||||||
serial,
|
serial,
|
||||||
|
@ -189,8 +165,7 @@ where
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
flags,
|
flags,
|
||||||
} => user_impl.receive(
|
} => (&mut *user_impl)(ShellRequest::SetKind {
|
||||||
ShellRequest::SetKind {
|
|
||||||
surface: make_handle(&shell_surface, ctoken),
|
surface: make_handle(&shell_surface, ctoken),
|
||||||
kind: ShellSurfaceKind::Popup {
|
kind: ShellSurfaceKind::Popup {
|
||||||
parent,
|
parent,
|
||||||
|
@ -199,16 +174,11 @@ where
|
||||||
location: (x, y),
|
location: (x, y),
|
||||||
inactive: flags.contains(wl_shell_surface::Transient::Inactive),
|
inactive: flags.contains(wl_shell_surface::Transient::Inactive),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
(),
|
Request::SetMaximized { output } => (&mut *user_impl)(ShellRequest::SetKind {
|
||||||
),
|
|
||||||
Request::SetMaximized { output } => user_impl.receive(
|
|
||||||
ShellRequest::SetKind {
|
|
||||||
surface: make_handle(&shell_surface, ctoken),
|
surface: make_handle(&shell_surface, ctoken),
|
||||||
kind: ShellSurfaceKind::Maximized { output },
|
kind: ShellSurfaceKind::Maximized { output },
|
||||||
},
|
}),
|
||||||
(),
|
|
||||||
),
|
|
||||||
Request::SetTitle { title } => {
|
Request::SetTitle { title } => {
|
||||||
ctoken
|
ctoken
|
||||||
.with_role_data(&data.surface, |data| data.title = title)
|
.with_role_data(&data.surface, |data| data.title = title)
|
||||||
|
@ -221,13 +191,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(|shell_surface: Resource<_>, _| {
|
Some(|shell_surface: Resource<_>| {
|
||||||
let data =
|
let data = shell_surface
|
||||||
unsafe { Box::from_raw(shell_surface.get_user_data() as *mut ShellSurfaceUserData<U, R, D>) };
|
.user_data::<ShellSurfaceUserData<U, R, SD>>()
|
||||||
|
.unwrap();
|
||||||
data.state.lock().unwrap().cleanup_surfaces();
|
data.state.lock().unwrap().cleanup_surfaces();
|
||||||
}),
|
}),
|
||||||
<oken,
|
ShellSurfaceUserData { surface, state },
|
||||||
);
|
&dtoken,
|
||||||
shell_surface.set_user_data(Box::into_raw(Box::new(ShellSurfaceUserData { surface, state })) as *mut ());
|
)
|
||||||
shell_surface
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
//! use smithay::wayland::compositor::CompositorToken;
|
//! use smithay::wayland::compositor::CompositorToken;
|
||||||
//! use smithay::wayland::shell::xdg::{xdg_shell_init, XdgSurfaceRole, XdgRequest};
|
//! use smithay::wayland::shell::xdg::{xdg_shell_init, XdgSurfaceRole, XdgRequest};
|
||||||
//! use wayland_protocols::unstable::xdg_shell::v6::server::zxdg_shell_v6::ZxdgShellV6;
|
//! use wayland_protocols::unstable::xdg_shell::v6::server::zxdg_shell_v6::ZxdgShellV6;
|
||||||
//! use wayland_server::{EventLoop, LoopToken};
|
|
||||||
//! # use wayland_server::protocol::{wl_seat, wl_output};
|
//! # use wayland_server::protocol::{wl_seat, wl_output};
|
||||||
//! # #[derive(Default)] struct MySurfaceData;
|
//! # #[derive(Default)] struct MySurfaceData;
|
||||||
//!
|
//!
|
||||||
|
@ -50,21 +49,19 @@
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # let (mut display, event_loop) = wayland_server::Display::new();
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
//! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::<(), MyRoles, _, _>(
|
//! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::<(), MyRoles, _, _>(
|
||||||
//! # &mut display,
|
//! # &mut display,
|
||||||
//! # event_loop.token(),
|
//! # |_, _, _| {},
|
||||||
//! # |_, _| {},
|
|
||||||
//! # None
|
//! # None
|
||||||
//! # );
|
//! # );
|
||||||
//! let (shell_state, _, _) = xdg_shell_init(
|
//! let (shell_state, _, _) = xdg_shell_init(
|
||||||
//! &mut display,
|
//! &mut display,
|
||||||
//! event_loop.token(),
|
|
||||||
//! // token from the compositor implementation
|
//! // token from the compositor implementation
|
||||||
//! compositor_token,
|
//! compositor_token,
|
||||||
//! // your implementation, can also be a strucy implementing the
|
//! // your implementation
|
||||||
//! // appropriate Implementation<(), XdgRequest<_, _, _>> trait
|
//! |event: XdgRequest<_, _, MyShellData>| { /* ... */ },
|
||||||
//! |event: XdgRequest<_, _, MyShellData>, ()| { /* ... */ },
|
|
||||||
//! None // put a logger if you want
|
//! None // put a logger if you want
|
||||||
//! );
|
//! );
|
||||||
//!
|
//!
|
||||||
|
@ -92,14 +89,16 @@ use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use utils::Rectangle;
|
use utils::Rectangle;
|
||||||
use wayland::compositor::CompositorToken;
|
|
||||||
use wayland::compositor::roles::Role;
|
use wayland::compositor::roles::Role;
|
||||||
use wayland_protocols::xdg_shell::server::{xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base};
|
use wayland::compositor::CompositorToken;
|
||||||
use wayland_protocols::unstable::xdg_shell::v6::server::{zxdg_popup_v6, zxdg_shell_v6, zxdg_surface_v6,
|
use wayland_protocols::unstable::xdg_shell::v6::server::{
|
||||||
zxdg_toplevel_v6};
|
zxdg_popup_v6, zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6,
|
||||||
use wayland_server::{Display, Global, LoopToken, Resource};
|
};
|
||||||
use wayland_server::commons::Implementation;
|
use wayland_protocols::xdg_shell::server::{
|
||||||
|
xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base,
|
||||||
|
};
|
||||||
use wayland_server::protocol::{wl_output, wl_seat, wl_surface};
|
use wayland_server::protocol::{wl_output, wl_seat, wl_surface};
|
||||||
|
use wayland_server::{Display, DisplayToken, Global, Resource};
|
||||||
|
|
||||||
// handlers for the xdg_shell protocol
|
// handlers for the xdg_shell protocol
|
||||||
mod xdg_handlers;
|
mod xdg_handlers;
|
||||||
|
@ -254,20 +253,20 @@ impl Default for XdgSurfacePendingState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ShellImplementation<U, R, SD> {
|
pub(crate) struct ShellData<U, R, SD> {
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
compositor_token: CompositorToken<U, R>,
|
compositor_token: CompositorToken<U, R>,
|
||||||
loop_token: LoopToken,
|
display_token: DisplayToken,
|
||||||
user_impl: Rc<RefCell<Implementation<(), XdgRequest<U, R, SD>>>>,
|
user_impl: Rc<RefCell<FnMut(XdgRequest<U, R, SD>)>>,
|
||||||
shell_state: Arc<Mutex<ShellState<U, R, SD>>>,
|
shell_state: Arc<Mutex<ShellState<U, R, SD>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, SD> Clone for ShellImplementation<U, R, SD> {
|
impl<U, R, SD> Clone for ShellData<U, R, SD> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
ShellImplementation {
|
ShellData {
|
||||||
log: self.log.clone(),
|
log: self.log.clone(),
|
||||||
compositor_token: self.compositor_token,
|
compositor_token: self.compositor_token,
|
||||||
loop_token: self.loop_token.clone(),
|
display_token: self.display_token.clone(),
|
||||||
user_impl: self.user_impl.clone(),
|
user_impl: self.user_impl.clone(),
|
||||||
shell_state: self.shell_state.clone(),
|
shell_state: self.shell_state.clone(),
|
||||||
}
|
}
|
||||||
|
@ -277,7 +276,6 @@ impl<U, R, SD> Clone for ShellImplementation<U, R, SD> {
|
||||||
/// Create a new `xdg_shell` globals
|
/// Create a new `xdg_shell` globals
|
||||||
pub fn xdg_shell_init<U, R, SD, L, Impl>(
|
pub fn xdg_shell_init<U, R, SD, L, Impl>(
|
||||||
display: &mut Display,
|
display: &mut Display,
|
||||||
ltoken: LoopToken,
|
|
||||||
ctoken: CompositorToken<U, R>,
|
ctoken: CompositorToken<U, R>,
|
||||||
implementation: Impl,
|
implementation: Impl,
|
||||||
logger: L,
|
logger: L,
|
||||||
|
@ -291,7 +289,7 @@ where
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
SD: Default + 'static,
|
SD: Default + 'static,
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
Impl: Implementation<(), XdgRequest<U, R, SD>>,
|
Impl: FnMut(XdgRequest<U, R, SD>) + 'static,
|
||||||
{
|
{
|
||||||
let log = ::slog_or_stdlog(logger);
|
let log = ::slog_or_stdlog(logger);
|
||||||
let shell_state = Arc::new(Mutex::new(ShellState {
|
let shell_state = Arc::new(Mutex::new(ShellState {
|
||||||
|
@ -299,22 +297,22 @@ where
|
||||||
known_popups: Vec::new(),
|
known_popups: Vec::new(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let shell_impl = ShellImplementation {
|
let shell_data = ShellData {
|
||||||
log: log.new(o!("smithay_module" => "xdg_shell_handler")),
|
log: log.new(o!("smithay_module" => "xdg_shell_handler")),
|
||||||
loop_token: ltoken.clone(),
|
display_token: display.get_token(),
|
||||||
compositor_token: ctoken,
|
compositor_token: ctoken,
|
||||||
user_impl: Rc::new(RefCell::new(implementation)),
|
user_impl: Rc::new(RefCell::new(implementation)),
|
||||||
shell_state: shell_state.clone(),
|
shell_state: shell_state.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let shell_impl_z = shell_impl.clone();
|
let shell_data_z = shell_data.clone();
|
||||||
|
|
||||||
let xdg_shell_global = display.create_global(<oken, 1, move |_version, shell| {
|
let xdg_shell_global = display.create_global(1, move |shell, _version| {
|
||||||
self::xdg_handlers::implement_wm_base(shell, &shell_impl);
|
self::xdg_handlers::implement_wm_base(shell, &shell_data);
|
||||||
});
|
});
|
||||||
|
|
||||||
let zxdgv6_shell_global = display.create_global(<oken, 1, move |_version, shell| {
|
let zxdgv6_shell_global = display.create_global(1, move |shell, _version| {
|
||||||
self::zxdgv6_handlers::implement_shell(shell, &shell_impl_z);
|
self::zxdgv6_handlers::implement_shell(shell, &shell_data_z);
|
||||||
});
|
});
|
||||||
|
|
||||||
(shell_state, xdg_shell_global, zxdgv6_shell_global)
|
(shell_state, xdg_shell_global, zxdgv6_shell_global)
|
||||||
|
@ -377,12 +375,18 @@ fn make_shell_client_data<SD: Default>() -> ShellClientData<SD> {
|
||||||
///
|
///
|
||||||
/// You can use this handle to access a storage for any
|
/// You can use this handle to access a storage for any
|
||||||
/// client-specific data you wish to associate with it.
|
/// client-specific data you wish to associate with it.
|
||||||
pub struct ShellClient<SD> {
|
pub struct ShellClient<U, R, SD> {
|
||||||
kind: ShellClientKind,
|
kind: ShellClientKind,
|
||||||
|
_token: CompositorToken<U, R>,
|
||||||
_data: ::std::marker::PhantomData<*mut SD>,
|
_data: ::std::marker::PhantomData<*mut SD>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SD> ShellClient<SD> {
|
impl<U, R, SD> ShellClient<U, R, SD>
|
||||||
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
|
SD: 'static,
|
||||||
|
{
|
||||||
/// Is the shell client represented by this handle still connected?
|
/// Is the shell client represented by this handle still connected?
|
||||||
pub fn alive(&self) -> bool {
|
pub fn alive(&self) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
|
@ -416,9 +420,10 @@ impl<SD> ShellClient<SD> {
|
||||||
}
|
}
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ShellClientKind::Xdg(ref shell) => {
|
ShellClientKind::Xdg(ref shell) => {
|
||||||
let mutex =
|
let user_data = shell
|
||||||
unsafe { &*(shell.get_user_data() as *mut self::xdg_handlers::ShellUserData<SD>) };
|
.user_data::<self::xdg_handlers::ShellUserData<U, R, SD>>()
|
||||||
let mut guard = mutex.lock().unwrap();
|
.unwrap();
|
||||||
|
let mut guard = user_data.client_data.lock().unwrap();
|
||||||
if guard.pending_ping == 0 {
|
if guard.pending_ping == 0 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -426,9 +431,10 @@ impl<SD> ShellClient<SD> {
|
||||||
shell.send(xdg_wm_base::Event::Ping { serial });
|
shell.send(xdg_wm_base::Event::Ping { serial });
|
||||||
}
|
}
|
||||||
ShellClientKind::ZxdgV6(ref shell) => {
|
ShellClientKind::ZxdgV6(ref shell) => {
|
||||||
let mutex =
|
let user_data = shell
|
||||||
unsafe { &*(shell.get_user_data() as *mut self::zxdgv6_handlers::ShellUserData<SD>) };
|
.user_data::<self::zxdgv6_handlers::ShellUserData<U, R, SD>>()
|
||||||
let mut guard = mutex.lock().unwrap();
|
.unwrap();
|
||||||
|
let mut guard = user_data.client_data.lock().unwrap();
|
||||||
if guard.pending_ping == 0 {
|
if guard.pending_ping == 0 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -449,15 +455,17 @@ impl<SD> ShellClient<SD> {
|
||||||
}
|
}
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ShellClientKind::Xdg(ref shell) => {
|
ShellClientKind::Xdg(ref shell) => {
|
||||||
let mutex =
|
let data = shell
|
||||||
unsafe { &*(shell.get_user_data() as *mut self::xdg_handlers::ShellUserData<SD>) };
|
.user_data::<self::xdg_handlers::ShellUserData<U, R, SD>>()
|
||||||
let mut guard = mutex.lock().unwrap();
|
.unwrap();
|
||||||
|
let mut guard = data.client_data.lock().unwrap();
|
||||||
Ok(f(&mut guard.data))
|
Ok(f(&mut guard.data))
|
||||||
}
|
}
|
||||||
ShellClientKind::ZxdgV6(ref shell) => {
|
ShellClientKind::ZxdgV6(ref shell) => {
|
||||||
let mutex =
|
let data = shell
|
||||||
unsafe { &*(shell.get_user_data() as *mut self::zxdgv6_handlers::ShellUserData<SD>) };
|
.user_data::<self::zxdgv6_handlers::ShellUserData<U, R, SD>>()
|
||||||
let mut guard = mutex.lock().unwrap();
|
.unwrap();
|
||||||
|
let mut guard = data.client_data.lock().unwrap();
|
||||||
Ok(f(&mut guard.data))
|
Ok(f(&mut guard.data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -500,26 +508,29 @@ where
|
||||||
/// Retrieve the shell client owning this toplevel surface
|
/// Retrieve the shell client owning this toplevel surface
|
||||||
///
|
///
|
||||||
/// Returns `None` if the surface does actually no longer exist.
|
/// Returns `None` if the surface does actually no longer exist.
|
||||||
pub fn client(&self) -> Option<ShellClient<SD>> {
|
pub fn client(&self) -> Option<ShellClient<U, R, SD>> {
|
||||||
if !self.alive() {
|
if !self.alive() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let shell = match self.shell_surface {
|
let shell = match self.shell_surface {
|
||||||
ToplevelKind::Xdg(ref s) => {
|
ToplevelKind::Xdg(ref s) => {
|
||||||
let &(_, ref shell, _) =
|
let data = s
|
||||||
unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) };
|
.user_data::<self::xdg_handlers::ShellSurfaceUserData<U, R, SD>>()
|
||||||
ShellClientKind::Xdg(shell.clone())
|
.unwrap();
|
||||||
|
ShellClientKind::Xdg(data.wm_base.clone())
|
||||||
}
|
}
|
||||||
ToplevelKind::ZxdgV6(ref s) => {
|
ToplevelKind::ZxdgV6(ref s) => {
|
||||||
let &(_, ref shell, _) =
|
let data = s
|
||||||
unsafe { &*(s.get_user_data() as *mut self::zxdgv6_handlers::ShellSurfaceUserData) };
|
.user_data::<self::zxdgv6_handlers::ShellSurfaceUserData<U, R, SD>>()
|
||||||
ShellClientKind::ZxdgV6(shell.clone())
|
.unwrap();
|
||||||
|
ShellClientKind::ZxdgV6(data.shell.clone())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(ShellClient {
|
Some(ShellClient {
|
||||||
kind: shell,
|
kind: shell,
|
||||||
|
_token: self.token,
|
||||||
_data: ::std::marker::PhantomData,
|
_data: ::std::marker::PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -532,8 +543,8 @@ where
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match self.shell_surface {
|
match self.shell_surface {
|
||||||
ToplevelKind::Xdg(ref s) => self::xdg_handlers::send_toplevel_configure(self.token, s, cfg),
|
ToplevelKind::Xdg(ref s) => self::xdg_handlers::send_toplevel_configure::<U, R, SD>(s, cfg),
|
||||||
ToplevelKind::ZxdgV6(ref s) => self::zxdgv6_handlers::send_toplevel_configure(self.token, s, cfg),
|
ToplevelKind::ZxdgV6(ref s) => self::zxdgv6_handlers::send_toplevel_configure::<U, R, SD>(s, cfg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,25 +560,26 @@ where
|
||||||
if !self.alive() {
|
if !self.alive() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let configured = self.token
|
let configured = self
|
||||||
|
.token
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(&self.wl_surface, |data| data.configured)
|
.with_role_data::<XdgSurfaceRole, _, _>(&self.wl_surface, |data| data.configured)
|
||||||
.expect("A shell surface object exists but the surface does not have the shell_surface role ?!");
|
.expect("A shell surface object exists but the surface does not have the shell_surface role ?!");
|
||||||
if !configured {
|
if !configured {
|
||||||
match self.shell_surface {
|
match self.shell_surface {
|
||||||
ToplevelKind::Xdg(ref s) => {
|
ToplevelKind::Xdg(ref s) => {
|
||||||
let ptr = s.get_user_data();
|
let data = s
|
||||||
let &(_, _, ref xdg_surface) =
|
.user_data::<self::xdg_handlers::ShellSurfaceUserData<U, R, SD>>()
|
||||||
unsafe { &*(ptr as *mut self::xdg_handlers::ShellSurfaceUserData) };
|
.unwrap();
|
||||||
xdg_surface.post_error(
|
data.xdg_surface.post_error(
|
||||||
xdg_surface::Error::NotConstructed as u32,
|
xdg_surface::Error::NotConstructed as u32,
|
||||||
"Surface has not been configured yet.".into(),
|
"Surface has not been configured yet.".into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ToplevelKind::ZxdgV6(ref s) => {
|
ToplevelKind::ZxdgV6(ref s) => {
|
||||||
let ptr = s.get_user_data();
|
let data = s
|
||||||
let &(_, _, ref xdg_surface) =
|
.user_data::<self::zxdgv6_handlers::ShellSurfaceUserData<U, R, SD>>()
|
||||||
unsafe { &*(ptr as *mut self::zxdgv6_handlers::ShellSurfaceUserData) };
|
.unwrap();
|
||||||
xdg_surface.post_error(
|
data.xdg_surface.post_error(
|
||||||
zxdg_surface_v6::Error::NotConstructed as u32,
|
zxdg_surface_v6::Error::NotConstructed as u32,
|
||||||
"Surface has not been configured yet.".into(),
|
"Surface has not been configured yet.".into(),
|
||||||
);
|
);
|
||||||
|
@ -607,8 +619,7 @@ where
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(&self.wl_surface, |data| match data.pending_state {
|
.with_role_data::<XdgSurfaceRole, _, _>(&self.wl_surface, |data| match data.pending_state {
|
||||||
XdgSurfacePendingState::Toplevel(ref state) => Some(state.clone()),
|
XdgSurfacePendingState::Toplevel(ref state) => Some(state.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
}).ok()
|
||||||
.ok()
|
|
||||||
.and_then(|x| x)
|
.and_then(|x| x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,26 +663,29 @@ where
|
||||||
/// Retrieve the shell client owning this popup surface
|
/// Retrieve the shell client owning this popup surface
|
||||||
///
|
///
|
||||||
/// Returns `None` if the surface does actually no longer exist.
|
/// Returns `None` if the surface does actually no longer exist.
|
||||||
pub fn client(&self) -> Option<ShellClient<SD>> {
|
pub fn client(&self) -> Option<ShellClient<U, R, SD>> {
|
||||||
if !self.alive() {
|
if !self.alive() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let shell = match self.shell_surface {
|
let shell = match self.shell_surface {
|
||||||
PopupKind::Xdg(ref p) => {
|
PopupKind::Xdg(ref p) => {
|
||||||
let &(_, ref shell, _) =
|
let data = p
|
||||||
unsafe { &*(p.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) };
|
.user_data::<self::xdg_handlers::ShellSurfaceUserData<U, R, SD>>()
|
||||||
ShellClientKind::Xdg(shell.clone())
|
.unwrap();
|
||||||
|
ShellClientKind::Xdg(data.wm_base.clone())
|
||||||
}
|
}
|
||||||
PopupKind::ZxdgV6(ref p) => {
|
PopupKind::ZxdgV6(ref p) => {
|
||||||
let &(_, ref shell, _) =
|
let data = p
|
||||||
unsafe { &*(p.get_user_data() as *mut self::zxdgv6_handlers::ShellSurfaceUserData) };
|
.user_data::<self::zxdgv6_handlers::ShellSurfaceUserData<U, R, SD>>()
|
||||||
ShellClientKind::ZxdgV6(shell.clone())
|
.unwrap();
|
||||||
|
ShellClientKind::ZxdgV6(data.shell.clone())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(ShellClient {
|
Some(ShellClient {
|
||||||
kind: shell,
|
kind: shell,
|
||||||
|
_token: self.token,
|
||||||
_data: ::std::marker::PhantomData,
|
_data: ::std::marker::PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -685,10 +699,10 @@ where
|
||||||
}
|
}
|
||||||
match self.shell_surface {
|
match self.shell_surface {
|
||||||
PopupKind::Xdg(ref p) => {
|
PopupKind::Xdg(ref p) => {
|
||||||
self::xdg_handlers::send_popup_configure(self.token, p, cfg);
|
self::xdg_handlers::send_popup_configure::<U, R, SD>(p, cfg);
|
||||||
}
|
}
|
||||||
PopupKind::ZxdgV6(ref p) => {
|
PopupKind::ZxdgV6(ref p) => {
|
||||||
self::zxdgv6_handlers::send_popup_configure(self.token, p, cfg);
|
self::zxdgv6_handlers::send_popup_configure::<U, R, SD>(p, cfg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -705,25 +719,26 @@ where
|
||||||
if !self.alive() {
|
if !self.alive() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let configured = self.token
|
let configured = self
|
||||||
|
.token
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(&self.wl_surface, |data| data.configured)
|
.with_role_data::<XdgSurfaceRole, _, _>(&self.wl_surface, |data| data.configured)
|
||||||
.expect("A shell surface object exists but the surface does not have the shell_surface role ?!");
|
.expect("A shell surface object exists but the surface does not have the shell_surface role ?!");
|
||||||
if !configured {
|
if !configured {
|
||||||
match self.shell_surface {
|
match self.shell_surface {
|
||||||
PopupKind::Xdg(ref s) => {
|
PopupKind::Xdg(ref s) => {
|
||||||
let ptr = s.get_user_data();
|
let data = s
|
||||||
let &(_, _, ref xdg_surface) =
|
.user_data::<self::xdg_handlers::ShellSurfaceUserData<U, R, SD>>()
|
||||||
unsafe { &*(ptr as *mut self::xdg_handlers::ShellSurfaceUserData) };
|
.unwrap();
|
||||||
xdg_surface.post_error(
|
data.xdg_surface.post_error(
|
||||||
xdg_surface::Error::NotConstructed as u32,
|
xdg_surface::Error::NotConstructed as u32,
|
||||||
"Surface has not been confgured yet.".into(),
|
"Surface has not been confgured yet.".into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
PopupKind::ZxdgV6(ref s) => {
|
PopupKind::ZxdgV6(ref s) => {
|
||||||
let ptr = s.get_user_data();
|
let data = s
|
||||||
let &(_, _, ref xdg_surface) =
|
.user_data::<self::zxdgv6_handlers::ShellSurfaceUserData<U, R, SD>>()
|
||||||
unsafe { &*(ptr as *mut self::zxdgv6_handlers::ShellSurfaceUserData) };
|
.unwrap();
|
||||||
xdg_surface.post_error(
|
data.xdg_surface.post_error(
|
||||||
zxdg_surface_v6::Error::NotConstructed as u32,
|
zxdg_surface_v6::Error::NotConstructed as u32,
|
||||||
"Surface has not been confgured yet.".into(),
|
"Surface has not been confgured yet.".into(),
|
||||||
);
|
);
|
||||||
|
@ -766,8 +781,7 @@ where
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(&self.wl_surface, |data| match data.pending_state {
|
.with_role_data::<XdgSurfaceRole, _, _>(&self.wl_surface, |data| match data.pending_state {
|
||||||
XdgSurfacePendingState::Popup(ref state) => Some(state.clone()),
|
XdgSurfacePendingState::Popup(ref state) => Some(state.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
}).ok()
|
||||||
.ok()
|
|
||||||
.and_then(|x| x)
|
.and_then(|x| x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -814,7 +828,7 @@ pub enum XdgRequest<U, R, SD> {
|
||||||
/// A new shell client was instanciated
|
/// A new shell client was instanciated
|
||||||
NewClient {
|
NewClient {
|
||||||
/// the client
|
/// the client
|
||||||
client: ShellClient<SD>,
|
client: ShellClient<U, R, SD>,
|
||||||
},
|
},
|
||||||
/// The pong for a pending ping of this shell client was received
|
/// The pong for a pending ping of this shell client was received
|
||||||
///
|
///
|
||||||
|
@ -822,7 +836,7 @@ pub enum XdgRequest<U, R, SD> {
|
||||||
/// from the pending ping.
|
/// from the pending ping.
|
||||||
ClientPong {
|
ClientPong {
|
||||||
/// the client
|
/// the client
|
||||||
client: ShellClient<SD>,
|
client: ShellClient<U, R, SD>,
|
||||||
},
|
},
|
||||||
/// A new toplevel surface was created
|
/// A new toplevel surface was created
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
use super::{make_shell_client_data, PopupConfigure, PopupKind, PopupState, PositionerState, ShellClient,
|
use std::cell::RefCell;
|
||||||
ShellClientData, ShellImplementation, ToplevelConfigure, ToplevelKind, ToplevelState,
|
|
||||||
XdgRequest, XdgSurfacePendingState, XdgSurfaceRole};
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use utils::Rectangle;
|
|
||||||
use wayland::compositor::CompositorToken;
|
|
||||||
use wayland::compositor::roles::*;
|
use wayland::compositor::roles::*;
|
||||||
use wayland_protocols::xdg_shell::server::{xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base};
|
use wayland::compositor::CompositorToken;
|
||||||
use wayland_server::{LoopToken, NewResource, Resource};
|
use wayland_protocols::xdg_shell::server::{
|
||||||
use wayland_server::commons::{downcast_impl, Implementation};
|
xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base,
|
||||||
|
};
|
||||||
use wayland_server::protocol::wl_surface;
|
use wayland_server::protocol::wl_surface;
|
||||||
|
use wayland_server::{DisplayToken, NewResource, Resource};
|
||||||
|
|
||||||
|
use utils::Rectangle;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
make_shell_client_data, PopupConfigure, PopupKind, PopupState, PositionerState, ShellClient,
|
||||||
|
ShellClientData, ShellData, ToplevelConfigure, ToplevelKind, ToplevelState, XdgRequest,
|
||||||
|
XdgSurfacePendingState, XdgSurfaceRole,
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) fn implement_wm_base<U, R, SD>(
|
pub(crate) fn implement_wm_base<U, R, SD>(
|
||||||
shell: NewResource<xdg_wm_base::XdgWmBase>,
|
shell: NewResource<xdg_wm_base::XdgWmBase>,
|
||||||
implem: &ShellImplementation<U, R, SD>,
|
shell_data: &ShellData<U, R, SD>,
|
||||||
) -> Resource<xdg_wm_base::XdgWmBase>
|
) -> Resource<xdg_wm_base::XdgWmBase>
|
||||||
where
|
where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
|
@ -20,18 +27,18 @@ where
|
||||||
SD: Default + 'static,
|
SD: Default + 'static,
|
||||||
{
|
{
|
||||||
let shell = shell.implement_nonsend(
|
let shell = shell.implement_nonsend(
|
||||||
implem.clone(),
|
wm_implementation::<U, R, SD>,
|
||||||
Some(|shell, _| destroy_shell::<SD>(&shell)),
|
None::<fn(_)>,
|
||||||
&implem.loop_token,
|
ShellUserData {
|
||||||
);
|
shell_data: shell_data.clone(),
|
||||||
shell.set_user_data(Box::into_raw(Box::new(Mutex::new(make_shell_client_data::<SD>()))) as *mut _);
|
client_data: Mutex::new(make_shell_client_data::<SD>()),
|
||||||
let mut user_impl = implem.user_impl.borrow_mut();
|
|
||||||
user_impl.receive(
|
|
||||||
XdgRequest::NewClient {
|
|
||||||
client: make_shell_client(&shell),
|
|
||||||
},
|
},
|
||||||
(),
|
&shell_data.display_token,
|
||||||
);
|
);
|
||||||
|
let mut user_impl = shell_data.user_impl.borrow_mut();
|
||||||
|
(&mut *user_impl)(XdgRequest::NewClient {
|
||||||
|
client: make_shell_client(&shell, shell_data.compositor_token),
|
||||||
|
});
|
||||||
shell
|
shell
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,37 +46,35 @@ where
|
||||||
* xdg_shell
|
* xdg_shell
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub(crate) type ShellUserData<SD> = Mutex<ShellClientData<SD>>;
|
pub(crate) struct ShellUserData<U, R, SD> {
|
||||||
|
shell_data: ShellData<U, R, SD>,
|
||||||
fn destroy_shell<SD>(shell: &Resource<xdg_wm_base::XdgWmBase>) {
|
pub(crate) client_data: Mutex<ShellClientData<SD>>,
|
||||||
let ptr = shell.get_user_data();
|
|
||||||
shell.set_user_data(::std::ptr::null_mut());
|
|
||||||
let data = unsafe { Box::from_raw(ptr as *mut ShellUserData<SD>) };
|
|
||||||
// explicit call to drop to not forget what we're doing here
|
|
||||||
::std::mem::drop(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn make_shell_client<SD>(resource: &Resource<xdg_wm_base::XdgWmBase>) -> ShellClient<SD> {
|
pub(crate) fn make_shell_client<U, R, SD>(
|
||||||
|
resource: &Resource<xdg_wm_base::XdgWmBase>,
|
||||||
|
token: CompositorToken<U, R>,
|
||||||
|
) -> ShellClient<U, R, SD> {
|
||||||
ShellClient {
|
ShellClient {
|
||||||
kind: super::ShellClientKind::Xdg(resource.clone()),
|
kind: super::ShellClientKind::Xdg(resource.clone()),
|
||||||
|
_token: token,
|
||||||
_data: ::std::marker::PhantomData,
|
_data: ::std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, SD> Implementation<Resource<xdg_wm_base::XdgWmBase>, xdg_wm_base::Request>
|
fn wm_implementation<U, R, SD>(request: xdg_wm_base::Request, shell: Resource<xdg_wm_base::XdgWmBase>)
|
||||||
for ShellImplementation<U, R, SD>
|
|
||||||
where
|
where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
SD: 'static,
|
SD: 'static,
|
||||||
{
|
{
|
||||||
fn receive(&mut self, request: xdg_wm_base::Request, shell: Resource<xdg_wm_base::XdgWmBase>) {
|
let data = shell.user_data::<ShellUserData<U, R, SD>>().unwrap();
|
||||||
match request {
|
match request {
|
||||||
xdg_wm_base::Request::Destroy => {
|
xdg_wm_base::Request::Destroy => {
|
||||||
// all is handled by destructor
|
// all is handled by destructor
|
||||||
}
|
}
|
||||||
xdg_wm_base::Request::CreatePositioner { id } => {
|
xdg_wm_base::Request::CreatePositioner { id } => {
|
||||||
implement_positioner(id, &self.loop_token);
|
implement_positioner(id, &data.shell_data.display_token);
|
||||||
}
|
}
|
||||||
xdg_wm_base::Request::GetXdgSurface { id, surface } => {
|
xdg_wm_base::Request::GetXdgSurface { id, surface } => {
|
||||||
let role_data = XdgSurfaceRole {
|
let role_data = XdgSurfaceRole {
|
||||||
|
@ -78,7 +83,9 @@ where
|
||||||
pending_configures: Vec::new(),
|
pending_configures: Vec::new(),
|
||||||
configured: false,
|
configured: false,
|
||||||
};
|
};
|
||||||
if self.compositor_token
|
if data
|
||||||
|
.shell_data
|
||||||
|
.compositor_token
|
||||||
.give_role_with(&surface, role_data)
|
.give_role_with(&surface, role_data)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
|
@ -88,18 +95,20 @@ where
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let xdg_surface = id.implement_nonsend(
|
id.implement_nonsend(
|
||||||
self.clone(),
|
xdg_surface_implementation::<U, R, SD>,
|
||||||
Some(destroy_surface::<U, R, SD>),
|
Some(destroy_surface::<U, R, SD>),
|
||||||
&self.loop_token,
|
XdgSurfaceUserData {
|
||||||
|
shell_data: data.shell_data.clone(),
|
||||||
|
wl_surface: surface,
|
||||||
|
wm_base: shell.clone(),
|
||||||
|
},
|
||||||
|
&data.shell_data.display_token,
|
||||||
);
|
);
|
||||||
xdg_surface
|
|
||||||
.set_user_data(Box::into_raw(Box::new((surface.clone(), shell.clone()))) as *mut _);
|
|
||||||
}
|
}
|
||||||
xdg_wm_base::Request::Pong { serial } => {
|
xdg_wm_base::Request::Pong { serial } => {
|
||||||
let valid = {
|
let valid = {
|
||||||
let mutex = unsafe { &*(shell.get_user_data() as *mut ShellUserData<SD>) };
|
let mut guard = data.client_data.lock().unwrap();
|
||||||
let mut guard = mutex.lock().unwrap();
|
|
||||||
if guard.pending_ping == serial {
|
if guard.pending_ping == serial {
|
||||||
guard.pending_ping = 0;
|
guard.pending_ping = 0;
|
||||||
true
|
true
|
||||||
|
@ -108,14 +117,10 @@ where
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if valid {
|
if valid {
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
user_impl.receive(
|
(&mut *user_impl)(XdgRequest::ClientPong {
|
||||||
XdgRequest::ClientPong {
|
client: make_shell_client(&shell, data.shell_data.compositor_token),
|
||||||
client: make_shell_client(&shell),
|
});
|
||||||
},
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,23 +130,14 @@ where
|
||||||
* xdg_positioner
|
* xdg_positioner
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn destroy_positioner(positioner: &Resource<xdg_positioner::XdgPositioner>) {
|
|
||||||
let ptr = positioner.get_user_data();
|
|
||||||
positioner.set_user_data(::std::ptr::null_mut());
|
|
||||||
// drop the PositionerState
|
|
||||||
let surface = unsafe { Box::from_raw(ptr as *mut PositionerState) };
|
|
||||||
// explicit call to drop to not forget what we're doing here
|
|
||||||
::std::mem::drop(surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn implement_positioner(
|
fn implement_positioner(
|
||||||
positioner: NewResource<xdg_positioner::XdgPositioner>,
|
positioner: NewResource<xdg_positioner::XdgPositioner>,
|
||||||
token: &LoopToken,
|
token: &DisplayToken,
|
||||||
) -> Resource<xdg_positioner::XdgPositioner> {
|
) -> Resource<xdg_positioner::XdgPositioner> {
|
||||||
let positioner = positioner.implement_nonsend(
|
positioner.implement_nonsend(
|
||||||
|request, positioner: Resource<_>| {
|
|request, positioner: Resource<_>| {
|
||||||
let ptr = positioner.get_user_data();
|
let mutex = positioner.user_data::<RefCell<PositionerState>>().unwrap();
|
||||||
let state = unsafe { &mut *(ptr as *mut PositionerState) };
|
let mut state = mutex.borrow_mut();
|
||||||
match request {
|
match request {
|
||||||
xdg_positioner::Request::Destroy => {
|
xdg_positioner::Request::Destroy => {
|
||||||
// handled by destructor
|
// handled by destructor
|
||||||
|
@ -156,24 +152,14 @@ fn implement_positioner(
|
||||||
state.rect_size = (width, height);
|
state.rect_size = (width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xdg_positioner::Request::SetAnchorRect {
|
xdg_positioner::Request::SetAnchorRect { x, y, width, height } => {
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
} => {
|
|
||||||
if width < 1 || height < 1 {
|
if width < 1 || height < 1 {
|
||||||
positioner.post_error(
|
positioner.post_error(
|
||||||
xdg_positioner::Error::InvalidInput as u32,
|
xdg_positioner::Error::InvalidInput as u32,
|
||||||
"Invalid size for positioner's anchor rectangle.".into(),
|
"Invalid size for positioner's anchor rectangle.".into(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
state.anchor_rect = Rectangle {
|
state.anchor_rect = Rectangle { x, y, width, height };
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xdg_positioner::Request::SetAnchor { anchor } => {
|
xdg_positioner::Request::SetAnchor { anchor } => {
|
||||||
|
@ -194,74 +180,66 @@ fn implement_positioner(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(|positioner, _| destroy_positioner(&positioner)),
|
None::<fn(_)>,
|
||||||
|
RefCell::new(PositionerState::new()),
|
||||||
token,
|
token,
|
||||||
);
|
)
|
||||||
let data = PositionerState::new();
|
|
||||||
positioner.set_user_data(Box::into_raw(Box::new(data)) as *mut _);
|
|
||||||
positioner
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xdg_surface
|
* xdg_surface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type XdgSurfaceUserData = (
|
struct XdgSurfaceUserData<U, R, SD> {
|
||||||
Resource<wl_surface::WlSurface>,
|
shell_data: ShellData<U, R, SD>,
|
||||||
Resource<xdg_wm_base::XdgWmBase>,
|
wl_surface: Resource<wl_surface::WlSurface>,
|
||||||
);
|
wm_base: Resource<xdg_wm_base::XdgWmBase>,
|
||||||
|
|
||||||
fn destroy_surface<U, R, SD>(
|
|
||||||
surface: Resource<xdg_surface::XdgSurface>,
|
|
||||||
implem: Box<Implementation<Resource<xdg_surface::XdgSurface>, xdg_surface::Request>>,
|
|
||||||
) where
|
|
||||||
U: 'static,
|
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
|
||||||
SD: 'static,
|
|
||||||
{
|
|
||||||
let implem: ShellImplementation<U, R, SD> = *downcast_impl(implem).unwrap_or_else(|_| unreachable!());
|
|
||||||
let ptr = surface.get_user_data();
|
|
||||||
surface.set_user_data(::std::ptr::null_mut());
|
|
||||||
// take back ownership of the userdata
|
|
||||||
let data = unsafe { Box::from_raw(ptr as *mut XdgSurfaceUserData) };
|
|
||||||
if !data.0.is_alive() {
|
|
||||||
// the wl_surface is destroyed, this means the client is not
|
|
||||||
// trying to change the role but it's a cleanup (possibly a
|
|
||||||
// disconnecting client), ignore the protocol check.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
implem
|
|
||||||
.compositor_token
|
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(&data.0, |rdata| {
|
|
||||||
if let XdgSurfacePendingState::None = rdata.pending_state {
|
|
||||||
// all is good
|
|
||||||
} else {
|
|
||||||
data.1.post_error(
|
|
||||||
xdg_wm_base::Error::Role as u32,
|
|
||||||
"xdg_surface was destroyed before its role object".into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, SD> Implementation<Resource<xdg_surface::XdgSurface>, xdg_surface::Request>
|
fn destroy_surface<U, R, SD>(surface: Resource<xdg_surface::XdgSurface>)
|
||||||
for ShellImplementation<U, R, SD>
|
|
||||||
where
|
where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
SD: 'static,
|
SD: 'static,
|
||||||
{
|
{
|
||||||
fn receive(&mut self, request: xdg_surface::Request, xdg_surface: Resource<xdg_surface::XdgSurface>) {
|
let data = surface.user_data::<XdgSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
let ptr = xdg_surface.get_user_data();
|
if !data.wl_surface.is_alive() {
|
||||||
let &(ref surface, ref shell) = unsafe { &*(ptr as *mut XdgSurfaceUserData) };
|
// the wl_surface is destroyed, this means the client is not
|
||||||
|
// trying to change the role but it's a cleanup (possibly a
|
||||||
|
// disconnecting client), ignore the protocol check.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.shell_data
|
||||||
|
.compositor_token
|
||||||
|
.with_role_data::<XdgSurfaceRole, _, _>(&data.wl_surface, |rdata| {
|
||||||
|
if let XdgSurfacePendingState::None = rdata.pending_state {
|
||||||
|
// all is good
|
||||||
|
} else {
|
||||||
|
data.wm_base.post_error(
|
||||||
|
xdg_wm_base::Error::Role as u32,
|
||||||
|
"xdg_surface was destroyed before its role object".into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}).expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xdg_surface_implementation<U, R, SD>(
|
||||||
|
request: xdg_surface::Request,
|
||||||
|
xdg_surface: Resource<xdg_surface::XdgSurface>,
|
||||||
|
) where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
|
SD: 'static,
|
||||||
|
{
|
||||||
|
let data = xdg_surface.user_data::<XdgSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
match request {
|
match request {
|
||||||
xdg_surface::Request::Destroy => {
|
xdg_surface::Request::Destroy => {
|
||||||
// all is handled by our destructor
|
// all is handled by our destructor
|
||||||
}
|
}
|
||||||
xdg_surface::Request::GetToplevel { id } => {
|
xdg_surface::Request::GetToplevel { id } => {
|
||||||
self.compositor_token
|
data.shell_data
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(surface, |data| {
|
.compositor_token
|
||||||
|
.with_role_data::<XdgSurfaceRole, _, _>(&data.wl_surface, |data| {
|
||||||
data.pending_state = XdgSurfacePendingState::Toplevel(ToplevelState {
|
data.pending_state = XdgSurfacePendingState::Toplevel(ToplevelState {
|
||||||
parent: None,
|
parent: None,
|
||||||
title: String::new(),
|
title: String::new(),
|
||||||
|
@ -269,92 +247,85 @@ where
|
||||||
min_size: (0, 0),
|
min_size: (0, 0),
|
||||||
max_size: (0, 0),
|
max_size: (0, 0),
|
||||||
});
|
});
|
||||||
})
|
}).expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
|
||||||
let toplevel = id.implement_nonsend(
|
let toplevel = id.implement_nonsend(
|
||||||
self.clone(),
|
toplevel_implementation::<U, R, SD>,
|
||||||
Some(destroy_toplevel::<U, R, SD>),
|
Some(destroy_toplevel::<U, R, SD>),
|
||||||
&self.loop_token,
|
ShellSurfaceUserData {
|
||||||
|
shell_data: data.shell_data.clone(),
|
||||||
|
wl_surface: data.wl_surface.clone(),
|
||||||
|
xdg_surface: xdg_surface.clone(),
|
||||||
|
wm_base: data.wm_base.clone(),
|
||||||
|
},
|
||||||
|
&data.shell_data.display_token,
|
||||||
);
|
);
|
||||||
toplevel.set_user_data(Box::into_raw(Box::new((
|
|
||||||
surface.clone(),
|
|
||||||
shell.clone(),
|
|
||||||
xdg_surface.clone(),
|
|
||||||
))) as *mut _);
|
|
||||||
|
|
||||||
self.shell_state
|
data.shell_data
|
||||||
|
.shell_state
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.known_toplevels
|
.known_toplevels
|
||||||
.push(make_toplevel_handle(self.compositor_token, &toplevel));
|
.push(make_toplevel_handle(&toplevel));
|
||||||
|
|
||||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
let handle = make_toplevel_handle(&toplevel);
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
user_impl.receive(XdgRequest::NewToplevel { surface: handle }, ());
|
(&mut *user_impl)(XdgRequest::NewToplevel { surface: handle });
|
||||||
}
|
}
|
||||||
xdg_surface::Request::GetPopup {
|
xdg_surface::Request::GetPopup {
|
||||||
id,
|
id,
|
||||||
parent,
|
parent,
|
||||||
positioner,
|
positioner,
|
||||||
} => {
|
} => {
|
||||||
let positioner_data = unsafe { &*(positioner.get_user_data() as *const PositionerState) };
|
let positioner_data = positioner.user_data::<RefCell<PositionerState>>().unwrap();
|
||||||
|
|
||||||
let parent_surface = parent.map(|parent| {
|
let parent_surface = parent.map(|parent| {
|
||||||
let parent_ptr = parent.get_user_data();
|
let parent_data = parent.user_data::<XdgSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
let &(ref parent_surface, _) = unsafe { &*(parent_ptr as *mut XdgSurfaceUserData) };
|
parent_data.wl_surface.clone()
|
||||||
parent_surface.clone()
|
|
||||||
});
|
});
|
||||||
self.compositor_token
|
data.shell_data
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(surface, |data| {
|
.compositor_token
|
||||||
|
.with_role_data::<XdgSurfaceRole, _, _>(&data.wl_surface, |data| {
|
||||||
data.pending_state = XdgSurfacePendingState::Popup(PopupState {
|
data.pending_state = XdgSurfacePendingState::Popup(PopupState {
|
||||||
parent: parent_surface,
|
parent: parent_surface,
|
||||||
positioner: positioner_data.clone(),
|
positioner: positioner_data.borrow().clone(),
|
||||||
});
|
});
|
||||||
})
|
}).expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
|
||||||
let popup = id.implement_nonsend(
|
let popup = id.implement_nonsend(
|
||||||
self.clone(),
|
xg_popup_implementation::<U, R, SD>,
|
||||||
Some(destroy_popup::<U, R, SD>),
|
Some(destroy_popup::<U, R, SD>),
|
||||||
&self.loop_token,
|
ShellSurfaceUserData {
|
||||||
|
shell_data: data.shell_data.clone(),
|
||||||
|
wl_surface: data.wl_surface.clone(),
|
||||||
|
xdg_surface: xdg_surface.clone(),
|
||||||
|
wm_base: data.wm_base.clone(),
|
||||||
|
},
|
||||||
|
&data.shell_data.display_token,
|
||||||
);
|
);
|
||||||
popup.set_user_data(Box::into_raw(Box::new((
|
|
||||||
surface.clone(),
|
|
||||||
shell.clone(),
|
|
||||||
xdg_surface.clone(),
|
|
||||||
))) as *mut _);
|
|
||||||
|
|
||||||
self.shell_state
|
data.shell_data
|
||||||
|
.shell_state
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.known_popups
|
.known_popups
|
||||||
.push(make_popup_handle(self.compositor_token, &popup));
|
.push(make_popup_handle(&popup));
|
||||||
|
|
||||||
let handle = make_popup_handle(self.compositor_token, &popup);
|
let handle = make_popup_handle(&popup);
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
user_impl.receive(XdgRequest::NewPopup { surface: handle }, ());
|
(&mut *user_impl)(XdgRequest::NewPopup { surface: handle });
|
||||||
}
|
}
|
||||||
xdg_surface::Request::SetWindowGeometry {
|
xdg_surface::Request::SetWindowGeometry { x, y, width, height } => {
|
||||||
x,
|
data.shell_data
|
||||||
y,
|
.compositor_token
|
||||||
width,
|
.with_role_data::<XdgSurfaceRole, _, _>(&data.wl_surface, |data| {
|
||||||
height,
|
data.window_geometry = Some(Rectangle { x, y, width, height });
|
||||||
} => {
|
}).expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||||
self.compositor_token
|
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(surface, |data| {
|
|
||||||
data.window_geometry = Some(Rectangle {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
|
||||||
}
|
}
|
||||||
xdg_surface::Request::AckConfigure { serial } => {
|
xdg_surface::Request::AckConfigure { serial } => {
|
||||||
self.compositor_token
|
data.shell_data
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(surface, |data| {
|
.compositor_token
|
||||||
|
.with_role_data::<XdgSurfaceRole, _, _>(&data.wl_surface, |role_data| {
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
data.pending_configures.retain(|&s| {
|
role_data.pending_configures.retain(|&s| {
|
||||||
if s == serial {
|
if s == serial {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
@ -362,15 +333,13 @@ where
|
||||||
});
|
});
|
||||||
if !found {
|
if !found {
|
||||||
// client responded to a non-existing configure
|
// client responded to a non-existing configure
|
||||||
shell.post_error(
|
data.wm_base.post_error(
|
||||||
xdg_wm_base::Error::InvalidSurfaceState as u32,
|
xdg_wm_base::Error::InvalidSurfaceState as u32,
|
||||||
format!("Wrong configure serial: {}", serial),
|
format!("Wrong configure serial: {}", serial),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
data.configured = true;
|
role_data.configured = true;
|
||||||
})
|
}).expect("xdg_surface exists but surface has not shell_surface role?!");
|
||||||
.expect("xdg_surface exists but surface has not shell_surface role?!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,15 +348,16 @@ where
|
||||||
* xdg_toplevel
|
* xdg_toplevel
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub type ShellSurfaceUserData = (
|
pub(crate) struct ShellSurfaceUserData<U, R, SD> {
|
||||||
Resource<wl_surface::WlSurface>,
|
pub(crate) shell_data: ShellData<U, R, SD>,
|
||||||
Resource<xdg_wm_base::XdgWmBase>,
|
pub(crate) wl_surface: Resource<wl_surface::WlSurface>,
|
||||||
Resource<xdg_surface::XdgSurface>,
|
pub(crate) wm_base: Resource<xdg_wm_base::XdgWmBase>,
|
||||||
);
|
pub(crate) xdg_surface: Resource<xdg_surface::XdgSurface>,
|
||||||
|
}
|
||||||
|
|
||||||
// Utility functions allowing to factor out a lot of the upcoming logic
|
// Utility functions allowing to factor out a lot of the upcoming logic
|
||||||
fn with_surface_toplevel_data<U, R, SD, F>(
|
fn with_surface_toplevel_data<U, R, SD, F>(
|
||||||
implem: &ShellImplementation<U, R, SD>,
|
shell_data: &ShellData<U, R, SD>,
|
||||||
toplevel: &Resource<xdg_toplevel::XdgToplevel>,
|
toplevel: &Resource<xdg_toplevel::XdgToplevel>,
|
||||||
f: F,
|
f: F,
|
||||||
) where
|
) where
|
||||||
|
@ -396,27 +366,24 @@ fn with_surface_toplevel_data<U, R, SD, F>(
|
||||||
SD: 'static,
|
SD: 'static,
|
||||||
F: FnOnce(&mut ToplevelState),
|
F: FnOnce(&mut ToplevelState),
|
||||||
{
|
{
|
||||||
let ptr = toplevel.get_user_data();
|
let toplevel_data = toplevel.user_data::<ShellSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
shell_data
|
||||||
implem
|
|
||||||
.compositor_token
|
.compositor_token
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(surface, |data| match data.pending_state {
|
.with_role_data::<XdgSurfaceRole, _, _>(&toplevel_data.wl_surface, |data| match data.pending_state {
|
||||||
XdgSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data),
|
XdgSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
}).expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
||||||
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_toplevel_configure<U, R>(
|
pub fn send_toplevel_configure<U, R, SD>(
|
||||||
token: CompositorToken<U, R>,
|
|
||||||
resource: &Resource<xdg_toplevel::XdgToplevel>,
|
resource: &Resource<xdg_toplevel::XdgToplevel>,
|
||||||
configure: ToplevelConfigure,
|
configure: ToplevelConfigure,
|
||||||
) where
|
) where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
|
SD: 'static,
|
||||||
{
|
{
|
||||||
let &(ref surface, _, ref shell_surface) =
|
let data = resource.user_data::<ShellSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
|
|
||||||
let (width, height) = configure.size.unwrap_or((0, 0));
|
let (width, height) = configure.size.unwrap_or((0, 0));
|
||||||
// convert the Vec<State> (which is really a Vec<u32>) into Vec<u8>
|
// convert the Vec<State> (which is really a Vec<u32>) into Vec<u8>
|
||||||
let states = {
|
let states = {
|
||||||
|
@ -433,177 +400,153 @@ pub fn send_toplevel_configure<U, R>(
|
||||||
height,
|
height,
|
||||||
states,
|
states,
|
||||||
});
|
});
|
||||||
shell_surface.send(xdg_surface::Event::Configure { serial });
|
data.xdg_surface.send(xdg_surface::Event::Configure { serial });
|
||||||
// Add the configure as pending
|
// Add the configure as pending
|
||||||
token
|
data.shell_data
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(surface, |data| data.pending_configures.push(serial))
|
.compositor_token
|
||||||
|
.with_role_data::<XdgSurfaceRole, _, _>(&data.wl_surface, |data| data.pending_configures.push(serial))
|
||||||
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_toplevel_handle<U, R, SD>(
|
fn make_toplevel_handle<U: 'static, R: 'static, SD: 'static>(
|
||||||
token: CompositorToken<U, R>,
|
|
||||||
resource: &Resource<xdg_toplevel::XdgToplevel>,
|
resource: &Resource<xdg_toplevel::XdgToplevel>,
|
||||||
) -> super::ToplevelSurface<U, R, SD> {
|
) -> super::ToplevelSurface<U, R, SD> {
|
||||||
let ptr = resource.get_user_data();
|
let data = resource.user_data::<ShellSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
|
||||||
super::ToplevelSurface {
|
super::ToplevelSurface {
|
||||||
wl_surface: wl_surface.clone(),
|
wl_surface: data.wl_surface.clone(),
|
||||||
shell_surface: ToplevelKind::Xdg(resource.clone()),
|
shell_surface: ToplevelKind::Xdg(resource.clone()),
|
||||||
token,
|
token: data.shell_data.compositor_token,
|
||||||
_shell_data: ::std::marker::PhantomData,
|
_shell_data: ::std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, SD> Implementation<Resource<xdg_toplevel::XdgToplevel>, xdg_toplevel::Request>
|
fn toplevel_implementation<U, R, SD>(
|
||||||
for ShellImplementation<U, R, SD>
|
request: xdg_toplevel::Request,
|
||||||
where
|
|
||||||
U: 'static,
|
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
|
||||||
SD: 'static,
|
|
||||||
{
|
|
||||||
fn receive(&mut self, request: xdg_toplevel::Request, toplevel: Resource<xdg_toplevel::XdgToplevel>) {
|
|
||||||
match request {
|
|
||||||
xdg_toplevel::Request::Destroy => {
|
|
||||||
// all it done by the destructor
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::SetParent { parent } => {
|
|
||||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
|
||||||
toplevel_data.parent = parent.map(|toplevel_surface_parent| {
|
|
||||||
let parent_ptr = toplevel_surface_parent.get_user_data();
|
|
||||||
let &(ref parent_surface, _, _) =
|
|
||||||
unsafe { &*(parent_ptr as *mut ShellSurfaceUserData) };
|
|
||||||
parent_surface.clone()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::SetTitle { title } => {
|
|
||||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
|
||||||
toplevel_data.title = title;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::SetAppId { app_id } => {
|
|
||||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
|
||||||
toplevel_data.app_id = app_id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::ShowWindowMenu { seat, serial, x, y } => {
|
|
||||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
|
||||||
user_impl.receive(
|
|
||||||
XdgRequest::ShowWindowMenu {
|
|
||||||
surface: handle,
|
|
||||||
seat,
|
|
||||||
serial,
|
|
||||||
location: (x, y),
|
|
||||||
},
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::Move { seat, serial } => {
|
|
||||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
|
||||||
user_impl.receive(
|
|
||||||
XdgRequest::Move {
|
|
||||||
surface: handle,
|
|
||||||
seat,
|
|
||||||
serial,
|
|
||||||
},
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::Resize {
|
|
||||||
seat,
|
|
||||||
serial,
|
|
||||||
edges,
|
|
||||||
} => {
|
|
||||||
let edges =
|
|
||||||
xdg_toplevel::ResizeEdge::from_raw(edges).unwrap_or(xdg_toplevel::ResizeEdge::None);
|
|
||||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
|
||||||
user_impl.receive(
|
|
||||||
XdgRequest::Resize {
|
|
||||||
surface: handle,
|
|
||||||
seat,
|
|
||||||
serial,
|
|
||||||
edges,
|
|
||||||
},
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::SetMaxSize { width, height } => {
|
|
||||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
|
||||||
toplevel_data.max_size = (width, height);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::SetMinSize { width, height } => {
|
|
||||||
with_surface_toplevel_data(self, &toplevel, |toplevel_data| {
|
|
||||||
toplevel_data.max_size = (width, height);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::SetMaximized => {
|
|
||||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
|
||||||
user_impl.receive(XdgRequest::Maximize { surface: handle }, ());
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::UnsetMaximized => {
|
|
||||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
|
||||||
user_impl.receive(XdgRequest::UnMaximize { surface: handle }, ());
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::SetFullscreen { output } => {
|
|
||||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
|
||||||
user_impl.receive(
|
|
||||||
XdgRequest::Fullscreen {
|
|
||||||
surface: handle,
|
|
||||||
output,
|
|
||||||
},
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::UnsetFullscreen => {
|
|
||||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
|
||||||
user_impl.receive(XdgRequest::UnFullscreen { surface: handle }, ());
|
|
||||||
}
|
|
||||||
xdg_toplevel::Request::SetMinimized => {
|
|
||||||
let handle = make_toplevel_handle(self.compositor_token, &toplevel);
|
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
|
||||||
user_impl.receive(XdgRequest::Minimize { surface: handle }, ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destroy_toplevel<U, R, SD>(
|
|
||||||
toplevel: Resource<xdg_toplevel::XdgToplevel>,
|
toplevel: Resource<xdg_toplevel::XdgToplevel>,
|
||||||
implem: Box<Implementation<Resource<xdg_toplevel::XdgToplevel>, xdg_toplevel::Request>>,
|
|
||||||
) where
|
) where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
SD: 'static,
|
SD: 'static,
|
||||||
{
|
{
|
||||||
let implem: ShellImplementation<U, R, SD> = *downcast_impl(implem).unwrap_or_else(|_| unreachable!());
|
let data = toplevel.user_data::<ShellSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
let ptr = toplevel.get_user_data();
|
match request {
|
||||||
toplevel.set_user_data(::std::ptr::null_mut());
|
xdg_toplevel::Request::Destroy => {
|
||||||
// take back ownership of the userdata
|
// all it done by the destructor
|
||||||
let data = *unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) };
|
}
|
||||||
if !data.0.is_alive() {
|
xdg_toplevel::Request::SetParent { parent } => {
|
||||||
|
with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| {
|
||||||
|
toplevel_data.parent = parent.map(|toplevel_surface_parent| {
|
||||||
|
toplevel_surface_parent
|
||||||
|
.user_data::<ShellSurfaceUserData<U, R, SD>>()
|
||||||
|
.unwrap()
|
||||||
|
.wl_surface
|
||||||
|
.clone()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::SetTitle { title } => {
|
||||||
|
with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| {
|
||||||
|
toplevel_data.title = title;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::SetAppId { app_id } => {
|
||||||
|
with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| {
|
||||||
|
toplevel_data.app_id = app_id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::ShowWindowMenu { seat, serial, x, y } => {
|
||||||
|
let handle = make_toplevel_handle(&toplevel);
|
||||||
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
|
(&mut *user_impl)(XdgRequest::ShowWindowMenu {
|
||||||
|
surface: handle,
|
||||||
|
seat,
|
||||||
|
serial,
|
||||||
|
location: (x, y),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::Move { seat, serial } => {
|
||||||
|
let handle = make_toplevel_handle(&toplevel);
|
||||||
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
|
(&mut *user_impl)(XdgRequest::Move {
|
||||||
|
surface: handle,
|
||||||
|
seat,
|
||||||
|
serial,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::Resize { seat, serial, edges } => {
|
||||||
|
let edges = xdg_toplevel::ResizeEdge::from_raw(edges).unwrap_or(xdg_toplevel::ResizeEdge::None);
|
||||||
|
let handle = make_toplevel_handle(&toplevel);
|
||||||
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
|
(&mut *user_impl)(XdgRequest::Resize {
|
||||||
|
surface: handle,
|
||||||
|
seat,
|
||||||
|
serial,
|
||||||
|
edges,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::SetMaxSize { width, height } => {
|
||||||
|
with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| {
|
||||||
|
toplevel_data.max_size = (width, height);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::SetMinSize { width, height } => {
|
||||||
|
with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| {
|
||||||
|
toplevel_data.max_size = (width, height);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::SetMaximized => {
|
||||||
|
let handle = make_toplevel_handle(&toplevel);
|
||||||
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
|
(&mut *user_impl)(XdgRequest::Maximize { surface: handle });
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::UnsetMaximized => {
|
||||||
|
let handle = make_toplevel_handle(&toplevel);
|
||||||
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
|
(&mut *user_impl)(XdgRequest::UnMaximize { surface: handle });
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::SetFullscreen { output } => {
|
||||||
|
let handle = make_toplevel_handle(&toplevel);
|
||||||
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
|
(&mut *user_impl)(XdgRequest::Fullscreen {
|
||||||
|
surface: handle,
|
||||||
|
output,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::UnsetFullscreen => {
|
||||||
|
let handle = make_toplevel_handle(&toplevel);
|
||||||
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
|
(&mut *user_impl)(XdgRequest::UnFullscreen { surface: handle });
|
||||||
|
}
|
||||||
|
xdg_toplevel::Request::SetMinimized => {
|
||||||
|
let handle = make_toplevel_handle(&toplevel);
|
||||||
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
|
(&mut *user_impl)(XdgRequest::Minimize { surface: handle });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy_toplevel<U, R, SD>(toplevel: Resource<xdg_toplevel::XdgToplevel>)
|
||||||
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
|
SD: 'static,
|
||||||
|
{
|
||||||
|
let data = toplevel.user_data::<ShellSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
|
if !data.wl_surface.is_alive() {
|
||||||
// the wl_surface is destroyed, this means the client is not
|
// the wl_surface is destroyed, this means the client is not
|
||||||
// trying to change the role but it's a cleanup (possibly a
|
// trying to change the role but it's a cleanup (possibly a
|
||||||
// disconnecting client), ignore the protocol check.
|
// disconnecting client), ignore the protocol check.
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
implem
|
data.shell_data
|
||||||
.compositor_token
|
.compositor_token
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(&data.0, |data| {
|
.with_role_data::<XdgSurfaceRole, _, _>(&data.wl_surface, |data| {
|
||||||
data.pending_state = XdgSurfacePendingState::None;
|
data.pending_state = XdgSurfacePendingState::None;
|
||||||
data.configured = false;
|
data.configured = false;
|
||||||
})
|
}).expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
||||||
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
|
||||||
}
|
}
|
||||||
// remove this surface from the known ones (as well as any leftover dead surface)
|
// remove this surface from the known ones (as well as any leftover dead surface)
|
||||||
implem
|
data.shell_data
|
||||||
.shell_state
|
.shell_state
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -615,103 +558,84 @@ fn destroy_toplevel<U, R, SD>(
|
||||||
* xdg_popup
|
* xdg_popup
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub(crate) fn send_popup_configure<U, R>(
|
pub(crate) fn send_popup_configure<U, R, SD>(
|
||||||
token: CompositorToken<U, R>,
|
|
||||||
resource: &Resource<xdg_popup::XdgPopup>,
|
resource: &Resource<xdg_popup::XdgPopup>,
|
||||||
configure: PopupConfigure,
|
configure: PopupConfigure,
|
||||||
) where
|
) where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
|
SD: 'static,
|
||||||
{
|
{
|
||||||
let &(ref surface, _, ref shell_surface) =
|
let data = resource.user_data::<ShellSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) };
|
|
||||||
let (x, y) = configure.position;
|
let (x, y) = configure.position;
|
||||||
let (width, height) = configure.size;
|
let (width, height) = configure.size;
|
||||||
let serial = configure.serial;
|
let serial = configure.serial;
|
||||||
resource.send(xdg_popup::Event::Configure {
|
resource.send(xdg_popup::Event::Configure { x, y, width, height });
|
||||||
x,
|
data.xdg_surface.send(xdg_surface::Event::Configure { serial });
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
});
|
|
||||||
shell_surface.send(xdg_surface::Event::Configure { serial });
|
|
||||||
// Add the configure as pending
|
// Add the configure as pending
|
||||||
token
|
data.shell_data
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(surface, |data| data.pending_configures.push(serial))
|
.compositor_token
|
||||||
|
.with_role_data::<XdgSurfaceRole, _, _>(&data.wl_surface, |data| data.pending_configures.push(serial))
|
||||||
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
.expect("xdg_toplevel exists but surface has not shell_surface role?!");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_popup_handle<U, R, SD>(
|
fn make_popup_handle<U: 'static, R: 'static, SD: 'static>(
|
||||||
token: CompositorToken<U, R>,
|
|
||||||
resource: &Resource<xdg_popup::XdgPopup>,
|
resource: &Resource<xdg_popup::XdgPopup>,
|
||||||
) -> super::PopupSurface<U, R, SD> {
|
) -> super::PopupSurface<U, R, SD> {
|
||||||
let ptr = resource.get_user_data();
|
let data = resource.user_data::<ShellSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) };
|
|
||||||
super::PopupSurface {
|
super::PopupSurface {
|
||||||
wl_surface: wl_surface.clone(),
|
wl_surface: data.wl_surface.clone(),
|
||||||
shell_surface: PopupKind::Xdg(resource.clone()),
|
shell_surface: PopupKind::Xdg(resource.clone()),
|
||||||
token,
|
token: data.shell_data.compositor_token,
|
||||||
_shell_data: ::std::marker::PhantomData,
|
_shell_data: ::std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, R, SD> Implementation<Resource<xdg_popup::XdgPopup>, xdg_popup::Request>
|
fn xg_popup_implementation<U, R, SD>(request: xdg_popup::Request, popup: Resource<xdg_popup::XdgPopup>)
|
||||||
for ShellImplementation<U, R, SD>
|
|
||||||
where
|
where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
SD: 'static,
|
SD: 'static,
|
||||||
{
|
{
|
||||||
fn receive(&mut self, request: xdg_popup::Request, popup: Resource<xdg_popup::XdgPopup>) {
|
let data = popup.user_data::<ShellSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
match request {
|
match request {
|
||||||
xdg_popup::Request::Destroy => {
|
xdg_popup::Request::Destroy => {
|
||||||
// all is handled by our destructor
|
// all is handled by our destructor
|
||||||
}
|
}
|
||||||
xdg_popup::Request::Grab { seat, serial } => {
|
xdg_popup::Request::Grab { seat, serial } => {
|
||||||
let handle = make_popup_handle(self.compositor_token, &popup);
|
let handle = make_popup_handle(&popup);
|
||||||
let mut user_impl = self.user_impl.borrow_mut();
|
let mut user_impl = data.shell_data.user_impl.borrow_mut();
|
||||||
user_impl.receive(
|
(&mut *user_impl)(XdgRequest::Grab {
|
||||||
XdgRequest::Grab {
|
|
||||||
surface: handle,
|
surface: handle,
|
||||||
seat,
|
seat,
|
||||||
serial,
|
serial,
|
||||||
},
|
});
|
||||||
(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy_popup<U, R, SD>(
|
fn destroy_popup<U, R, SD>(popup: Resource<xdg_popup::XdgPopup>)
|
||||||
popup: Resource<xdg_popup::XdgPopup>,
|
where
|
||||||
implem: Box<Implementation<Resource<xdg_popup::XdgPopup>, xdg_popup::Request>>,
|
|
||||||
) where
|
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: Role<XdgSurfaceRole> + 'static,
|
R: Role<XdgSurfaceRole> + 'static,
|
||||||
SD: 'static,
|
SD: 'static,
|
||||||
{
|
{
|
||||||
let implem: ShellImplementation<U, R, SD> = *downcast_impl(implem).unwrap_or_else(|_| unreachable!());
|
let data = popup.user_data::<ShellSurfaceUserData<U, R, SD>>().unwrap();
|
||||||
let ptr = popup.get_user_data();
|
if !data.wl_surface.is_alive() {
|
||||||
popup.set_user_data(::std::ptr::null_mut());
|
|
||||||
// take back ownership of the userdata
|
|
||||||
let data = *unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) };
|
|
||||||
if !data.0.is_alive() {
|
|
||||||
// the wl_surface is destroyed, this means the client is not
|
// the wl_surface is destroyed, this means the client is not
|
||||||
// trying to change the role but it's a cleanup (possibly a
|
// trying to change the role but it's a cleanup (possibly a
|
||||||
// disconnecting client), ignore the protocol check.
|
// disconnecting client), ignore the protocol check.
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
implem
|
data.shell_data
|
||||||
.compositor_token
|
.compositor_token
|
||||||
.with_role_data::<XdgSurfaceRole, _, _>(&data.0, |data| {
|
.with_role_data::<XdgSurfaceRole, _, _>(&data.wl_surface, |data| {
|
||||||
data.pending_state = XdgSurfacePendingState::None;
|
data.pending_state = XdgSurfacePendingState::None;
|
||||||
data.configured = false;
|
data.configured = false;
|
||||||
})
|
}).expect("xdg_popup exists but surface has not shell_surface role?!");
|
||||||
.expect("xdg_popup exists but surface has not shell_surface role?!");
|
|
||||||
}
|
}
|
||||||
// remove this surface from the known ones (as well as any leftover dead surface)
|
// remove this surface from the known ones (as well as any leftover dead surface)
|
||||||
implem
|
data.shell_data
|
||||||
.shell_state
|
.shell_state
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,21 +23,21 @@
|
||||||
//! use wayland_server::protocol::wl_shm::Format;
|
//! use wayland_server::protocol::wl_shm::Format;
|
||||||
//!
|
//!
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # let (mut display, mut event_loop) = wayland_server::Display::new();
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
//! // Insert the ShmGlobal into your event loop
|
//! // Insert the ShmGlobal into your event loop
|
||||||
//! // Here, we specify that Yuyv and C8 format are supported
|
//! // Here, we specify that Yuyv and C8 format are supported
|
||||||
//! // additionnaly to the standart Argb8888 and Xrgb8888.
|
//! // additionnaly to the standart Argb8888 and Xrgb8888.
|
||||||
//! let shm_global = init_shm_global(
|
//! let shm_global = init_shm_global(
|
||||||
//! &mut display,
|
//! &mut display,
|
||||||
//! event_loop.token(),
|
|
||||||
//! vec![Format::Yuyv, Format::C8],
|
//! vec![Format::Yuyv, Format::C8],
|
||||||
//! None // we don't provide a logger here
|
//! None // we don't provide a logger here
|
||||||
//! );
|
//! );
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to
|
//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the
|
||||||
//! do it:
|
//! `with_buffer_contents` function to do it:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # extern crate wayland_server;
|
//! # extern crate wayland_server;
|
||||||
|
@ -45,13 +45,27 @@
|
||||||
//! # use wayland_server::protocol::wl_buffer::WlBuffer;
|
//! # use wayland_server::protocol::wl_buffer::WlBuffer;
|
||||||
//! # use wayland_server::Resource;
|
//! # use wayland_server::Resource;
|
||||||
//! # fn wrap(buffer: &Resource<WlBuffer>) {
|
//! # fn wrap(buffer: &Resource<WlBuffer>) {
|
||||||
//! use smithay::wayland::shm::{with_buffer_contents, BufferData};
|
//! use smithay::wayland::shm::{with_buffer_contents, BufferData, BufferAccessError};
|
||||||
//!
|
//!
|
||||||
//! with_buffer_contents(&buffer,
|
//! let content = with_buffer_contents(&buffer,
|
||||||
//! |slice: &[u8], buffer_metadata: BufferData| {
|
//! |slice: &[u8], buffer_metadata: BufferData| {
|
||||||
//! // do something to draw it on the screen
|
//! // do something to extract the contents of the buffer
|
||||||
//! }
|
//! }
|
||||||
//! );
|
//! );
|
||||||
|
//!
|
||||||
|
//! match content {
|
||||||
|
//! Ok(something) => {
|
||||||
|
//! /* `something` is the content you returned from the closure */
|
||||||
|
//! },
|
||||||
|
//! Err(BufferAccessError::NotManaged) => {
|
||||||
|
//! /* This buffer is not managed by the SHM global, but by something else */
|
||||||
|
//! },
|
||||||
|
//! Err(BufferAccessError::BadMap) => {
|
||||||
|
//! /* The client supplied invalid content specification for this buffer,
|
||||||
|
//! and was killed.
|
||||||
|
//! */
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
//! # }
|
//! # }
|
||||||
//! # fn main() {}
|
//! # fn main() {}
|
||||||
//! ```
|
//! ```
|
||||||
|
@ -66,9 +80,8 @@
|
||||||
use self::pool::{Pool, ResizeError};
|
use self::pool::{Pool, ResizeError};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wayland_server::{Display, Global, LoopToken, NewResource, Resource};
|
|
||||||
use wayland_server::commons::Implementation;
|
|
||||||
use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool};
|
use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool};
|
||||||
|
use wayland_server::{Display, DisplayToken, Global, NewResource, Resource};
|
||||||
|
|
||||||
mod pool;
|
mod pool;
|
||||||
|
|
||||||
|
@ -80,7 +93,7 @@ mod pool;
|
||||||
pub struct ShmGlobalData {
|
pub struct ShmGlobalData {
|
||||||
formats: Rc<Vec<wl_shm::Format>>,
|
formats: Rc<Vec<wl_shm::Format>>,
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
token: LoopToken,
|
token: DisplayToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new SHM global advertizing given supported formats.
|
/// Create a new SHM global advertizing given supported formats.
|
||||||
|
@ -94,7 +107,6 @@ pub struct ShmGlobalData {
|
||||||
/// the future.
|
/// the future.
|
||||||
pub fn init_shm_global<L>(
|
pub fn init_shm_global<L>(
|
||||||
display: &mut Display,
|
display: &mut Display,
|
||||||
token: LoopToken,
|
|
||||||
mut formats: Vec<wl_shm::Format>,
|
mut formats: Vec<wl_shm::Format>,
|
||||||
logger: L,
|
logger: L,
|
||||||
) -> Global<wl_shm::WlShm>
|
) -> Global<wl_shm::WlShm>
|
||||||
|
@ -109,11 +121,19 @@ where
|
||||||
let data = ShmGlobalData {
|
let data = ShmGlobalData {
|
||||||
formats: Rc::new(formats),
|
formats: Rc::new(formats),
|
||||||
log: log.new(o!("smithay_module" => "shm_handler")),
|
log: log.new(o!("smithay_module" => "shm_handler")),
|
||||||
token: token.clone(),
|
token: display.get_token(),
|
||||||
};
|
};
|
||||||
|
|
||||||
display.create_global::<wl_shm::WlShm, _>(&token, 1, move |_version, shm_new: NewResource<_>| {
|
display.create_global::<wl_shm::WlShm, _>(1, move |shm_new: NewResource<_>, _version| {
|
||||||
let shm = shm_new.implement_nonsend(data.clone(), None::<fn(_, _)>, &data.token);
|
let shm = shm_new.implement_nonsend(
|
||||||
|
{
|
||||||
|
let mut data = data.clone();
|
||||||
|
move |req, shm| data.receive_shm_message(req, shm)
|
||||||
|
},
|
||||||
|
None::<fn(_)>,
|
||||||
|
(),
|
||||||
|
&data.token,
|
||||||
|
);
|
||||||
// send the formats
|
// send the formats
|
||||||
for f in &data.formats[..] {
|
for f in &data.formats[..] {
|
||||||
shm.send(wl_shm::Event::Format { format: *f });
|
shm.send(wl_shm::Event::Format { format: *f });
|
||||||
|
@ -152,10 +172,10 @@ pub fn with_buffer_contents<F, T>(
|
||||||
where
|
where
|
||||||
F: FnOnce(&[u8], BufferData) -> T,
|
F: FnOnce(&[u8], BufferData) -> T,
|
||||||
{
|
{
|
||||||
if !buffer.is_implemented_with::<ShmGlobalData>() {
|
let data = match buffer.user_data::<InternalBufferData>() {
|
||||||
return Err(BufferAccessError::NotManaged);
|
Some(d) => d,
|
||||||
}
|
None => return Err(BufferAccessError::NotManaged),
|
||||||
let data = unsafe { &*(buffer.get_user_data() as *mut InternalBufferData) };
|
};
|
||||||
|
|
||||||
match data.pool.with_data_slice(|slice| f(slice, data.data)) {
|
match data.pool.with_data_slice(|slice| f(slice, data.data)) {
|
||||||
Ok(t) => Ok(t),
|
Ok(t) => Ok(t),
|
||||||
|
@ -167,12 +187,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Implementation<Resource<wl_shm::WlShm>, wl_shm::Request> for ShmGlobalData {
|
impl ShmGlobalData {
|
||||||
fn receive(&mut self, request: wl_shm::Request, shm: Resource<wl_shm::WlShm>) {
|
fn receive_shm_message(&mut self, request: wl_shm::Request, shm: Resource<wl_shm::WlShm>) {
|
||||||
use self::wl_shm::{Error, Request};
|
use self::wl_shm::{Error, Request};
|
||||||
|
|
||||||
match request {
|
let Request::CreatePool { id: pool, fd, size } = request;
|
||||||
Request::CreatePool { id: pool, fd, size } => {
|
|
||||||
if size <= 0 {
|
if size <= 0 {
|
||||||
shm.post_error(
|
shm.post_error(
|
||||||
Error::InvalidFd as u32,
|
Error::InvalidFd as u32,
|
||||||
|
@ -190,17 +209,16 @@ impl Implementation<Resource<wl_shm::WlShm>, wl_shm::Request> for ShmGlobalData
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let arc_pool = Box::new(Arc::new(mmap_pool));
|
let arc_pool = Arc::new(mmap_pool);
|
||||||
let pool = pool.implement_nonsend(
|
pool.implement_nonsend(
|
||||||
self.clone(),
|
{
|
||||||
Some(|pool: Resource<_>, _| {
|
let mut data = self.clone();
|
||||||
drop(unsafe { Box::from_raw(pool.get_user_data() as *mut Arc<Pool>) })
|
move |req, pool| data.receive_pool_message(req, pool)
|
||||||
}),
|
},
|
||||||
|
None::<fn(_)>,
|
||||||
|
arc_pool,
|
||||||
&self.token,
|
&self.token,
|
||||||
);
|
);
|
||||||
pool.set_user_data(Box::into_raw(arc_pool) as *mut ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,11 +242,15 @@ struct InternalBufferData {
|
||||||
data: BufferData,
|
data: BufferData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Implementation<Resource<wl_shm_pool::WlShmPool>, wl_shm_pool::Request> for ShmGlobalData {
|
impl ShmGlobalData {
|
||||||
fn receive(&mut self, request: wl_shm_pool::Request, pool: Resource<wl_shm_pool::WlShmPool>) {
|
fn receive_pool_message(
|
||||||
|
&mut self,
|
||||||
|
request: wl_shm_pool::Request,
|
||||||
|
pool: Resource<wl_shm_pool::WlShmPool>,
|
||||||
|
) {
|
||||||
use self::wl_shm_pool::Request;
|
use self::wl_shm_pool::Request;
|
||||||
|
|
||||||
let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
|
let arc_pool = pool.user_data::<Arc<Pool>>().unwrap();
|
||||||
|
|
||||||
match request {
|
match request {
|
||||||
Request::CreateBuffer {
|
Request::CreateBuffer {
|
||||||
|
@ -246,7 +268,7 @@ impl Implementation<Resource<wl_shm_pool::WlShmPool>, wl_shm_pool::Request> for
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let data = Box::into_raw(Box::new(InternalBufferData {
|
let data = InternalBufferData {
|
||||||
pool: arc_pool.clone(),
|
pool: arc_pool.clone(),
|
||||||
data: BufferData {
|
data: BufferData {
|
||||||
offset,
|
offset,
|
||||||
|
@ -255,15 +277,16 @@ impl Implementation<Resource<wl_shm_pool::WlShmPool>, wl_shm_pool::Request> for
|
||||||
stride,
|
stride,
|
||||||
format,
|
format,
|
||||||
},
|
},
|
||||||
}));
|
};
|
||||||
let buffer = buffer.implement_nonsend(
|
buffer.implement_nonsend(
|
||||||
self.clone(),
|
|req, _| {
|
||||||
Some(|buffer: Resource<_>, _| {
|
// this will break if a variant is added to wl_buffer::Request
|
||||||
drop(unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) })
|
let wl_buffer::Request::Destroy = req;
|
||||||
}),
|
},
|
||||||
|
None::<fn(_)>,
|
||||||
|
data,
|
||||||
&self.token,
|
&self.token,
|
||||||
);
|
);
|
||||||
buffer.set_user_data(data as *mut ());
|
|
||||||
}
|
}
|
||||||
Request::Resize { size } => match arc_pool.resize(size) {
|
Request::Resize { size } => match arc_pool.resize(size) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
|
@ -281,10 +304,3 @@ impl Implementation<Resource<wl_shm_pool::WlShmPool>, wl_shm_pool::Request> for
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Implementation<Resource<wl_buffer::WlBuffer>, wl_buffer::Request> for ShmGlobalData {
|
|
||||||
fn receive(&mut self, request: wl_buffer::Request, _pool: Resource<wl_buffer::WlBuffer>) {
|
|
||||||
// this will break if new requests are added to buffer =)
|
|
||||||
let wl_buffer::Request::Destroy = request;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use nix::{libc, unistd};
|
|
||||||
use nix::sys::mman;
|
use nix::sys::mman;
|
||||||
use nix::sys::signal::{self, SigAction, SigHandler, Signal};
|
use nix::sys::signal::{self, SigAction, SigHandler, Signal};
|
||||||
|
use nix::{libc, unistd};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
mod xserver;
|
|
||||||
mod x11_sockets;
|
mod x11_sockets;
|
||||||
|
mod xserver;
|
||||||
|
|
||||||
pub use self::xserver::{XWayland, XWindowManager};
|
pub use self::xserver::{XWayland, XWindowManager};
|
||||||
|
|
|
@ -2,9 +2,9 @@ use std::io::{Read, Write};
|
||||||
use std::os::unix::io::FromRawFd;
|
use std::os::unix::io::FromRawFd;
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
|
|
||||||
use nix::{Error as NixError, Result as NixResult};
|
|
||||||
use nix::errno::Errno;
|
use nix::errno::Errno;
|
||||||
use nix::sys::socket;
|
use nix::sys::socket;
|
||||||
|
use nix::{Error as NixError, Result as NixResult};
|
||||||
|
|
||||||
/// Find a free X11 display slot and setup
|
/// Find a free X11 display slot and setup
|
||||||
pub(crate) fn prepare_x11_sockets(log: ::slog::Logger) -> Result<(X11Lock, [UnixStream; 2]), ()> {
|
pub(crate) fn prepare_x11_sockets(log: ::slog::Logger) -> Result<(X11Lock, [UnixStream; 2]), ()> {
|
||||||
|
@ -62,11 +62,13 @@ impl X11Lock {
|
||||||
let mut spid = [0u8; 11];
|
let mut spid = [0u8; 11];
|
||||||
file.read_exact(&mut spid).map_err(|_| ())?;
|
file.read_exact(&mut spid).map_err(|_| ())?;
|
||||||
::std::mem::drop(file);
|
::std::mem::drop(file);
|
||||||
let pid = ::nix::unistd::Pid::from_raw(::std::str::from_utf8(&spid)
|
let pid = ::nix::unistd::Pid::from_raw(
|
||||||
|
::std::str::from_utf8(&spid)
|
||||||
.map_err(|_| ())?
|
.map_err(|_| ())?
|
||||||
.trim()
|
.trim()
|
||||||
.parse::<i32>()
|
.parse::<i32>()
|
||||||
.map_err(|_| ())?);
|
.map_err(|_| ())?,
|
||||||
|
);
|
||||||
if let Err(NixError::Sys(Errno::ESRCH)) = ::nix::sys::signal::kill(pid, None) {
|
if let Err(NixError::Sys(Errno::ESRCH)) = ::nix::sys::signal::kill(pid, None) {
|
||||||
// no process whose pid equals the contents of the lockfile exists
|
// no process whose pid equals the contents of the lockfile exists
|
||||||
// remove the lockfile and try grabbing it again
|
// remove the lockfile and try grabbing it again
|
||||||
|
|
|
@ -25,21 +25,22 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::os::unix::io::{AsRawFd, IntoRawFd};
|
use std::os::unix::io::{AsRawFd, IntoRawFd};
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use nix::{Error as NixError, Result as NixResult};
|
|
||||||
use nix::errno::Errno;
|
use nix::errno::Errno;
|
||||||
use nix::unistd::{fork, ForkResult, Pid};
|
|
||||||
use nix::sys::signal;
|
use nix::sys::signal;
|
||||||
|
use nix::unistd::{fork, ForkResult, Pid};
|
||||||
|
use nix::{Error as NixError, Result as NixResult};
|
||||||
|
|
||||||
use wayland_server::{Client, Display, LoopToken};
|
use wayland_server::calloop::signals::{Signal, Signals};
|
||||||
use wayland_server::sources::{SignalEvent, Source};
|
use wayland_server::calloop::{LoopHandle, Source};
|
||||||
|
use wayland_server::{Client, Display};
|
||||||
|
|
||||||
use super::x11_sockets::{X11Lock, prepare_x11_sockets};
|
use super::x11_sockets::{prepare_x11_sockets, X11Lock};
|
||||||
|
|
||||||
/// The XWayland handle
|
/// The XWayland handle
|
||||||
pub struct XWayland<WM: XWindowManager> {
|
pub struct XWayland<WM: XWindowManager> {
|
||||||
|
@ -66,9 +67,9 @@ pub trait XWindowManager {
|
||||||
|
|
||||||
impl<WM: XWindowManager + 'static> XWayland<WM> {
|
impl<WM: XWindowManager + 'static> XWayland<WM> {
|
||||||
/// Start the XWayland server
|
/// Start the XWayland server
|
||||||
pub fn init<L>(
|
pub fn init<L, Data: 'static>(
|
||||||
wm: WM,
|
wm: WM,
|
||||||
token: LoopToken,
|
handle: LoopHandle<Data>,
|
||||||
display: Rc<RefCell<Display>>,
|
display: Rc<RefCell<Display>>,
|
||||||
logger: L,
|
logger: L,
|
||||||
) -> Result<XWayland<WM>, ()>
|
) -> Result<XWayland<WM>, ()>
|
||||||
|
@ -78,7 +79,16 @@ impl<WM: XWindowManager + 'static> XWayland<WM> {
|
||||||
let log = ::slog_or_stdlog(logger);
|
let log = ::slog_or_stdlog(logger);
|
||||||
let inner = Rc::new(RefCell::new(Inner {
|
let inner = Rc::new(RefCell::new(Inner {
|
||||||
wm,
|
wm,
|
||||||
token,
|
source_maker: Box::new(move |inner| {
|
||||||
|
handle
|
||||||
|
.insert_source(
|
||||||
|
Signals::new(&[Signal::SIGUSR1]).map_err(|_| ())?,
|
||||||
|
move |evt, _| {
|
||||||
|
debug_assert!(evt.signal() == Signal::SIGUSR1);
|
||||||
|
xwayland_ready(&inner);
|
||||||
|
},
|
||||||
|
).map_err(|_| ())
|
||||||
|
}),
|
||||||
wayland_display: display,
|
wayland_display: display,
|
||||||
instance: None,
|
instance: None,
|
||||||
log: log.new(o!("smithay_module" => "XWayland")),
|
log: log.new(o!("smithay_module" => "XWayland")),
|
||||||
|
@ -97,7 +107,7 @@ impl<WM: XWindowManager> Drop for XWayland<WM> {
|
||||||
struct XWaylandInstance {
|
struct XWaylandInstance {
|
||||||
display_lock: X11Lock,
|
display_lock: X11Lock,
|
||||||
wayland_client: Client,
|
wayland_client: Client,
|
||||||
sigusr1_handler: Option<Source<SignalEvent>>,
|
sigusr1_handler: Option<Source<Signals>>,
|
||||||
wm_fd: Option<UnixStream>,
|
wm_fd: Option<UnixStream>,
|
||||||
started_at: ::std::time::Instant,
|
started_at: ::std::time::Instant,
|
||||||
child_pid: Option<Pid>,
|
child_pid: Option<Pid>,
|
||||||
|
@ -106,7 +116,7 @@ struct XWaylandInstance {
|
||||||
// Inner implementation of the XWayland manager
|
// Inner implementation of the XWayland manager
|
||||||
struct Inner<WM: XWindowManager> {
|
struct Inner<WM: XWindowManager> {
|
||||||
wm: WM,
|
wm: WM,
|
||||||
token: LoopToken,
|
source_maker: Box<FnMut(Rc<RefCell<Inner<WM>>>) -> Result<Source<Signals>, ()>>,
|
||||||
wayland_display: Rc<RefCell<Display>>,
|
wayland_display: Rc<RefCell<Display>>,
|
||||||
instance: Option<XWaylandInstance>,
|
instance: Option<XWaylandInstance>,
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
|
@ -140,17 +150,11 @@ fn launch<WM: XWindowManager + 'static>(inner: &Rc<RefCell<Inner<WM>>>) -> Resul
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.create_client(wl_me.into_raw_fd())
|
.create_client(wl_me.into_raw_fd())
|
||||||
};
|
};
|
||||||
client.set_user_data(Rc::into_raw(inner.clone()) as *const () as *mut ());
|
client.data_map().insert_if_missing(|| inner.clone());
|
||||||
client.set_destructor(client_destroy::<WM>);
|
client.add_destructor(client_destroy::<WM>);
|
||||||
|
|
||||||
// setup the SIGUSR1 handler
|
// setup the SIGUSR1 handler
|
||||||
let my_inner = inner.clone();
|
let sigusr1_handler = (&mut *guard.source_maker)(inner.clone())?;
|
||||||
let sigusr1_handler = guard
|
|
||||||
.token
|
|
||||||
.add_signal_event_source(signal::Signal::SIGUSR1, move |_, ()| {
|
|
||||||
xwayland_ready(&my_inner)
|
|
||||||
})
|
|
||||||
.map_err(|_| ())?;
|
|
||||||
|
|
||||||
// all is ready, we can do the fork dance
|
// all is ready, we can do the fork dance
|
||||||
let child_pid = match fork() {
|
let child_pid = match fork() {
|
||||||
|
@ -242,8 +246,8 @@ impl<WM: XWindowManager> Inner<WM> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn client_destroy<WM: XWindowManager + 'static>(data: *mut ()) {
|
fn client_destroy<WM: XWindowManager + 'static>(map: &::wayland_server::UserDataMap) {
|
||||||
let inner = unsafe { Rc::from_raw(data as *const () as *const RefCell<Inner<WM>>) };
|
let inner = map.get::<Rc<RefCell<Inner<WM>>>>().unwrap();
|
||||||
|
|
||||||
// shutdown the server
|
// shutdown the server
|
||||||
let started_at = inner.borrow().instance.as_ref().map(|i| i.started_at);
|
let started_at = inner.borrow().instance.as_ref().map(|i| i.started_at);
|
||||||
|
|
|
@ -19,6 +19,9 @@ containers:
|
||||||
- !Container base
|
- !Container base
|
||||||
- !Env HOME: /work/.vagga/stable-home
|
- !Env HOME: /work/.vagga/stable-home
|
||||||
- !Sh curl https://sh.rustup.rs -sSf | sh -s -- -y --default-host x86_64-unknown-linux-gnu --default-toolchain stable --no-modify-path
|
- !Sh curl https://sh.rustup.rs -sSf | sh -s -- -y --default-host x86_64-unknown-linux-gnu --default-toolchain stable --no-modify-path
|
||||||
|
- !Env PATH: /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/work/.vagga/stable-home/.cargo/bin:/work/.vagga/stable-home/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/
|
||||||
|
- !Sh rustup self update
|
||||||
|
- !Sh rustup component add rustfmt-preview
|
||||||
|
|
||||||
beta:
|
beta:
|
||||||
auto-clean: true
|
auto-clean: true
|
||||||
|
@ -45,7 +48,7 @@ containers:
|
||||||
- !Sh curl https://sh.rustup.rs -sSf | sh -s -- -y --default-host x86_64-unknown-linux-gnu --default-toolchain nightly --no-modify-path
|
- !Sh curl https://sh.rustup.rs -sSf | sh -s -- -y --default-host x86_64-unknown-linux-gnu --default-toolchain nightly --no-modify-path
|
||||||
- !Env PATH: /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/work/.vagga/nightly-home/.cargo/bin:/work/.vagga/nightly-home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/
|
- !Env PATH: /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/work/.vagga/nightly-home/.cargo/bin:/work/.vagga/nightly-home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/
|
||||||
- !Sh rustup self update
|
- !Sh rustup self update
|
||||||
- !Sh rustup component add rustfmt-preview
|
- !Sh rustup component add clippy-preview
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
update-stable: !Command
|
update-stable: !Command
|
||||||
|
|
Loading…
Reference in New Issue