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_session_lock_manager_v1::ExtSessionLockManagerV1Global,
|
||||
head_management::jay_head_manager_v1::JayHeadManagerV1Global,
|
||||
hyprland_focus_grab_manager_v1::HyprlandFocusGrabManagerV1Global,
|
||||
ipc::{
|
||||
data_control::{
|
||||
ext_data_control_manager_v1::ExtDataControlManagerV1Global,
|
||||
|
|
@ -205,6 +206,7 @@ singletons! {
|
|||
ZwlrScreencopyManagerV1,
|
||||
ZwpRelativePointerManagerV1,
|
||||
ExtSessionLockManagerV1,
|
||||
HyprlandFocusGrabManagerV1,
|
||||
WpViewporter,
|
||||
WpFractionalScaleManagerV1,
|
||||
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_v1;
|
||||
pub mod head_management;
|
||||
pub mod hyprland_focus_grab_manager_v1;
|
||||
pub mod hyprland_focus_grab_v1;
|
||||
pub mod ipc;
|
||||
pub mod jay_acceptor_request;
|
||||
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,
|
||||
state::{DeviceHandlerData, State},
|
||||
tree::{
|
||||
ContainerNode, ContainerSplit, Direction, FoundNode, Node, NodeLayer, NodeLayerLink,
|
||||
NodeLocation, OutputNode, StackedNode, ToplevelNode, WorkspaceNode,
|
||||
ContainerNode, ContainerSplit, Direction, FoundNode, Node, NodeId, NodeLayer,
|
||||
NodeLayerLink, NodeLocation, OutputNode, StackedNode, ToplevelNode, WorkspaceNode,
|
||||
generic_node_visitor, toplevel_create_split, toplevel_parent_container,
|
||||
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);
|
||||
|
||||
pub struct PhysicalKeyboard {
|
||||
|
|
@ -258,6 +263,7 @@ pub struct WlSeatGlobal {
|
|||
warp_mouse_to_focus_scheduled: Cell<bool>,
|
||||
warp_mouse_to_focus_skip_target_check: Cell<bool>,
|
||||
mouse_follows_focus: Cell<bool>,
|
||||
pub focus_grab: CloneCell<Option<Rc<dyn SeatFocusGrab>>>,
|
||||
}
|
||||
|
||||
impl PartialEq for WlSeatGlobal {
|
||||
|
|
@ -403,6 +409,7 @@ impl WlSeatGlobal {
|
|||
warp_mouse_to_focus_scheduled: Cell::new(false),
|
||||
warp_mouse_to_focus_skip_target_check: Cell::new(false),
|
||||
mouse_follows_focus: Cell::new(false),
|
||||
focus_grab: Default::default(),
|
||||
});
|
||||
slf.pointer_cursor.set_owner(slf.clone());
|
||||
slf.modifiers_listener
|
||||
|
|
|
|||
|
|
@ -1140,6 +1140,11 @@ impl WlSeatGlobal {
|
|||
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>) {
|
||||
self.kb_owner.grab(self, node);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,6 +400,7 @@ impl<T: SimplePointerOwnerUsecase> PointerOwner for SimplePointerOwner<T> {
|
|||
seat.state
|
||||
.root
|
||||
.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());
|
||||
for (i, (found, stack)) in found_tree.iter().zip(stack.iter()).enumerate() {
|
||||
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 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>) {
|
||||
let _ = seat;
|
||||
let _ = node;
|
||||
|
|
@ -829,13 +835,29 @@ impl SimplePointerOwnerUsecase for DefaultPointerUsecase {
|
|||
fn default_button(
|
||||
&self,
|
||||
_spo: &SimplePointerOwner<Self>,
|
||||
_seat: &Rc<WlSeatGlobal>,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
_button: u32,
|
||||
_pn: &Rc<dyn Node>,
|
||||
pn: &Rc<dyn Node>,
|
||||
) -> bool {
|
||||
if let Some(grab) = seat.focus_grab.get() {
|
||||
if !grab.contains_node(pn.node_id()) {
|
||||
grab.clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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(
|
||||
&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