diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index d482d4c..2d289f6 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -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::().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; - -// remember to call `.manage(MyState::default())` #[tauri::command] -fn set_interactable(interactable: bool, state: tauri::State>) { +fn set_interactable(interactable: bool, state: tauri::State>) { 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>) { +fn set_auto_hide(auto_hide: bool, state: tauri::State) { 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::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::().lock() { - // state.bounds = bounds; - // } - // } - // underlayer::UnderlayEvent::Detach => { - // hide(&window); - // } - // underlayer::UnderlayEvent::MoveResize(bounds) => { - // if let Ok(mut state) = window.state::().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(()) }) diff --git a/src-tauri/src/overlay.rs b/src-tauri/src/overlay.rs index d92d633..9b81449 100644 --- a/src-tauri/src/overlay.rs +++ b/src-tauri/src/overlay.rs @@ -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; + fn wrap_underlay_rx(rx: MpscReceiver) -> Receiver { let (cb_underlay_tx, cb_underlay_rx) = crossbeam::channel::unbounded(); std::thread::spawn(move || { @@ -53,15 +49,18 @@ fn wrap_underlay_rx(rx: MpscReceiver) -> Receiver } impl Overlay { - pub fn new(window: Window, target_title: &str) -> Sender { + pub fn new(window: Window, target_title: &str) -> Sender { 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, 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, event: UnderlayEvent) { - log::info!("EVENT: {event:?}"); + let settings = fsm.window.state::(); 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::() + .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, - event: EnforceableEvent, - ) { + fn handle_event(fsm: &mut InitializedStateMachine, 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 { + fn visible(&mut self, event: &Event) -> Response { 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 { - 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 { - 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 { + fn hidden(&mut self, event: &Event) -> Response { 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 { - 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 { + fn interactable(&mut self, event: &Event) -> Response { 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 { - 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 { - log::info!("in super_visible"); + fn super_visible(&mut self, event: &Event) -> Response { + 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 { - log::info!("in super_interactable"); + fn super_interactable(&mut self, event: &Event) -> Response { + 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 { - log::info!("in super_hidden"); + fn super_hidden(&mut self, event: &Event) -> Response { + log::trace!("in super_hidden"); Super } #[superstate] - fn common(&mut self, event: &EnforceableEvent) -> Response { - log::info!("in common"); + fn common(&mut self, event: &Event) -> Response { + 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); } } diff --git a/src/app/app.component.ts b/src/app/app.component.ts index abbf1a6..ef649cb 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -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() {