You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Nothing/src-tauri/src/overlay.rs

343 lines
11 KiB

#![allow(unused)]
use std::{
borrow::BorrowMut,
cell::RefCell,
ops::DerefMut,
sync::{mpsc::Receiver as MpscReceiver, Arc, Mutex},
time::Duration,
};
use crossbeam::{
channel::{Receiver, Sender},
select,
};
// The prelude module re-exports the most common used items from statig.
use statig::prelude::*;
use tauri::{PhysicalPosition, PhysicalSize, Window};
use underlayer::{Bounds, UnderlayEvent};
use crate::overlay;
pub enum StateEvent {
Visible,
Hidden,
Interactable,
}
pub enum EnforceableEvent {
Force(StateEvent),
Request(StateEvent),
Relax,
Bounds(Bounds),
AutoHide(bool),
Return
}
#[derive(Clone)]
pub struct Overlay {
bounds: Bounds,
window: Window,
auto_hide: bool,
previous: State,
}
fn wrap_underlay_rx(rx: MpscReceiver<UnderlayEvent>) -> Receiver<UnderlayEvent> {
let (cb_underlay_tx, cb_underlay_rx) = crossbeam::channel::unbounded();
std::thread::spawn(move || {
while let Ok(event) = rx.recv() {
cb_underlay_tx.send(event).ok();
}
});
cb_underlay_rx
}
impl Overlay {
pub fn new(window: Window, target_title: &str) -> Sender<EnforceableEvent> {
log::warn!("New overlay object");
let mut overlay = Self {
window: window.clone(),
bounds: Bounds::default(),
auto_hide: true,
previous: State::hidden(),
};
let mut fsm = Overlay::uninitialized_state_machine(overlay).init();
let underlay_rx = wrap_underlay_rx(underlayer::register(target_title));
let (ee_tx, ee_rx) = crossbeam::channel::unbounded();
let (window_event_tx, window_event_rx) = crossbeam::channel::unbounded();
window.on_window_event(move |event| match event {
tauri::WindowEvent::Focused(focus) => {
window_event_tx.send(*focus).ok();
}
_ => {}
});
std::thread::spawn(move || loop {
select! {
recv(underlay_rx) -> msg => {
match msg {
Ok(event) => {
Self::handle_underlay_event(&mut fsm, event);
},
Err(_) => break,
}
},
recv(ee_rx) -> msg => {
match msg {
Ok(event) => {
Self::handle_enforceable_event(&mut fsm, event);
},
Err(_) => break,
}
},
recv(window_event_rx) -> msg => {
match msg {
Ok(focus) => Self::handle_overlay_focused(&mut fsm, focus),
Err(_) => break,
}
}
}
});
ee_tx
}
fn handle_overlay_focused(fsm: &mut InitializedStateMachine<Overlay>, focus: bool) {
match fsm.state() {
State::Visible {} | State::EnforcedVisible {} => {
if focus {
fsm.window.set_ignore_cursor_events(true);
underlayer::focus_target();
}
}
_ => {}
}
}
fn handle_underlay_event(fsm: &mut InitializedStateMachine<Overlay>, event: UnderlayEvent) {
log::info!("EVENT: {event:?}");
match event {
UnderlayEvent::Attach {
bounds,
has_access,
is_fullscreen,
} => {
fsm.handle(&EnforceableEvent::Bounds(bounds));
}
UnderlayEvent::MoveResize(bounds) => fsm.handle(&EnforceableEvent::Bounds(bounds)),
UnderlayEvent::Detach => fsm.handle(&EnforceableEvent::Request(StateEvent::Hidden)),
UnderlayEvent::Focus => fsm.handle(&EnforceableEvent::Request(StateEvent::Visible)),
UnderlayEvent::Blur => {
if !fsm.window.is_focused().unwrap() && fsm.auto_hide {
fsm.handle(&EnforceableEvent::Request(StateEvent::Hidden))
}
}
UnderlayEvent::X11FullscreenEvent { is_fullscreen } => {}
}
}
fn handle_enforceable_event(
fsm: &mut InitializedStateMachine<Overlay>,
event: EnforceableEvent,
) {
fsm.handle(&event);
}
}
// let mut fsm = fsm::Overlay::uninitialized_state_machine(Default::default()).init();
// fsm.handle(&EnforceableEvent::Force(fsm::StateEvent::Visible));
// fsm.handle(&EnforceableEvent::Relax);
// fsm.handle(&EnforceableEvent::Request(fsm::StateEvent::Interactable));
// fsm.handle(&EnforceableEvent::Request(fsm::StateEvent::Hidden));
/// The `state_machine` procedural macro generates the `State` and `Superstate`
/// enums by parsing the function signatures with a `state`, `superstate` or
/// `action` attribute. It also implements the `statig::State` and
/// `statig::Superstate` traits. We also pass an argument that will add the
/// derive macro with the Debug trait to the `State` enum.
#[state_machine(
initial = "State::hidden()",
state(derive(Debug, Clone, PartialEq, Eq)),
superstate(derive(Debug)),
on_transition = "Self::on_transition"
)]
impl Overlay {
#[action]
fn on_enter_visible(&mut self) {
self.window.set_always_on_top(true);
self.window.show();
self.window.set_resizable(true);
if self.bounds.width > 0 && self.bounds.height > 0 {
self.window
.set_position(PhysicalPosition::new(self.bounds.x, self.bounds.y));
self.window
.set_size(PhysicalSize::new(self.bounds.width, self.bounds.height));
}
log::info!("on_enter_visible");
}
#[action]
fn on_enter_interactable(&mut self) {
log::info!("on_enter_interactable");
self.window.set_ignore_cursor_events(false);
}
#[action]
fn on_enter_hidden(&mut self) {
log::info!("on_enter_hidden");
self.window.hide();
self.window.set_resizable(false);
}
#[action]
fn on_exit_interactable(&mut self) {
log::info!("on_exit_interactable");
self.window.set_ignore_cursor_events(true);
}
#[state(superstate = "super_visible")]
fn enforced_visible(&mut self, event: &EnforceableEvent) -> Response<State> {
match event {
EnforceableEvent::Force(StateEvent::Visible) => Super,
EnforceableEvent::Force(event) => Self::match_forced(event),
EnforceableEvent::Request(_) => Handled,
EnforceableEvent::Relax => Transition(State::visible()),
_ => Super,
}
}
#[state(superstate = "super_visible")]
fn visible(&mut self, event: &EnforceableEvent) -> Response<State> {
match event {
EnforceableEvent::Force(underlying) => Self::match_forced(underlying),
EnforceableEvent::Request(underlying) => match underlying {
StateEvent::Visible => Super,
StateEvent::Hidden => Transition(State::hidden()),
StateEvent::Interactable => Transition(State::interactable()),
},
EnforceableEvent::Relax => Super,
_ => Super,
}
}
#[state(superstate = "super_hidden")]
fn enforced_hidden(&mut self, event: &EnforceableEvent) -> Response<State> {
match event {
EnforceableEvent::Force(StateEvent::Hidden) => Super,
EnforceableEvent::Force(event) => Self::match_forced(event),
EnforceableEvent::Request(_) => Handled,
EnforceableEvent::Relax => Transition(State::hidden()),
_ => Super,
}
}
#[state(superstate = "super_hidden")]
fn hidden(&mut self, event: &EnforceableEvent) -> Response<State> {
match event {
EnforceableEvent::Force(underlying) => Self::match_forced(underlying),
EnforceableEvent::Request(underlying) => match underlying {
StateEvent::Visible => Transition(State::visible()),
StateEvent::Hidden => Super,
StateEvent::Interactable => Transition(State::interactable()),
},
EnforceableEvent::Relax => Super,
_ => Super,
}
}
#[state(superstate = "super_interactable")]
fn enforced_interactable(&mut self, event: &EnforceableEvent) -> Response<State> {
match event {
EnforceableEvent::Force(StateEvent::Interactable) => Super,
EnforceableEvent::Force(event) => Self::match_forced(event),
EnforceableEvent::Request(_) => Handled,
EnforceableEvent::Relax => Transition(State::interactable()),
_ => Super,
}
}
#[state(superstate = "super_interactable")]
fn interactable(&mut self, event: &EnforceableEvent) -> Response<State> {
match event {
EnforceableEvent::Force(underlying) => Self::match_forced(underlying),
EnforceableEvent::Request(underlying) => match underlying {
StateEvent::Visible => Transition(State::visible()),
StateEvent::Hidden => Transition(State::hidden()),
StateEvent::Interactable => Super,
},
EnforceableEvent::Relax => Super,
_ => Super,
}
}
fn match_forced(event: &StateEvent) -> Response<State> {
match event {
StateEvent::Hidden => Transition(State::enforced_hidden()),
StateEvent::Interactable => Transition(State::enforced_interactable()),
StateEvent::Visible => Transition(State::enforced_visible()),
}
}
#[superstate(superstate = "common", entry_action = "on_enter_visible")]
fn super_visible(&mut self, event: &EnforceableEvent) -> Response<State> {
log::info!("in super_visible");
Super
}
#[superstate(
superstate = "super_visible",
entry_action = "on_enter_interactable",
exit_action = "on_exit_interactable"
)]
fn super_interactable(&mut self, event: &EnforceableEvent) -> Response<State> {
log::info!("in super_interactable");
Super
}
#[superstate(
superstate = "common",
entry_action = "on_visible",
entry_action = "on_enter_hidden"
)]
fn super_hidden(&mut self, event: &EnforceableEvent) -> Response<State> {
log::info!("in super_hidden");
Super
}
#[superstate]
fn common(&mut self, event: &EnforceableEvent) -> Response<State> {
log::info!("in common");
match event {
EnforceableEvent::Bounds(bounds) => {
self.bounds = *bounds;
if bounds.width > 0 && bounds.height > 0 {
self.window
.set_position(PhysicalPosition::new(bounds.x, bounds.y));
self.window
.set_size(PhysicalSize::new(bounds.width, bounds.height));
}
Super
}
EnforceableEvent::Relax => Super,
EnforceableEvent::AutoHide(auto_hide) => {
self.auto_hide = *auto_hide;
Super
}
EnforceableEvent::Return => {
log::info!("Returning to: {:?}", self.previous);
Transition(self.previous.clone())
}
_ => Super,
}
}
fn on_transition(&mut self, src: &State, dest: &State) {
log::info!("from {src:?} to {dest:?}");
self.previous = src.clone();
}
}