ifs: init hyprland_focus_grab_manager_v1
This commit is contained in:
parent
a75d388e97
commit
2591dc739b
9 changed files with 315 additions and 4 deletions
|
|
@ -10,6 +10,7 @@ use {
|
||||||
ext_output_image_capture_source_manager_v1::ExtOutputImageCaptureSourceManagerV1Global,
|
ext_output_image_capture_source_manager_v1::ExtOutputImageCaptureSourceManagerV1Global,
|
||||||
ext_session_lock_manager_v1::ExtSessionLockManagerV1Global,
|
ext_session_lock_manager_v1::ExtSessionLockManagerV1Global,
|
||||||
head_management::jay_head_manager_v1::JayHeadManagerV1Global,
|
head_management::jay_head_manager_v1::JayHeadManagerV1Global,
|
||||||
|
hyprland_focus_grab_manager_v1::HyprlandFocusGrabManagerV1Global,
|
||||||
ipc::{
|
ipc::{
|
||||||
data_control::{
|
data_control::{
|
||||||
ext_data_control_manager_v1::ExtDataControlManagerV1Global,
|
ext_data_control_manager_v1::ExtDataControlManagerV1Global,
|
||||||
|
|
@ -205,6 +206,7 @@ singletons! {
|
||||||
ZwlrScreencopyManagerV1,
|
ZwlrScreencopyManagerV1,
|
||||||
ZwpRelativePointerManagerV1,
|
ZwpRelativePointerManagerV1,
|
||||||
ExtSessionLockManagerV1,
|
ExtSessionLockManagerV1,
|
||||||
|
HyprlandFocusGrabManagerV1,
|
||||||
WpViewporter,
|
WpViewporter,
|
||||||
WpFractionalScaleManagerV1,
|
WpFractionalScaleManagerV1,
|
||||||
ZwpPointerConstraintsV1,
|
ZwpPointerConstraintsV1,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ pub mod ext_output_image_capture_source_manager_v1;
|
||||||
pub mod ext_session_lock_manager_v1;
|
pub mod ext_session_lock_manager_v1;
|
||||||
pub mod ext_session_lock_v1;
|
pub mod ext_session_lock_v1;
|
||||||
pub mod head_management;
|
pub mod head_management;
|
||||||
|
pub mod hyprland_focus_grab_manager_v1;
|
||||||
|
pub mod hyprland_focus_grab_v1;
|
||||||
pub mod ipc;
|
pub mod ipc;
|
||||||
pub mod jay_acceptor_request;
|
pub mod jay_acceptor_request;
|
||||||
pub mod jay_client_query;
|
pub mod jay_client_query;
|
||||||
|
|
|
||||||
97
src/ifs/hyprland_focus_grab_manager_v1.rs
Normal file
97
src/ifs/hyprland_focus_grab_manager_v1.rs
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientError},
|
||||||
|
globals::{Global, GlobalName},
|
||||||
|
ifs::hyprland_focus_grab_v1::HyprlandFocusGrabV1,
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
wire::{HyprlandFocusGrabManagerV1Id, hyprland_focus_grab_manager_v1::*},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct HyprlandFocusGrabManagerV1Global {
|
||||||
|
pub name: GlobalName,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HyprlandFocusGrabManagerV1Global {
|
||||||
|
pub fn new(name: GlobalName) -> Self {
|
||||||
|
Self { name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_(
|
||||||
|
self: Rc<Self>,
|
||||||
|
id: HyprlandFocusGrabManagerV1Id,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
version: Version,
|
||||||
|
) -> Result<(), HyprlandFocusGrabManagerV1Error> {
|
||||||
|
let obj = Rc::new(HyprlandFocusGrabManagerV1 {
|
||||||
|
id,
|
||||||
|
client: client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
});
|
||||||
|
track!(client, obj);
|
||||||
|
client.add_client_obj(&obj)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HyprlandFocusGrabManagerV1 {
|
||||||
|
pub id: HyprlandFocusGrabManagerV1Id,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HyprlandFocusGrabManagerV1RequestHandler for HyprlandFocusGrabManagerV1 {
|
||||||
|
type Error = HyprlandFocusGrabManagerV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_grab(&self, req: CreateGrab, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let grab = Rc::new(HyprlandFocusGrabV1::new(
|
||||||
|
req.grab,
|
||||||
|
&self.client,
|
||||||
|
self.version,
|
||||||
|
));
|
||||||
|
track!(self.client, grab);
|
||||||
|
self.client.add_client_obj(&grab)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_base!(
|
||||||
|
HyprlandFocusGrabManagerV1Global,
|
||||||
|
HyprlandFocusGrabManagerV1,
|
||||||
|
HyprlandFocusGrabManagerV1Error
|
||||||
|
);
|
||||||
|
|
||||||
|
impl Global for HyprlandFocusGrabManagerV1Global {
|
||||||
|
fn version(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_global!(HyprlandFocusGrabManagerV1Global);
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = HyprlandFocusGrabManagerV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for HyprlandFocusGrabManagerV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(HyprlandFocusGrabManagerV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum HyprlandFocusGrabManagerV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
}
|
||||||
|
|
||||||
|
efrom!(HyprlandFocusGrabManagerV1Error, ClientError);
|
||||||
154
src/ifs/hyprland_focus_grab_v1.rs
Normal file
154
src/ifs/hyprland_focus_grab_v1.rs
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientError},
|
||||||
|
ifs::wl_seat::SeatFocusGrab,
|
||||||
|
ifs::wl_surface::WlSurface,
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
tree::NodeId,
|
||||||
|
wire::{HyprlandFocusGrabV1Id, hyprland_focus_grab_v1::*},
|
||||||
|
},
|
||||||
|
ahash::AHashMap,
|
||||||
|
std::{
|
||||||
|
cell::Cell,
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct HyprlandFocusGrabV1 {
|
||||||
|
pub id: HyprlandFocusGrabV1Id,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
pending: std::cell::RefCell<Option<AHashMap<NodeId, Rc<WlSurface>>>>,
|
||||||
|
committed: std::cell::RefCell<AHashMap<NodeId, Rc<WlSurface>>>,
|
||||||
|
active: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HyprlandFocusGrabV1 {
|
||||||
|
pub fn new(id: HyprlandFocusGrabV1Id, client: &Rc<Client>, version: Version) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
client: client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
pending: Default::default(),
|
||||||
|
committed: Default::default(),
|
||||||
|
active: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_cleared(&self) {
|
||||||
|
self.client.event(Cleared { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate(self: &Rc<Self>) {
|
||||||
|
let state = &self.client.state;
|
||||||
|
let seats = state.globals.seats.lock();
|
||||||
|
let focus_node = self
|
||||||
|
.committed
|
||||||
|
.borrow()
|
||||||
|
.values()
|
||||||
|
.find_map(|s| s.get_focus_node());
|
||||||
|
|
||||||
|
for seat in seats.values() {
|
||||||
|
if let Some(old) = seat.focus_grab.get() {
|
||||||
|
old.clear();
|
||||||
|
}
|
||||||
|
seat.focus_grab.set(Some(self.clone() as Rc<dyn SeatFocusGrab>));
|
||||||
|
if let Some(node) = focus_node.clone() {
|
||||||
|
seat.grab(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.active.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deactivate(&self) {
|
||||||
|
if !self.active.get() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.active.set(false);
|
||||||
|
let state = &self.client.state;
|
||||||
|
for seat in state.globals.seats.lock().values() {
|
||||||
|
seat.clear_focus_grab();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SeatFocusGrab for HyprlandFocusGrabV1 {
|
||||||
|
fn contains_node(&self, node_id: NodeId) -> bool {
|
||||||
|
self.committed.borrow().contains_key(&node_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(self: Rc<Self>) {
|
||||||
|
if !self.active.get() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.active.set(false);
|
||||||
|
self.send_cleared();
|
||||||
|
let state = &self.client.state;
|
||||||
|
for seat in state.globals.seats.lock().values() {
|
||||||
|
seat.clear_focus_grab();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HyprlandFocusGrabV1RequestHandler for HyprlandFocusGrabV1 {
|
||||||
|
type Error = HyprlandFocusGrabV1Error;
|
||||||
|
|
||||||
|
fn add_surface(&self, req: AddSurface, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let surface = self.client.lookup(req.surface)?;
|
||||||
|
let node_id: NodeId = surface.node_id.into();
|
||||||
|
let mut pending = self.pending.borrow_mut();
|
||||||
|
let pending = pending.get_or_insert_with(|| self.committed.borrow().clone());
|
||||||
|
pending.insert(node_id, surface);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_surface(&self, req: RemoveSurface, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let surface = self.client.lookup(req.surface)?;
|
||||||
|
let node_id: NodeId = surface.node_id.into();
|
||||||
|
let mut pending = self.pending.borrow_mut();
|
||||||
|
let pending = pending.get_or_insert_with(|| self.committed.borrow().clone());
|
||||||
|
pending.remove(&node_id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit(&self, _req: Commit, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let was_empty = self.committed.borrow().is_empty();
|
||||||
|
if let Some(new_committed) = self.pending.borrow_mut().take() {
|
||||||
|
*self.committed.borrow_mut() = new_committed;
|
||||||
|
}
|
||||||
|
let is_empty = self.committed.borrow().is_empty();
|
||||||
|
match (was_empty, is_empty) {
|
||||||
|
(true, false) => slf.activate(),
|
||||||
|
(false, true) => self.deactivate(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.deactivate();
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = HyprlandFocusGrabV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for HyprlandFocusGrabV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(HyprlandFocusGrabV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum HyprlandFocusGrabV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
}
|
||||||
|
|
||||||
|
efrom!(HyprlandFocusGrabV1Error, ClientError);
|
||||||
|
|
@ -83,8 +83,8 @@ use {
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
state::{DeviceHandlerData, State},
|
state::{DeviceHandlerData, State},
|
||||||
tree::{
|
tree::{
|
||||||
ContainerNode, ContainerSplit, Direction, FoundNode, Node, NodeLayer, NodeLayerLink,
|
ContainerNode, ContainerSplit, Direction, FoundNode, Node, NodeId, NodeLayer,
|
||||||
NodeLocation, OutputNode, StackedNode, ToplevelNode, WorkspaceNode,
|
NodeLayerLink, NodeLocation, OutputNode, StackedNode, ToplevelNode, WorkspaceNode,
|
||||||
generic_node_visitor, toplevel_create_split, toplevel_parent_container,
|
generic_node_visitor, toplevel_create_split, toplevel_parent_container,
|
||||||
toplevel_set_floating, toplevel_set_workspace,
|
toplevel_set_floating, toplevel_set_workspace,
|
||||||
},
|
},
|
||||||
|
|
@ -164,6 +164,11 @@ impl Drop for DroppedDnd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait SeatFocusGrab {
|
||||||
|
fn contains_node(&self, node_id: NodeId) -> bool;
|
||||||
|
fn clear(self: Rc<Self>);
|
||||||
|
}
|
||||||
|
|
||||||
linear_ids!(PhysicalKeyboardIds, PhysicalKeyboardId, u64);
|
linear_ids!(PhysicalKeyboardIds, PhysicalKeyboardId, u64);
|
||||||
|
|
||||||
pub struct PhysicalKeyboard {
|
pub struct PhysicalKeyboard {
|
||||||
|
|
@ -258,6 +263,7 @@ pub struct WlSeatGlobal {
|
||||||
warp_mouse_to_focus_scheduled: Cell<bool>,
|
warp_mouse_to_focus_scheduled: Cell<bool>,
|
||||||
warp_mouse_to_focus_skip_target_check: Cell<bool>,
|
warp_mouse_to_focus_skip_target_check: Cell<bool>,
|
||||||
mouse_follows_focus: Cell<bool>,
|
mouse_follows_focus: Cell<bool>,
|
||||||
|
pub focus_grab: CloneCell<Option<Rc<dyn SeatFocusGrab>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for WlSeatGlobal {
|
impl PartialEq for WlSeatGlobal {
|
||||||
|
|
@ -403,6 +409,7 @@ impl WlSeatGlobal {
|
||||||
warp_mouse_to_focus_scheduled: Cell::new(false),
|
warp_mouse_to_focus_scheduled: Cell::new(false),
|
||||||
warp_mouse_to_focus_skip_target_check: Cell::new(false),
|
warp_mouse_to_focus_skip_target_check: Cell::new(false),
|
||||||
mouse_follows_focus: Cell::new(false),
|
mouse_follows_focus: Cell::new(false),
|
||||||
|
focus_grab: Default::default(),
|
||||||
});
|
});
|
||||||
slf.pointer_cursor.set_owner(slf.clone());
|
slf.pointer_cursor.set_owner(slf.clone());
|
||||||
slf.modifiers_listener
|
slf.modifiers_listener
|
||||||
|
|
|
||||||
|
|
@ -1140,6 +1140,11 @@ impl WlSeatGlobal {
|
||||||
self.kb_owner.ungrab(self);
|
self.kb_owner.ungrab(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear_focus_grab(self: &Rc<Self>) {
|
||||||
|
self.focus_grab.take();
|
||||||
|
self.ungrab_kb();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn grab(self: &Rc<Self>, node: Rc<dyn Node>) {
|
pub fn grab(self: &Rc<Self>, node: Rc<dyn Node>) {
|
||||||
self.kb_owner.grab(self, node);
|
self.kb_owner.grab(self, node);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -400,6 +400,7 @@ impl<T: SimplePointerOwnerUsecase> PointerOwner for SimplePointerOwner<T> {
|
||||||
seat.state
|
seat.state
|
||||||
.root
|
.root
|
||||||
.node_find_tree_at(x_int, y_int, &mut found_tree, T::FIND_TREE_USECASE);
|
.node_find_tree_at(x_int, y_int, &mut found_tree, T::FIND_TREE_USECASE);
|
||||||
|
self.usecase.filter_found_tree(seat, &mut found_tree);
|
||||||
let mut divergence = found_tree.len().min(stack.len());
|
let mut divergence = found_tree.len().min(stack.len());
|
||||||
for (i, (found, stack)) in found_tree.iter().zip(stack.iter()).enumerate() {
|
for (i, (found, stack)) in found_tree.iter().zip(stack.iter()).enumerate() {
|
||||||
if found.node.node_id() != stack.node_id() {
|
if found.node.node_id() != stack.node_id() {
|
||||||
|
|
@ -717,6 +718,11 @@ trait SimplePointerOwnerUsecase: Sized + Clone + 'static {
|
||||||
|
|
||||||
fn release_grab(&self, seat: &Rc<WlSeatGlobal>);
|
fn release_grab(&self, seat: &Rc<WlSeatGlobal>);
|
||||||
|
|
||||||
|
fn filter_found_tree(&self, seat: &Rc<WlSeatGlobal>, found_tree: &mut Vec<FoundNode>) {
|
||||||
|
let _ = seat;
|
||||||
|
let _ = found_tree;
|
||||||
|
}
|
||||||
|
|
||||||
fn node_focus(&self, seat: &Rc<WlSeatGlobal>, node: &Rc<dyn Node>) {
|
fn node_focus(&self, seat: &Rc<WlSeatGlobal>, node: &Rc<dyn Node>) {
|
||||||
let _ = seat;
|
let _ = seat;
|
||||||
let _ = node;
|
let _ = node;
|
||||||
|
|
@ -829,13 +835,29 @@ impl SimplePointerOwnerUsecase for DefaultPointerUsecase {
|
||||||
fn default_button(
|
fn default_button(
|
||||||
&self,
|
&self,
|
||||||
_spo: &SimplePointerOwner<Self>,
|
_spo: &SimplePointerOwner<Self>,
|
||||||
_seat: &Rc<WlSeatGlobal>,
|
seat: &Rc<WlSeatGlobal>,
|
||||||
_button: u32,
|
_button: u32,
|
||||||
_pn: &Rc<dyn Node>,
|
pn: &Rc<dyn Node>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
if let Some(grab) = seat.focus_grab.get() {
|
||||||
|
if !grab.contains_node(pn.node_id()) {
|
||||||
|
grab.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn filter_found_tree(&self, seat: &Rc<WlSeatGlobal>, found_tree: &mut Vec<FoundNode>) {
|
||||||
|
if let Some(grab) = seat.focus_grab.get() {
|
||||||
|
if let Some(leaf) = found_tree.last() {
|
||||||
|
if !grab.contains_node(leaf.node.node_id()) {
|
||||||
|
found_tree.truncate(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn start_drag(
|
fn start_drag(
|
||||||
&self,
|
&self,
|
||||||
grab: &SimpleGrabPointerOwner<Self>,
|
grab: &SimpleGrabPointerOwner<Self>,
|
||||||
|
|
|
||||||
6
wire/hyprland_focus_grab_manager_v1.txt
Normal file
6
wire/hyprland_focus_grab_manager_v1.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
request create_grab {
|
||||||
|
grab: id(hyprland_focus_grab_v1) (new),
|
||||||
|
}
|
||||||
|
|
||||||
|
request destroy (destructor) {
|
||||||
|
}
|
||||||
16
wire/hyprland_focus_grab_v1.txt
Normal file
16
wire/hyprland_focus_grab_v1.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
request add_surface {
|
||||||
|
surface: id(wl_surface),
|
||||||
|
}
|
||||||
|
|
||||||
|
request remove_surface {
|
||||||
|
surface: id(wl_surface),
|
||||||
|
}
|
||||||
|
|
||||||
|
request commit {
|
||||||
|
}
|
||||||
|
|
||||||
|
request destroy (destructor) {
|
||||||
|
}
|
||||||
|
|
||||||
|
event cleared {
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue