CosmicStack: Share Focus type with CosmicWindow

There's probably more duplicated logic that can be abstracted, but this
removes a bit of redundancy at least.
This commit is contained in:
Ian Douglas Scott 2024-03-28 11:59:33 -07:00 committed by Victoria Brekenfeld
parent 26d2556be0
commit c957d673ba
2 changed files with 41 additions and 110 deletions

View file

@ -1,4 +1,4 @@
use super::{surface::RESIZE_BORDER, CosmicSurface}; use super::{surface::RESIZE_BORDER, window::Focus, CosmicSurface};
use crate::{ use crate::{
backend::render::cursor::{CursorShape, CursorState}, backend::render::cursor::{CursorShape, CursorState},
shell::{ shell::{
@ -104,36 +104,18 @@ pub struct CosmicStackInternal {
} }
impl CosmicStackInternal { impl CosmicStackInternal {
pub fn swap_focus(&self, focus: Focus) -> Focus { pub fn swap_focus(&self, focus: Option<Focus>) -> Option<Focus> {
unsafe { let value = focus.map_or(0, |x| x as u8);
std::mem::transmute::<u8, Focus>( unsafe { Focus::from_u8(self.pointer_entered.swap(value, Ordering::SeqCst)) }
self.pointer_entered.swap(focus as u8, Ordering::SeqCst),
)
}
} }
pub fn current_focus(&self) -> Focus { pub fn current_focus(&self) -> Option<Focus> {
unsafe { std::mem::transmute::<u8, Focus>(self.pointer_entered.load(Ordering::SeqCst)) } unsafe { Focus::from_u8(self.pointer_entered.load(Ordering::SeqCst)) }
} }
} }
pub const TAB_HEIGHT: i32 = 24; pub const TAB_HEIGHT: i32 = 24;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Focus {
None,
Header,
ResizeTop,
ResizeLeft,
ResizeRight,
ResizeBottom,
ResizeTopRight,
ResizeTopLeft,
ResizeBottomRight,
ResizeBottomLeft,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum MoveResult { pub enum MoveResult {
Handled, Handled,
@ -165,7 +147,7 @@ impl CosmicStack {
group_focused: Arc::new(AtomicBool::new(false)), group_focused: Arc::new(AtomicBool::new(false)),
scroll_to_focus: Arc::new(AtomicBool::new(false)), scroll_to_focus: Arc::new(AtomicBool::new(false)),
previous_keyboard: Arc::new(AtomicUsize::new(0)), previous_keyboard: Arc::new(AtomicUsize::new(0)),
pointer_entered: Arc::new(AtomicU8::new(Focus::None as u8)), pointer_entered: Arc::new(AtomicU8::new(0)),
reenter: Arc::new(AtomicBool::new(false)), reenter: Arc::new(AtomicBool::new(false)),
potential_drag: Arc::new(Mutex::new(None)), potential_drag: Arc::new(Mutex::new(None)),
override_alive: Arc::new(AtomicBool::new(true)), override_alive: Arc::new(AtomicBool::new(true)),
@ -1131,46 +1113,13 @@ impl PointerTarget<State> for CosmicStack {
let mut event = event.clone(); let mut event = event.clone();
self.0.with_program(|p| { self.0.with_program(|p| {
let active_window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; let active_window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
let geo = active_window.geometry(); let Some(next) = Focus::under(active_window, TAB_HEIGHT, event.location) else {
let loc = event.location.to_i32_round::<i32>();
let (_old_focus, shape) = if loc.y - geo.loc.y < 0 && loc.x - geo.loc.x < 0 {
(
p.swap_focus(Focus::ResizeTopLeft),
CursorShape::NorthWestResize,
)
} else if loc.y - geo.loc.y < 0 && loc.x - geo.loc.x >= geo.size.w {
(
p.swap_focus(Focus::ResizeTopRight),
CursorShape::NorthEastResize,
)
} else if loc.y - geo.loc.y < 0 {
(p.swap_focus(Focus::ResizeTop), CursorShape::NorthResize)
} else if loc.y - geo.loc.y >= TAB_HEIGHT + geo.size.h && loc.x - geo.loc.x < 0 {
(
p.swap_focus(Focus::ResizeBottomLeft),
CursorShape::SouthWestResize,
)
} else if loc.y - geo.loc.y >= TAB_HEIGHT + geo.size.h
&& loc.x - geo.loc.x >= geo.size.w
{
(
p.swap_focus(Focus::ResizeBottomRight),
CursorShape::SouthEastResize,
)
} else if loc.y - geo.loc.y >= TAB_HEIGHT + geo.size.h {
(p.swap_focus(Focus::ResizeBottom), CursorShape::SouthResize)
} else if loc.x - geo.loc.x < 0 {
(p.swap_focus(Focus::ResizeLeft), CursorShape::WestResize)
} else if loc.x - geo.loc.x >= geo.size.w {
(p.swap_focus(Focus::ResizeRight), CursorShape::EastResize)
} else if loc.y - geo.loc.y < TAB_HEIGHT {
(p.swap_focus(Focus::Header), CursorShape::Default)
} else {
return; return;
}; };
let _old_focus = p.swap_focus(Some(next));
let cursor_state = seat.user_data().get::<CursorState>().unwrap(); let cursor_state = seat.user_data().get::<CursorState>().unwrap();
cursor_state.set_shape(shape); cursor_state.set_shape(next.cursor_shape());
let cursor_status = seat let cursor_status = seat
.user_data() .user_data()
.get::<RefCell<CursorImageStatus>>() .get::<RefCell<CursorImageStatus>>()
@ -1192,36 +1141,13 @@ impl PointerTarget<State> for CosmicStack {
self.0.with_program(|p| { self.0.with_program(|p| {
let active = p.active.load(Ordering::SeqCst); let active = p.active.load(Ordering::SeqCst);
let active_window = &p.windows.lock().unwrap()[active]; let active_window = &p.windows.lock().unwrap()[active];
let geo = active_window.geometry(); let Some(next) = Focus::under(active_window, TAB_HEIGHT, event.location) else {
let loc = event.location.to_i32_round::<i32>();
let (next, shape) = if loc.y - geo.loc.y < 0 && loc.x - geo.loc.x < 0 {
(Focus::ResizeTopLeft, CursorShape::NorthWestResize)
} else if loc.y - geo.loc.y < 0 && loc.x - geo.loc.x >= geo.size.w {
(Focus::ResizeTopRight, CursorShape::NorthEastResize)
} else if loc.y - geo.loc.y < 0 {
(Focus::ResizeTop, CursorShape::NorthResize)
} else if loc.y - geo.loc.y >= TAB_HEIGHT + geo.size.h && loc.x - geo.loc.x < 0 {
(Focus::ResizeBottomLeft, CursorShape::SouthWestResize)
} else if loc.y - geo.loc.y >= TAB_HEIGHT + geo.size.h
&& loc.x - geo.loc.x >= geo.size.w
{
(Focus::ResizeBottomRight, CursorShape::SouthEastResize)
} else if loc.y - geo.loc.y >= TAB_HEIGHT + geo.size.h {
(Focus::ResizeBottom, CursorShape::SouthResize)
} else if loc.x - geo.loc.x < 0 {
(Focus::ResizeLeft, CursorShape::WestResize)
} else if loc.x - geo.loc.x >= geo.size.w {
(Focus::ResizeRight, CursorShape::EastResize)
} else if (loc.y - geo.loc.y) < TAB_HEIGHT {
(Focus::Header, CursorShape::Default)
} else {
return; return;
}; };
let _previous = p.swap_focus(Some(next));
let _previous = p.swap_focus(next);
let cursor_state = seat.user_data().get::<CursorState>().unwrap(); let cursor_state = seat.user_data().get::<CursorState>().unwrap();
cursor_state.set_shape(shape); cursor_state.set_shape(next.cursor_shape());
let cursor_status = seat let cursor_status = seat
.user_data() .user_data()
.get::<RefCell<CursorImageStatus>>() .get::<RefCell<CursorImageStatus>>()
@ -1278,14 +1204,13 @@ impl PointerTarget<State> for CosmicStack {
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) { fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
match self.0.with_program(|p| p.current_focus()) { match self.0.with_program(|p| p.current_focus()) {
Focus::Header => { Some(Focus::Header) => {
self.0.with_program(|p| { self.0.with_program(|p| {
*p.last_seat.lock().unwrap() = Some((seat.clone(), event.serial)); *p.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
}); });
PointerTarget::button(&self.0, seat, data, event) PointerTarget::button(&self.0, seat, data, event)
} }
Focus::None => {} Some(x) => {
x => {
let serial = event.serial; let serial = event.serial;
let seat = seat.clone(); let seat = seat.clone();
let Some(surface) = self.0.with_program(|p| { let Some(surface) = self.0.with_program(|p| {
@ -1309,24 +1234,25 @@ impl PointerTarget<State> for CosmicStack {
Focus::ResizeBottomRight => ResizeEdge::BOTTOM_RIGHT, Focus::ResizeBottomRight => ResizeEdge::BOTTOM_RIGHT,
Focus::ResizeLeft => ResizeEdge::LEFT, Focus::ResizeLeft => ResizeEdge::LEFT,
Focus::ResizeRight => ResizeEdge::RIGHT, Focus::ResizeRight => ResizeEdge::RIGHT,
Focus::Header | Focus::None => unreachable!(), Focus::Header => unreachable!(),
}, },
) )
}); });
} }
None => {}
} }
} }
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) { fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
match self.0.with_program(|p| p.current_focus()) { match self.0.with_program(|p| p.current_focus()) {
Focus::Header => PointerTarget::axis(&self.0, seat, data, frame), Some(Focus::Header) => PointerTarget::axis(&self.0, seat, data, frame),
_ => {} _ => {}
} }
} }
fn frame(&self, seat: &Seat<State>, data: &mut State) { fn frame(&self, seat: &Seat<State>, data: &mut State) {
match self.0.with_program(|p| p.current_focus()) { match self.0.with_program(|p| p.current_focus()) {
Focus::Header => PointerTarget::frame(&self.0, seat, data), Some(Focus::Header) => PointerTarget::frame(&self.0, seat, data),
_ => {} _ => {}
} }
} }
@ -1335,7 +1261,7 @@ impl PointerTarget<State> for CosmicStack {
self.0.with_program(|p| { self.0.with_program(|p| {
let cursor_state = seat.user_data().get::<CursorState>().unwrap(); let cursor_state = seat.user_data().get::<CursorState>().unwrap();
cursor_state.set_shape(CursorShape::Default); cursor_state.set_shape(CursorShape::Default);
let _previous = p.swap_focus(Focus::None); let _previous = p.swap_focus(None);
}); });
PointerTarget::leave(&self.0, seat, data, serial, time); PointerTarget::leave(&self.0, seat, data, serial, time);

View file

@ -110,7 +110,11 @@ pub enum Focus {
} }
impl Focus { impl Focus {
fn under(surface: &CosmicSurface, location: Point<f64, Logical>) -> Option<Focus> { pub fn under(
surface: &CosmicSurface,
header_height: i32,
location: Point<f64, Logical>,
) -> Option<Focus> {
let loc = location.to_i32_round::<i32>(); let loc = location.to_i32_round::<i32>();
let geo = surface.geometry(); let geo = surface.geometry();
if loc.y < 0 && loc.x < 0 { if loc.y < 0 && loc.x < 0 {
@ -119,24 +123,24 @@ impl Focus {
Some(Focus::ResizeTopRight) Some(Focus::ResizeTopRight)
} else if loc.y < 0 { } else if loc.y < 0 {
Some(Focus::ResizeTop) Some(Focus::ResizeTop)
} else if loc.y >= SSD_HEIGHT + geo.size.h && loc.x < 0 { } else if loc.y >= header_height + geo.size.h && loc.x < 0 {
Some(Focus::ResizeBottomLeft) Some(Focus::ResizeBottomLeft)
} else if loc.y >= SSD_HEIGHT + geo.size.h && loc.x >= geo.size.w { } else if loc.y >= header_height + geo.size.h && loc.x >= geo.size.w {
Some(Focus::ResizeBottomRight) Some(Focus::ResizeBottomRight)
} else if loc.y >= SSD_HEIGHT + geo.size.h { } else if loc.y >= header_height + geo.size.h {
Some(Focus::ResizeBottom) Some(Focus::ResizeBottom)
} else if loc.x < 0 { } else if loc.x < 0 {
Some(Focus::ResizeLeft) Some(Focus::ResizeLeft)
} else if loc.x >= geo.size.w { } else if loc.x >= geo.size.w {
Some(Focus::ResizeRight) Some(Focus::ResizeRight)
} else if loc.y < SSD_HEIGHT { } else if loc.y < header_height {
Some(Focus::Header) Some(Focus::Header)
} else { } else {
None None
} }
} }
fn cursor_shape(&self) -> CursorShape { pub fn cursor_shape(&self) -> CursorShape {
match self { match self {
Focus::ResizeTopLeft => CursorShape::NorthWestResize, Focus::ResizeTopLeft => CursorShape::NorthWestResize,
Focus::ResizeTopRight => CursorShape::NorthEastResize, Focus::ResizeTopRight => CursorShape::NorthEastResize,
@ -149,22 +153,23 @@ impl Focus {
Focus::Header => CursorShape::Default, Focus::Header => CursorShape::Default,
} }
} }
pub unsafe fn from_u8(value: u8) -> Option<Focus> {
match value {
0 => None,
focus => unsafe { Some(std::mem::transmute::<u8, Focus>(focus)) },
}
}
} }
impl CosmicWindowInternal { impl CosmicWindowInternal {
pub fn swap_focus(&self, focus: Option<Focus>) -> Option<Focus> { pub fn swap_focus(&self, focus: Option<Focus>) -> Option<Focus> {
let value = focus.map_or(0, |x| x as u8); let value = focus.map_or(0, |x| x as u8);
match self.pointer_entered.swap(value, Ordering::SeqCst) { unsafe { Focus::from_u8(self.pointer_entered.swap(value, Ordering::SeqCst)) }
0 => None,
focus => unsafe { Some(std::mem::transmute::<u8, Focus>(focus)) },
}
} }
pub fn current_focus(&self) -> Option<Focus> { pub fn current_focus(&self) -> Option<Focus> {
match self.pointer_entered.load(Ordering::SeqCst) { unsafe { Focus::from_u8(self.pointer_entered.load(Ordering::SeqCst)) }
0 => None,
focus => unsafe { Some(std::mem::transmute::<u8, Focus>(focus)) },
}
} }
pub fn has_ssd(&self, pending: bool) -> bool { pub fn has_ssd(&self, pending: bool) -> bool {
@ -659,7 +664,7 @@ impl PointerTarget<State> for CosmicWindow {
let mut event = event.clone(); let mut event = event.clone();
self.0.with_program(|p| { self.0.with_program(|p| {
if p.has_ssd(false) { if p.has_ssd(false) {
let Some(next) = Focus::under(&p.window, event.location) else { let Some(next) = Focus::under(&p.window, SSD_HEIGHT, event.location) else {
return; return;
}; };
let old_focus = p.swap_focus(Some(next)); let old_focus = p.swap_focus(Some(next));
@ -683,7 +688,7 @@ impl PointerTarget<State> for CosmicWindow {
let mut event = event.clone(); let mut event = event.clone();
self.0.with_program(|p| { self.0.with_program(|p| {
if p.has_ssd(false) { if p.has_ssd(false) {
let Some(next) = Focus::under(&p.window, event.location) else { let Some(next) = Focus::under(&p.window, SSD_HEIGHT, event.location) else {
return; return;
}; };
let _previous = p.swap_focus(Some(next)); let _previous = p.swap_focus(Some(next));