use std::ops::{Deref, DerefMut};
use std::time::Duration;
use bevy::app::{PostUpdate, PreUpdate};
use bevy::ecs::resource::Resource;
use bevy::ecs::system::Commands;
use bevy::prelude::Event as BevyEvent;
use bevy::time::Timer;
use bevy::{
app::Update,
ecs::{
component::Component,
entity::Entity,
schedule::{IntoScheduleConfigs, common_conditions::resource_equals},
},
};
use objc2_core_foundation::{CGPoint, CGSize};
use objc2_core_graphics::CGDirectDisplayID;
use crate::commands::Command;
use crate::events::Event;
use crate::manager::{ProcessApi, Window, WindowPane};
use crate::platform::WinID;
pub use systems::gather_displays;
pub use systems::run_initial_oneshot_systems;
pub mod params;
mod systems;
mod triggers;
pub fn register_systems(app: &mut bevy::app::App) {
app.add_systems(
PreUpdate,
(systems::dispatch_toplevel_triggers, systems::pump_events),
);
app.add_systems(
Update,
(
systems::reshuffle_around_window,
systems::window_swiper,
systems::add_launched_process,
systems::add_launched_application,
systems::fresh_marker_cleanup,
systems::timeout_ticker,
systems::retry_stray_focus,
systems::find_orphaned_spaces,
systems::window_update_frame,
),
);
app.add_systems(
Update,
(
systems::display_changes_watcher,
systems::workspace_change_watcher,
)
.run_if(resource_equals(PollForNotifications(true))),
);
app.add_systems(
PostUpdate,
(systems::animate_windows, systems::animate_resize_windows),
);
}
pub fn register_triggers(app: &mut bevy::app::App) {
app.add_observer(triggers::mouse_moved_trigger)
.add_observer(triggers::mouse_down_trigger)
.add_observer(triggers::mouse_dragged_trigger)
.add_observer(triggers::workspace_change_trigger)
.add_observer(triggers::display_change_trigger)
.add_observer(triggers::active_display_trigger)
.add_observer(triggers::display_add_trigger)
.add_observer(triggers::display_remove_trigger)
.add_observer(triggers::display_moved_trigger)
.add_observer(triggers::front_switched_trigger)
.add_observer(triggers::center_mouse_trigger)
.add_observer(triggers::window_focused_trigger)
.add_observer(triggers::swipe_gesture_trigger)
.add_observer(triggers::mission_control_trigger)
.add_observer(triggers::application_event_trigger)
.add_observer(triggers::dispatch_application_messages)
.add_observer(triggers::window_destroyed_trigger)
.add_observer(triggers::window_unmanaged_trigger)
.add_observer(triggers::window_managed_trigger)
.add_observer(triggers::spawn_window_trigger)
.add_observer(triggers::refresh_configuration_trigger)
.add_observer(triggers::print_internal_state_trigger);
}
#[derive(Component)]
pub struct FocusedMarker;
#[derive(Component)]
pub struct ActiveDisplayMarker;
#[derive(Component)]
pub struct FreshMarker;
#[derive(Component)]
pub struct ExistingMarker;
#[derive(Component)]
pub struct RepositionMarker {
pub origin: CGPoint,
pub display_id: CGDirectDisplayID,
}
#[derive(Component)]
pub struct ResizeMarker {
pub size: CGSize,
pub display_id: CGDirectDisplayID,
}
#[derive(Component)]
pub struct WindowDraggedMarker {
pub entity: Entity,
pub display_id: CGDirectDisplayID,
}
#[derive(Component)]
pub struct ReshuffleAroundMarker;
#[derive(Component)]
pub struct WindowSwipeMarker(pub f64);
#[derive(Component, Debug)]
pub enum Unmanaged {
Floating,
Minimized,
Hidden,
}
#[derive(Component)]
pub struct BProcess(pub Box<dyn ProcessApi>);
impl Deref for BProcess {
type Target = Box<dyn ProcessApi>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for BProcess {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Component)]
pub struct Timeout {
pub timer: Timer,
pub message: Option<String>,
}
impl Timeout {
pub fn new(duration: Duration, message: Option<String>) -> Self {
let timer = Timer::from_seconds(duration.as_secs_f32(), bevy::time::TimerMode::Once);
Self { timer, message }
}
}
#[derive(Component)]
pub struct StrayFocusEvent(pub WinID);
#[derive(Component)]
pub struct OrphanedPane {
pub id: u64,
pub pane: WindowPane,
}
#[derive(Resource)]
pub struct SkipReshuffle(pub bool);
#[derive(Resource)]
pub struct MissionControlActive(pub bool);
#[derive(Resource)]
pub struct FocusFollowsMouse(pub Option<WinID>);
#[derive(PartialEq, Resource)]
pub struct PollForNotifications(pub bool);
#[derive(BevyEvent)]
pub struct WMEventTrigger(pub Event);
#[derive(BevyEvent)]
pub struct CommandTrigger(pub Command);
#[derive(BevyEvent)]
pub struct SpawnWindowTrigger(pub Vec<Window>);
pub fn reposition_entity(
entity: Entity,
x: f64,
y: f64,
display_id: CGDirectDisplayID,
commands: &mut Commands,
) {
if let Ok(mut entity_cmmands) = commands.get_entity(entity) {
entity_cmmands.try_insert(RepositionMarker {
origin: CGPoint { x, y },
display_id,
});
}
}
pub fn resize_entity(
entity: Entity,
width: f64,
height: f64,
display_id: CGDirectDisplayID,
commands: &mut Commands,
) {
if let Ok(mut entity_cmmands) = commands.get_entity(entity) {
entity_cmmands.try_insert(ResizeMarker {
size: CGSize { width, height },
display_id,
});
}
}
pub fn reshuffle_around(entity: Entity, commands: &mut Commands) {
if let Ok(mut entity_commands) = commands.get_entity(entity) {
entity_commands.try_insert(ReshuffleAroundMarker);
}
}