1
0
Fork 0
forked from wry/wry

cursor: ensure software cursors are drawn if some outputs don't have HC

This commit is contained in:
Julian Orth 2025-07-27 12:11:19 +02:00
parent dc9a3c20ea
commit 31a045e01b
5 changed files with 35 additions and 10 deletions

View file

@ -359,6 +359,7 @@ fn start_compositor2(
enable_primary_selection: Cell::new(true), enable_primary_selection: Cell::new(true),
xdg_surface_configure_events: Default::default(), xdg_surface_configure_events: Default::default(),
workspace_display_order: Cell::new(WorkspaceDisplayOrder::Manual), workspace_display_order: Cell::new(WorkspaceDisplayOrder::Manual),
outputs_without_hc: Default::default(),
}); });
state.tracker.register(ClientId::from_raw(0)); state.tracker.register(ClientId::from_raw(0));
create_dummy_output(&state); create_dummy_output(&state);

View file

@ -85,7 +85,7 @@ impl CursorUserGroup {
let x_int = x.round_down(); let x_int = x.round_down();
let y_int = y.round_down(); let y_int = y.round_down();
let extents = cursor.extents_at_scale(Scale::default()); let extents = cursor.extents_at_scale(Scale::default());
self.state.damage2(true, extents.move_(x_int, y_int)); self.damage(extents.move_(x_int, y_int));
} }
} }
@ -248,6 +248,10 @@ impl CursorUserGroup {
}; };
active.present_hardware_cursor(output, hc); active.present_hardware_cursor(output, hc);
} }
fn damage(&self, rect: Rect) {
self.state.damage2(true, self.hardware_cursor.get(), rect);
}
} }
impl CursorUser { impl CursorUser {
@ -416,10 +420,8 @@ impl CursorUser {
let old_x_int = old_x.round_down(); let old_x_int = old_x.round_down();
let old_y_int = old_y.round_down(); let old_y_int = old_y.round_down();
let extents = cursor.extents_at_scale(Scale::default()); let extents = cursor.extents_at_scale(Scale::default());
self.group self.group.damage(extents.move_(old_x_int, old_y_int));
.state self.group.damage(extents.move_(x_int, y_int));
.damage2(true, extents.move_(old_x_int, old_y_int));
self.group.state.damage2(true, extents.move_(x_int, y_int));
} }
self.pos.set((x, y)); self.pos.set((x, y));
self.update_hardware_cursor_(false); self.update_hardware_cursor_(false);
@ -435,7 +437,8 @@ impl CursorUser {
} }
pub fn software_cursor(&self) -> bool { pub fn software_cursor(&self) -> bool {
self.is_active() && !self.group.hardware_cursor.get() self.is_active()
&& (!self.group.hardware_cursor.get() || self.group.state.outputs_without_hc.get() > 0)
} }
fn update_hardware_cursor_(&self, render: bool) { fn update_hardware_cursor_(&self, render: bool) {

View file

@ -277,6 +277,7 @@ pub struct State {
pub enable_primary_selection: Cell<bool>, pub enable_primary_selection: Cell<bool>,
pub xdg_surface_configure_events: AsyncQueue<XdgSurfaceConfigureEvent>, pub xdg_surface_configure_events: AsyncQueue<XdgSurfaceConfigureEvent>,
pub workspace_display_order: Cell<WorkspaceDisplayOrder>, pub workspace_display_order: Cell<WorkspaceDisplayOrder>,
pub outputs_without_hc: NumCell<usize>,
} }
// impl Drop for State { // impl Drop for State {
@ -648,7 +649,7 @@ impl State {
fn visit_output(&mut self, node: &Rc<OutputNode>) { fn visit_output(&mut self, node: &Rc<OutputNode>) {
node.render_data.borrow_mut().titles.clear(); node.render_data.borrow_mut().titles.clear();
node.render_data.borrow_mut().status.take(); node.render_data.borrow_mut().status.take();
node.hardware_cursor.set(None); node.set_hardware_cursor(None);
node.node_visit_children(self); node.node_visit_children(self);
} }
fn visit_float(&mut self, node: &Rc<FloatNode>) { fn visit_float(&mut self, node: &Rc<FloatNode>) {
@ -968,16 +969,19 @@ impl State {
} }
pub fn damage(&self, rect: Rect) { pub fn damage(&self, rect: Rect) {
self.damage2(false, rect); self.damage2(false, false, rect);
} }
pub fn damage2(&self, cursor: bool, rect: Rect) { pub fn damage2(&self, cursor: bool, skip_hc: bool, rect: Rect) {
if rect.is_empty() { if rect.is_empty() {
return; return;
} }
self.damage_visualizer.add(rect); self.damage_visualizer.add(rect);
for output in self.root.outputs.lock().values() { for output in self.root.outputs.lock().values() {
if output.global.pos.get().intersects(&rect) { if output.global.pos.get().intersects(&rect) {
if skip_hc && output.hardware_cursor.is_some() {
continue;
}
output.global.add_damage_area(&rect); output.global.add_damage_area(&rect);
if cursor && output.schedule.defer_cursor_updates() { if cursor && output.schedule.defer_cursor_updates() {
output.schedule.software_cursor_changed(); output.schedule.software_cursor_changed();

View file

@ -271,6 +271,7 @@ impl ConnectorHandler {
self.state.outputs.set(self.id, output_data.clone()); self.state.outputs.set(self.id, output_data.clone());
on.schedule_update_render_data(); on.schedule_update_render_data();
self.state.root.outputs.set(self.id, on.clone()); self.state.root.outputs.set(self.id, on.clone());
self.state.outputs_without_hc.fetch_add(1);
self.state.output_extents_changed(); self.state.output_extents_changed();
global.opt.node.set(Some(on.clone())); global.opt.node.set(Some(on.clone()));
global.opt.global.set(Some(global.clone())); global.opt.global.set(Some(global.clone()));
@ -330,7 +331,7 @@ impl ConnectorHandler {
ConnectorEvent::Disconnected => break 'outer, ConnectorEvent::Disconnected => break 'outer,
ConnectorEvent::HardwareCursor(hc) => { ConnectorEvent::HardwareCursor(hc) => {
on.schedule.set_hardware_cursor(&hc); on.schedule.set_hardware_cursor(&hc);
on.hardware_cursor.set(hc); on.set_hardware_cursor(hc);
self.state.refresh_hardware_cursors(); self.state.refresh_hardware_cursors();
} }
ConnectorEvent::FormatsChanged(formats) => { ConnectorEvent::FormatsChanged(formats) => {
@ -363,6 +364,9 @@ impl ConnectorHandler {
sc.stop(); sc.stop();
} }
global.destroyed.set(true); global.destroyed.set(true);
if on.hardware_cursor.is_none() {
self.state.outputs_without_hc.fetch_sub(1);
}
self.state.root.outputs.remove(&self.id); self.state.root.outputs.remove(&self.id);
self.state.output_extents_changed(); self.state.output_extents_changed();
self.state.outputs.remove(&self.id); self.state.outputs.remove(&self.id);

View file

@ -1433,6 +1433,19 @@ impl OutputNode {
.handle_tearing_mode_change(mode.to_config()); .handle_tearing_mode_change(mode.to_config());
} }
} }
pub fn set_hardware_cursor(&self, hc: Option<Rc<dyn HardwareCursor>>) {
let is_none = hc.is_none();
let old = self.hardware_cursor.set(hc);
let was_none = old.is_none();
if was_none != is_none {
if is_none {
self.state.outputs_without_hc.fetch_add(1);
} else {
self.state.outputs_without_hc.fetch_sub(1);
}
}
}
} }
pub struct OutputTitle { pub struct OutputTitle {