use crate::types::wire::{Response, ScriptStateRequest};
use bevy::ecs::message::Message;
use objc2::rc::Retained;
use objc2_core_foundation::{CFRetained, CGPoint};
use objc2_core_graphics::CGDirectDisplayID;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender, channel};
use crate::commands::Command;
use crate::config::Config;
use crate::ecs::state::StateQueryKind;
use crate::errors::Result;
use crate::platform::{
EventLoopWaker, Modifiers, Pid, ProcessSerialNumber, WinID, WorkspaceId, WorkspaceObserver,
};
use crate::util::AXUIWrapper;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DestroySource {
Accessibility,
SpaceNotification,
}
pub type Reply = async_channel::Sender<Response>;
#[cfg_attr(not(feature = "lua"), allow(dead_code))]
#[derive(Clone, Debug, Message)]
pub struct InputEvent(pub Event);
#[cfg_attr(not(feature = "lua"), allow(dead_code))]
#[derive(Clone, Debug, Message)]
pub enum Event {
Exit,
ProcessesLoaded,
InitialConfig(Config),
ConfigRefresh(notify::Event),
ApplicationLaunched {
psn: ProcessSerialNumber,
observer: Retained<WorkspaceObserver>,
},
ApplicationTerminated { psn: ProcessSerialNumber },
ApplicationFrontSwitched { psn: ProcessSerialNumber },
ApplicationActivated { pid: i32 },
ApplicationDeactivated { pid: i32 },
ApplicationVisible { pid: i32 },
ApplicationHidden { pid: i32 },
WindowCreated { element: CFRetained<AXUIWrapper> },
WindowSpawned {
window_id: WinID,
pid: Pid,
app_name: String,
bundle_id: String,
title: String,
frame: crate::types::state::Frame,
floating: bool,
managed: bool,
},
WindowDestroyed {
window_id: WinID,
source: DestroySource,
},
WindowFocused { window_id: WinID },
WindowMoved { window_id: WinID },
WindowResized { window_id: WinID },
WindowMinimized { window_id: WinID },
WindowDeminimized { window_id: WinID },
WindowTitleChanged { window_id: WinID },
MouseDown {
point: CGPoint,
modifiers: Modifiers,
},
MouseUp {
point: CGPoint,
modifiers: Modifiers,
},
MouseDragged {
point: CGPoint,
modifiers: Modifiers,
},
MouseMoved {
point: CGPoint,
modifiers: Modifiers,
},
Swipe { delta: f64, fingers: usize },
VerticalSwipe { delta: f64, fingers: usize },
VerticalScrollTick { delta: f64 },
Scroll { delta: f64 },
TouchpadDown,
TouchpadUp,
SpaceCreated { space_id: WorkspaceId },
SpaceDestroyed { space_id: WorkspaceId },
SpaceChanged,
DisplayAdded { display_id: CGDirectDisplayID },
DisplayRemoved { display_id: CGDirectDisplayID },
DisplayMoved { display_id: CGDirectDisplayID },
DisplayResized { display_id: CGDirectDisplayID },
DisplayConfigured { display_id: CGDirectDisplayID },
DisplayChanged,
MissionControlShowAllWindows,
MissionControlShowFrontWindows,
MissionControlShowDesktop,
MissionControlExit,
DockDidChangePref { msg: String },
DockDidRestart { msg: String },
MenuOpened { window_id: WinID },
MenuClosed { window_id: WinID },
MenuBarHiddenChanged { msg: String },
SystemWoke { msg: String },
ThemeChanged,
Command { command: Command },
StateQuery {
kind: StateQueryKind,
respond_to: Reply,
},
WindowSetQuery { respond_to: Reply },
StateSubscribe {
subscriber: Arc<crate::types::wire::Subscriber>,
},
ScriptState {
request: ScriptStateRequest,
respond_to: Reply,
},
}
#[derive(Clone, Debug)]
pub struct EventSender {
tx: Sender<Event>,
waker: Arc<EventLoopWaker>,
}
impl Event {
pub fn is_input(&self) -> bool {
matches!(
self,
Event::MouseDown { .. }
| Event::MouseUp { .. }
| Event::MouseDragged { .. }
| Event::MouseMoved { .. }
| Event::Swipe { .. }
| Event::VerticalSwipe { .. }
| Event::VerticalScrollTick { .. }
| Event::Scroll { .. }
| Event::TouchpadDown
| Event::TouchpadUp
)
}
}
impl EventSender {
pub fn new() -> (Self, Receiver<Event>) {
let (tx, rx) = channel::<Event>();
(
Self {
tx,
waker: Arc::new(EventLoopWaker::new()),
},
rx,
)
}
pub fn waker(&self) -> &Arc<EventLoopWaker> {
&self.waker
}
pub fn send(&self, event: Event) -> Result<()> {
self.tx.send(event)?;
self.waker.wake();
Ok(())
}
}