deps: Update smithay

Integrate new multigpu allocator code for gpu->gpu copies using the vulkan allocator.

Also integrates Xwayland clipboard sync.
This commit is contained in:
Victoria Brekenfeld 2023-02-13 17:44:24 +01:00
parent 32762fb983
commit 4a9dfcead0
11 changed files with 450 additions and 115 deletions

7
Cargo.lock generated
View file

@ -1753,9 +1753,9 @@ dependencies = [
[[package]]
name = "input"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4669c07fe301ce2eb323ff23b9480e6a19d8e94520236862caca51b2b5c45e3"
checksum = "eeb3afdf1f8137428002b354eaf87aa629178995683941d94b04c6d145ec8937"
dependencies = [
"bitflags",
"input-sys",
@ -3292,9 +3292,10 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "smithay"
version = "0.3.0"
source = "git+https://github.com/pop-os/smithay?rev=3437fe15ca#3437fe15caf1661bc3e93a9a20425be3189a4dc7"
source = "git+https://github.com/smithay//smithay?rev=09e29418e5#09e29418e5d973dd21fc636433cca0b4dc3a17b3"
dependencies = [
"appendlist",
"ash",
"bitflags",
"calloop",
"cc",

View file

@ -47,7 +47,7 @@ version = "0.3"
git = "https://github.com/Smithay/smithay.git"
rev = "2de946cf9e"
default-features = false
features = ["backend_drm", "backend_gbm", "backend_egl", "backend_libinput", "backend_session_libseat", "backend_udev", "backend_winit", "backend_x11", "desktop", "use_system_lib", "renderer_glow", "renderer_multi", "wayland_frontend", "slog-stdlog", "xwayland"]
features = ["backend_drm", "backend_gbm", "backend_egl", "backend_libinput", "backend_session_libseat", "backend_udev", "backend_winit", "backend_vulkan", "backend_x11", "desktop", "use_system_lib", "renderer_glow", "renderer_multi", "wayland_frontend", "slog-stdlog", "xwayland"]
[dependencies.smithay-egui]
git = "https://github.com/Smithay/smithay-egui.git"
@ -70,4 +70,4 @@ debug = true
lto = "fat"
[patch."https://github.com/Smithay/smithay.git"]
smithay = { git = "https://github.com/pop-os/smithay", rev = "3437fe15ca" }
smithay = { git = "https://github.com/smithay//smithay", rev = "09e29418e5" }

View file

@ -15,7 +15,12 @@ use crate::{
use anyhow::{Context, Result};
use smithay::{
backend::{
allocator::{dmabuf::Dmabuf, gbm::GbmDevice, Format},
allocator::{
dmabuf::{AnyError, Dmabuf, DmabufAllocator},
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
vulkan::{ImageUsageFlags, VulkanAllocator},
Allocator, Format,
},
drm::{
DrmDevice, DrmDeviceFd, DrmEvent, DrmEventTime, DrmNode, GbmBufferedSurface, NodeType,
},
@ -26,10 +31,11 @@ use smithay::{
damage::DamageTrackedRenderer,
gles2::Gles2Renderbuffer,
glow::GlowRenderer,
multigpu::{egl::EglGlesBackend, GpuManager},
multigpu::{gbm::GbmGlesBackend, GpuManager},
},
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
vulkan::{version::Version, Instance, PhysicalDevice},
},
desktop::utils::OutputPresentationFeedback,
input::Seat,
@ -53,6 +59,7 @@ use smithay::{
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
ffi::CStr,
os::unix::io::FromRawFd,
path::PathBuf,
time::Duration,
@ -68,7 +75,7 @@ const MIN_RENDER_TIME: Duration = Duration::from_millis(3);
pub struct KmsState {
devices: HashMap<DrmNode, Device>,
pub api: GpuManager<EglGlesBackend<GlowRenderer>>,
pub api: GpuManager<GbmGlesBackend<GlowRenderer>>,
pub primary: DrmNode,
session: LibSeatSession,
_tokens: Vec<RegistrationToken>,
@ -77,8 +84,9 @@ pub struct KmsState {
pub struct Device {
render_node: DrmNode,
surfaces: HashMap<crtc::Handle, Surface>,
allocator: GbmDevice<DrmDeviceFd>,
drm: Dispatcher<'static, DrmDevice, Data>,
gbm: GbmDevice<DrmDeviceFd>,
allocator: Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>,
formats: HashSet<Format>,
supports_atomic: bool,
event_token: Option<RegistrationToken>,
@ -86,7 +94,8 @@ pub struct Device {
}
pub struct Surface {
surface: Option<GbmBufferedSurface<GbmDevice<DrmDeviceFd>, Option<OutputPresentationFeedback>>>,
surface:
Option<GbmBufferedSurface<GbmAllocator<DrmDeviceFd>, Option<OutputPresentationFeedback>>>,
damage_tracker: DamageTrackedRenderer,
connector: connector::Handle,
output: Output,
@ -137,7 +146,7 @@ pub fn init_backend(
})
.map_err(|err| err.error)
.context("Failed to initialize libinput event source")?;
let api = GpuManager::new(EglGlesBackend::<GlowRenderer>::default(), None)
let api = GpuManager::new(GbmGlesBackend::<GlowRenderer>::default(), None)
.context("Failed to initialize renderers")?;
// TODO get this info from system76-power, if available and setup a watcher
@ -359,12 +368,7 @@ impl State {
.try_get_render_node()
.ok()
.and_then(std::convert::identity)
.with_context(|| {
format!(
"Failed to determine path of egl device for {}",
path.display()
)
})?;
.unwrap_or(drm_node);
let egl_context = EGLContext::new(&egl_display, None).with_context(|| {
format!(
"Failed to create EGLContext for device {:?}:{}",
@ -483,10 +487,15 @@ impl State {
}
};
let allocator = Box::new(DmabufAllocator(GbmAllocator::new(
gbm.clone(),
GbmBufferFlags::RENDERING,
)));
let mut device = Device {
render_node,
surfaces: HashMap::new(),
allocator: gbm,
gbm,
allocator,
drm: dispatcher,
formats,
supports_atomic,
@ -500,7 +509,7 @@ impl State {
{
let backend = self.backend.kms();
for (crtc, conn) in outputs {
let mut renderer = match backend.api.renderer(&render_node, &render_node) {
let mut renderer = match backend.api.single_renderer(&render_node) {
Ok(renderer) => renderer,
Err(err) => {
slog_scope::warn!("Failed to initialize output: {}", err);
@ -536,6 +545,44 @@ impl State {
&self.common.event_loop_handle,
);
if let Ok(instance) = Instance::new(Version::VERSION_1_2, None, None) {
if let Some(physical_device) =
PhysicalDevice::enumerate(&instance)
.ok()
.and_then(|devices| {
devices
.filter(|phd| {
phd.has_device_extension(unsafe {
CStr::from_bytes_with_nul_unchecked(
b"VK_EXT_physical_device_drm\0",
)
})
})
.find(|phd| {
phd.primary_node().unwrap() == Some(render_node)
|| phd.render_node().unwrap() == Some(render_node)
})
})
{
match VulkanAllocator::new(
&physical_device,
ImageUsageFlags::COLOR_ATTACHMENT | ImageUsageFlags::SAMPLED,
) {
Ok(allocator) => {
self.backend
.kms()
.devices
.get_mut(&drm_node)
.unwrap()
.allocator = Box::new(DmabufAllocator(allocator));
}
Err(err) => {
slog_scope::warn!("Failed to create vulkan allocator: {}", err);
}
}
}
}
Ok(())
}
@ -562,10 +609,7 @@ impl State {
}
}
for (crtc, conn) in changes.added {
let mut renderer = match backend
.api
.renderer(&device.render_node, &device.render_node)
{
let mut renderer = match backend.api.single_renderer(&device.render_node) {
Ok(renderer) => renderer,
Err(err) => {
slog_scope::warn!("Failed to initialize output: {}", err);
@ -701,7 +745,7 @@ impl Device {
crtc: crtc::Handle,
conn: connector::Handle,
position: (i32, i32),
renderer: &mut GlMultiRenderer<'_>,
renderer: &mut GlMultiRenderer<'_, '_>,
) -> Result<Output> {
let drm = &mut *self.drm.as_source_mut();
let crtc_info = drm.get_crtc(crtc)?;
@ -828,8 +872,11 @@ fn render_node_for_output(
impl Surface {
pub fn render_output(
&mut self,
dh: &DisplayHandle,
api: &mut GpuManager<EglGlesBackend<GlowRenderer>>,
api: &mut GpuManager<GbmGlesBackend<GlowRenderer>>,
render_node: Option<(
&DrmNode,
&mut dyn Allocator<Buffer = Dmabuf, Error = AnyError>,
)>,
target_node: &DrmNode,
state: &mut Common,
screencopy: Option<&[(ScreencopySession, BufferParams)]>,
@ -838,10 +885,16 @@ impl Surface {
return Ok(());
}
let render_node = render_node_for_output(dh, &self.output, *target_node, &state.shell);
let mut renderer: GlMultiRenderer = api.renderer(&render_node, &target_node).unwrap();
let surface = self.surface.as_mut().unwrap();
let (render_node, mut renderer) = match render_node {
Some((render_node, allocator)) => (
render_node,
api.renderer(&render_node, &target_node, allocator, surface.format())
.unwrap(),
),
None => (target_node, api.single_renderer(&target_node).unwrap()),
};
let (buffer, age) = surface
.next_buffer()
.with_context(|| "Failed to allocate buffer")?;
@ -957,7 +1010,10 @@ impl KmsState {
let drm_surface = drm.create_surface(*crtc, *mode, &[conn])?;
let target = GbmBufferedSurface::new(
drm_surface,
device.allocator.clone(),
GbmAllocator::new(
device.gbm.clone(),
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
),
device.formats.clone(),
None,
)
@ -1051,7 +1107,7 @@ impl KmsState {
{
return self
.api
.renderer::<Gles2Renderbuffer>(&device.render_node, &device.render_node)?
.single_renderer(&device.render_node)?
.import_dmabuf(&dmabuf, None)
.map(|_| ())
.map_err(Into::into);
@ -1100,28 +1156,59 @@ impl KmsState {
},
move |_time, _, data| {
let backend = data.state.backend.kms();
if let Some(device) = backend.devices.get_mut(&device) {
if let Some(surface) = device.surfaces.get_mut(&crtc) {
match surface.render_output(
&data.display.handle(),
let (mut device, mut other) = backend
.devices
.iter_mut()
.partition::<Vec<_>, _>(|(key, _val)| *key == &device);
let target_device = &mut device[0].1;
if let Some(surface) = target_device.surfaces.get_mut(&crtc) {
let target_node = target_device.render_node;
let render_node = render_node_for_output(
&data.display.handle(),
&surface.output,
target_node,
&data.state.common.shell,
);
let state = &mut data.state.common;
let result = if render_node != target_node {
let render_device = &mut other
.iter_mut()
.find(|(_, val)| val.render_node == render_node)
.unwrap()
.1;
surface.render_output(
&mut backend.api,
&device.render_node,
&mut data.state.common,
Some((
&render_device.render_node,
render_device.allocator.as_mut(),
)),
&target_node,
state,
screencopy_sessions.as_deref(),
) {
Ok(_) => return TimeoutAction::Drop,
Err(err) => {
if backend.session.is_active() {
slog_scope::error!("Error rendering: {}", err);
return TimeoutAction::ToDuration(
Duration::from_secs_f64(
(1000.0 / surface.refresh_rate as f64) - 0.003,
),
);
}
)
} else {
surface.render_output(
&mut backend.api,
None,
&target_node,
state,
screencopy_sessions.as_deref(),
)
};
match result {
Ok(_) => return TimeoutAction::Drop,
Err(err) => {
if backend.session.is_active() {
slog_scope::error!("Error rendering: {}", err);
return TimeoutAction::ToDuration(Duration::from_secs_f64(
(1000.0 / surface.refresh_rate as f64) - 0.003,
));
}
};
}
}
};
}
if let Some(sessions) = screencopy_sessions.as_mut() {

View file

@ -154,15 +154,15 @@ impl RenderElement<GlowRenderer> for CosmicElement<GlowRenderer> {
}
}
impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicElement<GlMultiRenderer<'a>> {
impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>> for CosmicElement<GlMultiRenderer<'a, 'b>> {
fn draw<'frame>(
&self,
frame: &mut GlMultiFrame<'a, 'frame>,
frame: &mut GlMultiFrame<'a, 'b, 'frame>,
src: Rectangle<f64, BufferCoords>,
dst: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<(), <GlMultiRenderer<'_> as Renderer>::Error> {
) -> Result<(), <GlMultiRenderer<'a, 'b> as Renderer>::Error> {
match self {
CosmicElement::Workspace(elem) => elem.draw(frame, src, dst, damage, log),
CosmicElement::Cursor(elem) => elem.draw(frame, src, dst, damage, log),
@ -181,8 +181,8 @@ impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicElement<GlMultiRenderer<'a
fn underlying_storage(
&self,
renderer: &GlMultiRenderer<'a>,
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a>>> {
renderer: &GlMultiRenderer<'a, 'b>,
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a, 'b>>> {
match self {
CosmicElement::Workspace(elem) => elem.underlying_storage(renderer),
CosmicElement::Cursor(elem) => elem.underlying_storage(renderer),
@ -263,7 +263,7 @@ impl AsGlowRenderer for GlowRenderer {
}
}
impl<'a> AsGlowRenderer for GlMultiRenderer<'a> {
impl<'a, 'b> AsGlowRenderer for GlMultiRenderer<'a, 'b> {
fn glow_renderer(&self) -> &GlowRenderer {
self.as_ref()
}
@ -289,7 +289,7 @@ impl<'frame> AsGlowFrame<'frame> for GlowFrame<'frame> {
}
}
impl<'renderer, 'frame> AsGlowFrame<'frame> for GlMultiFrame<'renderer, 'frame> {
impl<'renderer, 'alloc, 'frame> AsGlowFrame<'frame> for GlMultiFrame<'renderer, 'alloc, 'frame> {
fn glow_frame(&self) -> &GlowFrame<'frame> {
self.as_ref()
}

View file

@ -27,9 +27,9 @@ use smithay::{
DamageTrackedRenderer, DamageTrackedRendererError as RenderError, OutputNoMode,
},
element::{RenderElement, RenderElementStates},
gles2::{Gles2Error, Gles2Renderbuffer},
gles2::Gles2Error,
glow::GlowRenderer,
multigpu::{egl::EglGlesBackend, MultiFrame, MultiRenderer},
multigpu::{gbm::GbmGlesBackend, MultiFrame, MultiRenderer},
Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter,
},
},
@ -43,21 +43,10 @@ use self::cursor::CursorRenderElement;
pub mod element;
use self::element::{AsGlowRenderer, CosmicElement};
pub type GlMultiRenderer<'a> = MultiRenderer<
'a,
'a,
EglGlesBackend<GlowRenderer>,
EglGlesBackend<GlowRenderer>,
Gles2Renderbuffer,
>;
pub type GlMultiFrame<'a, 'frame> = MultiFrame<
'a,
'a,
'frame,
EglGlesBackend<GlowRenderer>,
EglGlesBackend<GlowRenderer>,
Gles2Renderbuffer,
>;
pub type GlMultiRenderer<'a, 'b> =
MultiRenderer<'a, 'a, 'b, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
pub type GlMultiFrame<'a, 'b, 'frame> =
MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0];

View file

@ -11,14 +11,19 @@ use crate::{
use anyhow::{Context, Result};
use smithay::{
backend::{
allocator::dmabuf::Dmabuf,
drm::DrmDeviceFd,
egl::{EGLContext, EGLDisplay},
allocator::{
dmabuf::{Dmabuf, DmabufAllocator},
gbm::{GbmAllocator, GbmBufferFlags},
vulkan::{ImageUsageFlags, VulkanAllocator},
},
drm::{DrmDeviceFd, DrmNode},
egl::{EGLContext, EGLDevice, EGLDisplay},
input::{Event, InputEvent},
renderer::{
damage::DamageTrackedRenderer, gles2::Gles2Renderbuffer, glow::GlowRenderer, Bind,
ImportDma, ImportEgl,
},
vulkan::{version::Version, Instance, PhysicalDevice},
x11::{Window, WindowBuilder, X11Backend, X11Event, X11Handle, X11Input, X11Surface},
},
desktop::layer_map_for_output,
@ -31,13 +36,18 @@ use smithay::{
},
utils::{DeviceFd, Transform},
};
use std::cell::RefCell;
use std::{cell::RefCell, os::unix::io::OwnedFd};
#[cfg(feature = "debug")]
use crate::state::Fps;
enum Allocator {
Gbm(GbmAllocator<DrmDeviceFd>),
Vulkan(PhysicalDevice),
}
pub struct X11State {
allocator: GbmDevice<DrmDeviceFd>,
allocator: Allocator,
_egl: EGLDisplay,
pub renderer: GlowRenderer,
surfaces: Vec<Surface>,
@ -51,18 +61,28 @@ impl X11State {
.build(&self.handle)
.with_context(|| "Failed to create window")?;
let fourcc = window.format();
let surface = self
.handle
.create_surface(
&window,
self.allocator.clone(),
Bind::<Dmabuf>::supported_formats(&self.renderer)
.unwrap()
.iter()
.filter(|format| format.code == fourcc)
.map(|format| format.modifier),
)
.with_context(|| "Failed to create surface")?;
let modifiers = Bind::<Dmabuf>::supported_formats(&self.renderer).unwrap();
let filtered_modifiers = modifiers
.iter()
.filter(|format| format.code == fourcc)
.map(|format| format.modifier);
let surface = match &self.allocator {
Allocator::Gbm(gbm) => self
.handle
.create_surface(&window, DmabufAllocator(gbm.clone()), filtered_modifiers)
.with_context(|| "Failed to create surface")?,
Allocator::Vulkan(vulkan) => self
.handle
.create_surface(
&window,
DmabufAllocator(
VulkanAllocator::new(vulkan, ImageUsageFlags::COLOR_ATTACHMENT)
.with_context(|| "Failed to create vulkan allocator for window")?,
),
filtered_modifiers,
)
.with_context(|| "Failed to create surface")?,
};
let name = format!("X11-{}", self.surfaces.len());
let size = window.size();
@ -251,6 +271,57 @@ impl Surface {
}
}
fn try_vulkan_allocator(node: &DrmNode) -> Option<Allocator> {
let instance = match Instance::new(Version::VERSION_1_2, None, None) {
Ok(instance) => instance,
Err(err) => {
slog_scope::warn!(
"Failed to instanciate vulkan, falling back to gbm allocator: {}",
err
);
return None;
}
};
let devices = match PhysicalDevice::enumerate(&instance) {
Ok(devices) => devices,
Err(err) => {
slog_scope::debug!("No vulkan devices, falling back to gbm: {}", err);
return None;
}
};
let Some(device) = devices
.filter(|phd| {
phd.has_device_extension(smithay::reexports::ash::extensions::ext::PhysicalDeviceDrm::name())
})
.find(|phd| {
phd.primary_node().unwrap() == Some(*node) || phd.render_node().unwrap() == Some(*node)
})
else {
slog_scope::debug!("No vulkan device for node {:?}, falling back to gbm", node);
return None;
};
Some(Allocator::Vulkan(device))
}
fn try_gbm_allocator(fd: OwnedFd) -> Option<Allocator> {
// Create the gbm device for buffer allocation.
let device = match GbmDevice::new(DrmDeviceFd::new(DeviceFd::from(fd), None)) {
Ok(gbm) => gbm,
Err(err) => {
slog_scope::error!("Failed to create GBM device: {}", err);
return None;
}
};
Some(Allocator::Gbm(GbmAllocator::new(
device,
GbmBufferFlags::RENDERING,
)))
}
pub fn init_backend(
dh: &DisplayHandle,
event_loop: &mut EventLoop<Data>,
@ -260,16 +331,16 @@ pub fn init_backend(
let handle = backend.handle();
// Obtain the DRM node the X server uses for direct rendering.
let (_drm_node, fd) = handle
let (drm_node, fd) = handle
.drm_node()
.with_context(|| "Could not get DRM node used by X server")?;
// Create the gbm device for buffer allocation.
let device = GbmDevice::new(DrmDeviceFd::new(DeviceFd::from(fd), None))
.with_context(|| "Failed to create GBM device")?;
// Initialize EGL using the GBM device.
let egl =
EGLDisplay::new(device.clone(), None).with_context(|| "Failed to create EGL display")?;
let device = EGLDevice::enumerate()
.with_context(|| "Failed to enumerate EGL devices")?
.find(|device| device.try_get_render_node().ok().flatten() == Some(drm_node))
.with_context(|| format!("Failed to find EGLDevice for node {}", drm_node))?;
// Initialize EGL
let egl = EGLDisplay::new(device, None).with_context(|| "Failed to create EGL display")?;
// Create the OpenGL context
let context = EGLContext::new(&egl, None).with_context(|| "Failed to create EGL context")?;
// Create a renderer
@ -280,7 +351,9 @@ pub fn init_backend(
state.backend = BackendData::X11(X11State {
handle,
allocator: device,
allocator: try_vulkan_allocator(&drm_node)
.or_else(|| try_gbm_allocator(fd))
.expect("Failed to create allocator for x11"),
_egl: egl,
renderer,
surfaces: Vec::new(),

View file

@ -775,15 +775,17 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
}
}
impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicMappedRenderElement<GlMultiRenderer<'a>> {
impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
for CosmicMappedRenderElement<GlMultiRenderer<'a, 'b>>
{
fn draw<'frame>(
&self,
frame: &mut GlMultiFrame<'a, 'frame>,
frame: &mut GlMultiFrame<'a, 'b, 'frame>,
src: Rectangle<f64, BufferCoords>,
dst: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<(), <GlMultiRenderer<'_> as Renderer>::Error> {
) -> Result<(), <GlMultiRenderer<'a, 'b> as Renderer>::Error> {
match self {
CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage, log),
CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage, log),
@ -798,8 +800,8 @@ impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicMappedRenderElement<GlMult
fn underlying_storage(
&self,
renderer: &GlMultiRenderer<'a>,
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a>>> {
renderer: &GlMultiRenderer<'a, 'b>,
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a, 'b>>> {
match self {
CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer),

View file

@ -7,10 +7,12 @@ use smithay::{
reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface},
utils::IsAlive,
wayland::data_device::{
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
with_source_metadata, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState,
ServerDndGrabHandler,
},
xwayland::xwm::{SelectionType, XwmId},
};
use std::cell::RefCell;
use std::{cell::RefCell, os::unix::io::OwnedFd};
pub struct DnDIcon {
surface: RefCell<Option<WlSurface>>,
@ -48,9 +50,54 @@ impl ClientDndGrabHandler for State {
}
impl ServerDndGrabHandler for State {}
impl DataDeviceHandler for State {
type SelectionUserData = XwmId;
fn data_device_state(&self) -> &DataDeviceState {
&self.common.data_device_state
}
fn new_selection(&mut self, source: Option<WlDataSource>) {
for xstate in self.common.xwayland_state.values_mut() {
if let Some(xwm) = xstate.xwm.as_mut() {
if let Some(source) = &source {
if let Ok(Err(err)) = with_source_metadata(source, |metadata| {
xwm.new_selection(
SelectionType::Clipboard,
Some(metadata.mime_types.clone()),
)
}) {
slog_scope::warn!("Failed to set Xwayland clipboard selection: {}", err);
}
} else if let Err(err) = xwm.new_selection(SelectionType::Clipboard, None) {
slog_scope::warn!("Failed to clear Xwayland clipboard selection: {}", err);
}
}
}
}
fn send_selection(
&mut self,
mime_type: String,
fd: OwnedFd,
user_data: &Self::SelectionUserData,
) {
if let Some(xwm) = self
.common
.xwayland_state
.values_mut()
.flat_map(|xstate| xstate.xwm.as_mut())
.find(|xwm| &xwm.id() == user_data)
{
if let Err(err) = xwm.send_selection(
SelectionType::Clipboard,
mime_type,
fd,
self.common.event_loop_handle.clone(),
) {
slog_scope::warn!("Failed to send clipboard (X11 -> Wayland): {}", err);
}
}
}
}
delegate_data_device!(State);

View file

@ -3,13 +3,57 @@
use crate::state::State;
use smithay::{
delegate_primary_selection,
wayland::primary_selection::{PrimarySelectionHandler, PrimarySelectionState},
wayland::primary_selection::{PrimarySelectionHandler, PrimarySelectionState, with_source_metadata}, xwayland::xwm::{XwmId, SelectionType}, reexports::wayland_protocols::wp::primary_selection::zv1::server::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
};
use std::os::unix::io::OwnedFd;
impl PrimarySelectionHandler for State {
type SelectionUserData = XwmId;
fn primary_selection_state(&self) -> &PrimarySelectionState {
&self.common.primary_selection_state
}
fn new_selection(&mut self, source: Option<ZwpPrimarySelectionSourceV1>) {
for xstate in self.common.xwayland_state.values_mut() {
if let Some(xwm) = xstate.xwm.as_mut() {
if let Some(source) = &source {
if let Ok(Err(err)) = with_source_metadata(source, |metadata| {
xwm.new_selection(SelectionType::Primary, Some(metadata.mime_types.clone()))
}) {
slog_scope::warn!("Failed to set Xwayland primary selection: {}", err);
}
} else if let Err(err) = xwm.new_selection(SelectionType::Primary, None) {
slog_scope::warn!("Failed to clear Xwayland primary selection: {}", err);
}
}
}
}
fn send_selection(
&mut self,
mime_type: String,
fd: OwnedFd,
user_data: &Self::SelectionUserData,
) {
if let Some(xwm) = self
.common
.xwayland_state
.values_mut()
.flat_map(|xstate| xstate.xwm.as_mut())
.find(|xwm| &xwm.id() == user_data)
{
if let Err(err) = xwm.send_selection(
SelectionType::Primary,
mime_type,
fd,
self.common.event_loop_handle.clone(),
) {
slog_scope::warn!("Failed to send primary selection (X11 -> Wayland): {}", err);
}
}
}
}
delegate_primary_selection!(State);

View file

@ -183,7 +183,7 @@ impl ScreencopyHandler for State {
None
})
.unwrap_or(kms.primary.clone());
_kms_renderer = Some(kms.api.renderer::<Gles2Renderbuffer>(&node, &node).unwrap());
_kms_renderer = Some(kms.api.single_renderer(&node).unwrap());
_kms_renderer.as_mut().unwrap().as_mut()
}
BackendData::Winit(ref mut winit) => winit.backend.renderer(),
@ -423,7 +423,7 @@ fn formats_for_output(
let renderer = match backend {
BackendData::Kms(ref mut kms) => {
let node = kms.target_node_for_output(&output).unwrap_or(kms.primary);
_kms_renderer = Some(kms.api.renderer::<Gles2Renderbuffer>(&node, &node).unwrap());
_kms_renderer = Some(kms.api.single_renderer(&node).unwrap());
_kms_renderer.as_mut().unwrap().as_mut()
}
BackendData::Winit(ref mut winit) => winit.backend.renderer(),
@ -664,7 +664,7 @@ pub fn render_output_to_buffer(
BackendData::Kms(kms) => {
let mut multirenderer = kms
.api
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
.single_renderer(node.as_ref().unwrap())
.map_err(|err| (FailureReason::Unspec, err.into()))?;
render_session::<_, _>(
node,
@ -794,7 +794,7 @@ pub fn render_workspace_to_buffer(
BackendData::Kms(kms) => {
let mut multirenderer = kms
.api
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
.single_renderer(node.as_ref().unwrap())
.map_err(|err| (FailureReason::Unspec, err.into()))?;
render_session::<_, _>(
node,
@ -959,7 +959,7 @@ pub fn render_window_to_buffer(
BackendData::Kms(kms) => {
let mut multirenderer = kms
.api
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
.single_renderer(node.as_ref().unwrap())
.map_err(|err| (FailureReason::Unspec, err.into()))?;
render_session::<_, _>(
node,

View file

@ -1,8 +1,8 @@
use std::ffi::OsString;
use std::{ffi::OsString, os::unix::io::OwnedFd};
use crate::{
backend::render::cursor::Cursor,
shell::{CosmicSurface, Shell},
shell::{focus::target::KeyboardFocusTarget, CosmicSurface, Shell},
state::{Data, State},
utils::prelude::*,
wayland::{handlers::screencopy::PendingScreencopyBuffers, protocols::screencopy::SessionType},
@ -12,8 +12,18 @@ use smithay::{
desktop::space::SpaceElement,
reexports::x11rb::protocol::xproto::Window as X11Window,
utils::{Logical, Point, Rectangle, Size},
wayland::{
data_device::{
clear_data_device_selection, current_data_device_selection_userdata,
request_data_device_client_selection, set_data_device_selection,
},
primary_selection::{
clear_primary_selection, current_primary_selection_userdata,
request_primary_client_selection, set_primary_selection,
},
},
xwayland::{
xwm::{Reorder, XwmId},
xwm::{Reorder, SelectionType, XwmId},
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
},
};
@ -449,4 +459,86 @@ impl XwmHandler for Data {
}
}
}
fn send_selection(
&mut self,
_xwm: XwmId,
selection: SelectionType,
mime_type: String,
fd: OwnedFd,
) {
let seat = self.state.common.last_active_seat();
match selection {
SelectionType::Clipboard => {
if let Err(err) = request_data_device_client_selection(seat, mime_type, fd) {
slog_scope::error!(
"Failed to request current wayland clipboard for Xwayland: {}",
err
);
}
}
SelectionType::Primary => {
if let Err(err) = request_primary_client_selection(seat, mime_type, fd) {
slog_scope::error!(
"Failed to request current wayland primary selection for Xwayland: {}",
err
);
}
}
}
}
fn allow_selection_access(&mut self, xwm: XwmId, _selection: SelectionType) -> bool {
self.state.common.is_x_focused(xwm)
}
fn new_selection(&mut self, xwm: XwmId, selection: SelectionType, mime_types: Vec<String>) {
slog_scope::info!("Got Selection {:?} from X11: {:?}", selection, mime_types);
if self.state.common.is_x_focused(xwm) {
let seat = self.state.common.last_active_seat();
match selection {
SelectionType::Clipboard => set_data_device_selection(
&self.state.common.display_handle,
&seat,
mime_types,
xwm,
),
SelectionType::Primary => {
set_primary_selection(&self.state.common.display_handle, &seat, mime_types, xwm)
}
}
}
}
fn cleared_selection(&mut self, xwm: XwmId, selection: SelectionType) {
for seat in self.state.common.seats() {
match selection {
SelectionType::Clipboard => {
if current_data_device_selection_userdata(seat).as_deref() == Some(&xwm) {
clear_data_device_selection(&self.state.common.display_handle, seat)
}
}
SelectionType::Primary => {
if current_primary_selection_userdata(seat).as_deref() == Some(&xwm) {
clear_primary_selection(&self.state.common.display_handle, seat)
}
}
}
}
}
}
impl Common {
fn is_x_focused(&self, xwm: XwmId) -> bool {
if let Some(keyboard) = self.last_active_seat().get_keyboard() {
if let Some(KeyboardFocusTarget::Element(mapped)) = keyboard.current_focus() {
if let CosmicSurface::X11(surface) = mapped.active_window() {
return surface.xwm_id().unwrap() == xwm;
}
}
}
false
}
}