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 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 {
|
pub struct Overlay {
|
||||||
should_take_focus: bool,
|
|
||||||
bounds: Bounds,
|
bounds: Bounds,
|
||||||
|
window: Window,
|
||||||
|
auto_hide: bool,
|
||||||
|
previous: State,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Manager<State> {
|
fn wrap_underlay_rx(rx: MpscReceiver<UnderlayEvent>) -> Receiver<UnderlayEvent> {
|
||||||
window: Window,
|
let (cb_underlay_tx, cb_underlay_rx) = crossbeam::channel::unbounded();
|
||||||
should_take_focus: bool,
|
std::thread::spawn(move || {
|
||||||
bounds: Bounds,
|
while let Ok(event) = rx.recv() {
|
||||||
state: PhantomData<State>
|
cb_underlay_tx.send(event).ok();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cb_underlay_rx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ManagerData = Arc<Mutex<Manager>>;
|
impl Overlay {
|
||||||
|
pub fn new(window: Window, target_title: &str) -> Sender<EnforceableEvent> {
|
||||||
impl<S> Manager<S> {
|
log::warn!("New overlay object");
|
||||||
pub fn init(window: Window, target_label: &str) {
|
let mut overlay = Self {
|
||||||
std::thread::spawn(move || {
|
window: window.clone(),
|
||||||
let manager = Arc::new(Mutex::new(Manager {
|
bounds: Bounds::default(),
|
||||||
window,
|
auto_hide: true,
|
||||||
should_take_focus: false,
|
previous: State::hidden(),
|
||||||
bounds: Default::default(),
|
};
|
||||||
state: PhantomData,
|
|
||||||
}));
|
let mut fsm = Overlay::uninitialized_state_machine(overlay).init();
|
||||||
|
|
||||||
let app = window.app_handle();
|
let underlay_rx = wrap_underlay_rx(underlayer::register(target_title));
|
||||||
let underlay_rx = underlayer::register(target_label);
|
let (ee_tx, ee_rx) = crossbeam::channel::unbounded();
|
||||||
app.manage(manager.clone());
|
let (window_event_tx, window_event_rx) = crossbeam::channel::unbounded();
|
||||||
|
|
||||||
while let Ok(event) = underlay_rx.recv() {
|
window.on_window_event(move |event| match event {
|
||||||
app.state::<ManagerData>().lock().and_then(|mut manager| {
|
tauri::WindowEvent::Focused(focus) => {
|
||||||
manager.on_event(event);
|
window_event_tx.send(*focus).ok();
|
||||||
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 on_event(&mut self, event: UnderlayEvent) {
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
struct Visible;
|
#[action]
|
||||||
struct Interactable;
|
fn on_exit_interactable(&mut self) {
|
||||||
struct Hidden;
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
should_take_focus
|
#[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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Overlay visible
|
#[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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Overlay interactable
|
#[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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Overlay hidden
|
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 { invoke } from "@tauri-apps/api/tauri";
|
||||||
|
import { register } from "@tauri-apps/api/globalShortcut";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-root",
|
selector: "app-root",
|
||||||
templateUrl: "./app.component.html",
|
templateUrl: "./app.component.html",
|
||||||
styleUrls: ["./app.component.css"],
|
styleUrls: ["./app.component.css"],
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent implements OnInit {
|
||||||
greetingMessage = "";
|
auto_hide: boolean = true;
|
||||||
|
interactable: boolean = false;
|
||||||
|
|
||||||
greet(event: SubmitEvent, name: string): void {
|
ngOnInit(): void {
|
||||||
event.preventDefault();
|
register('F6', () => {
|
||||||
|
this.interactable = !this.interactable;
|
||||||
|
invoke("set_interactable", {interactable: this.interactable}).then();
|
||||||
|
}).then();
|
||||||
|
|
||||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
invoke("set_auto_hide", {auto_hide: this.auto_hide}).then();
|
||||||
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