Compare commits
No commits in common. "934db8277555e8c6c6ec38b34c5097fcefeb7295" and "61149d95d01d7ee84295841b55b2c2af1e73c593" have entirely different histories.
934db82775
...
61149d95d0
13 changed files with 360 additions and 1785 deletions
1315
Cargo.lock
generated
1315
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
51
Cargo.toml
51
Cargo.toml
|
|
@ -17,18 +17,18 @@ cosmic-comp-config = { path = "cosmic-comp-config", features = [
|
||||||
"libdisplay-info",
|
"libdisplay-info",
|
||||||
"output",
|
"output",
|
||||||
] }
|
] }
|
||||||
cosmic-config = { path = "../libcosmic/cosmic-config", features = [
|
cosmic-config = { git = "https://github.com/pop-os/libcosmic", features = [
|
||||||
"calloop",
|
"calloop",
|
||||||
"macro",
|
"macro",
|
||||||
] }
|
] }
|
||||||
cosmic-protocols = { path = "../cosmic-protocols", default-features = false, features = [
|
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", rev = "160b086", default-features = false, features = [
|
||||||
"server",
|
"server",
|
||||||
] }
|
] }
|
||||||
cosmic-settings-config = { path = "../cosmic-settings-daemon/config" }
|
cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon" }
|
||||||
cosmic-settings-daemon-config = { path = "../cosmic-settings-daemon/cosmic-settings-daemon-config", features = [
|
cosmic-settings-daemon-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", features = [
|
||||||
"greeter",
|
"greeter",
|
||||||
] }
|
] }
|
||||||
cosmic-text = { git = "https://forge.aditua.com/leyoda/cosmic-text.git", branch = "local/pr-503", features = [
|
cosmic-text = { git = "https://github.com/pop-os/cosmic-text.git", features = [
|
||||||
"shape-run-cache",
|
"shape-run-cache",
|
||||||
] }
|
] }
|
||||||
libdisplay-info = "0.3.0"
|
libdisplay-info = "0.3.0"
|
||||||
|
|
@ -39,14 +39,10 @@ i18n-embed = { version = "0.16", features = [
|
||||||
"desktop-requester",
|
"desktop-requester",
|
||||||
] }
|
] }
|
||||||
i18n-embed-fl = "0.10"
|
i18n-embed-fl = "0.10"
|
||||||
iced_tiny_skia = { path = "../libcosmic/iced/tiny_skia" }
|
iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic" }
|
||||||
indexmap = "2.13"
|
indexmap = "2.13"
|
||||||
keyframe = "1.1.1"
|
keyframe = "1.1.1"
|
||||||
cosmic = { package = "libcosmic-yoda", path = "../libcosmic", default-features = false, features = [
|
libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false }
|
||||||
"tokio",
|
|
||||||
"wayland",
|
|
||||||
"multi-window",
|
|
||||||
] }
|
|
||||||
libsystemd = { version = "0.7", optional = true }
|
libsystemd = { version = "0.7", optional = true }
|
||||||
log-panics = { version = "2", features = ["with-backtrace"] }
|
log-panics = { version = "2", features = ["with-backtrace"] }
|
||||||
ordered-float = "5.1"
|
ordered-float = "5.1"
|
||||||
|
|
@ -142,36 +138,9 @@ inherits = "release"
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
|
|
||||||
[patch.'https://github.com/pop-os/libcosmic']
|
[patch."https://github.com/pop-os/cosmic-protocols"]
|
||||||
cosmic-config = { path = "../libcosmic/cosmic-config" }
|
cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" }
|
||||||
cosmic-theme = { path = "../libcosmic/cosmic-theme" }
|
cosmic-client-toolkit = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" }
|
||||||
iced = { path = "../libcosmic/iced" }
|
|
||||||
iced_accessibility = { path = "../libcosmic/iced/accessibility" }
|
|
||||||
iced_core = { path = "../libcosmic/iced/core" }
|
|
||||||
iced_futures = { path = "../libcosmic/iced/futures" }
|
|
||||||
iced_graphics = { path = "../libcosmic/iced/graphics" }
|
|
||||||
iced_renderer = { path = "../libcosmic/iced/renderer" }
|
|
||||||
iced_runtime = { path = "../libcosmic/iced/runtime" }
|
|
||||||
iced_tiny_skia = { path = "../libcosmic/iced/tiny_skia" }
|
|
||||||
iced_wgpu = { path = "../libcosmic/iced/wgpu" }
|
|
||||||
iced_widget = { path = "../libcosmic/iced/widget" }
|
|
||||||
iced_winit = { path = "../libcosmic/iced/winit" }
|
|
||||||
|
|
||||||
[patch.'https://github.com/pop-os/cosmic-protocols']
|
|
||||||
cosmic-protocols = { path = "../cosmic-protocols" }
|
|
||||||
cosmic-client-toolkit = { path = "../cosmic-protocols/client-toolkit" }
|
|
||||||
|
|
||||||
[patch.'https://github.com/pop-os/cosmic-settings-daemon']
|
|
||||||
cosmic-settings-config = { path = "../cosmic-settings-daemon/config" }
|
|
||||||
cosmic-settings-daemon-config = { path = "../cosmic-settings-daemon/cosmic-settings-daemon-config" }
|
|
||||||
|
|
||||||
[patch.'https://github.com/pop-os/cosmic-text.git']
|
|
||||||
cosmic-text = { git = "https://forge.aditua.com/leyoda/cosmic-text.git", branch = "local/pr-503" }
|
|
||||||
|
|
||||||
[patch.'https://forge.aditua.com/leyoda/window_clipboard.git']
|
|
||||||
window_clipboard = { path = "../window_clipboard" }
|
|
||||||
dnd = { path = "../window_clipboard/dnd" }
|
|
||||||
mime = { path = "../window_clipboard/mime" }
|
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
smithay = { git = "https://github.com/smithay/smithay.git", rev = "774f2ab" }
|
smithay = { git = "https://github.com/smithay/smithay.git", rev = "774f2ab" }
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ version = "1.0.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cosmic-config = { path = "../../libcosmic/cosmic-config" }
|
cosmic-config = { git = "https://github.com/pop-os/libcosmic/" }
|
||||||
cosmic-randr-shell = { path = "../../cosmic-randr/shell", optional = true }
|
cosmic-randr-shell = { git = "https://github.com/pop-os/cosmic-randr/", optional = true }
|
||||||
input = "0.10.0"
|
input = "0.10.0"
|
||||||
libdisplay-info = { version = "0.3.0", optional = true }
|
libdisplay-info = { version = "0.3.0", optional = true }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
|
|
||||||
|
|
@ -99,8 +99,6 @@ pub struct CosmicCompConfig {
|
||||||
pub edge_snap_threshold: u32,
|
pub edge_snap_threshold: u32,
|
||||||
pub accessibility_zoom: ZoomConfig,
|
pub accessibility_zoom: ZoomConfig,
|
||||||
pub appearance_settings: AppearanceConfig,
|
pub appearance_settings: AppearanceConfig,
|
||||||
/// Hide the cursor after this many seconds of pointer inactivity (None disables)
|
|
||||||
pub cursor_hide_timeout: Option<u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CosmicCompConfig {
|
impl Default for CosmicCompConfig {
|
||||||
|
|
@ -137,7 +135,6 @@ impl Default for CosmicCompConfig {
|
||||||
edge_snap_threshold: 0,
|
edge_snap_threshold: 0,
|
||||||
accessibility_zoom: ZoomConfig::default(),
|
accessibility_zoom: ZoomConfig::default(),
|
||||||
appearance_settings: AppearanceConfig::default(),
|
appearance_settings: AppearanceConfig::default(),
|
||||||
cursor_hide_timeout: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
egl::{EGLContext, EGLDevice, EGLDisplay, context::ContextPriority},
|
egl::{EGLContext, EGLDevice, EGLDisplay, context::ContextPriority},
|
||||||
renderer::glow::GlowRenderer,
|
renderer::glow::GlowRenderer,
|
||||||
session::{Session, libseat::LibSeatSession},
|
session::Session,
|
||||||
},
|
},
|
||||||
desktop::utils::OutputPresentationFeedback,
|
desktop::utils::OutputPresentationFeedback,
|
||||||
output::{Mode as OutputMode, Output, PhysicalProperties, Scale, Subpixel},
|
output::{Mode as OutputMode, Output, PhysicalProperties, Scale, Subpixel},
|
||||||
|
|
@ -40,10 +40,7 @@ use smithay::{
|
||||||
wayland_server::DisplayHandle,
|
wayland_server::DisplayHandle,
|
||||||
},
|
},
|
||||||
utils::{Clock, DevPath, DeviceFd, Monotonic, Point, Transform},
|
utils::{Clock, DevPath, DeviceFd, Monotonic, Point, Transform},
|
||||||
wayland::{
|
wayland::drm_lease::{DrmLease, DrmLeaseState},
|
||||||
drm_lease::{DrmLease, DrmLeaseState},
|
|
||||||
drm_syncobj::supports_syncobj_eventfd,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
use wayland_backend::server::ClientId;
|
use wayland_backend::server::ClientId;
|
||||||
|
|
@ -102,20 +99,6 @@ pub struct Device {
|
||||||
pub socket: Option<Socket>,
|
pub socket: Option<Socket>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ReusableDevice {
|
|
||||||
leasing_global: Option<DrmLeaseState>,
|
|
||||||
active_clients: HashSet<ClientId>,
|
|
||||||
socket: Option<Socket>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct OldDeviceState {
|
|
||||||
fd: DeviceFd,
|
|
||||||
outputs: HashMap<connector::Handle, Output>,
|
|
||||||
leased_connectors: HashSet<connector::Handle>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LockedDevice<'a> {
|
pub struct LockedDevice<'a> {
|
||||||
pub inner: &'a mut InnerDevice,
|
pub inner: &'a mut InnerDevice,
|
||||||
|
|
@ -239,14 +222,138 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut device = Device::new(
|
let fd = DrmDeviceFd::new(DeviceFd::from(
|
||||||
dev,
|
self.backend
|
||||||
path,
|
.kms()
|
||||||
&mut self.backend.kms().session,
|
.session
|
||||||
&mut self.common,
|
.open(
|
||||||
dh,
|
path,
|
||||||
None,
|
OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK,
|
||||||
)?;
|
)
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to optain file descriptor for drm device: {}",
|
||||||
|
path.display()
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
));
|
||||||
|
let (drm, notifier) = DrmDevice::new(fd.clone(), false)
|
||||||
|
.with_context(|| format!("Failed to initialize drm device for: {}", path.display()))?;
|
||||||
|
let drm_node = DrmNode::from_dev_id(dev)?;
|
||||||
|
let supports_atomic = drm.is_atomic();
|
||||||
|
|
||||||
|
let gbm = GbmDevice::new(fd)
|
||||||
|
.with_context(|| format!("Failed to initialize GBM device for {}", path.display()))?;
|
||||||
|
let (render_node, render_formats, texture_formats, is_software) = {
|
||||||
|
let egl = init_egl(&gbm)?;
|
||||||
|
|
||||||
|
let render_node = egl
|
||||||
|
.device
|
||||||
|
.try_get_render_node()
|
||||||
|
.ok()
|
||||||
|
.and_then(std::convert::identity)
|
||||||
|
.unwrap_or(drm_node);
|
||||||
|
let render_formats = egl.context.dmabuf_render_formats().clone();
|
||||||
|
let texture_formats = egl.context.dmabuf_texture_formats().clone();
|
||||||
|
|
||||||
|
(
|
||||||
|
render_node,
|
||||||
|
render_formats,
|
||||||
|
texture_formats,
|
||||||
|
egl.device.is_software(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let token = self
|
||||||
|
.common
|
||||||
|
.event_loop_handle
|
||||||
|
.insert_source(
|
||||||
|
notifier,
|
||||||
|
move |event, metadata, state: &mut State| match event {
|
||||||
|
DrmEvent::VBlank(crtc) => {
|
||||||
|
if let Some(device) = state.backend.kms().drm_devices.get_mut(&drm_node)
|
||||||
|
&& let Some(surface) = device.inner.surfaces.get_mut(&crtc)
|
||||||
|
{
|
||||||
|
surface.on_vblank(metadata.take());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DrmEvent::Error(err) => {
|
||||||
|
warn!(?err, "Failed to read events of device {:?}.", dev);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_context(|| format!("Failed to add drm device to event loop: {}", dev))?;
|
||||||
|
|
||||||
|
let socket = match (!is_software)
|
||||||
|
.then(|| self.create_socket(dh, render_node, texture_formats.clone()))
|
||||||
|
.transpose()
|
||||||
|
{
|
||||||
|
Ok(socket) => socket,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(
|
||||||
|
?err,
|
||||||
|
"Failed to initialize hardware-acceleration for clients on {}.", render_node,
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let leasing_global = match (!is_software)
|
||||||
|
.then(|| DrmLeaseState::new::<State>(dh, &drm_node))
|
||||||
|
.transpose()
|
||||||
|
{
|
||||||
|
Ok(global) => global,
|
||||||
|
Err(err) => {
|
||||||
|
// TODO: replace with inspect_err, once stable
|
||||||
|
warn!(
|
||||||
|
?err,
|
||||||
|
"Failed to initialize drm lease global for: {}", drm_node
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let drm = GbmDrmOutputManager::new(
|
||||||
|
drm,
|
||||||
|
GbmAllocator::new(
|
||||||
|
gbm.clone(),
|
||||||
|
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
||||||
|
),
|
||||||
|
GbmFramebufferExporter::new(gbm.clone(), render_node.into()),
|
||||||
|
Some(gbm.clone()),
|
||||||
|
[
|
||||||
|
Fourcc::Abgr2101010,
|
||||||
|
Fourcc::Argb2101010,
|
||||||
|
Fourcc::Abgr8888,
|
||||||
|
Fourcc::Argb8888,
|
||||||
|
],
|
||||||
|
render_formats,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut device = Device {
|
||||||
|
drm,
|
||||||
|
inner: InnerDevice {
|
||||||
|
dev_node: drm_node,
|
||||||
|
render_node,
|
||||||
|
is_software,
|
||||||
|
egl: None,
|
||||||
|
|
||||||
|
outputs: HashMap::new(),
|
||||||
|
surfaces: HashMap::new(),
|
||||||
|
gbm,
|
||||||
|
|
||||||
|
leased_connectors: Vec::new(),
|
||||||
|
leasing_global,
|
||||||
|
active_leases: Vec::new(),
|
||||||
|
active_clients: HashSet::new(),
|
||||||
|
},
|
||||||
|
|
||||||
|
supports_atomic,
|
||||||
|
texture_formats,
|
||||||
|
event_token: Some(token),
|
||||||
|
socket,
|
||||||
|
};
|
||||||
|
|
||||||
let connectors = device.enumerate_surfaces()?.added; // There are no removed outputs on newly added devices
|
let connectors = device.enumerate_surfaces()?.added; // There are no removed outputs on newly added devices
|
||||||
let mut wl_outputs = Vec::new();
|
let mut wl_outputs = Vec::new();
|
||||||
let mut w = self.common.shell.read().global_space().size.w as u32;
|
let mut w = self.common.shell.read().global_space().size.w as u32;
|
||||||
|
|
@ -280,7 +387,7 @@ impl State {
|
||||||
// TODO atomic commit all surfaces together and drop surfaces, if it fails due to bandwidth
|
// TODO atomic commit all surfaces together and drop surfaces, if it fails due to bandwidth
|
||||||
|
|
||||||
let kms = self.backend.kms();
|
let kms = self.backend.kms();
|
||||||
kms.drm_devices.insert(device.inner.dev_node, device);
|
kms.drm_devices.insert(drm_node, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.common
|
self.common
|
||||||
|
|
@ -382,218 +489,6 @@ impl State {
|
||||||
Ok(outputs_added)
|
Ok(outputs_added)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reopen_device(
|
|
||||||
&mut self,
|
|
||||||
dev: dev_t,
|
|
||||||
path: &Path,
|
|
||||||
dh: &DisplayHandle,
|
|
||||||
) -> Result<Vec<Output>> {
|
|
||||||
let backend = self.backend.kms();
|
|
||||||
let drm_node = backend
|
|
||||||
.drm_devices
|
|
||||||
.values()
|
|
||||||
.find_map(|device| {
|
|
||||||
(device.inner.dev_node.dev_id() == dev).then_some(device.inner.dev_node)
|
|
||||||
})
|
|
||||||
.with_context(|| format!("Couldn't find drm node for {}", dev))?;
|
|
||||||
|
|
||||||
if let Some(mut device) = backend.drm_devices.shift_remove(&drm_node) {
|
|
||||||
let is_primary = backend
|
|
||||||
.primary_node
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.is_some_and(|node| node == device.inner.render_node);
|
|
||||||
|
|
||||||
// all drm resources become inert
|
|
||||||
if let Some(token) = device.event_token.take() {
|
|
||||||
self.common.event_loop_handle.remove(token);
|
|
||||||
}
|
|
||||||
for (_, surface) in device.inner.surfaces.drain() {
|
|
||||||
surface.drop_and_join();
|
|
||||||
}
|
|
||||||
if let Some(leasing_global) = device.inner.leasing_global.as_mut() {
|
|
||||||
for (connector, _) in &device.inner.leased_connectors {
|
|
||||||
leasing_global.withdraw_connector(*connector);
|
|
||||||
}
|
|
||||||
device.inner.active_leases.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// These contain a reference to the file descriptor
|
|
||||||
backend.api.as_mut().remove_node(&device.inner.render_node);
|
|
||||||
// trigger enumeration
|
|
||||||
let _ = backend.api.devices();
|
|
||||||
|
|
||||||
for surface in backend
|
|
||||||
.drm_devices
|
|
||||||
.values_mut()
|
|
||||||
.flat_map(|device| device.inner.surfaces.values_mut())
|
|
||||||
{
|
|
||||||
surface.remove_node(device.inner.render_node);
|
|
||||||
}
|
|
||||||
let syncobj_guard =
|
|
||||||
if is_primary && let Some(syncobj_state) = backend.syncobj_state.as_mut() {
|
|
||||||
Some(syncobj_state.close_device())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let (reusable, mut old_state) = device.reuse();
|
|
||||||
|
|
||||||
match TryInto::<OwnedFd>::try_into(old_state.fd) {
|
|
||||||
Ok(fd) => {
|
|
||||||
if let Err(err) = backend.session.close(fd) {
|
|
||||||
warn!("Failed to close drm device fd: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
warn!(?drm_node, "Unable to close drm device fd cleanly.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut new_device = Device::new(
|
|
||||||
dev,
|
|
||||||
path,
|
|
||||||
&mut backend.session,
|
|
||||||
&mut self.common,
|
|
||||||
dh,
|
|
||||||
Some(reusable),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let Some(guard) = syncobj_guard {
|
|
||||||
let import_device = new_device.drm.device().device_fd().clone();
|
|
||||||
if supports_syncobj_eventfd(&import_device) {
|
|
||||||
guard.update_device(import_device);
|
|
||||||
} else {
|
|
||||||
drop(guard);
|
|
||||||
dh.remove_global::<State>(backend.syncobj_state.take().unwrap().into_global());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let connectors = new_device.enumerate_surfaces()?.added;
|
|
||||||
let mut outputs_added = Vec::new();
|
|
||||||
let mut w = self.common.shell.read().global_space().size.w as u32;
|
|
||||||
|
|
||||||
{
|
|
||||||
for (conn, maybe_crtc) in connectors {
|
|
||||||
if let Some(output) = old_state.outputs.remove(&conn) {
|
|
||||||
let has_surface = if old_state.leased_connectors.contains(&conn) {
|
|
||||||
if let Some(crtc) = maybe_crtc {
|
|
||||||
new_device.inner.leased_connectors.push((conn, crtc));
|
|
||||||
info!(
|
|
||||||
"Connector {} is non-desktop, setting up for leasing",
|
|
||||||
output.name()
|
|
||||||
);
|
|
||||||
if let Some(lease_state) = new_device.inner.leasing_global.as_mut()
|
|
||||||
{
|
|
||||||
let physical = output.physical_properties();
|
|
||||||
lease_state.add_connector::<State>(
|
|
||||||
conn,
|
|
||||||
output.name(),
|
|
||||||
format!("{} {}", physical.make, physical.model),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warn!(
|
|
||||||
"Connector {} is non-desktop, but we don't have a free crtc: not leasing",
|
|
||||||
output.name()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
let loc = output.current_location();
|
|
||||||
populate_modes(
|
|
||||||
new_device.drm.device_mut(),
|
|
||||||
&output,
|
|
||||||
conn,
|
|
||||||
true,
|
|
||||||
(loc.x as u32, loc.y as u32),
|
|
||||||
)
|
|
||||||
.with_context(|| "Failed to enumerate connector modes")?;
|
|
||||||
|
|
||||||
if let Some(crtc) = maybe_crtc {
|
|
||||||
match Surface::new(
|
|
||||||
&output,
|
|
||||||
crtc,
|
|
||||||
conn,
|
|
||||||
backend.primary_node.clone(),
|
|
||||||
new_device.inner.dev_node,
|
|
||||||
new_device.inner.render_node,
|
|
||||||
&self.common.event_loop_handle,
|
|
||||||
self.common.config.dynamic_conf.screen_filter().clone(),
|
|
||||||
self.common.shell.clone(),
|
|
||||||
self.common.startup_done.clone(),
|
|
||||||
) {
|
|
||||||
Ok(data) => {
|
|
||||||
new_device.inner.surfaces.insert(crtc, data);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
error!(?crtc, "Failed to initialize surface: {}", err);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if !has_surface {
|
|
||||||
output
|
|
||||||
.user_data()
|
|
||||||
.get::<RefCell<OutputConfig>>()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.enabled = OutputState::Disabled;
|
|
||||||
}
|
|
||||||
new_device.inner.outputs.insert(conn, output);
|
|
||||||
} else {
|
|
||||||
match new_device.inner.connector_added(
|
|
||||||
new_device.drm.device_mut(),
|
|
||||||
backend.primary_node.clone(),
|
|
||||||
conn,
|
|
||||||
maybe_crtc,
|
|
||||||
(w, 0),
|
|
||||||
&self.common.event_loop_handle,
|
|
||||||
self.common.config.dynamic_conf.screen_filter().clone(),
|
|
||||||
self.common.shell.clone(),
|
|
||||||
self.common.startup_done.clone(),
|
|
||||||
) {
|
|
||||||
Ok((output, should_expose)) => {
|
|
||||||
if should_expose {
|
|
||||||
w += output.geometry().size.w as u32;
|
|
||||||
outputs_added.push(output.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
new_device.inner.outputs.insert(conn, output);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
warn!(?err, "Failed to initialize output, skipping");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.common
|
|
||||||
.output_configuration_state
|
|
||||||
.remove_heads(old_state.outputs.values());
|
|
||||||
self.common
|
|
||||||
.output_configuration_state
|
|
||||||
.add_heads(outputs_added.iter());
|
|
||||||
|
|
||||||
for output in old_state.outputs.values() {
|
|
||||||
self.common.remove_output(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
backend.drm_devices.insert(drm_node, new_device);
|
|
||||||
backend.refresh_used_devices()?;
|
|
||||||
|
|
||||||
Ok(outputs_added)
|
|
||||||
} else {
|
|
||||||
Ok(Vec::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn device_removed(&mut self, dev: dev_t, dh: &DisplayHandle) -> Result<()> {
|
pub fn device_removed(&mut self, dev: dev_t, dh: &DisplayHandle) -> Result<()> {
|
||||||
let backend = self.backend.kms();
|
let backend = self.backend.kms();
|
||||||
// we can't use DrmNode::from_node_id, because that assumes the node is still on sysfs
|
// we can't use DrmNode::from_node_id, because that assumes the node is still on sysfs
|
||||||
|
|
@ -686,158 +581,6 @@ pub struct OutputChanges {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device {
|
impl Device {
|
||||||
fn new(
|
|
||||||
dev: dev_t,
|
|
||||||
path: impl AsRef<Path>,
|
|
||||||
session: &mut LibSeatSession,
|
|
||||||
common: &mut Common,
|
|
||||||
dh: &DisplayHandle,
|
|
||||||
reuse: Option<ReusableDevice>,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
let fd = DrmDeviceFd::new(DeviceFd::from(
|
|
||||||
session
|
|
||||||
.open(
|
|
||||||
path,
|
|
||||||
OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK,
|
|
||||||
)
|
|
||||||
.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Failed to optain file descriptor for drm device: {}",
|
|
||||||
path.display()
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
));
|
|
||||||
let (drm, notifier) = DrmDevice::new(fd.clone(), false)
|
|
||||||
.with_context(|| format!("Failed to initialize drm device for: {}", path.display()))?;
|
|
||||||
let dev_node = DrmNode::from_dev_id(dev)?;
|
|
||||||
let supports_atomic = drm.is_atomic();
|
|
||||||
|
|
||||||
let gbm = GbmDevice::new(fd)
|
|
||||||
.with_context(|| format!("Failed to initialize GBM device for {}", path.display()))?;
|
|
||||||
let (render_node, render_formats, texture_formats, is_software) = {
|
|
||||||
let egl = init_egl(&gbm)?;
|
|
||||||
|
|
||||||
let render_node = egl
|
|
||||||
.device
|
|
||||||
.try_get_render_node()
|
|
||||||
.ok()
|
|
||||||
.and_then(std::convert::identity)
|
|
||||||
.unwrap_or(dev_node);
|
|
||||||
let render_formats = egl.context.dmabuf_render_formats().clone();
|
|
||||||
let texture_formats = egl.context.dmabuf_texture_formats().clone();
|
|
||||||
|
|
||||||
(
|
|
||||||
render_node,
|
|
||||||
render_formats,
|
|
||||||
texture_formats,
|
|
||||||
egl.device.is_software(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let token = common
|
|
||||||
.event_loop_handle
|
|
||||||
.insert_source(
|
|
||||||
notifier,
|
|
||||||
move |event, metadata, state: &mut State| match event {
|
|
||||||
DrmEvent::VBlank(crtc) => {
|
|
||||||
if let Some(device) = state.backend.kms().drm_devices.get_mut(&dev_node)
|
|
||||||
&& let Some(surface) = device.inner.surfaces.get_mut(&crtc)
|
|
||||||
{
|
|
||||||
surface.on_vblank(metadata.take());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DrmEvent::Error(err) => {
|
|
||||||
warn!(?err, "Failed to read events of device {:?}.", dev);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.with_context(|| format!("Failed to add drm device to event loop: {}", dev))?;
|
|
||||||
|
|
||||||
let ReusableDevice {
|
|
||||||
leasing_global,
|
|
||||||
active_clients,
|
|
||||||
socket,
|
|
||||||
} = reuse.unwrap_or_else(|| {
|
|
||||||
let socket = match (!is_software)
|
|
||||||
.then(|| common.create_socket(dh, render_node, texture_formats.clone()))
|
|
||||||
.transpose()
|
|
||||||
{
|
|
||||||
Ok(socket) => socket,
|
|
||||||
Err(err) => {
|
|
||||||
warn!(
|
|
||||||
?err,
|
|
||||||
"Failed to initialize hardware-acceleration for clients on {}.",
|
|
||||||
render_node,
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let leasing_global = match (!is_software)
|
|
||||||
.then(|| DrmLeaseState::new::<State>(dh, &dev_node))
|
|
||||||
.transpose()
|
|
||||||
{
|
|
||||||
Ok(global) => global,
|
|
||||||
Err(err) => {
|
|
||||||
// TODO: replace with inspect_err, once stable
|
|
||||||
warn!(
|
|
||||||
?err,
|
|
||||||
"Failed to initialize drm lease global for: {}", dev_node
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ReusableDevice {
|
|
||||||
leasing_global,
|
|
||||||
active_clients: HashSet::new(),
|
|
||||||
socket,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let drm = GbmDrmOutputManager::new(
|
|
||||||
drm,
|
|
||||||
GbmAllocator::new(
|
|
||||||
gbm.clone(),
|
|
||||||
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
|
||||||
),
|
|
||||||
GbmFramebufferExporter::new(gbm.clone(), render_node.into()),
|
|
||||||
Some(gbm.clone()),
|
|
||||||
[
|
|
||||||
Fourcc::Abgr2101010,
|
|
||||||
Fourcc::Argb2101010,
|
|
||||||
Fourcc::Abgr8888,
|
|
||||||
Fourcc::Argb8888,
|
|
||||||
],
|
|
||||||
render_formats,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Device {
|
|
||||||
drm,
|
|
||||||
inner: InnerDevice {
|
|
||||||
dev_node,
|
|
||||||
render_node,
|
|
||||||
is_software,
|
|
||||||
egl: None,
|
|
||||||
|
|
||||||
outputs: HashMap::new(),
|
|
||||||
surfaces: HashMap::new(),
|
|
||||||
gbm,
|
|
||||||
|
|
||||||
leased_connectors: Vec::new(),
|
|
||||||
leasing_global,
|
|
||||||
active_leases: Vec::new(),
|
|
||||||
active_clients,
|
|
||||||
},
|
|
||||||
|
|
||||||
supports_atomic,
|
|
||||||
texture_formats,
|
|
||||||
event_token: Some(token),
|
|
||||||
socket,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enumerate_surfaces(&mut self) -> Result<OutputChanges> {
|
pub fn enumerate_surfaces(&mut self) -> Result<OutputChanges> {
|
||||||
// enumerate our outputs
|
// enumerate our outputs
|
||||||
let config =
|
let config =
|
||||||
|
|
@ -891,27 +634,6 @@ impl Device {
|
||||||
drm: self.drm.lock(),
|
drm: self.drm.lock(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reuse(self) -> (ReusableDevice, OldDeviceState) {
|
|
||||||
let device = ReusableDevice {
|
|
||||||
leasing_global: self.inner.leasing_global,
|
|
||||||
active_clients: self.inner.active_clients,
|
|
||||||
socket: self.socket,
|
|
||||||
};
|
|
||||||
|
|
||||||
let state = OldDeviceState {
|
|
||||||
fd: self.drm.device().device_fd().device_fd(),
|
|
||||||
outputs: self.inner.outputs,
|
|
||||||
leased_connectors: self
|
|
||||||
.inner
|
|
||||||
.leased_connectors
|
|
||||||
.iter()
|
|
||||||
.map(|(conn, _)| *conn)
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
|
|
||||||
(device, state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LockedDevice<'_> {
|
impl LockedDevice<'_> {
|
||||||
|
|
|
||||||
|
|
@ -394,37 +394,15 @@ impl State {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let dh = state.common.display_handle.clone();
|
|
||||||
|
|
||||||
if state.backend.kms().drm_devices.contains_key(&drm_node) {
|
if state.backend.kms().drm_devices.contains_key(&drm_node) {
|
||||||
match state.device_changed(dev) {
|
match state.device_changed(dev) {
|
||||||
Ok(outputs) => added.extend(outputs),
|
Ok(outputs) => added.extend(outputs),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(
|
error!(?err, "Failed to update drm device {}.", path.display(),)
|
||||||
?err,
|
|
||||||
"Failed to update drm device {}. Re-opening",
|
|
||||||
path.display(),
|
|
||||||
);
|
|
||||||
match state.reopen_device(dev, path, &dh) {
|
|
||||||
Ok(outputs) => added.extend(outputs),
|
|
||||||
Err(err) => {
|
|
||||||
error!(
|
|
||||||
?err,
|
|
||||||
"Failed to re-open drm device {}. Device lost",
|
|
||||||
path.display(),
|
|
||||||
);
|
|
||||||
if let Err(err) = state.device_removed(dev, &dh) {
|
|
||||||
error!(
|
|
||||||
?err,
|
|
||||||
"Failed to close drm device {}.",
|
|
||||||
path.display(),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let dh = state.common.display_handle.clone();
|
||||||
match state.device_added(dev, path, &dh) {
|
match state.device_added(dev, path, &dh) {
|
||||||
Ok(outputs) => added.extend(outputs),
|
Ok(outputs) => added.extend(outputs),
|
||||||
Err(err) => error!(?err, "Failed to add drm device {}.", path.display(),),
|
Err(err) => error!(?err, "Failed to add drm device {}.", path.display(),),
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use smithay::{
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use crate::state::{ClientState, Common, State, advertised_node_for_client};
|
use crate::state::{ClientState, State, advertised_node_for_client};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Socket {
|
pub struct Socket {
|
||||||
|
|
@ -27,7 +27,7 @@ pub struct Socket {
|
||||||
pub dmabuf_global: DmabufGlobal,
|
pub dmabuf_global: DmabufGlobal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Common {
|
impl State {
|
||||||
pub(super) fn create_socket(
|
pub(super) fn create_socket(
|
||||||
&mut self,
|
&mut self,
|
||||||
dh: &DisplayHandle,
|
dh: &DisplayHandle,
|
||||||
|
|
@ -36,7 +36,7 @@ impl Common {
|
||||||
) -> Result<Socket> {
|
) -> Result<Socket> {
|
||||||
let socket_name = format!(
|
let socket_name = format!(
|
||||||
"{}-{}",
|
"{}-{}",
|
||||||
&self.socket.to_string_lossy(),
|
&self.common.socket.to_string_lossy(),
|
||||||
render_node
|
render_node
|
||||||
.dev_path()
|
.dev_path()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -53,28 +53,33 @@ impl Common {
|
||||||
.with_context(|| "Failed to create drm format shared memory table")?;
|
.with_context(|| "Failed to create drm format shared memory table")?;
|
||||||
|
|
||||||
let dmabuf_global = self
|
let dmabuf_global = self
|
||||||
|
.common
|
||||||
.dmabuf_state
|
.dmabuf_state
|
||||||
.create_global_with_filter_and_default_feedback::<State, _>(dh, &feedback, filter);
|
.create_global_with_filter_and_default_feedback::<State, _>(dh, &feedback, filter);
|
||||||
|
|
||||||
let drm_global_id = self.wl_drm_state.create_global_with_filter::<State, _>(
|
let drm_global_id = self
|
||||||
dh,
|
.common
|
||||||
render_node
|
.wl_drm_state
|
||||||
.dev_path_with_type(NodeType::Render)
|
.create_global_with_filter::<State, _>(
|
||||||
.or_else(|| render_node.dev_path())
|
dh,
|
||||||
.ok_or(anyhow!(
|
render_node
|
||||||
"Could not determine path for gpu node: {}",
|
.dev_path_with_type(NodeType::Render)
|
||||||
render_node
|
.or_else(|| render_node.dev_path())
|
||||||
))?,
|
.ok_or(anyhow!(
|
||||||
formats,
|
"Could not determine path for gpu node: {}",
|
||||||
&dmabuf_global,
|
render_node
|
||||||
filter,
|
))?,
|
||||||
);
|
formats,
|
||||||
|
&dmabuf_global,
|
||||||
|
filter,
|
||||||
|
);
|
||||||
|
|
||||||
// add a special socket for the gpu
|
// add a special socket for the gpu
|
||||||
let listener = ListeningSocketSource::with_name(&socket_name)
|
let listener = ListeningSocketSource::with_name(&socket_name)
|
||||||
.with_context(|| format!("Failed to bind socket to {}", socket_name))?;
|
.with_context(|| format!("Failed to bind socket to {}", socket_name))?;
|
||||||
let socket_name_clone = socket_name.clone();
|
let socket_name_clone = socket_name.clone();
|
||||||
let token = self
|
let token = self
|
||||||
|
.common
|
||||||
.event_loop_handle
|
.event_loop_handle
|
||||||
.insert_source(listener, move |client_stream, _, state: &mut State| {
|
.insert_source(listener, move |client_stream, _, state: &mut State| {
|
||||||
if let Err(err) = state.common.display_handle.insert_client(
|
if let Err(err) = state.common.display_handle.insert_client(
|
||||||
|
|
|
||||||
|
|
@ -464,7 +464,7 @@ impl Surface {
|
||||||
|
|
||||||
pub fn drop_and_join(mut self) {
|
pub fn drop_and_join(mut self) {
|
||||||
let thread = self.thread.take();
|
let thread = self.thread.take();
|
||||||
std::mem::drop(self);
|
let _ = self;
|
||||||
if let Some(thread) = thread {
|
if let Some(thread) = thread {
|
||||||
let name = thread.thread().name().unwrap().to_string();
|
let name = thread.thread().name().unwrap().to_string();
|
||||||
let _ = thread.join();
|
let _ = thread.join();
|
||||||
|
|
|
||||||
|
|
@ -17,25 +17,14 @@ use smithay::{
|
||||||
Seat,
|
Seat,
|
||||||
pointer::{CursorIcon, CursorImageAttributes, CursorImageStatus},
|
pointer::{CursorIcon, CursorImageAttributes, CursorImageStatus},
|
||||||
},
|
},
|
||||||
reexports::{
|
reexports::wayland_server::protocol::wl_surface,
|
||||||
calloop::{
|
|
||||||
RegistrationToken,
|
|
||||||
timer::{TimeoutAction, Timer},
|
|
||||||
},
|
|
||||||
wayland_server::protocol::wl_surface,
|
|
||||||
},
|
|
||||||
render_elements,
|
render_elements,
|
||||||
utils::{
|
utils::{
|
||||||
Buffer as BufferCoords, Logical, Monotonic, Physical, Point, Scale, Size, Time, Transform,
|
Buffer as BufferCoords, Logical, Monotonic, Physical, Point, Scale, Size, Time, Transform,
|
||||||
},
|
},
|
||||||
wayland::compositor::{get_role, with_states},
|
wayland::compositor::{get_role, with_states},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{collections::HashMap, io::Read, sync::Mutex};
|
||||||
collections::HashMap,
|
|
||||||
io::Read,
|
|
||||||
sync::Mutex,
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
use xcursor::{
|
use xcursor::{
|
||||||
CursorTheme,
|
CursorTheme,
|
||||||
|
|
@ -207,10 +196,6 @@ pub struct CursorStateInner {
|
||||||
cursors: HashMap<CursorIcon, Cursor>,
|
cursors: HashMap<CursorIcon, Cursor>,
|
||||||
current_image: Option<Image>,
|
current_image: Option<Image>,
|
||||||
image_cache: Vec<(Image, MemoryRenderBuffer)>,
|
image_cache: Vec<(Image, MemoryRenderBuffer)>,
|
||||||
|
|
||||||
hidden: bool,
|
|
||||||
idle_timer: Option<RegistrationToken>,
|
|
||||||
last_armed: Option<Instant>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CursorStateInner {
|
impl CursorStateInner {
|
||||||
|
|
@ -261,10 +246,6 @@ impl Default for CursorStateInner {
|
||||||
cursors: HashMap::new(),
|
cursors: HashMap::new(),
|
||||||
current_image: None,
|
current_image: None,
|
||||||
image_cache: Vec::new(),
|
image_cache: Vec::new(),
|
||||||
|
|
||||||
hidden: false,
|
|
||||||
idle_timer: None,
|
|
||||||
last_armed: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -290,10 +271,6 @@ where
|
||||||
let mut state_ref = seat_userdata.get::<CursorState>().unwrap().lock().unwrap();
|
let mut state_ref = seat_userdata.get::<CursorState>().unwrap().lock().unwrap();
|
||||||
let state = &mut *state_ref;
|
let state = &mut *state_ref;
|
||||||
|
|
||||||
if state.hidden {
|
|
||||||
return Vec::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
let named_cursor = state.current_cursor.or(match cursor_status {
|
let named_cursor = state.current_cursor.or(match cursor_status {
|
||||||
CursorImageStatus::Named(named_cursor) => Some(named_cursor),
|
CursorImageStatus::Named(named_cursor) => Some(named_cursor),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
@ -358,71 +335,3 @@ where
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ACTIVITY_THROTTLE: Duration = Duration::from_millis(100);
|
|
||||||
|
|
||||||
/// Reveal the cursor and (re)arm the idle-hide timer; returns true if it was previously hidden
|
|
||||||
pub fn notify_cursor_activity(state: &State, seat: &Seat<State>) -> bool {
|
|
||||||
let timeout = state.common.config.cosmic_conf.cursor_hide_timeout;
|
|
||||||
let loop_handle = &state.common.event_loop_handle;
|
|
||||||
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
|
|
||||||
let now = Instant::now();
|
|
||||||
|
|
||||||
let (was_hidden, old_token) = {
|
|
||||||
let mut inner = cursor_state.lock().unwrap();
|
|
||||||
let was_hidden = inner.hidden;
|
|
||||||
inner.hidden = false;
|
|
||||||
|
|
||||||
let throttled = timeout.is_some()
|
|
||||||
&& !was_hidden
|
|
||||||
&& inner.idle_timer.is_some()
|
|
||||||
&& inner
|
|
||||||
.last_armed
|
|
||||||
.is_some_and(|t| now.duration_since(t) < ACTIVITY_THROTTLE);
|
|
||||||
if throttled {
|
|
||||||
return was_hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
let old_token = inner.idle_timer.take();
|
|
||||||
inner.last_armed = None;
|
|
||||||
(was_hidden, old_token)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(token) = old_token {
|
|
||||||
loop_handle.remove(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(secs) = timeout {
|
|
||||||
let timer = Timer::from_duration(Duration::from_secs(secs as u64));
|
|
||||||
let seat = seat.clone();
|
|
||||||
if let Ok(token) = loop_handle.insert_source(timer, move |_, _, state| {
|
|
||||||
hide_cursor(state, &seat);
|
|
||||||
TimeoutAction::Drop
|
|
||||||
}) {
|
|
||||||
let mut inner = cursor_state.lock().unwrap();
|
|
||||||
inner.idle_timer = Some(token);
|
|
||||||
inner.last_armed = Some(now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
was_hidden
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hide_cursor(state: &mut State, seat: &Seat<State>) {
|
|
||||||
if let Some(ptr) = seat.get_pointer()
|
|
||||||
&& ptr.is_grabbed()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
|
|
||||||
{
|
|
||||||
let mut inner = cursor_state.lock().unwrap();
|
|
||||||
inner.hidden = true;
|
|
||||||
inner.idle_timer = None;
|
|
||||||
inner.last_armed = None;
|
|
||||||
}
|
|
||||||
let outputs: Vec<_> = state.common.shell.read().outputs().cloned().collect();
|
|
||||||
for output in outputs {
|
|
||||||
state.backend.schedule_render(&output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -947,25 +947,6 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"cursor_hide_timeout" => {
|
|
||||||
let new = get_config::<Option<u32>>(&config, "cursor_hide_timeout");
|
|
||||||
if new != state.common.config.cosmic_conf.cursor_hide_timeout {
|
|
||||||
state.common.config.cosmic_conf.cursor_hide_timeout = new;
|
|
||||||
let seats: Vec<_> = state.common.shell.read().seats.iter().cloned().collect();
|
|
||||||
let mut needs_render = false;
|
|
||||||
for seat in seats {
|
|
||||||
needs_render |=
|
|
||||||
crate::backend::render::cursor::notify_cursor_activity(state, &seat);
|
|
||||||
}
|
|
||||||
if needs_render {
|
|
||||||
let outputs: Vec<_> =
|
|
||||||
state.common.shell.read().outputs().cloned().collect();
|
|
||||||
for output in outputs {
|
|
||||||
state.backend.schedule_render(&output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::{ElementFilter, cursor::notify_cursor_activity},
|
backend::render::ElementFilter,
|
||||||
config::{
|
config::{
|
||||||
Action, Config, PrivateAction,
|
Action, Config, PrivateAction,
|
||||||
key_bindings::{
|
key_bindings::{
|
||||||
|
|
@ -37,12 +37,11 @@ use cosmic_settings_config::shortcuts;
|
||||||
use cosmic_settings_config::shortcuts::action::{Direction, ResizeDirection};
|
use cosmic_settings_config::shortcuts::action::{Direction, ResizeDirection};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::{
|
backend::input::{
|
||||||
AbsolutePositionEvent, Axis, AxisRelativeDirection, AxisSource, Device, DeviceCapability,
|
AbsolutePositionEvent, Axis, AxisSource, Device, DeviceCapability, GestureBeginEvent,
|
||||||
GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _,
|
GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, InputBackend,
|
||||||
GestureSwipeUpdateEvent as _, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
|
InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, ProximityState, Switch,
|
||||||
PointerAxisEvent, ProximityState, Switch, SwitchState, SwitchToggleEvent,
|
SwitchState, SwitchToggleEvent, TabletToolButtonEvent, TabletToolEvent,
|
||||||
TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent,
|
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent,
|
||||||
TabletToolTipState, TouchEvent,
|
|
||||||
},
|
},
|
||||||
desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree},
|
desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree},
|
||||||
input::{
|
input::{
|
||||||
|
|
@ -309,7 +308,6 @@ impl State {
|
||||||
let shell = self.common.shell.write();
|
let shell = self.common.shell.write();
|
||||||
if let Some(seat) = shell.seats.for_device(&event.device()).cloned() {
|
if let Some(seat) = shell.seats.for_device(&event.device()).cloned() {
|
||||||
self.common.idle_notifier_state.notify_activity(&seat);
|
self.common.idle_notifier_state.notify_activity(&seat);
|
||||||
notify_cursor_activity(self, &seat);
|
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
||||||
let mut position = seat.get_pointer().unwrap().current_location().as_global();
|
let mut position = seat.get_pointer().unwrap().current_location().as_global();
|
||||||
|
|
@ -623,7 +621,6 @@ impl State {
|
||||||
.cloned();
|
.cloned();
|
||||||
if let Some(seat) = maybe_seat {
|
if let Some(seat) = maybe_seat {
|
||||||
self.common.idle_notifier_state.notify_activity(&seat);
|
self.common.idle_notifier_state.notify_activity(&seat);
|
||||||
notify_cursor_activity(self, &seat);
|
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
let geometry = output.geometry();
|
let geometry = output.geometry();
|
||||||
let position = geometry.loc.to_f64()
|
let position = geometry.loc.to_f64()
|
||||||
|
|
@ -690,7 +687,6 @@ impl State {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.common.idle_notifier_state.notify_activity(&seat);
|
self.common.idle_notifier_state.notify_activity(&seat);
|
||||||
notify_cursor_activity(self, &seat);
|
|
||||||
|
|
||||||
let current_focus = seat.get_keyboard().unwrap().current_focus();
|
let current_focus = seat.get_keyboard().unwrap().current_focus();
|
||||||
let shortcuts_inhibited = current_focus.as_ref().is_some_and(|f| {
|
let shortcuts_inhibited = current_focus.as_ref().is_some_and(|f| {
|
||||||
|
|
@ -902,7 +898,6 @@ impl State {
|
||||||
.cloned();
|
.cloned();
|
||||||
if let Some(seat) = maybe_seat {
|
if let Some(seat) = maybe_seat {
|
||||||
self.common.idle_notifier_state.notify_activity(&seat);
|
self.common.idle_notifier_state.notify_activity(&seat);
|
||||||
notify_cursor_activity(self, &seat);
|
|
||||||
|
|
||||||
if seat.get_keyboard().unwrap().modifier_state().logo
|
if seat.get_keyboard().unwrap().modifier_state().logo
|
||||||
&& self
|
&& self
|
||||||
|
|
@ -919,12 +914,6 @@ impl State {
|
||||||
.or_else(|| event.amount(Axis::Vertical))
|
.or_else(|| event.amount(Axis::Vertical))
|
||||||
.map(|val| val * scroll_factor)
|
.map(|val| val * scroll_factor)
|
||||||
{
|
{
|
||||||
if event.relative_direction(Axis::Vertical)
|
|
||||||
== AxisRelativeDirection::Inverted
|
|
||||||
{
|
|
||||||
percentage *= -1.;
|
|
||||||
}
|
|
||||||
|
|
||||||
if event.source() == AxisSource::Wheel {
|
if event.source() == AxisSource::Wheel {
|
||||||
percentage *= 5.;
|
percentage *= 5.;
|
||||||
}
|
}
|
||||||
|
|
@ -1371,7 +1360,6 @@ impl State {
|
||||||
let shell = self.common.shell.write();
|
let shell = self.common.shell.write();
|
||||||
if let Some(seat) = shell.seats.for_device(&event.device()).cloned() {
|
if let Some(seat) = shell.seats.for_device(&event.device()).cloned() {
|
||||||
self.common.idle_notifier_state.notify_activity(&seat);
|
self.common.idle_notifier_state.notify_activity(&seat);
|
||||||
notify_cursor_activity(self, &seat);
|
|
||||||
let Some(output) =
|
let Some(output) =
|
||||||
mapped_output_for_device(&self.common.config, &shell, &event.device())
|
mapped_output_for_device(&self.common.config, &shell, &event.device())
|
||||||
.cloned()
|
.cloned()
|
||||||
|
|
@ -1437,7 +1425,6 @@ impl State {
|
||||||
let shell = self.common.shell.write();
|
let shell = self.common.shell.write();
|
||||||
if let Some(seat) = shell.seats.for_device(&event.device()).cloned() {
|
if let Some(seat) = shell.seats.for_device(&event.device()).cloned() {
|
||||||
self.common.idle_notifier_state.notify_activity(&seat);
|
self.common.idle_notifier_state.notify_activity(&seat);
|
||||||
notify_cursor_activity(self, &seat);
|
|
||||||
let Some(output) =
|
let Some(output) =
|
||||||
mapped_output_for_device(&self.common.config, &shell, &event.device())
|
mapped_output_for_device(&self.common.config, &shell, &event.device())
|
||||||
.cloned()
|
.cloned()
|
||||||
|
|
@ -1499,7 +1486,6 @@ impl State {
|
||||||
.cloned();
|
.cloned();
|
||||||
if let Some(seat) = maybe_seat {
|
if let Some(seat) = maybe_seat {
|
||||||
self.common.idle_notifier_state.notify_activity(&seat);
|
self.common.idle_notifier_state.notify_activity(&seat);
|
||||||
notify_cursor_activity(self, &seat);
|
|
||||||
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
||||||
match event.tip_state() {
|
match event.tip_state() {
|
||||||
TabletToolTipState::Down => {
|
TabletToolTipState::Down => {
|
||||||
|
|
@ -1522,7 +1508,6 @@ impl State {
|
||||||
.cloned();
|
.cloned();
|
||||||
if let Some(seat) = maybe_seat {
|
if let Some(seat) = maybe_seat {
|
||||||
self.common.idle_notifier_state.notify_activity(&seat);
|
self.common.idle_notifier_state.notify_activity(&seat);
|
||||||
notify_cursor_activity(self, &seat);
|
|
||||||
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
||||||
tool.button(
|
tool.button(
|
||||||
event.button(),
|
event.button(),
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use cosmic::{
|
||||||
};
|
};
|
||||||
use cosmic_comp_config::ZoomMovement;
|
use cosmic_comp_config::ZoomMovement;
|
||||||
use cosmic_config::ConfigSet;
|
use cosmic_config::ConfigSet;
|
||||||
use keyframe::{ease, functions::Linear};
|
use keyframe::{ease, functions::EaseInOutCubic};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{ImportMem, Renderer, element::AsRenderElements},
|
backend::renderer::{ImportMem, Renderer, element::AsRenderElements},
|
||||||
desktop::space::SpaceElement,
|
desktop::space::SpaceElement,
|
||||||
|
|
@ -135,7 +135,7 @@ impl OutputZoomState {
|
||||||
let percentage =
|
let percentage =
|
||||||
duration_since.as_millis() as f32 / ANIMATION_DURATION.as_millis() as f32;
|
duration_since.as_millis() as f32 / ANIMATION_DURATION.as_millis() as f32;
|
||||||
ease(
|
ease(
|
||||||
Linear,
|
EaseInOutCubic,
|
||||||
EasePoint(*old_point),
|
EasePoint(*old_point),
|
||||||
EasePoint(self.focal_point),
|
EasePoint(self.focal_point),
|
||||||
percentage,
|
percentage,
|
||||||
|
|
@ -159,7 +159,7 @@ impl OutputZoomState {
|
||||||
let percentage = Instant::now().duration_since(*start).as_millis() as f32
|
let percentage = Instant::now().duration_since(*start).as_millis() as f32
|
||||||
/ ANIMATION_DURATION.as_millis() as f32;
|
/ ANIMATION_DURATION.as_millis() as f32;
|
||||||
|
|
||||||
ease(Linear, *old_level, self.level, percentage)
|
ease(EaseInOutCubic, *old_level, self.level, percentage)
|
||||||
} else {
|
} else {
|
||||||
self.level
|
self.level
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -809,14 +809,12 @@ impl XwmHandler for State {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if !shell.pending_windows.iter().any(|w| w.surface == window) {
|
if !shell.pending_windows.iter().any(|w| w.surface == window) {
|
||||||
let fullscreen = window.is_fullscreen().then(|| seat.active_output());
|
|
||||||
let maximized = window.is_maximized();
|
|
||||||
let surface = CosmicSurface::from(window);
|
let surface = CosmicSurface::from(window);
|
||||||
shell.pending_windows.push(PendingWindow {
|
shell.pending_windows.push(PendingWindow {
|
||||||
surface,
|
surface,
|
||||||
seat,
|
seat,
|
||||||
fullscreen,
|
fullscreen: None,
|
||||||
maximized,
|
maximized: false,
|
||||||
sticky: false,
|
sticky: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -916,11 +914,7 @@ impl XwmHandler for State {
|
||||||
// We only allow floating X11 windows to resize themselves. Nothing else
|
// We only allow floating X11 windows to resize themselves. Nothing else
|
||||||
let shell = self.common.shell.read();
|
let shell = self.common.shell.read();
|
||||||
|
|
||||||
if window.is_fullscreen() {
|
// TODO: Fullscreen
|
||||||
let _ = window.configure(None);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(mapped) = shell
|
if let Some(mapped) = shell
|
||||||
.element_for_surface(&window)
|
.element_for_surface(&window)
|
||||||
.filter(|mapped| !mapped.is_minimized())
|
.filter(|mapped| !mapped.is_minimized())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue