some cleanup of the messy overlay state machine

merge-notes
isark 2 years ago
parent 9c514830bc
commit 08f0da9746

@ -1,80 +1,41 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use std::{sync::Mutex, time::Duration};
use crossbeam::channel::Sender;
use overlay::{EnforceableEvent, Overlay};
use log::Level;
use overlay::{Event, LockedOverlaySettings, Overlay};
use simple_logger::SimpleLogger;
// use overlay::{Overlay, Manager};
use tauri::{LogicalSize, Manager, PhysicalPosition, PhysicalSize, Window, StateManager};
use underlayer::Bounds;
use x11rb::protocol::xproto::ConnectionExt;
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
use tauri::Manager;
mod overlay;
// fn show(window: &Window) {
// window.set_always_on_top(true);
// window.show();
// window.set_resizable(true);
// if let Ok(mut state) = window.state::<RuntimeWrapper>().lock() {
// if state.bounds.height == 0 || state.bounds.width == 0 {
// return;
// }
// window
// .set_position(PhysicalPosition {
// x: state.bounds.x,
// y: state.bounds.y,
// })
// .expect("msg");
// window
// .set_size(PhysicalSize {
// width: state.bounds.width,
// height: state.bounds.height,
// })
// .expect("msg");
// }
// std::thread::spawn(|| {
// std::thread::sleep(Duration::from_millis(50));
// underlayer::focus_target();
// });
// }
// fn hide(window: &Window) {
// window.hide();
// window.set_resizable(false);
// }
// type RuntimeWrapper = Mutex<Overlay>;
// remember to call `.manage(MyState::default())`
#[tauri::command]
fn set_interactable(interactable: bool, state: tauri::State<Sender<EnforceableEvent>>) {
fn set_interactable(interactable: bool, state: tauri::State<Sender<Event>>) {
log::info!("set_interactable: {interactable:?}");
if interactable {
state.send(EnforceableEvent::Force(overlay::StateEvent::Interactable));
state
.send(Event::State(overlay::State::Interactable{}))
.ok();
} else {
state.send(EnforceableEvent::Return);
state.send(Event::Return).ok();
}
}
#[tauri::command]
fn set_auto_hide(auto_hide: bool, state: tauri::State<Sender<EnforceableEvent>>) {
fn set_auto_hide(auto_hide: bool, state: tauri::State<LockedOverlaySettings>) {
log::info!("set_auto_hide: {auto_hide:?}");
state.send(EnforceableEvent::AutoHide(auto_hide));
if let Ok(mut settings) = state.lock() {
settings.auto_hide = auto_hide;
}
}
fn main() {
SimpleLogger::new().with_module_level("underlayer", log::LevelFilter::Info).with_level(log::LevelFilter::Trace).init().expect("Could not init logger");
SimpleLogger::new()
.with_module_level("underlayer", log::LevelFilter::Info)
.with_level(log::LevelFilter::Trace)
.init()
.expect("Could not init logger");
tauri::Builder::default()
.setup(|app| {
@ -83,65 +44,7 @@ fn main() {
.expect("Could not get main overlay window"),
"Untitled 1 - Mousepad",
);
app.manage(tx);
// std::thread::spawn(move || {
// log::info!("Running event thread");
// let mut target_is_focused = false;
// let underlay: std::sync::mpsc::Receiver<underlayer::UnderlayEvent> =
// underlayer::register("Untitled 1 - Mousepad");
// while let Ok(event) = underlay.recv() {
// log::info!("Got event: {event:?}");
// match event {
// underlayer::UnderlayEvent::Attach {
// bounds,
// has_access,
// is_fullscreen,
// } => {
// if let Ok(mut state) = window.state::<RuntimeWrapper>().lock() {
// state.bounds = bounds;
// }
// }
// underlayer::UnderlayEvent::Detach => {
// hide(&window);
// }
// underlayer::UnderlayEvent::MoveResize(bounds) => {
// if let Ok(mut state) = window.state::<RuntimeWrapper>().lock() {
// state.bounds = bounds;
// if bounds.height == 0 || bounds.width == 0 {
// return;
// }
// window
// .set_position(PhysicalPosition {
// x: bounds.x,
// y: bounds.y,
// })
// .expect("msg");
// window
// .set_size(PhysicalSize {
// width: bounds.width + 10,
// height: bounds.height,
// })
// .expect("msg");
// }
// }
// underlayer::UnderlayEvent::Focus => {
// target_is_focused = true;
// show(&window);
// }
// underlayer::UnderlayEvent::Blur => {
// target_is_focused = false;
// if !window.is_focused().unwrap() {
// hide(&window);
// }
// }
// underlayer::UnderlayEvent::X11FullscreenEvent { is_fullscreen } => {}
// }
// }
// });
Ok(())
})

@ -9,39 +9,35 @@ use std::{
};
use crossbeam::{
channel::{Receiver, Sender},
channel::{Receiver, Select, Sender},
select,
};
use serde::Serialize;
// The prelude module re-exports the most common used items from statig.
use statig::prelude::*;
use tauri::{PhysicalPosition, PhysicalSize, Window};
use tauri::{Manager, PhysicalPosition, PhysicalSize, Window};
use underlayer::{Bounds, UnderlayEvent};
use crate::overlay;
pub enum StateEvent {
Visible,
Hidden,
Interactable,
}
pub enum EnforceableEvent {
Force(StateEvent),
Request(StateEvent),
Relax,
pub enum Event {
State(State),
Bounds(Bounds),
AutoHide(bool),
Return
Return,
}
#[derive(Clone)]
pub struct Overlay {
bounds: Bounds,
window: Window,
auto_hide: bool,
previous: State,
}
pub struct OverlaySettings {
pub auto_hide: bool,
}
pub type LockedOverlaySettings = Mutex<OverlaySettings>;
fn wrap_underlay_rx(rx: MpscReceiver<UnderlayEvent>) -> Receiver<UnderlayEvent> {
let (cb_underlay_tx, cb_underlay_rx) = crossbeam::channel::unbounded();
std::thread::spawn(move || {
@ -53,15 +49,18 @@ fn wrap_underlay_rx(rx: MpscReceiver<UnderlayEvent>) -> Receiver<UnderlayEvent>
}
impl Overlay {
pub fn new(window: Window, target_title: &str) -> Sender<EnforceableEvent> {
pub fn new(window: Window, target_title: &str) -> Sender<Event> {
log::warn!("New overlay object");
let mut overlay = Self {
window: window.clone(),
bounds: Bounds::default(),
auto_hide: true,
previous: State::hidden(),
};
window.manage(Mutex::new(OverlaySettings {
auto_hide: true,
}));
let mut fsm = Overlay::uninitialized_state_machine(overlay).init();
let underlay_rx = wrap_underlay_rx(underlayer::register(target_title));
@ -88,7 +87,7 @@ impl Overlay {
recv(ee_rx) -> msg => {
match msg {
Ok(event) => {
Self::handle_enforceable_event(&mut fsm, event);
Self::handle_event(&mut fsm, event);
},
Err(_) => break,
}
@ -107,60 +106,54 @@ impl Overlay {
fn handle_overlay_focused(fsm: &mut InitializedStateMachine<Overlay>, focus: bool) {
match fsm.state() {
State::Visible {} | State::EnforcedVisible {} => {
State::Visible {} => {
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:?}");
let settings = fsm.window.state::<LockedOverlaySettings>();
match event {
UnderlayEvent::Attach {
bounds,
has_access,
is_fullscreen,
} => {
fsm.handle(&EnforceableEvent::Bounds(bounds));
fsm.handle(&Event::Bounds(bounds));
}
UnderlayEvent::MoveResize(bounds) => fsm.handle(&Event::Bounds(bounds)),
UnderlayEvent::Detach => fsm.handle(&Event::State(State::hidden())),
UnderlayEvent::Focus => {
fsm.handle(&Event::State(State::Visible {}))
}
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))
if !fsm.window.is_focused().unwrap()
&& fsm
.window
.state::<LockedOverlaySettings>()
.lock()
.is_ok_and(|s| s.auto_hide)
{
fsm.handle(&Event::State(State::Hidden {}))
}
}
UnderlayEvent::X11FullscreenEvent { is_fullscreen } => {}
}
}
fn handle_enforceable_event(
fsm: &mut InitializedStateMachine<Overlay>,
event: EnforceableEvent,
) {
fn handle_event(fsm: &mut InitializedStateMachine<Overlay>, event: Event) {
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)),
state(derive(Debug, Clone, PartialEq, Eq, Serialize)),
superstate(derive(Debug)),
on_transition = "Self::on_transition"
)]
@ -177,114 +170,68 @@ impl Overlay {
.set_size(PhysicalSize::new(self.bounds.width, self.bounds.height));
}
log::info!("on_enter_visible");
log::trace!("on_enter_visible");
}
#[action]
fn on_enter_interactable(&mut self) {
log::info!("on_enter_interactable");
log::trace!("on_enter_interactable");
self.window.set_ignore_cursor_events(false);
self.window.set_focus();
}
#[action]
fn on_enter_hidden(&mut self) {
log::info!("on_enter_hidden");
log::trace!("on_enter_hidden");
self.window.hide();
self.window.set_resizable(false);
}
#[action]
fn on_exit_interactable(&mut self) {
log::info!("on_exit_interactable");
log::trace!("on_exit_interactable");
self.window.set_ignore_cursor_events(true);
}
#[state(superstate = "super_visible")]
fn enforced_visible(&mut self, event: &EnforceableEvent) -> Response<State> {
fn visible(&mut self, event: &Event) -> 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()),
Event::State(underlying) => match underlying {
State::Visible {} => Handled,
State::Hidden {} => Transition(State::hidden()),
State::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> {
fn hidden(&mut self, event: &Event) -> 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()),
Event::State(underlying) => match underlying {
State::Visible {} => Transition(State::visible()),
State::Hidden {} => Handled,
State::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> {
fn interactable(&mut self, event: &Event) -> 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,
Event::State(underlying) => match underlying {
State::Visible {} => Transition(State::visible()),
State::Hidden {} => Transition(State::hidden()),
State::Interactable {} => Handled,
},
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");
fn super_visible(&mut self, event: &Event) -> Response<State> {
log::trace!("in super_visible");
Super
}
@ -293,8 +240,8 @@ impl Overlay {
entry_action = "on_enter_interactable",
exit_action = "on_exit_interactable"
)]
fn super_interactable(&mut self, event: &EnforceableEvent) -> Response<State> {
log::info!("in super_interactable");
fn super_interactable(&mut self, event: &Event) -> Response<State> {
log::trace!("in super_interactable");
Super
}
@ -303,16 +250,16 @@ impl Overlay {
entry_action = "on_visible",
entry_action = "on_enter_hidden"
)]
fn super_hidden(&mut self, event: &EnforceableEvent) -> Response<State> {
log::info!("in super_hidden");
fn super_hidden(&mut self, event: &Event) -> Response<State> {
log::trace!("in super_hidden");
Super
}
#[superstate]
fn common(&mut self, event: &EnforceableEvent) -> Response<State> {
log::info!("in common");
fn common(&mut self, event: &Event) -> Response<State> {
log::trace!("in common");
match event {
EnforceableEvent::Bounds(bounds) => {
Event::Bounds(bounds) => {
self.bounds = *bounds;
if bounds.width > 0 && bounds.height > 0 {
self.window
@ -322,21 +269,19 @@ impl Overlay {
}
Super
}
EnforceableEvent::Relax => Super,
EnforceableEvent::AutoHide(auto_hide) => {
self.auto_hide = *auto_hide;
Super
}
EnforceableEvent::Return => {
log::info!("Returning to: {:?}", self.previous);
Event::Return => {
log::trace!("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();
fn on_transition(&mut self, src: &State, dest: &State) {
log::trace!("from {src:?} to {dest:?}");
if src != dest {
self.previous = src.clone();
}
self.window.emit("OverlayStateChange", dest);
}
}

@ -2,6 +2,7 @@ import { AfterViewInit, Component, OnInit } from "@angular/core";
import { app } from "@tauri-apps/api";
import { invoke } from "@tauri-apps/api/tauri";
import { register } from "@tauri-apps/api/globalShortcut";
import { listen } from '@tauri-apps/api/event';
@Component({
selector: "app-root",
@ -19,6 +20,10 @@ export class AppComponent implements OnInit {
}).then();
invoke("set_auto_hide", {auto_hide: this.auto_hide}).then();
listen('OverlayStateChange', (event) => {
console.log(event, 'OverlayStateChange');
}).then();
}
toggleAutoHide() {

Loading…
Cancel
Save