diff --git a/src/compositor.rs b/src/compositor.rs index eeebec41..ae663ce0 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -236,6 +236,11 @@ fn start_compositor2( explicit_sync_enabled: Cell::new(true), keyboard_state_ids: Default::default(), security_context_acceptors: Default::default(), + cursor_user_group_ids: Default::default(), + cursor_user_ids: Default::default(), + cursor_users: Default::default(), + cursor_user_groups: Default::default(), + cursor_user_group_hardware_cursor: Default::default(), }); state.tracker.register(ClientId::from_raw(0)); create_dummy_output(&state); diff --git a/src/config/handler.rs b/src/config/handler.rs index a5e74c19..2b97c782 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -956,7 +956,7 @@ impl ConfigProxyHandler { if size < 0 { return Err(CphError::NegativeCursorSize); } - seat.set_cursor_size(size as _); + seat.cursor_group().set_cursor_size(size as _); Ok(()) } @@ -972,14 +972,7 @@ impl ConfigProxyHandler { use_hardware_cursor: bool, ) -> Result<(), CphError> { let seat = self.get_seat(seat)?; - if use_hardware_cursor { - for other in self.state.globals.seats.lock().values() { - if other.id() != seat.id() { - other.set_hardware_cursor(false); - } - } - } - seat.set_hardware_cursor(use_hardware_cursor); + seat.cursor_group().set_hardware_cursor(use_hardware_cursor); self.state.refresh_hardware_cursors(); Ok(()) } @@ -1037,18 +1030,7 @@ impl ConfigProxyHandler { if x < 0 || y < 0 || x > MAX_EXTENTS || y > MAX_EXTENTS { return Err(CphError::InvalidConnectorPosition(x, y)); } - let old_pos = connector.global.pos.get(); connector.set_position(x, y); - let seats = self.state.globals.seats.lock(); - for seat in seats.values() { - if seat.get_output().id == connector.id { - let seat_pos = seat.position(); - seat.set_position( - seat_pos.0.round_down() + x - old_pos.x1(), - seat_pos.1.round_down() + y - old_pos.y1(), - ); - } - } Ok(()) } diff --git a/src/cursor_user.rs b/src/cursor_user.rs new file mode 100644 index 00000000..f16abf3c --- /dev/null +++ b/src/cursor_user.rs @@ -0,0 +1,462 @@ +use { + crate::{ + cursor::{Cursor, KnownCursor, DEFAULT_CURSOR_SIZE}, + fixed::Fixed, + rect::Rect, + state::State, + tree::OutputNode, + utils::{ + clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, rc_eq::rc_eq, + transform_ext::TransformExt, + }, + }, + std::{cell::Cell, ops::Deref, rc::Rc}, +}; + +linear_ids!(CursorUserGroupIds, CursorUserGroupId, u64); +linear_ids!(CursorUserIds, CursorUserId, u64); + +pub trait CursorUserOwner { + fn output_changed(&self, output: &Rc); +} + +pub struct CursorUserGroup { + pub id: CursorUserGroupId, + state: Rc, + active_id: Cell>, + active: CloneCell>>, + users: CopyHashMap>, + hardware_cursor: Cell, + size: Cell, + latest_output: CloneCell>, +} + +pub struct CursorUser { + pub id: CursorUserId, + group: Rc, + desired_known_cursor: Cell>, + cursor: CloneCell>>, + output: CloneCell>, + output_pos: Cell, + pos: Cell<(Fixed, Fixed)>, + owner: CloneCell>>, +} + +impl CursorUserGroup { + pub fn create(state: &Rc) -> Rc { + let output = state + .root + .outputs + .lock() + .values() + .next() + .cloned() + .or_else(|| state.dummy_output.get()) + .unwrap(); + let hardware_cursor = state.cursor_user_group_hardware_cursor.is_none(); + let group = Rc::new(Self { + id: state.cursor_user_group_ids.next(), + state: state.clone(), + active_id: Default::default(), + active: Default::default(), + users: Default::default(), + hardware_cursor: Cell::new(hardware_cursor), + size: Cell::new(*DEFAULT_CURSOR_SIZE), + latest_output: CloneCell::new(output), + }); + state.add_cursor_size(*DEFAULT_CURSOR_SIZE); + state.cursor_user_groups.set(group.id, group.clone()); + if hardware_cursor { + state + .cursor_user_group_hardware_cursor + .set(Some(group.clone())); + } + group + } + + pub fn deactivate(&self) { + if self.hardware_cursor.get() { + self.remove_hardware_cursor(); + } + self.active_id.take(); + self.active.take(); + self.state.damage(); + } + + pub fn latest_output(&self) -> Rc { + self.latest_output.get() + } + + fn remove_hardware_cursor(&self) { + self.state.hardware_tick_cursor.push(None); + self.state.disable_hardware_cursors(); + self.state.cursor_user_group_hardware_cursor.take(); + } + + pub fn detach(&self) { + self.deactivate(); + self.latest_output + .set(self.state.dummy_output.get().unwrap()); + self.state.remove_cursor_size(self.size.get()); + self.state.cursor_user_groups.remove(&self.id); + for (_, user) in self.users.lock().drain() { + user.detach(); + } + } + + pub fn create_user(self: &Rc) -> Rc { + let output = self.latest_output.get(); + let user = Rc::new(CursorUser { + id: self.state.cursor_user_ids.next(), + group: self.clone(), + desired_known_cursor: Cell::new(None), + cursor: Default::default(), + pos: Cell::new(self.output_center(&output)), + output_pos: Cell::new(output.global.pos.get()), + output: CloneCell::new(output), + owner: Default::default(), + }); + self.users.set(user.id, user.clone()); + user + } + + pub fn set_visible(&self, visible: bool) { + if let Some(user) = self.active.get() { + if let Some(cursor) = user.cursor.get() { + cursor.set_visible(visible); + } + } + } + + pub fn active(&self) -> Option> { + self.active.get() + } + + pub fn render_ctx_changed(&self) { + for user in self.users.lock().values() { + if let Some(cursor) = user.desired_known_cursor.get() { + user.set_known(cursor); + } + } + } + + pub fn reload_known_cursor(&self) { + for user in self.users.lock().values() { + user.reload_known_cursor(); + } + } + + pub fn set_hardware_cursor(self: &Rc, hardware_cursor: bool) { + if self.hardware_cursor.replace(hardware_cursor) == hardware_cursor { + return; + } + if hardware_cursor { + let prev = self + .state + .cursor_user_group_hardware_cursor + .set(Some(self.clone())); + if let Some(prev) = prev { + prev.hardware_cursor.set(false); + } + match self.active.get() { + None => self.remove_hardware_cursor(), + Some(a) => a.update_hardware_cursor(), + } + } else { + self.remove_hardware_cursor(); + } + } + + pub fn hardware_cursor(&self) -> bool { + self.hardware_cursor.get() + } + + pub fn set_cursor_size(&self, size: u32) { + let old = self.size.replace(size); + if size != old { + self.state.remove_cursor_size(old); + self.state.add_cursor_size(size); + self.reload_known_cursor(); + } + } + + fn output_center(&self, output: &Rc) -> (Fixed, Fixed) { + let pos = output.global.pos.get(); + let x = Fixed::from_int((pos.x1() + pos.x2()) / 2); + let y = Fixed::from_int((pos.y1() + pos.y2()) / 2); + (x, y) + } + + pub fn first_output_connected(&self, output: &Rc) { + self.latest_output.set(output.clone()); + let (x, y) = self.output_center(output); + for user in self.users.lock().values() { + user.set_output(output); + user.set_position(x, y); + } + } + + pub fn output_disconnected(&self, output: &Rc, next: &Rc) { + if self.latest_output.get().id == output.id { + self.latest_output.set(next.clone()); + } + let (x, y) = self.output_center(next); + for user in self.users.lock().values() { + if user.output.get().id == output.id { + user.set_output(next); + user.set_position(x, y); + } + } + } + + pub fn output_pos_changed(&self, output: &Rc) { + let (x, y) = self.output_center(output); + for user in self.users.lock().values() { + if user.output.get().id == output.id { + user.output_pos.set(output.global.pos.get()); + user.set_position(x, y); + } + } + } +} + +impl CursorUser { + pub fn set_owner(&self, owner: Rc) { + self.owner.set(Some(owner)); + } + + pub fn detach(&self) { + self.set(None); + self.owner.take(); + self.group.users.remove(&self.id); + if self.group.active_id.get() == Some(self.id) { + self.group.active_id.take(); + self.group.active.take(); + self.group.state.damage(); + } + } + + pub fn activate(self: &Rc) { + if self.group.active_id.replace(Some(self.id)) == Some(self.id) { + return; + } + self.group.latest_output.set(self.output.get()); + self.group.active.set(Some(self.clone())); + self.update_hardware_cursor(); + self.group.state.damage(); + } + + #[cfg_attr(not(feature = "it"), allow(dead_code))] + pub fn desired_known_cursor(&self) -> Option { + self.desired_known_cursor.get() + } + + pub fn set_known(&self, cursor: KnownCursor) { + self.desired_known_cursor.set(Some(cursor)); + let cursors = match self.group.state.cursors.get() { + Some(c) => c, + None => { + self.set_cursor2(None); + return; + } + }; + let tpl = match cursor { + KnownCursor::Default => &cursors.default, + KnownCursor::ContextMenu => &cursors.context_menu, + KnownCursor::Help => &cursors.help, + KnownCursor::Pointer => &cursors.pointer, + KnownCursor::Progress => &cursors.progress, + KnownCursor::Wait => &cursors.wait, + KnownCursor::Cell => &cursors.cell, + KnownCursor::Crosshair => &cursors.crosshair, + KnownCursor::Text => &cursors.text, + KnownCursor::VerticalText => &cursors.vertical_text, + KnownCursor::Alias => &cursors.alias, + KnownCursor::Copy => &cursors.copy, + KnownCursor::Move => &cursors.r#move, + KnownCursor::NoDrop => &cursors.no_drop, + KnownCursor::NotAllowed => &cursors.not_allowed, + KnownCursor::Grab => &cursors.grab, + KnownCursor::Grabbing => &cursors.grabbing, + KnownCursor::EResize => &cursors.e_resize, + KnownCursor::NResize => &cursors.n_resize, + KnownCursor::NeResize => &cursors.ne_resize, + KnownCursor::NwResize => &cursors.nw_resize, + KnownCursor::SResize => &cursors.s_resize, + KnownCursor::SeResize => &cursors.se_resize, + KnownCursor::SwResize => &cursors.sw_resize, + KnownCursor::WResize => &cursors.w_resize, + KnownCursor::EwResize => &cursors.ew_resize, + KnownCursor::NsResize => &cursors.ns_resize, + KnownCursor::NeswResize => &cursors.nesw_resize, + KnownCursor::NwseResize => &cursors.nwse_resize, + KnownCursor::ColResize => &cursors.col_resize, + KnownCursor::RowResize => &cursors.row_resize, + KnownCursor::AllScroll => &cursors.all_scroll, + KnownCursor::ZoomIn => &cursors.zoom_in, + KnownCursor::ZoomOut => &cursors.zoom_out, + }; + self.set_cursor2(Some(tpl.instantiate(self.group.size.get()))); + } + + fn set_output(&self, output: &Rc) { + self.output.set(output.clone()); + self.output_pos.set(output.global.pos.get()); + if self.is_active() { + self.group.latest_output.set(output.clone()); + } + if let Some(cursor) = self.cursor.get() { + cursor.set_output(output); + } + if let Some(owner) = self.owner.get() { + owner.output_changed(output); + } + } + + pub fn output(&self) -> Rc { + self.output.get() + } + + pub fn get(&self) -> Option> { + self.cursor.get() + } + + pub fn set(&self, cursor: Option>) { + self.set_cursor2(cursor); + self.desired_known_cursor.set(None); + } + + fn is_active(&self) -> bool { + self.group.active_id.get() == Some(self.id) + } + + fn set_cursor2(&self, cursor: Option>) { + if let Some(old) = self.cursor.get() { + if let Some(new) = cursor.as_ref() { + if rc_eq(&old, new) { + self.update_hardware_cursor(); + return; + } + } + old.handle_unset(); + } + if let Some(cursor) = cursor.as_ref() { + cursor.clone().handle_set(); + cursor.set_output(&self.output.get()); + } + self.cursor.set(cursor.clone()); + self.update_hardware_cursor(); + } + + pub fn position(&self) -> (Fixed, Fixed) { + self.pos.get() + } + + pub fn set_position(&self, mut x: Fixed, mut y: Fixed) -> (Fixed, Fixed) { + let x_int = x.round_down(); + let y_int = y.round_down(); + if !self.output_pos.get().contains(x_int, y_int) { + let (output, x_tmp, y_tmp) = self.group.state.find_closest_output(x_int, y_int); + self.set_output(&output); + x = x.apply_fract(x_tmp); + y = y.apply_fract(y_tmp); + } + self.pos.set((x, y)); + self.update_hardware_cursor_(false); + (x, y) + } + + pub fn update_hardware_cursor(&self) { + self.update_hardware_cursor_(true); + } + + fn hardware_cursor(&self) -> bool { + self.is_active() && self.group.hardware_cursor.get() + } + + fn update_hardware_cursor_(&self, render: bool) { + if !self.hardware_cursor() { + return; + } + let cursor = self.cursor.get(); + self.group.state.hardware_tick_cursor.push(cursor.clone()); + let cursor = match cursor { + Some(c) => c, + _ => { + self.group.state.disable_hardware_cursors(); + return; + } + }; + if render { + cursor.tick(); + } + let (x, y) = self.pos.get(); + for output in self.group.state.root.outputs.lock().values() { + if let Some(hc) = output.hardware_cursor.get() { + let transform = output.global.persistent.transform.get(); + let render = render | output.hardware_cursor_needs_render.take(); + let scale = output.global.persistent.scale.get(); + let extents = cursor.extents_at_scale(scale); + let (hc_width, hc_height) = hc.size(); + if render { + let (max_width, max_height) = transform.maybe_swap((hc_width, hc_height)); + if extents.width() > max_width || extents.height() > max_height { + hc.set_enabled(false); + hc.commit(); + continue; + } + } + let opos = output.global.pos.get(); + let (x_rel, y_rel); + if scale == 1 { + x_rel = x.round_down() - opos.x1(); + y_rel = y.round_down() - opos.y1(); + } else { + let scalef = scale.to_f64(); + x_rel = ((x - Fixed::from_int(opos.x1())).to_f64() * scalef).round() as i32; + y_rel = ((y - Fixed::from_int(opos.y1())).to_f64() * scalef).round() as i32; + } + let (width, height) = output.global.pixel_size(); + if extents.intersects(&Rect::new_sized(-x_rel, -y_rel, width, height).unwrap()) { + if render { + let buffer = hc.get_buffer(); + let res = buffer.render_hardware_cursor( + cursor.deref(), + &self.group.state, + scale, + transform, + ); + match res { + Ok(sync_file) => { + hc.set_sync_file(sync_file); + hc.swap_buffer(); + } + Err(e) => { + log::error!("Could not render hardware cursor: {}", ErrorFmt(e)); + } + } + } + hc.set_enabled(true); + let mode = output.global.mode.get(); + let (x_rel, y_rel) = + transform.apply_point(mode.width, mode.height, (x_rel, y_rel)); + let (hot_x, hot_y) = + transform.apply_point(hc_width, hc_height, (-extents.x1(), -extents.y1())); + hc.set_position(x_rel - hot_x, y_rel - hot_y); + } else { + if render { + output.hardware_cursor_needs_render.set(true); + } + hc.set_enabled(false); + } + hc.commit(); + } + } + } + + fn reload_known_cursor(&self) { + if let Some(kc) = self.desired_known_cursor.get() { + self.set_known(kc); + } + } +} diff --git a/src/gfx_api.rs b/src/gfx_api.rs index a8f79551..51b45d8c 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -345,7 +345,7 @@ impl dyn GfxFramebuffer { if let Some(rect) = cursor_rect { let seats = state.globals.lock_seats(); for seat in seats.values() { - let (mut x, mut y) = seat.get_position(); + let (x, y) = seat.pointer_cursor().position(); if let Some(im) = seat.input_method() { for (_, popup) in &im.popups { if popup.surface.node_visible() { @@ -380,12 +380,16 @@ impl dyn GfxFramebuffer { } } if render_cursor { - if let Some(cursor) = seat.get_cursor() { - if render_hardware_cursor || !seat.hardware_cursor() { - cursor.tick(); - x -= Fixed::from_int(rect.x1()); - y -= Fixed::from_int(rect.y1()); - cursor.render(&mut renderer, x, y); + let cursor_user_group = seat.cursor_group(); + if render_hardware_cursor || !cursor_user_group.hardware_cursor() { + if let Some(cursor_user) = cursor_user_group.active() { + if let Some(cursor) = cursor_user.get() { + cursor.tick(); + let (mut x, mut y) = cursor_user.position(); + x -= Fixed::from_int(rect.x1()); + y -= Fixed::from_int(rect.y1()); + cursor.render(&mut renderer, x, y); + } } } } diff --git a/src/ifs/jay_input.rs b/src/ifs/jay_input.rs index f9368f6e..13284139 100644 --- a/src/ifs/jay_input.rs +++ b/src/ifs/jay_input.rs @@ -57,7 +57,7 @@ impl JayInput { name: data.seat_name(), repeat_rate: data.get_rate().0, repeat_delay: data.get_rate().1, - hardware_cursor: data.hardware_cursor() as _, + hardware_cursor: data.cursor_group().hardware_cursor() as _, }); } @@ -202,7 +202,8 @@ impl JayInputRequestHandler for JayInput { ) -> Result<(), Self::Error> { self.or_error(|| { let seat = self.seat(req.seat)?; - seat.set_hardware_cursor(req.use_hardware_cursor != 0); + seat.cursor_group() + .set_hardware_cursor(req.use_hardware_cursor != 0); Ok(()) }) } @@ -316,7 +317,7 @@ impl JayInputRequestHandler for JayInput { fn set_cursor_size(&self, req: SetCursorSize, _slf: &Rc) -> Result<(), Self::Error> { self.or_error(|| { let seat = self.seat(req.seat)?; - seat.set_cursor_size(req.size); + seat.cursor_group().set_cursor_size(req.size); Ok(()) }) } diff --git a/src/ifs/jay_pointer.rs b/src/ifs/jay_pointer.rs index 35170189..1e8fdb86 100644 --- a/src/ifs/jay_pointer.rs +++ b/src/ifs/jay_pointer.rs @@ -42,7 +42,7 @@ impl JayPointerRequestHandler for JayPointer { if pointer_node.node_client_id() != Some(self.client.id) { return Ok(()); } - self.seat.set_known_cursor(cursor); + self.seat.pointer_cursor().set_known(cursor); Ok(()) } } diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 6f073be1..440d6ae0 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -22,7 +22,7 @@ use { crate::{ async_engine::SpawnedFuture, client::{Client, ClientError, ClientId}, - cursor::{Cursor, KnownCursor, DEFAULT_CURSOR_SIZE}, + cursor_user::{CursorUser, CursorUserGroup, CursorUserOwner}, fixed::Fixed, globals::{Global, GlobalName}, ifs::{ @@ -63,7 +63,6 @@ use { }, leaks::Tracker, object::{Object, Version}, - rect::Rect, state::{DeviceHandlerData, State}, time::now_usec, tree::{ @@ -73,7 +72,7 @@ use { utils::{ asyncevent::AsyncEvent, bindings::PerClientBindings, clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, linkedlist::LinkedNode, numcell::NumCell, - rc_eq::rc_eq, smallmap::SmallMap, transform_ext::TransformExt, + rc_eq::rc_eq, smallmap::SmallMap, }, wire::{ wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId, @@ -141,7 +140,6 @@ pub struct WlSeatGlobal { state: Rc, seat_name: String, pos_time_usec: Cell, - pos: Cell<(Fixed, Fixed)>, pointer_stack: RefCell>>, pointer_stack_modified: Cell, found_tree: RefCell>, @@ -162,7 +160,8 @@ pub struct WlSeatGlobal { seat_xkb_state: CloneCell>>, latest_kb_state: CloneCell>, xkb_states: CopyHashMap>>, - cursor: CloneCell>>, + cursor_user_group: Rc, + pointer_cursor: Rc, tree_changed: Rc, selection: CloneCell>>, selection_serial: Cell, @@ -175,11 +174,7 @@ pub struct WlSeatGlobal { shortcuts: RefCell>>, queue_link: RefCell>>>, tree_changed_handler: Cell>>, - output: CloneCell>, - desired_known_cursor: Cell>, changes: NumCell, - cursor_size: Cell, - hardware_cursor: Cell, constraint: CloneCell>>, idle_notifications: CopyHashMap<(ClientId, ExtIdleNotificationV1Id), Rc>, last_input_usec: Cell, @@ -197,12 +192,6 @@ pub struct WlSeatGlobal { const CHANGE_CURSOR_MOVED: u32 = 1 << 0; const CHANGE_TREE: u32 = 1 << 1; -impl Drop for WlSeatGlobal { - fn drop(&mut self) { - self.state.remove_cursor_size(self.cursor_size.get()); - } -} - impl WlSeatGlobal { pub fn new(name: GlobalName, seat_name: &str, state: &Rc) -> Rc { let seat_xkb_state = state @@ -212,13 +201,15 @@ impl WlSeatGlobal { .unwrap(); let xkb_states = CopyHashMap::new(); xkb_states.set(state.default_keymap.id, Rc::downgrade(&seat_xkb_state)); + let cursor_user_group = CursorUserGroup::create(state); + let cursor_user = cursor_user_group.create_user(); + cursor_user.activate(); let slf = Rc::new(Self { id: state.seat_ids.next(), name, state: state.clone(), seat_name: seat_name.to_string(), pos_time_usec: Cell::new(0), - pos: Cell::new((Fixed(0), Fixed(0))), pointer_stack: RefCell::new(vec![]), pointer_stack_modified: Cell::new(false), found_tree: RefCell::new(vec![]), @@ -232,7 +223,8 @@ impl WlSeatGlobal { seat_xkb_state: CloneCell::new(seat_xkb_state.clone()), latest_kb_state: CloneCell::new(seat_xkb_state.clone()), xkb_states, - cursor: Default::default(), + cursor_user_group, + pointer_cursor: cursor_user, tree_changed: Default::default(), selection: Default::default(), selection_serial: Cell::new(0), @@ -245,11 +237,7 @@ impl WlSeatGlobal { shortcuts: Default::default(), queue_link: Default::default(), tree_changed_handler: Cell::new(None), - output: CloneCell::new(state.dummy_output.get().unwrap()), - desired_known_cursor: Cell::new(None), changes: NumCell::new(CHANGE_CURSOR_MOVED | CHANGE_TREE), - cursor_size: Cell::new(*DEFAULT_CURSOR_SIZE), - hardware_cursor: Cell::new(state.globals.seats.len() == 0), constraint: Default::default(), idle_notifications: Default::default(), last_input_usec: Cell::new(now_usec()), @@ -264,7 +252,7 @@ impl WlSeatGlobal { pinch_bindings: Default::default(), hold_bindings: Default::default(), }); - state.add_cursor_size(*DEFAULT_CURSOR_SIZE); + slf.pointer_cursor.set_owner(slf.clone()); let seat = slf.clone(); let future = state.eng.spawn(async move { loop { @@ -291,109 +279,6 @@ impl WlSeatGlobal { self.pointer_owner.toplevel_drag() } - pub fn set_hardware_cursor(&self, hardware_cursor: bool) { - self.hardware_cursor.set(hardware_cursor); - } - - pub fn hardware_cursor(&self) -> bool { - self.hardware_cursor.get() - } - - fn update_hardware_cursor_position(&self) { - self.update_hardware_cursor_(false); - } - - pub fn update_hardware_cursor(&self) { - self.update_hardware_cursor_(true); - } - - fn update_hardware_cursor_(&self, render: bool) { - if !self.hardware_cursor.get() { - return; - } - let cursor = match self.get_cursor() { - Some(c) => c, - _ => { - self.state.disable_hardware_cursors(); - return; - } - }; - if render { - cursor.tick(); - } - let (x, y) = self.get_position(); - for output in self.state.root.outputs.lock().values() { - if let Some(hc) = output.hardware_cursor.get() { - let transform = output.global.persistent.transform.get(); - let render = render | output.hardware_cursor_needs_render.take(); - let scale = output.global.persistent.scale.get(); - let extents = cursor.extents_at_scale(scale); - let (hc_width, hc_height) = hc.size(); - if render { - let (max_width, max_height) = transform.maybe_swap((hc_width, hc_height)); - if extents.width() > max_width || extents.height() > max_height { - hc.set_enabled(false); - hc.commit(); - continue; - } - } - let opos = output.global.pos.get(); - let (x_rel, y_rel); - if scale == 1 { - x_rel = x.round_down() - opos.x1(); - y_rel = y.round_down() - opos.y1(); - } else { - let scalef = scale.to_f64(); - x_rel = ((x - Fixed::from_int(opos.x1())).to_f64() * scalef).round() as i32; - y_rel = ((y - Fixed::from_int(opos.y1())).to_f64() * scalef).round() as i32; - } - let (width, height) = output.global.pixel_size(); - if extents.intersects(&Rect::new_sized(-x_rel, -y_rel, width, height).unwrap()) { - if render { - let buffer = hc.get_buffer(); - let res = buffer.render_hardware_cursor( - cursor.deref(), - &self.state, - scale, - transform, - ); - match res { - Ok(sync_file) => { - hc.set_sync_file(sync_file); - hc.swap_buffer(); - } - Err(e) => { - log::error!("Could not render hardware cursor: {}", ErrorFmt(e)); - } - } - } - hc.set_enabled(true); - let mode = output.global.mode.get(); - let (x_rel, y_rel) = - transform.apply_point(mode.width, mode.height, (x_rel, y_rel)); - let (hot_x, hot_y) = - transform.apply_point(hc_width, hc_height, (-extents.x1(), -extents.y1())); - hc.set_position(x_rel - hot_x, y_rel - hot_y); - } else { - if render { - output.hardware_cursor_needs_render.set(true); - } - hc.set_enabled(false); - } - hc.commit(); - } - } - } - - pub fn set_cursor_size(&self, size: u32) { - let old = self.cursor_size.replace(size); - if size != old { - self.state.remove_cursor_size(old); - self.state.add_cursor_size(size); - self.reload_known_cursor(); - } - } - pub fn add_data_device(&self, device: &Rc) { let mut dd = self.data_devices.borrow_mut(); dd.entry(device.client.id) @@ -452,7 +337,7 @@ impl WlSeatGlobal { } pub fn get_output(&self) -> Rc { - self.output.get() + self.cursor_user_group.latest_output() } pub fn set_workspace(&self, ws: &Rc) { @@ -517,7 +402,7 @@ impl WlSeatGlobal { fn maybe_constrain_pointer_node(&self) { if let Some(pn) = self.pointer_node() { if let Some(surface) = pn.node_into_surface() { - let (mut x, mut y) = self.pos.get(); + let (mut x, mut y) = self.pointer_cursor.position(); let (sx, sy) = surface.buffer_abs_pos.get().position(); x -= Fixed::from_int(sx); y -= Fixed::from_int(sy); @@ -608,47 +493,6 @@ impl WlSeatGlobal { self.kb_owner.ungrab(self); } - pub fn set_position(&self, x: i32, y: i32) { - self.pos.set((Fixed::from_int(x), Fixed::from_int(y))); - self.update_hardware_cursor_position(); - self.trigger_tree_changed(); - let output = 'set_output: { - let outputs = self.state.root.outputs.lock(); - for output in outputs.values() { - if output.global.pos.get().contains(x, y) { - break 'set_output output.clone(); - } - } - self.state.dummy_output.get().unwrap() - }; - self.set_output(&output); - } - - fn set_output(&self, output: &Rc) { - self.output.set(output.clone()); - if let Some(cursor) = self.cursor.get() { - cursor.set_output(output); - } - if let Some(dnd) = self.pointer_owner.dnd_icon() { - dnd.set_output(output); - } - if let Some(drag) = self.pointer_owner.toplevel_drag() { - if let Some(tl) = drag.toplevel.get() { - tl.xdg.set_output(output); - } - } - } - - pub fn position(&self) -> (Fixed, Fixed) { - self.pos.get() - } - - pub fn render_ctx_changed(&self) { - if let Some(cursor) = self.desired_known_cursor.get() { - self.set_known_cursor(cursor); - } - } - pub fn kb_parent_container(&self) -> Option> { if let Some(tl) = self.keyboard_node.get().node_toplevel() { if let Some(parent) = tl.tl_data().parent.get() { @@ -877,7 +721,7 @@ impl WlSeatGlobal { serial: u32, ) -> Result<(), WlSeatError> { if let Some(icon) = &icon { - icon.set_output(&self.output.get()); + icon.set_output(&self.pointer_cursor.output()); } self.pointer_owner .start_drag(self, origin, source, icon, serial) @@ -969,89 +813,6 @@ impl WlSeatGlobal { self.primary_selection.get() } - pub fn reload_known_cursor(&self) { - if let Some(kc) = self.desired_known_cursor.get() { - self.set_known_cursor(kc); - } - } - - #[cfg_attr(not(feature = "it"), allow(dead_code))] - pub fn get_desired_known_cursor(&self) -> Option { - self.desired_known_cursor.get() - } - - pub fn set_known_cursor(&self, cursor: KnownCursor) { - self.desired_known_cursor.set(Some(cursor)); - let cursors = match self.state.cursors.get() { - Some(c) => c, - None => { - self.set_cursor2(None); - return; - } - }; - let tpl = match cursor { - KnownCursor::Default => &cursors.default, - KnownCursor::ContextMenu => &cursors.context_menu, - KnownCursor::Help => &cursors.help, - KnownCursor::Pointer => &cursors.pointer, - KnownCursor::Progress => &cursors.progress, - KnownCursor::Wait => &cursors.wait, - KnownCursor::Cell => &cursors.cell, - KnownCursor::Crosshair => &cursors.crosshair, - KnownCursor::Text => &cursors.text, - KnownCursor::VerticalText => &cursors.vertical_text, - KnownCursor::Alias => &cursors.alias, - KnownCursor::Copy => &cursors.copy, - KnownCursor::Move => &cursors.r#move, - KnownCursor::NoDrop => &cursors.no_drop, - KnownCursor::NotAllowed => &cursors.not_allowed, - KnownCursor::Grab => &cursors.grab, - KnownCursor::Grabbing => &cursors.grabbing, - KnownCursor::EResize => &cursors.e_resize, - KnownCursor::NResize => &cursors.n_resize, - KnownCursor::NeResize => &cursors.ne_resize, - KnownCursor::NwResize => &cursors.nw_resize, - KnownCursor::SResize => &cursors.s_resize, - KnownCursor::SeResize => &cursors.se_resize, - KnownCursor::SwResize => &cursors.sw_resize, - KnownCursor::WResize => &cursors.w_resize, - KnownCursor::EwResize => &cursors.ew_resize, - KnownCursor::NsResize => &cursors.ns_resize, - KnownCursor::NeswResize => &cursors.nesw_resize, - KnownCursor::NwseResize => &cursors.nwse_resize, - KnownCursor::ColResize => &cursors.col_resize, - KnownCursor::RowResize => &cursors.row_resize, - KnownCursor::AllScroll => &cursors.all_scroll, - KnownCursor::ZoomIn => &cursors.zoom_in, - KnownCursor::ZoomOut => &cursors.zoom_out, - }; - self.set_cursor2(Some(tpl.instantiate(self.cursor_size.get()))); - } - - pub fn set_app_cursor(&self, cursor: Option>) { - self.set_cursor2(cursor); - self.desired_known_cursor.set(None); - } - - fn set_cursor2(&self, cursor: Option>) { - if let Some(old) = self.cursor.get() { - if let Some(new) = cursor.as_ref() { - if rc_eq(&old, new) { - self.update_hardware_cursor(); - return; - } - } - old.handle_unset(); - } - if let Some(cursor) = cursor.as_ref() { - cursor.clone().handle_set(); - cursor.set_output(&self.output.get()); - } - self.cursor.set(cursor.clone()); - self.state.hardware_tick_cursor.push(cursor); - self.update_hardware_cursor(); - } - pub fn dnd_icon(&self) -> Option> { self.pointer_owner.dnd_icon() } @@ -1060,12 +821,12 @@ impl WlSeatGlobal { self.pointer_owner.remove_dnd_icon(); } - pub fn get_position(&self) -> (Fixed, Fixed) { - self.pos.get() + pub fn pointer_cursor(&self) -> &Rc { + &self.pointer_cursor } - pub fn get_cursor(&self) -> Option> { - self.cursor.get() + pub fn cursor_group(&self) -> &Rc { + &self.cursor_user_group } pub fn clear(self: &Rc) { @@ -1082,7 +843,7 @@ impl WlSeatGlobal { self.data_devices.borrow_mut().clear(); self.primary_selection_devices.borrow_mut().clear(); self.wlr_data_devices.clear(); - self.cursor.set(None); + self.cursor_user_group.detach(); self.selection.set(None); self.primary_selection.set(None); self.pointer_owner.clear(); @@ -1090,7 +851,6 @@ impl WlSeatGlobal { *self.dropped_dnd.borrow_mut() = None; self.queue_link.take(); self.tree_changed_handler.set(None); - self.output.set(self.state.dummy_output.get().unwrap()); self.constraint.take(); self.text_inputs.borrow_mut().clear(); self.text_input.take(); @@ -1099,6 +859,7 @@ impl WlSeatGlobal { self.swipe_bindings.clear(); self.pinch_bindings.clear(); self.hold_bindings.clear(); + self.cursor_user_group.detach(); } pub fn id(&self) -> SeatId { @@ -1156,9 +917,7 @@ impl WlSeatGlobal { } pub fn set_visible(&self, visible: bool) { - if let Some(cursor) = self.cursor.get() { - cursor.set_visible(visible); - } + self.cursor_user_group.set_visible(visible); if let Some(icon) = self.dnd_icon() { icon.set_visible(visible); } @@ -1191,6 +950,19 @@ impl WlSeatGlobal { } } +impl CursorUserOwner for WlSeatGlobal { + fn output_changed(&self, output: &Rc) { + if let Some(dnd) = self.pointer_owner.dnd_icon() { + dnd.set_output(output); + } + if let Some(drag) = self.pointer_owner.toplevel_drag() { + if let Some(tl) = drag.toplevel.get() { + tl.xdg.set_output(output); + } + } + } +} + global_base!(WlSeatGlobal, WlSeat, WlSeatError); impl Global for WlSeatGlobal { diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index a314af1f..7bb9cd18 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -120,8 +120,7 @@ impl NodeSeatState { seat.kb_owner.set_kb_node(&seat, seat.state.root.clone()); // log::info!("keyboard_node = root"); if focus_last { - seat.output - .get() + seat.get_output() .node_do_focus(&seat, Direction::Unspecified); } } @@ -320,10 +319,10 @@ impl WlSeatGlobal { Some(o) => o, _ => return, }; - self.set_output(&output); let pos = output.global.pos.get(); x += Fixed::from_int(pos.x1()); y += Fixed::from_int(pos.y1()); + (x, y) = self.pointer_cursor.set_position(x, y); if let Some(c) = self.constraint.get() { if c.ty == ConstraintType::Lock || !c.contains(x.round_down(), y.round_down()) { c.deactivate(); @@ -332,7 +331,7 @@ impl WlSeatGlobal { self.state.for_each_seat_tester(|t| { t.send_pointer_abs(self.id, time_usec, x, y); }); - self.set_new_position(time_usec, x, y); + self.cursor_moved(time_usec); } fn motion_event( @@ -356,7 +355,7 @@ impl WlSeatGlobal { Some(c) if c.ty == ConstraintType::Lock => true, _ => false, }; - let (mut x, mut y) = self.pos.get(); + let (mut x, mut y) = self.pointer_cursor.position(); if !locked { x += dx; y += dy; @@ -383,34 +382,8 @@ impl WlSeatGlobal { dy_unaccelerated, ); }); - let output = self.output.get(); - let pos = output.global.pos.get(); - let mut x_int = x.round_down(); - let mut y_int = y.round_down(); - if !pos.contains(x_int, y_int) { - 'warp: { - let outputs = self.state.root.outputs.lock(); - for output in outputs.values() { - if output.global.pos.get().contains(x_int, y_int) { - self.set_output(output); - break 'warp; - } - } - if x_int < pos.x1() { - x_int = pos.x1(); - } else if x_int >= pos.x2() { - x_int = pos.x2() - 1; - } - if y_int < pos.y1() { - y_int = pos.y1(); - } else if y_int >= pos.y2() { - y_int = pos.y2() - 1; - } - x = Fixed::from_int(x_int); - y = Fixed::from_int(y_int); - } - } - self.set_new_position(time_usec, x, y); + self.pointer_cursor.set_position(x, y); + self.cursor_moved(time_usec); } fn button_event(self: &Rc, time_usec: u64, button: u32, state: KeyState) { @@ -776,10 +749,8 @@ impl WlSeatGlobal { // client.flush(); } - fn set_new_position(self: &Rc, time_usec: u64, x: Fixed, y: Fixed) { + fn cursor_moved(self: &Rc, time_usec: u64) { self.pos_time_usec.set(time_usec); - self.pos.set((x, y)); - self.update_hardware_cursor_position(); self.changes.or_assign(CHANGE_CURSOR_MOVED); self.apply_changes(); } diff --git a/src/ifs/wl_seat/pointer_owner.rs b/src/ifs/wl_seat/pointer_owner.rs index f02e1605..86cd5229 100644 --- a/src/ifs/wl_seat/pointer_owner.rs +++ b/src/ifs/wl_seat/pointer_owner.rs @@ -274,7 +274,7 @@ impl PointerOwner for SimplePointerOwner { } fn apply_changes(&self, seat: &Rc) { - let (x, y) = seat.pos.get(); + let (x, y) = seat.pointer_cursor.position(); let mut found_tree = seat.found_tree.borrow_mut(); let mut stack = seat.pointer_stack.borrow_mut(); let x_int = x.round_down(); @@ -408,7 +408,7 @@ impl PointerOwner for SimpleGrabPointerOwner { } fn apply_changes(&self, seat: &Rc) { - let (x, y) = seat.pos.get(); + let (x, y) = seat.pointer_cursor.position(); let pos = self.node.node_absolute_position(); let (x_int, y_int) = pos.translate(x.round_down(), y.round_down()); // log::info!("apply_changes"); @@ -493,7 +493,7 @@ impl PointerOwner for DndPointerOwner { } fn apply_changes(&self, seat: &Rc) { - let (x, y) = seat.pos.get(); + let (x, y) = seat.pointer_cursor.position(); let (x_int, y_int) = (x.round_down(), y.round_down()); let (node, x_int, y_int) = { let mut found_tree = seat.found_tree.borrow_mut(); @@ -781,7 +781,7 @@ impl NodeSelectorUsecase for SelectToplevelUsecase { if let Some(tl) = &tl { tl.tl_data().render_highlight.fetch_add(1); if !tl.tl_admits_children() { - seat.set_known_cursor(KnownCursor::Pointer); + seat.pointer_cursor().set_known(KnownCursor::Pointer); } damage = true; } @@ -829,7 +829,7 @@ impl NodeSelectorUsecase for SelectWorkspaceUsecase { let ws = node.clone().node_into_workspace(); if let Some(ws) = &ws { ws.render_highlight.fetch_add(1); - seat.set_known_cursor(KnownCursor::Pointer); + seat.pointer_cursor().set_known(KnownCursor::Pointer); damage = true; } if let Some(prev) = self.latest.set(ws) { diff --git a/src/ifs/wl_seat/wl_pointer.rs b/src/ifs/wl_seat/wl_pointer.rs index cfd16383..839828cc 100644 --- a/src/ifs/wl_seat/wl_pointer.rs +++ b/src/ifs/wl_seat/wl_pointer.rs @@ -186,7 +186,7 @@ impl WlPointerRequestHandler for WlPointer { let mut cursor_opt = None; if req.surface.is_some() { let surface = self.seat.client.lookup(req.surface)?; - let cursor = surface.get_cursor(&self.seat.global)?; + let cursor = surface.get_cursor(&self.seat.global.pointer_cursor)?; cursor.set_hotspot(req.hotspot_x, req.hotspot_y); cursor_opt = Some(cursor as Rc); } @@ -211,7 +211,7 @@ impl WlPointerRequestHandler for WlPointer { // ); // return Ok(()); // } - self.seat.global.set_app_cursor(cursor_opt); + self.seat.global.pointer_cursor().set(cursor_opt); Ok(()) } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index be783528..d6c22126 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -18,6 +18,7 @@ use { crate::{ backend::KeyState, client::{Client, ClientError}, + cursor_user::{CursorUser, CursorUserId}, drm_feedback::DrmFeedback, fixed::Fixed, gfx_api::{AcquireSync, BufferResv, BufferResvUser, ReleaseSync, SampleRect, SyncFile}, @@ -262,7 +263,7 @@ pub struct WlSurface { pub presentation_feedback: RefCell>>, seat_state: NodeSeatState, toplevel: CloneCell>>, - cursors: SmallMap, 1>, + cursors: SmallMap, 1>, dnd_icons: SmallMap, 1>, pub tracker: Tracker, idle_inhibitors: SmallMap, 1>, @@ -655,13 +656,13 @@ impl WlSurface { pub fn get_cursor( self: &Rc, - seat: &Rc, + user: &Rc, ) -> Result, WlSurfaceError> { - if let Some(cursor) = self.cursors.get(&seat.id()) { + if let Some(cursor) = self.cursors.get(&user.id) { return Ok(cursor); } self.set_role(SurfaceRole::Cursor)?; - let cursor = Rc::new(CursorSurface::new(seat, self)); + let cursor = Rc::new(CursorSurface::new(user, self)); track!(self.client, cursor); cursor.handle_buffer_change(); Ok(cursor) diff --git a/src/ifs/wl_surface/cursor.rs b/src/ifs/wl_surface/cursor.rs index 9de08603..2d6208c5 100644 --- a/src/ifs/wl_surface/cursor.rs +++ b/src/ifs/wl_surface/cursor.rs @@ -1,8 +1,9 @@ use { crate::{ cursor::Cursor, + cursor_user::CursorUser, fixed::Fixed, - ifs::{wl_seat::WlSeatGlobal, wl_surface::WlSurface}, + ifs::wl_surface::WlSurface, leaks::Tracker, rect::Rect, renderer::Renderer, @@ -13,7 +14,7 @@ use { }; pub struct CursorSurface { - seat: Rc, + user: Rc, surface: Rc, hotspot: Cell<(i32, i32)>, extents: Cell, @@ -21,9 +22,9 @@ pub struct CursorSurface { } impl CursorSurface { - pub fn new(seat: &Rc, surface: &Rc) -> Self { + pub fn new(user: &Rc, surface: &Rc) -> Self { Self { - seat: seat.clone(), + user: user.clone(), surface: surface.clone(), hotspot: Cell::new((0, 0)), extents: Cell::new(Default::default()), @@ -38,7 +39,7 @@ impl CursorSurface { } pub fn handle_surface_destroy(&self) { - self.seat.set_app_cursor(None); + self.user.set(None); } pub fn handle_buffer_change(&self) { @@ -57,9 +58,7 @@ impl CursorSurface { } pub fn update_hardware_cursor(&self) { - if self.seat.hardware_cursor() { - self.seat.update_hardware_cursor(); - } + self.user.update_hardware_cursor(); } } @@ -124,7 +123,7 @@ impl Cursor for CursorSurface { } fn handle_set(self: Rc) { - self.surface.cursors.insert(self.seat.id(), self.clone()); + self.surface.cursors.insert(self.user.id, self.clone()); if self.surface.cursors.is_not_empty() { self.surface .set_visible(self.surface.client.state.root_visible()); @@ -132,7 +131,7 @@ impl Cursor for CursorSurface { } fn handle_unset(&self) { - self.surface.cursors.remove(&self.seat.id()); + self.surface.cursors.remove(&self.user.id); if self.surface.cursors.is_empty() { self.surface.set_visible(false); } diff --git a/src/ifs/wl_surface/x_surface/xwindow.rs b/src/ifs/wl_surface/x_surface/xwindow.rs index 28b8c391..850f3625 100644 --- a/src/ifs/wl_surface/x_surface/xwindow.rs +++ b/src/ifs/wl_surface/x_surface/xwindow.rs @@ -366,7 +366,7 @@ impl Node for Xwindow { fn node_on_pointer_focus(&self, seat: &Rc) { // log::info!("wl-surface focus"); - seat.set_known_cursor(KnownCursor::Default); + seat.pointer_cursor().set_known(KnownCursor::Default); } fn node_into_toplevel(self: Rc) -> Option> { diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs index 96bb64a1..33c9b690 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs @@ -344,7 +344,7 @@ impl Node for XdgPopup { fn node_on_pointer_focus(&self, seat: &Rc) { // log::info!("xdg-popup focus"); - seat.set_known_cursor(KnownCursor::Default); + seat.pointer_cursor().set_known(KnownCursor::Default); } } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 185060dc..50f4d41f 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -526,7 +526,7 @@ impl Node for XdgToplevel { fn node_on_pointer_focus(&self, seat: &Rc) { // log::info!("xdg-toplevel focus"); - seat.set_known_cursor(KnownCursor::Default); + seat.pointer_cursor().set_known(KnownCursor::Default); } fn node_into_toplevel(self: Rc) -> Option> { diff --git a/src/ifs/wp_cursor_shape_device_v1.rs b/src/ifs/wp_cursor_shape_device_v1.rs index ede3c710..8524d2ae 100644 --- a/src/ifs/wp_cursor_shape_device_v1.rs +++ b/src/ifs/wp_cursor_shape_device_v1.rs @@ -107,7 +107,7 @@ impl WpCursorShapeDeviceV1RequestHandler for WpCursorShapeDeviceV1 { if pointer_node.node_client_id() != Some(self.client.id) { return Ok(()); } - self.seat.set_known_cursor(cursor); + self.seat.pointer_cursor().set_known(cursor); Ok(()) } } diff --git a/src/ifs/xdg_toplevel_drag_v1.rs b/src/ifs/xdg_toplevel_drag_v1.rs index 3a8e0eb7..d8ce9513 100644 --- a/src/ifs/xdg_toplevel_drag_v1.rs +++ b/src/ifs/xdg_toplevel_drag_v1.rs @@ -102,7 +102,7 @@ impl XdgToplevelDragV1 { if self.source.data.was_used() { if let Some(tl) = self.toplevel.get() { let output = seat.get_output(); - let (x, y) = seat.position(); + let (x, y) = seat.pointer_cursor().position(); tl.drag.take(); tl.after_toplevel_drag( &output, diff --git a/src/it/testrun.rs b/src/it/testrun.rs index 46f6953d..ad3a5b6f 100644 --- a/src/it/testrun.rs +++ b/src/it/testrun.rs @@ -156,7 +156,7 @@ pub struct DefaultSetup { impl DefaultSetup { pub fn move_to(&self, x: i32, y: i32) { - let (ox, oy) = self.seat.position(); + let (ox, oy) = self.seat.pointer_cursor().position(); let (nx, ny) = (Fixed::from_int(x), Fixed::from_int(y)); let (dx, dy) = (nx - ox, ny - oy); self.mouse.rel(dx.to_f64(), dy.to_f64()) diff --git a/src/it/tests/t0030_cursor_shape.rs b/src/it/tests/t0030_cursor_shape.rs index 0067cbcd..dbf9fe7c 100644 --- a/src/it/tests/t0030_cursor_shape.rs +++ b/src/it/tests/t0030_cursor_shape.rs @@ -24,7 +24,7 @@ async fn test(run: Rc) -> TestResult { client.sync().await; tassert_eq!( - ds.seat.get_desired_known_cursor(), + ds.seat.pointer_cursor().desired_known_cursor(), Some(KnownCursor::ContextMenu) ); diff --git a/src/main.rs b/src/main.rs index d3b54551..d7cc40b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,6 +53,7 @@ mod clientmem; mod compositor; mod config; mod cursor; +mod cursor_user; mod dbus; mod drm_feedback; mod edid; diff --git a/src/state.rs b/src/state.rs index 628440cb..77d6cab2 100644 --- a/src/state.rs +++ b/src/state.rs @@ -12,6 +12,7 @@ use { clientmem::ClientMemOffset, config::ConfigProxy, cursor::{Cursor, ServerCursors}, + cursor_user::{CursorUserGroup, CursorUserGroupId, CursorUserGroupIds, CursorUserIds}, dbus::Dbus, drm_feedback::{DrmFeedback, DrmFeedbackIds}, fixed::Fixed, @@ -185,6 +186,11 @@ pub struct State { pub explicit_sync_enabled: Cell, pub keyboard_state_ids: KeyboardStateIds, pub security_context_acceptors: SecurityContextAcceptors, + pub cursor_user_group_ids: CursorUserGroupIds, + pub cursor_user_ids: CursorUserIds, + pub cursor_users: CopyHashMap>, + pub cursor_user_groups: CopyHashMap>, + pub cursor_user_group_hardware_cursor: CloneCell>>, } // impl Drop for State { @@ -460,9 +466,8 @@ impl State { UpdateTextTexturesVisitor.visit_display(&self.root); } - let seats = self.globals.seats.lock(); - for seat in seats.values() { - seat.render_ctx_changed(); + for cursor_user_groups in self.cursor_user_groups.lock().values() { + cursor_user_groups.render_ctx_changed(); } if let Some(ctx) = &ctx { @@ -505,8 +510,8 @@ impl State { } }; self.cursors.set(cursors); - for seat in self.globals.seats.lock().values() { - seat.reload_known_cursor(); + for cursor_user_group in self.cursor_user_groups.lock().values() { + cursor_user_group.reload_known_cursor(); } } } @@ -785,21 +790,13 @@ impl State { } pub fn refresh_hardware_cursors(&self) { - let seat = self - .globals - .seats - .lock() - .values() - .find(|s| s.hardware_cursor()) - .cloned(); - let seat = match seat { - Some(s) => s, - _ => { - self.disable_hardware_cursors(); + if let Some(g) = self.cursor_user_group_hardware_cursor.get() { + if let Some(u) = g.active() { + u.update_hardware_cursor(); return; } - }; - seat.update_hardware_cursor(); + } + self.disable_hardware_cursors() } pub fn for_each_seat_tester(&self, f: F) { @@ -868,10 +865,10 @@ impl State { ReleaseSync::Implicit, ); if render_hardware_cursors { - for seat in self.globals.lock_seats().values() { - if let Some(cursor) = seat.get_cursor() { - let (mut x, mut y) = seat.get_position(); - if seat.hardware_cursor() { + if let Some(cursor_user_group) = self.cursor_user_group_hardware_cursor.get() { + if let Some(cursor_user) = cursor_user_group.active() { + if let Some(cursor) = cursor_user.get() { + let (mut x, mut y) = cursor_user.position(); x = x + x_off - Fixed::from_int(position.x1()); y = y + y_off - Fixed::from_int(position.y1()); cursor.render(&mut renderer, x, y); @@ -883,9 +880,9 @@ impl State { } fn have_hardware_cursor(&self) -> bool { - for seat in self.globals.lock_seats().values() { - if seat.get_cursor().is_some() { - if seat.hardware_cursor() { + if let Some(group) = self.cursor_user_group_hardware_cursor.get() { + if let Some(user) = group.active() { + if user.get().is_some() { return true; } } @@ -995,6 +992,43 @@ impl State { pub fn root_visible(&self) -> bool { !self.idle.backend_idle.get() } + + pub fn find_closest_output(&self, mut x: i32, mut y: i32) -> (Rc, i32, i32) { + let mut optimal_dist = i32::MAX; + let mut optimal_output = None; + let outputs = self.root.outputs.lock(); + for output in outputs.values() { + let pos = output.global.pos.get(); + let dist = pos.dist_squared(x, y); + if dist == 0 { + if pos.contains(x, y) { + return (output.clone(), x, y); + } + } + if dist < optimal_dist { + optimal_dist = dist; + optimal_output = Some(output.clone()); + } + } + if let Some(output) = optimal_output { + let pos = output.global.pos.get(); + if pos.is_empty() { + return (output, pos.x1(), pos.y1()); + } + if x < pos.x1() { + x = pos.x1(); + } else if x >= pos.x2() { + x = pos.x2() - 1; + } + if y < pos.y1() { + y = pos.y1(); + } else if y >= pos.y2() { + y = pos.y2() - 1; + } + return (output, x, y); + } + (self.dummy_output.get().unwrap(), 0, 0) + } } #[derive(Debug, Error)] diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index bd61ea59..2824010c 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -185,12 +185,8 @@ impl ConnectorHandler { global.opt.global.set(Some(global.clone())); let mut ws_to_move = VecDeque::new(); if self.state.root.outputs.len() == 1 { - let seats = self.state.globals.seats.lock(); - let pos = global.pos.get(); - let x = (pos.x1() + pos.x2()) / 2; - let y = (pos.y1() + pos.y2()) / 2; - for seat in seats.values() { - seat.set_position(x, y); + for seat in self.state.globals.seats.lock().values() { + seat.cursor_group().first_output_connected(&on); } let dummy = self.state.dummy_output.get().unwrap(); for ws in dummy.workspaces.iter() { @@ -287,12 +283,8 @@ impl ConnectorHandler { }; move_ws_to_output(&ws, &target, config); } - let seats = self.state.globals.seats.lock(); - for seat in seats.values() { - if seat.get_output().id == on.id { - let tpos = target.global.pos.get(); - seat.set_position((tpos.x1() + tpos.x2()) / 2, (tpos.y1() + tpos.y2()) / 2); - } + for seat in self.state.globals.seats.lock().values() { + seat.cursor_group().output_disconnected(&on, &target); } self.state .remove_output_scale(on.global.persistent.scale.get()); diff --git a/src/tree/container.rs b/src/tree/container.rs index 650d5b0b..ba41875b 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -601,7 +601,7 @@ impl ContainerNode { }; if new_cursor != mem::replace(&mut seat_state.cursor, new_cursor) { if seat_state.target { - seat.set_known_cursor(new_cursor); + seat.pointer_cursor().set_known(new_cursor); } } } @@ -1315,7 +1315,7 @@ impl Node for ContainerNode { let mut seats = self.seats.borrow_mut(); if let Some(seat_state) = seats.get_mut(&seat.id()) { seat_state.target = true; - seat.set_known_cursor(seat_state.cursor); + seat.pointer_cursor().set_known(seat_state.cursor); } } diff --git a/src/tree/display.rs b/src/tree/display.rs index 0288bc4a..610d6480 100644 --- a/src/tree/display.rs +++ b/src/tree/display.rs @@ -140,6 +140,6 @@ impl Node for DisplayNode { fn node_on_pointer_focus(&self, seat: &Rc) { // log::info!("display focus"); - seat.set_known_cursor(KnownCursor::Default); + seat.pointer_cursor().set_known(KnownCursor::Default); } } diff --git a/src/tree/float.rs b/src/tree/float.rs index 949ac892..fdf8516b 100644 --- a/src/tree/float.rs +++ b/src/tree/float.rs @@ -334,7 +334,7 @@ impl FloatNode { seat_state.op_type = op_type; if new_cursor != mem::replace(&mut seat_state.cursor, new_cursor) { if seat_state.target { - seat.set_known_cursor(new_cursor); + seat.pointer_cursor().set_known(new_cursor); } } } @@ -564,7 +564,7 @@ impl Node for FloatNode { let mut seats = self.seats.borrow_mut(); if let Some(seat_state) = seats.get_mut(&seat.id()) { seat_state.target = true; - seat.set_known_cursor(seat_state.cursor); + seat.pointer_cursor().set_known(seat_state.cursor); } } diff --git a/src/tree/output.rs b/src/tree/output.rs index 2b71957d..dfeac4ef 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -553,6 +553,10 @@ impl OutputNode { } } self.global.send_mode(); + for seat in self.state.globals.seats.lock().values() { + seat.cursor_group().output_pos_changed(self) + } + self.state.tree_changed(); } pub fn find_layer_surface_at( @@ -906,7 +910,7 @@ impl Node for OutputNode { fn node_on_pointer_focus(&self, seat: &Rc) { // log::info!("output focus"); - seat.set_known_cursor(KnownCursor::Default); + seat.pointer_cursor().set_known(KnownCursor::Default); } fn node_on_pointer_motion(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { diff --git a/src/tree/placeholder.rs b/src/tree/placeholder.rs index fc8b0d8c..549a301d 100644 --- a/src/tree/placeholder.rs +++ b/src/tree/placeholder.rs @@ -139,7 +139,7 @@ impl Node for PlaceholderNode { } fn node_on_pointer_enter(self: Rc, seat: &Rc, _x: Fixed, _y: Fixed) { - seat.set_known_cursor(KnownCursor::Default); + seat.pointer_cursor().set_known(KnownCursor::Default); seat.enter_toplevel(self.clone()); } diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index b986c44c..9eac5444 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -274,7 +274,7 @@ impl Node for WorkspaceNode { fn node_on_pointer_focus(&self, seat: &Rc) { // log::info!("workspace focus"); - seat.set_known_cursor(KnownCursor::Default); + seat.pointer_cursor().set_known(KnownCursor::Default); } fn node_into_workspace(self: Rc) -> Option> {