Compare commits
1 commit
master
...
feat/scree
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b2550d567 |
38 changed files with 162 additions and 208 deletions
|
|
@ -86,9 +86,7 @@ impl ExtImageCopyCaptureFrameV1 {
|
|||
let buffer = self.session.buffer.get().unwrap();
|
||||
if size != buffer.rect.size() {
|
||||
self.session.buffer_size_changed();
|
||||
// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/222
|
||||
// self.fail(FrameFailureReason::BufferConstraints);
|
||||
// return;
|
||||
return Err(FrameFailureReason::BufferConstraints);
|
||||
}
|
||||
if let Err(e) = buffer.update_framebuffer() {
|
||||
log::error!("Could not import buffer: {}", ErrorFmt(e));
|
||||
|
|
@ -102,6 +100,13 @@ impl ExtImageCopyCaptureFrameV1 {
|
|||
let mut shm_staging = self.session.shm_staging.take();
|
||||
match storage {
|
||||
WlBufferStorage::Shm { mem, stride, .. } => {
|
||||
log::debug!(
|
||||
"ext-image-copy frame {:?} using wl_shm readback path: {}x{}, stride {}",
|
||||
self.id,
|
||||
buffer.rect.width(),
|
||||
buffer.rect.height(),
|
||||
*stride,
|
||||
);
|
||||
if let Some(b) = &shm_bridge
|
||||
&& (b.physical_size() != buffer.rect.size()
|
||||
|| b.format() != buffer.format
|
||||
|
|
@ -159,6 +164,12 @@ impl ExtImageCopyCaptureFrameV1 {
|
|||
self.session.shm_staging.set(Some(staging));
|
||||
}
|
||||
WlBufferStorage::Dmabuf { fb, .. } => {
|
||||
log::debug!(
|
||||
"ext-image-copy frame {:?} using dmabuf GPU copy path: {}x{}",
|
||||
self.id,
|
||||
buffer.rect.width(),
|
||||
buffer.rect.height(),
|
||||
);
|
||||
let Some(fb) = fb else {
|
||||
return Err(FrameFailureReason::BufferConstraints);
|
||||
};
|
||||
|
|
@ -187,7 +198,11 @@ impl ExtImageCopyCaptureFrameV1 {
|
|||
) {
|
||||
match self.try_copy(on, size, f) {
|
||||
Ok(()) => self.session.status.set(FrameStatus::Captured),
|
||||
Err(e) => self.fail(e),
|
||||
Err(e) => {
|
||||
if self.session.status.get() != FrameStatus::Failed {
|
||||
self.fail(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,11 @@ impl ExtImageCopyCaptureSessionV1 {
|
|||
if self.size_debounce.replace(true) {
|
||||
return;
|
||||
}
|
||||
if let Some(frame) = self.frame.get()
|
||||
&& let FrameStatus::Capturing | FrameStatus::Captured = self.status.get()
|
||||
{
|
||||
frame.fail(FrameFailureReason::BufferConstraints);
|
||||
}
|
||||
self.force_capture.set(true);
|
||||
self.send_current_buffer_size();
|
||||
self.send_done();
|
||||
|
|
|
|||
|
|
@ -1520,25 +1520,25 @@ impl WlSurface {
|
|||
let bounds = self.toplevel.get().and_then(|tl| tl.tl_render_bounds());
|
||||
let pos = self.buffer_abs_pos.get();
|
||||
let apply_damage = |pos: Rect| {
|
||||
let clip_damage = |mut damage: Rect| {
|
||||
damage = damage.intersect(pos);
|
||||
if pending.damage_full {
|
||||
let mut damage = pos;
|
||||
if let Some(bounds) = bounds {
|
||||
damage = damage.intersect(bounds);
|
||||
}
|
||||
damage
|
||||
};
|
||||
if pending.damage_full {
|
||||
self.client.state.damage(clip_damage(pos));
|
||||
self.client.state.damage(damage);
|
||||
} else {
|
||||
let matrix = self.damage_matrix.get();
|
||||
if let Some(buffer) = self.buffer.get() {
|
||||
for damage in &pending.buffer_damage {
|
||||
let damage = matrix.apply(
|
||||
let mut damage = matrix.apply(
|
||||
pos.x1(),
|
||||
pos.y1(),
|
||||
damage.intersect(buffer.buffer.buf.rect),
|
||||
);
|
||||
self.client.state.damage(clip_damage(damage));
|
||||
if let Some(bounds) = bounds {
|
||||
damage = damage.intersect(bounds);
|
||||
}
|
||||
self.client.state.damage(damage);
|
||||
}
|
||||
}
|
||||
for damage in &pending.surface_damage {
|
||||
|
|
@ -1550,7 +1550,8 @@ impl WlSurface {
|
|||
let y2 = (damage.y2() + scale - 1) / scale;
|
||||
damage = Rect::new_saturating(x1, y1, x2, y2);
|
||||
}
|
||||
self.client.state.damage(clip_damage(damage));
|
||||
damage = damage.intersect(bounds.unwrap_or(pos));
|
||||
self.client.state.damage(damage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -48,16 +48,13 @@ impl ZwlrScreencopyFrameV1 {
|
|||
}
|
||||
|
||||
pub fn send_damage(&self) {
|
||||
if let Some(output) = self.output.get() {
|
||||
let pos = output.pos.get();
|
||||
self.client.event(Damage {
|
||||
self_id: self.id,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: pos.width() as _,
|
||||
height: pos.height() as _,
|
||||
});
|
||||
}
|
||||
self.client.event(Damage {
|
||||
self_id: self.id,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: self.rect.width() as _,
|
||||
height: self.rect.height() as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_buffer(&self) {
|
||||
|
|
@ -111,10 +108,28 @@ impl ZwlrScreencopyFrameV1 {
|
|||
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferFormat);
|
||||
}
|
||||
buffer.update_framebuffer()?;
|
||||
if let Some(WlBufferStorage::Shm { stride, .. }) = buffer.storage.borrow_mut().deref()
|
||||
&& *stride != self.rect.width() * 4
|
||||
{
|
||||
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferStride);
|
||||
match buffer.storage.borrow_mut().deref() {
|
||||
Some(WlBufferStorage::Shm { stride, .. }) => {
|
||||
if *stride != self.rect.width() * 4 {
|
||||
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferStride);
|
||||
}
|
||||
log::debug!(
|
||||
"zwlr_screencopy frame {:?} using wl_shm readback path: {}x{}, stride {}",
|
||||
self.id,
|
||||
self.rect.width(),
|
||||
self.rect.height(),
|
||||
*stride,
|
||||
);
|
||||
}
|
||||
Some(WlBufferStorage::Dmabuf { .. }) => {
|
||||
log::debug!(
|
||||
"zwlr_screencopy frame {:?} using dmabuf GPU copy path: {}x{}",
|
||||
self.id,
|
||||
self.rect.width(),
|
||||
self.rect.height(),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.buffer.set(Some(buffer));
|
||||
if !with_damage && let Some(global) = self.output.get() {
|
||||
|
|
@ -134,6 +149,12 @@ impl ZwlrScreencopyFrameV1 {
|
|||
}
|
||||
self.pending.take();
|
||||
}
|
||||
|
||||
pub fn cancel(&self) {
|
||||
self.buffer.take();
|
||||
self.pending.take();
|
||||
self.send_failed();
|
||||
}
|
||||
}
|
||||
|
||||
impl ZwlrScreencopyFrameV1RequestHandler for ZwlrScreencopyFrameV1 {
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@ impl ZwlrScreencopyManagerV1 {
|
|||
let Some(global) = output.global.get() else {
|
||||
return Ok(());
|
||||
};
|
||||
let mode = global.mode.get();
|
||||
let mut rect = Rect::new_sized_saturating(0, 0, mode.width, mode.height);
|
||||
let (width, height) = global.pixel_size();
|
||||
let mut rect = Rect::new_sized_saturating(0, 0, width, height);
|
||||
if let Some(region) = region {
|
||||
let scale = global.persistent.scale.get().to_f64();
|
||||
let x1 = (region.x1() as f64 * scale).round() as i32;
|
||||
|
|
|
|||
|
|
@ -29,17 +29,6 @@ impl TestViewport {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unset_source(&self) -> Result<(), TestError> {
|
||||
self.tran.send(SetSource {
|
||||
self_id: self.id,
|
||||
x: Fixed::from_int(-1),
|
||||
y: Fixed::from_int(-1),
|
||||
width: Fixed::from_int(-1),
|
||||
height: Fixed::from_int(-1),
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_destination(&self, width: i32, height: i32) -> Result<(), TestError> {
|
||||
self.tran.send(SetDestination {
|
||||
self_id: self.id,
|
||||
|
|
@ -48,15 +37,6 @@ impl TestViewport {
|
|||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unset_destination(&self) -> Result<(), TestError> {
|
||||
self.tran.send(SetDestination {
|
||||
self_id: self.id,
|
||||
width: -1,
|
||||
height: -1,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestViewport {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{test_error::TestError, testrun::TestRun},
|
||||
rect::Rect,
|
||||
tree::Node,
|
||||
},
|
||||
std::rc::Rc,
|
||||
|
|
@ -10,19 +11,29 @@ testcase!();
|
|||
|
||||
/// Create and map a single surface
|
||||
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||
let ds = run.create_default_setup().await?;
|
||||
run.backend.install_default()?;
|
||||
|
||||
let client = run.create_client().await?;
|
||||
|
||||
let window = client.create_window().await?;
|
||||
window.map().await?;
|
||||
|
||||
let workspace_rect = ds.output.workspace_rect.get();
|
||||
tassert_eq!(window.tl.core.width.get(), 800);
|
||||
tassert_eq!(
|
||||
window.tl.core.height.get(),
|
||||
600 - 2 * run.state.theme.title_plus_underline_height()
|
||||
);
|
||||
|
||||
tassert_eq!(window.tl.core.width.get(), workspace_rect.width());
|
||||
tassert_eq!(window.tl.core.height.get(), workspace_rect.height());
|
||||
|
||||
tassert_eq!(window.tl.server.node_absolute_position(), workspace_rect);
|
||||
tassert_eq!(
|
||||
window.tl.server.node_absolute_position(),
|
||||
Rect::new_sized(
|
||||
0,
|
||||
2 * run.state.theme.title_plus_underline_height(),
|
||||
window.tl.core.width.get(),
|
||||
window.tl.core.height.get(),
|
||||
)
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ testcase!();
|
|||
|
||||
/// Create and map two surfaces
|
||||
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||
let ds = run.create_default_setup().await?;
|
||||
run.backend.install_default()?;
|
||||
|
||||
let client = run.create_client().await?;
|
||||
|
||||
|
|
@ -21,30 +21,17 @@ async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
|||
let window2 = client.create_window().await?;
|
||||
window2.map().await?;
|
||||
|
||||
let workspace_rect = ds.output.workspace_rect.get();
|
||||
let otop = 2 * run.state.theme.title_plus_underline_height();
|
||||
let bw = run.state.theme.sizes.border_width.get();
|
||||
let child_width = (workspace_rect.width() - bw) / 2;
|
||||
|
||||
tassert_eq!(
|
||||
window.tl.server.node_absolute_position(),
|
||||
Rect::new_sized(
|
||||
workspace_rect.x1(),
|
||||
workspace_rect.y1(),
|
||||
child_width,
|
||||
workspace_rect.height(),
|
||||
)
|
||||
.unwrap()
|
||||
Rect::new_sized(0, otop, (800 - bw) / 2, 600 - otop).unwrap()
|
||||
);
|
||||
|
||||
tassert_eq!(
|
||||
window2.tl.server.node_absolute_position(),
|
||||
Rect::new_sized(
|
||||
workspace_rect.x1() + child_width + bw,
|
||||
workspace_rect.y1(),
|
||||
child_width,
|
||||
workspace_rect.height(),
|
||||
)
|
||||
.unwrap()
|
||||
Rect::new_sized((800 - bw) / 2 + bw, otop, (800 - bw) / 2, 600 - otop).unwrap()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -48,18 +48,13 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
|
||||
let mono_container = w_mono2.tl.container_parent()?;
|
||||
let container_pos = mono_container.tl_data().pos.get();
|
||||
let (tab_x, tab_y) = {
|
||||
let tab_bar = mono_container.tab_bar.borrow();
|
||||
let Some(tab_bar) = tab_bar.as_ref() else {
|
||||
bail!("no tab bar");
|
||||
};
|
||||
let w_mono1_title = &tab_bar.entries[0];
|
||||
(
|
||||
container_pos.x1() + w_mono1_title.x.get() + w_mono1_title.width.get() / 2,
|
||||
container_pos.y1() + tab_bar.height / 2,
|
||||
)
|
||||
};
|
||||
ds.mouse.abs(&ds.connector, tab_x as _, tab_y as _);
|
||||
let w_mono1_title = mono_container.render_data.borrow_mut().title_rects[0]
|
||||
.move_(container_pos.x1(), container_pos.y1());
|
||||
ds.mouse.abs(
|
||||
&ds.connector,
|
||||
w_mono1_title.x1() as _,
|
||||
w_mono1_title.y1() as _,
|
||||
);
|
||||
|
||||
client.sync().await;
|
||||
tassert!(enters.next().is_err());
|
||||
|
|
|
|||
|
|
@ -26,18 +26,12 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
|
||||
let container = w_mono2.tl.container_parent()?;
|
||||
let pos = container.tl_data().pos.get();
|
||||
let (tab_x, tab_y) = {
|
||||
let tab_bar = container.tab_bar.borrow();
|
||||
let Some(tab_bar) = tab_bar.as_ref() else {
|
||||
bail!("no tab bar");
|
||||
};
|
||||
let w_mono1_title = &tab_bar.entries[0];
|
||||
(
|
||||
pos.x1() + w_mono1_title.x.get() + w_mono1_title.width.get() / 2,
|
||||
pos.y1() + tab_bar.height / 2,
|
||||
)
|
||||
};
|
||||
ds.mouse.abs(&ds.connector, tab_x as f64, tab_y as f64);
|
||||
let w_mono1_title = container.render_data.borrow_mut().title_rects[0].move_(pos.x1(), pos.y1());
|
||||
ds.mouse.abs(
|
||||
&ds.connector,
|
||||
w_mono1_title.x1() as f64,
|
||||
w_mono1_title.y1() as f64,
|
||||
);
|
||||
client.sync().await;
|
||||
|
||||
let enters = dss.kb.enter.expect()?;
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -2,7 +2,7 @@ use {
|
|||
crate::{
|
||||
ifs::wl_surface::xdg_surface::xdg_toplevel::STATE_SUSPENDED,
|
||||
it::{
|
||||
test_error::{TestErrorExt, TestResult},
|
||||
test_error::TestResult,
|
||||
test_utils::{
|
||||
test_ouput_node_ext::TestOutputNodeExt, test_toplevel_node_ext::TestToplevelNodeExt,
|
||||
},
|
||||
|
|
@ -10,7 +10,7 @@ use {
|
|||
},
|
||||
},
|
||||
isnt::std_1::collections::IsntHashSetExt,
|
||||
std::{rc::Rc, time::Duration},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
testcase!();
|
||||
|
|
@ -19,7 +19,6 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
let ds = run.create_default_setup().await?;
|
||||
|
||||
let client = run.create_client().await?;
|
||||
let default_seat = client.get_default_seat().await?;
|
||||
|
||||
let win1 = client.create_window().await?;
|
||||
win1.set_color(255, 0, 0, 255);
|
||||
|
|
@ -45,23 +44,5 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
client.sync().await;
|
||||
tassert!(win2.tl.core.states.borrow().not_contains(&STATE_SUSPENDED));
|
||||
|
||||
let leaves = default_seat.kb.leave.expect()?;
|
||||
let enters = default_seat.kb.enter.expect()?;
|
||||
|
||||
run.cfg.set_idle(Duration::from_micros(100))?;
|
||||
run.cfg.set_idle_grace_period(Duration::from_secs(0))?;
|
||||
run.state.wheel.timeout(3).await?;
|
||||
|
||||
client.sync().await;
|
||||
tassert!(win2.tl.core.states.borrow().contains(&STATE_SUSPENDED));
|
||||
let leave = leaves.next().with_context(|| "no leave on suspend")?;
|
||||
tassert_eq!(leave.surface, win2.surface.id);
|
||||
|
||||
ds.mouse.rel(1.0, 1.0);
|
||||
client.sync().await;
|
||||
tassert!(win2.tl.core.states.borrow().not_contains(&STATE_SUSPENDED));
|
||||
let enter = enters.next().with_context(|| "no enter on restore")?;
|
||||
tassert_eq!(enter.surface, win2.surface.id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -308,8 +308,9 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
let output_damage = connector_data.damage.borrow();
|
||||
tassert!(!output_damage.is_empty());
|
||||
|
||||
// The test window maps its 1x1 buffer through a viewport to the full window size.
|
||||
let expected_buffer_damage = surface_pos;
|
||||
// Buffer damage is transformed by the damage matrix which includes the surface position
|
||||
// The buffer damage (0,0,1,1) should be transformed to surface coordinates
|
||||
let expected_buffer_damage = buffer_damage.move_(surface_pos.x1(), surface_pos.y1());
|
||||
|
||||
// Find the exact output damage that matches our expected buffer damage
|
||||
let mut found_exact_buffer_damage = false;
|
||||
|
|
@ -330,12 +331,10 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
// Test 7: Check output damage from existing window's viewport (which already has scaling)
|
||||
connector_data.damage.borrow_mut().clear();
|
||||
|
||||
// The existing window was created with create_surface_ext() which automatically creates a viewport.
|
||||
// Commit the viewport size change separately; that commit intentionally damages the old/new extents.
|
||||
window.surface.viewport.set_destination(150, 100)?;
|
||||
window.surface.commit()?;
|
||||
client.sync().await;
|
||||
connector_data.damage.borrow_mut().clear();
|
||||
// The existing window was created with create_surface_ext() which automatically creates a viewport
|
||||
// Let's verify that the viewport's existing scaling affects buffer damage correctly
|
||||
// First, let's modify the viewport scaling that already exists on the window
|
||||
window.surface.viewport.set_destination(150, 100)?; // Change scaling to 150x100
|
||||
|
||||
// Add buffer damage to test viewport scaling coordinate transformation
|
||||
window.surface.damage_buffer(0, 0, 1, 1)?; // Damage entire 1x1 buffer
|
||||
|
|
@ -347,8 +346,8 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
let output_damage = connector_data.damage.borrow();
|
||||
tassert!(!output_damage.is_empty());
|
||||
|
||||
// With viewporter scaling, the 1x1 buffer damage should scale to the viewport destination.
|
||||
let surface_pos = window.surface.server.buffer_abs_pos.get();
|
||||
// With viewporter scaling, the 1x1 buffer damage should scale to 150x100
|
||||
// and be moved by surface position (0, 36) to get output coordinates (0, 36, 150, 136)
|
||||
let expected_scaled_damage = Rect::new_sized(0, 0, 150, 100).unwrap();
|
||||
let expected_output_damage =
|
||||
expected_scaled_damage.move_(surface_pos.x1(), surface_pos.y1());
|
||||
|
|
@ -403,9 +402,8 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
rotation_window.map().await?;
|
||||
client.sync().await;
|
||||
|
||||
// Disable viewporter to rely purely on buffer dimensions.
|
||||
rotation_window.surface.viewport.unset_source()?;
|
||||
rotation_window.surface.viewport.unset_destination()?;
|
||||
// Disable viewporter by setting destination to 0x0 to rely purely on buffer dimensions
|
||||
rotation_window.surface.viewport.set_destination(0, 0)?; // Disable viewporter
|
||||
|
||||
// Use a rectangular buffer (4x2) so rotation has a visible geometric effect
|
||||
// Attach AFTER mapping to avoid being overwritten by map()'s single-pixel buffer
|
||||
|
|
|
|||
|
|
@ -315,6 +315,14 @@ impl PwClientNodeOwner for StartedScreencast {
|
|||
}
|
||||
}
|
||||
}
|
||||
log::debug!(
|
||||
"Portal screencast using PipeWire dmabuf GPU copy path: {} buffers, format {}, modifier 0x{:08x}, size {}x{}",
|
||||
self.buffers.borrow().len(),
|
||||
self.format.get().name,
|
||||
self.modifier.get(),
|
||||
self.width.get(),
|
||||
self.height.get(),
|
||||
);
|
||||
self.node
|
||||
.send_port_output_buffers(&self.port, &self.buffers.borrow());
|
||||
}
|
||||
|
|
@ -633,15 +641,18 @@ impl UsrJayScreencastOwner for StartedScreencast {
|
|||
|
||||
fn ready(&self, ev: &Ready) {
|
||||
let idx = ev.idx as usize;
|
||||
let buffers = &*self.buffers.borrow();
|
||||
let pbuffers = self.port.buffers.borrow();
|
||||
let buffer = &buffers[idx];
|
||||
let discard_buffer = || {
|
||||
self.jay_screencast.release_buffer(idx);
|
||||
};
|
||||
if !self.buffers_valid.get() {
|
||||
return;
|
||||
}
|
||||
let buffers = self.buffers.borrow();
|
||||
let Some(buffer) = buffers.get(idx) else {
|
||||
log::warn!("Ignoring ready event for unknown screencast buffer {idx}");
|
||||
return;
|
||||
};
|
||||
let pbuffers = self.port.buffers.borrow();
|
||||
let Some(io) = self.port.io_buffers.get() else {
|
||||
discard_buffer();
|
||||
return;
|
||||
|
|
@ -767,7 +778,7 @@ pub(super) fn add_screencast_dbus_members(
|
|||
object.add_method::<Start, _>(move |req, pr| {
|
||||
dbus_start(&state, req, pr);
|
||||
});
|
||||
object.set_property::<AvailableSourceTypes>(Variant::U32(MONITOR.0));
|
||||
object.set_property::<AvailableSourceTypes>(Variant::U32((MONITOR | WINDOW).0));
|
||||
object.set_property::<AvailableCursorModes>(Variant::U32(EMBEDDED.0));
|
||||
object.set_property::<version>(Variant::U32(5));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ use {
|
|||
numcell::NumCell,
|
||||
on_drop_event::OnDropEvent,
|
||||
rc_eq::rc_eq,
|
||||
scroller::Scroller,
|
||||
threshold_counter::ThresholdCounter,
|
||||
},
|
||||
},
|
||||
|
|
@ -151,7 +150,6 @@ pub struct ContainerNode {
|
|||
pub child_removed: Rc<LazyEventSource>,
|
||||
pub all_children_resized: Rc<LazyEventSource>,
|
||||
pub tab_bar: RefCell<Option<TabBar>>,
|
||||
scroll: Scroller,
|
||||
pub update_tab_textures_scheduled: Cell<bool>,
|
||||
pub ephemeral: Cell<Ephemeral>,
|
||||
}
|
||||
|
|
@ -268,7 +266,6 @@ impl ContainerNode {
|
|||
child_removed: state.lazy_event_sources.create_source(),
|
||||
all_children_resized: state.post_layout_event_sources.create_source(),
|
||||
tab_bar: RefCell::new(None),
|
||||
scroll: Default::default(),
|
||||
update_tab_textures_scheduled: Cell::new(false),
|
||||
ephemeral: Cell::new(Ephemeral::Off),
|
||||
});
|
||||
|
|
@ -796,18 +793,6 @@ impl ContainerNode {
|
|||
self.activate_child2(child, false);
|
||||
}
|
||||
|
||||
fn activate_child_from_input(
|
||||
self: &Rc<Self>,
|
||||
child: &NodeRef<ContainerChild>,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
) {
|
||||
self.activate_child(child);
|
||||
child
|
||||
.node
|
||||
.clone()
|
||||
.node_do_focus(seat, Direction::Unspecified);
|
||||
}
|
||||
|
||||
fn activate_child2(self: &Rc<Self>, child: &NodeRef<ContainerChild>, preserve_focus: bool) {
|
||||
if let Some(mc) = self.mono_child.get() {
|
||||
if mc.node.node_id() == child.node.node_id() {
|
||||
|
|
@ -1534,7 +1519,7 @@ impl ContainerNode {
|
|||
fn button(
|
||||
self: Rc<Self>,
|
||||
id: CursorType,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
_seat: &Rc<WlSeatGlobal>,
|
||||
_time_usec: u64,
|
||||
pressed: bool,
|
||||
button: u32,
|
||||
|
|
@ -1564,7 +1549,7 @@ impl ContainerNode {
|
|||
if let Some(child) = children.get(&child_id) {
|
||||
let child_ref = child.to_ref();
|
||||
drop(children);
|
||||
self.activate_child_from_input(&child_ref, seat);
|
||||
self.activate_child(&child_ref);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -2081,33 +2066,31 @@ impl Node for ContainerNode {
|
|||
self.button(id, seat, time_usec, state == ButtonState::Pressed, button);
|
||||
}
|
||||
|
||||
fn node_on_axis_event(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, event: &PendingScroll) {
|
||||
fn node_on_axis_event(self: Rc<Self>, _seat: &Rc<WlSeatGlobal>, event: &PendingScroll) {
|
||||
if self.mono_child.is_none() {
|
||||
return;
|
||||
}
|
||||
let steps = match self.scroll.handle(event) {
|
||||
Some(steps) => steps,
|
||||
// Use vertical scroll (index 1) to switch tabs.
|
||||
let v = match event.v120[1].get() {
|
||||
Some(v) if v != 0 => v,
|
||||
_ => return,
|
||||
};
|
||||
let mut target = match self.mono_child.get() {
|
||||
let mono = match self.mono_child.get() {
|
||||
Some(m) => m,
|
||||
None => return,
|
||||
};
|
||||
let current_id = target.node.node_id();
|
||||
for _ in 0..steps.abs() {
|
||||
let next = if steps > 0 {
|
||||
target.next().or_else(|| self.children.first())
|
||||
} else {
|
||||
target.prev().or_else(|| self.children.last())
|
||||
};
|
||||
match next {
|
||||
Some(next) => target = next,
|
||||
None => break,
|
||||
let next = if v > 0 {
|
||||
// Scroll down → next tab.
|
||||
mono.next().or_else(|| self.children.first())
|
||||
} else {
|
||||
// Scroll up → previous tab.
|
||||
mono.prev().or_else(|| self.children.last())
|
||||
};
|
||||
if let Some(next) = next {
|
||||
if next.node.node_id() != mono.node.node_id() {
|
||||
self.activate_child(&next);
|
||||
}
|
||||
}
|
||||
if target.node.node_id() != current_id {
|
||||
self.activate_child_from_input(&target, seat);
|
||||
}
|
||||
}
|
||||
|
||||
fn node_on_leave(&self, seat: &WlSeatGlobal) {
|
||||
|
|
|
|||
|
|
@ -8,25 +8,18 @@ use {
|
|||
renderer::Renderer,
|
||||
state::State,
|
||||
tree::{
|
||||
Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink,
|
||||
NodeLocation, OutputNode, StackedNode, TileDragDestination, WorkspaceDragDestination,
|
||||
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink, NodeLocation,
|
||||
OutputNode, StackedNode, TileDragDestination, WorkspaceDragDestination,
|
||||
WorkspaceNodeId, walker::NodeVisitor,
|
||||
},
|
||||
utils::{copyhashmap::CopyHashMap, linkedlist::LinkedList},
|
||||
},
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
mem,
|
||||
ops::Deref,
|
||||
rc::{Rc, Weak},
|
||||
},
|
||||
std::{cell::Cell, ops::Deref, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct DisplayNode {
|
||||
pub id: NodeId,
|
||||
pub extents: Cell<Rect>,
|
||||
visible: Cell<bool>,
|
||||
suspend_restore_kb_foci: RefCell<Vec<(Rc<WlSeatGlobal>, Weak<dyn Node>)>>,
|
||||
pub outputs: CopyHashMap<ConnectorId, Rc<OutputNode>>,
|
||||
pub stacked: Rc<LinkedList<Rc<dyn StackedNode>>>,
|
||||
pub stacked_above_layers: Rc<LinkedList<Rc<dyn StackedNode>>>,
|
||||
|
|
@ -38,8 +31,6 @@ impl DisplayNode {
|
|||
let slf = Self {
|
||||
id,
|
||||
extents: Default::default(),
|
||||
visible: Default::default(),
|
||||
suspend_restore_kb_foci: Default::default(),
|
||||
outputs: Default::default(),
|
||||
stacked: Default::default(),
|
||||
stacked_above_layers: Default::default(),
|
||||
|
|
@ -80,17 +71,6 @@ impl DisplayNode {
|
|||
|
||||
pub fn update_visible(&self, state: &State) {
|
||||
let visible = state.root_visible();
|
||||
let was_visible = self.visible.replace(visible);
|
||||
if !visible && was_visible {
|
||||
let mut foci = self.suspend_restore_kb_foci.borrow_mut();
|
||||
foci.clear();
|
||||
for seat in state.globals.seats.lock().values() {
|
||||
let node = seat.get_keyboard_node();
|
||||
if node.node_id() != self.id {
|
||||
foci.push((seat.clone(), Rc::downgrade(&node)));
|
||||
}
|
||||
}
|
||||
}
|
||||
for output in self.outputs.lock().values() {
|
||||
output.update_visible();
|
||||
}
|
||||
|
|
@ -102,20 +82,6 @@ impl DisplayNode {
|
|||
for seat in state.globals.seats.lock().values() {
|
||||
seat.set_visible(visible);
|
||||
}
|
||||
if visible && !was_visible {
|
||||
for (seat, node) in mem::take(&mut *self.suspend_restore_kb_foci.borrow_mut()) {
|
||||
if seat.get_keyboard_node().node_id() == self.id {
|
||||
if let Some(node) = node.upgrade()
|
||||
&& node.node_visible()
|
||||
{
|
||||
seat.focus_node(node);
|
||||
} else {
|
||||
seat.get_fallback_output()
|
||||
.take_keyboard_navigation_focus(&seat, Direction::Unspecified);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if visible {
|
||||
state.damage(self.extents.get());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -460,9 +460,15 @@ impl OutputNode {
|
|||
}
|
||||
self.lock_surface.take();
|
||||
self.jay_outputs.clear();
|
||||
self.screencasts.clear();
|
||||
self.screencopies.clear();
|
||||
self.ext_copy_sessions.clear();
|
||||
for screencast in self.screencasts.lock().drain_values() {
|
||||
screencast.do_destroy();
|
||||
}
|
||||
for screencopy in self.screencopies.lock().drain_values() {
|
||||
screencopy.cancel();
|
||||
}
|
||||
for session in self.ext_copy_sessions.lock().drain_values() {
|
||||
session.stop();
|
||||
}
|
||||
self.ext_workspace_groups.clear();
|
||||
self.latch_event.clear();
|
||||
self.vblank_event.clear();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue