parent
1936d33407
commit
9c514830bc
@ -0,0 +1,16 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug",
|
||||
"program": "${workspaceFolder}/<executable file>",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,65 +1,342 @@
|
||||
use std::{sync::{Arc, Mutex}, marker::PhantomData};
|
||||
#![allow(unused)]
|
||||
|
||||
use tauri::{Manager as TManager, Window};
|
||||
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 {
|
||||
should_take_focus: bool,
|
||||
bounds: Bounds,
|
||||
window: Window,
|
||||
auto_hide: bool,
|
||||
previous: State,
|
||||
}
|
||||
|
||||
pub struct Manager<State> {
|
||||
window: Window,
|
||||
should_take_focus: bool,
|
||||
bounds: Bounds,
|
||||
state: PhantomData<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
|
||||
}
|
||||
|
||||
pub type ManagerData = Arc<Mutex<Manager>>;
|
||||
|
||||
impl<S> Manager<S> {
|
||||
pub fn init(window: Window, target_label: &str) {
|
||||
std::thread::spawn(move || {
|
||||
let manager = Arc::new(Mutex::new(Manager {
|
||||
window,
|
||||
should_take_focus: false,
|
||||
bounds: Default::default(),
|
||||
state: PhantomData,
|
||||
}));
|
||||
|
||||
let app = window.app_handle();
|
||||
let underlay_rx = underlayer::register(target_label);
|
||||
app.manage(manager.clone());
|
||||
|
||||
while let Ok(event) = underlay_rx.recv() {
|
||||
app.state::<ManagerData>().lock().and_then(|mut manager| {
|
||||
manager.on_event(event);
|
||||
Ok(())
|
||||
});
|
||||
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 on_event(&mut self, event: UnderlayEvent) {
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
struct Visible;
|
||||
struct Interactable;
|
||||
struct Hidden;
|
||||
log::info!("on_enter_visible");
|
||||
}
|
||||
|
||||
/*
|
||||
#[action]
|
||||
fn on_enter_interactable(&mut self) {
|
||||
log::info!("on_enter_interactable");
|
||||
self.window.set_ignore_cursor_events(false);
|
||||
}
|
||||
|
||||
should_take_focus
|
||||
#[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);
|
||||
}
|
||||
|
||||
Overlay visible
|
||||
#[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,
|
||||
}
|
||||
}
|
||||
|
||||
Overlay interactable
|
||||
#[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,
|
||||
}
|
||||
}
|
||||
|
||||
Overlay hidden
|
||||
#[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();
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,29 @@
|
||||
import { Component } from "@angular/core";
|
||||
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";
|
||||
|
||||
@Component({
|
||||
selector: "app-root",
|
||||
templateUrl: "./app.component.html",
|
||||
styleUrls: ["./app.component.css"],
|
||||
})
|
||||
export class AppComponent {
|
||||
greetingMessage = "";
|
||||
export class AppComponent implements OnInit {
|
||||
auto_hide: boolean = true;
|
||||
interactable: boolean = false;
|
||||
|
||||
ngOnInit(): void {
|
||||
register('F6', () => {
|
||||
this.interactable = !this.interactable;
|
||||
invoke("set_interactable", {interactable: this.interactable}).then();
|
||||
}).then();
|
||||
|
||||
greet(event: SubmitEvent, name: string): void {
|
||||
event.preventDefault();
|
||||
invoke("set_auto_hide", {auto_hide: this.auto_hide}).then();
|
||||
}
|
||||
|
||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
||||
invoke<string>("greet", { name }).then((text) => {
|
||||
this.greetingMessage = text;
|
||||
});
|
||||
toggleAutoHide() {
|
||||
console.log("toggle auto hide!!");
|
||||
invoke("set_auto_hide", {autoHide: this.auto_hide}).then();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in new issue