2024-02-14 22:50:11 +00:00
use std ::{
any ::{ type_name , TypeId } ,
cell ::{ Ref , RefCell , RefMut } ,
marker ::PhantomData ,
ops ::{ Deref , DerefMut } ,
path ::{ Path , PathBuf } ,
rc ::{ Rc , Weak } ,
sync ::{ atomic ::Ordering ::SeqCst , Arc } ,
time ::Duration ,
} ;
2024-01-03 20:59:39 +00:00
2024-02-14 22:50:11 +00:00
use anyhow ::{ anyhow , Result } ;
2024-01-03 20:59:39 +00:00
use derive_more ::{ Deref , DerefMut } ;
2024-02-14 22:50:11 +00:00
use futures ::{ channel ::oneshot , future ::LocalBoxFuture , Future } ;
use slotmap ::SlotMap ;
use smol ::future ::FutureExt ;
use time ::UtcOffset ;
pub use async_context ::* ;
use collections ::{ FxHashMap , FxHashSet , VecDeque } ;
2024-01-03 20:59:39 +00:00
pub use entity_map ::* ;
pub use model_context ::* ;
use refineable ::Refineable ;
#[ cfg(any(test, feature = " test-support " )) ]
pub use test_context ::* ;
2024-02-14 22:50:11 +00:00
use util ::{
http ::{ self , HttpClient } ,
ResultExt ,
} ;
2022-04-07 23:20:49 +00:00
2023-08-10 16:26:48 +00:00
use crate ::{
2024-01-03 20:59:39 +00:00
current_platform , image_cache ::ImageCache , init_app_menus , Action , ActionRegistry , Any ,
AnyView , AnyWindowHandle , AppMetadata , AssetSource , BackgroundExecutor , ClipboardItem , Context ,
2024-02-08 18:47:12 +00:00
DispatchPhase , Entity , EventEmitter , ForegroundExecutor , Global , KeyBinding , Keymap , Keystroke ,
2024-03-07 02:15:06 +00:00
LayoutId , Menu , PathPromptOptions , Pixels , Platform , PlatformDisplay , Point , PromptBuilder ,
PromptHandle , PromptLevel , Render , RenderablePromptHandle , SharedString , SubscriberSet ,
Subscription , SvgRenderer , Task , TextStyle , TextStyleRefinement , TextSystem , View , ViewContext ,
Window , WindowAppearance , WindowContext , WindowHandle , WindowId ,
2023-08-10 16:26:48 +00:00
} ;
2024-01-21 23:35:47 +00:00
2024-02-14 22:50:11 +00:00
mod async_context ;
mod entity_map ;
mod model_context ;
#[ cfg(any(test, feature = " test-support " )) ]
mod test_context ;
2022-10-10 21:46:07 +00:00
2024-01-17 18:00:21 +00:00
/// The duration for which futures returned from [AppContext::on_app_context] or [ModelContext::on_app_quit] can run before the application fully quits.
pub const SHUTDOWN_TIMEOUT : Duration = Duration ::from_millis ( 100 ) ;
2024-01-07 13:14:21 +00:00
/// Temporary(?) wrapper around [`RefCell<AppContext>`] to help us debug any double borrows.
2024-01-03 20:59:39 +00:00
/// Strongly consider removing after stabilization.
2024-01-09 18:46:43 +00:00
#[ doc(hidden) ]
2024-01-03 20:59:39 +00:00
pub struct AppCell {
app : RefCell < AppContext > ,
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
impl AppCell {
2024-01-09 18:46:43 +00:00
#[ doc(hidden) ]
2024-01-03 20:59:39 +00:00
#[ track_caller ]
pub fn borrow ( & self ) -> AppRef {
if option_env! ( " TRACK_THREAD_BORROWS " ) . is_some ( ) {
let thread_id = std ::thread ::current ( ) . id ( ) ;
eprintln! ( " borrowed {thread_id:?} " ) ;
}
AppRef ( self . app . borrow ( ) )
2021-03-10 04:00:51 +00:00
}
2023-05-04 10:04:30 +00:00
2024-01-09 18:46:43 +00:00
#[ doc(hidden) ]
2024-01-03 20:59:39 +00:00
#[ track_caller ]
pub fn borrow_mut ( & self ) -> AppRefMut {
if option_env! ( " TRACK_THREAD_BORROWS " ) . is_some ( ) {
let thread_id = std ::thread ::current ( ) . id ( ) ;
eprintln! ( " borrowed {thread_id:?} " ) ;
}
AppRefMut ( self . app . borrow_mut ( ) )
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
}
2023-05-04 10:04:30 +00:00
2024-01-09 18:46:43 +00:00
#[ doc(hidden) ]
2024-01-03 20:59:39 +00:00
#[ derive(Deref, DerefMut) ]
pub struct AppRef < ' a > ( Ref < ' a , AppContext > ) ;
2022-07-20 23:44:26 +00:00
2024-01-03 20:59:39 +00:00
impl < ' a > Drop for AppRef < ' a > {
fn drop ( & mut self ) {
if option_env! ( " TRACK_THREAD_BORROWS " ) . is_some ( ) {
let thread_id = std ::thread ::current ( ) . id ( ) ;
eprintln! ( " dropped borrow from {thread_id:?} " ) ;
}
2022-07-20 23:44:26 +00:00
}
2021-03-10 04:00:51 +00:00
}
2024-01-09 18:46:43 +00:00
#[ doc(hidden) ]
2024-01-03 20:59:39 +00:00
#[ derive(Deref, DerefMut) ]
pub struct AppRefMut < ' a > ( RefMut < ' a , AppContext > ) ;
2023-08-03 14:10:16 +00:00
2024-01-03 20:59:39 +00:00
impl < ' a > Drop for AppRefMut < ' a > {
fn drop ( & mut self ) {
if option_env! ( " TRACK_THREAD_BORROWS " ) . is_some ( ) {
let thread_id = std ::thread ::current ( ) . id ( ) ;
eprintln! ( " dropped {thread_id:?} " ) ;
}
}
2021-03-10 04:00:51 +00:00
}
2024-01-09 18:46:43 +00:00
/// A reference to a GPUI application, typically constructed in the `main` function of your app.
/// You won't interact with this type much outside of initial configuration and startup.
2024-01-03 20:59:39 +00:00
pub struct App ( Rc < AppCell > ) ;
2021-03-10 04:00:51 +00:00
2024-01-03 20:59:39 +00:00
/// Represents an application before it is fully launched. Once your app is
/// configured, you'll start the app with `App::run`.
2021-03-10 04:00:51 +00:00
impl App {
2024-01-03 20:59:39 +00:00
/// Builds an app with the given asset source.
2024-01-21 23:35:47 +00:00
#[ allow(clippy::new_without_default) ]
2024-01-18 04:18:07 +00:00
pub fn new ( ) -> Self {
2024-02-14 20:24:12 +00:00
#[ cfg(any(test, feature = " test-support " )) ]
log ::info! ( " GPUI was compiled in test mode " ) ;
2024-01-03 20:59:39 +00:00
Self ( AppContext ::new (
current_platform ( ) ,
2024-01-18 04:18:07 +00:00
Arc ::new ( ( ) ) ,
2024-01-03 20:59:39 +00:00
http ::client ( ) ,
) )
2022-04-15 23:33:56 +00:00
}
2024-01-18 04:18:07 +00:00
/// Assign
pub fn with_assets ( self , asset_source : impl AssetSource ) -> Self {
2024-01-18 15:26:20 +00:00
let mut context_lock = self . 0. borrow_mut ( ) ;
let asset_source = Arc ::new ( asset_source ) ;
context_lock . asset_source = asset_source . clone ( ) ;
context_lock . svg_renderer = SvgRenderer ::new ( asset_source ) ;
drop ( context_lock ) ;
2024-01-18 04:18:07 +00:00
self
}
2024-01-03 20:59:39 +00:00
/// Start the application. The provided callback will be called once the
/// app is fully launched.
2021-04-10 03:33:17 +00:00
pub fn run < F > ( self , on_finish_launching : F )
where
2023-04-06 21:49:03 +00:00
F : 'static + FnOnce ( & mut AppContext ) ,
2021-04-10 03:33:17 +00:00
{
2024-01-03 20:59:39 +00:00
let this = self . 0. clone ( ) ;
let platform = self . 0. borrow ( ) . platform . clone ( ) ;
2021-06-07 23:21:34 +00:00
platform . run ( Box ::new ( move | | {
2024-01-03 20:59:39 +00:00
let cx = & mut * this . borrow_mut ( ) ;
2021-08-31 00:59:13 +00:00
on_finish_launching ( cx ) ;
2024-01-03 20:59:39 +00:00
} ) ) ;
2023-05-02 17:28:58 +00:00
}
2024-01-03 20:59:39 +00:00
/// Register a handler to be invoked when the platform instructs the application
/// to open one or more URLs.
pub fn on_open_urls < F > ( & self , mut callback : F ) -> & Self
2021-05-12 21:16:49 +00:00
where
2024-03-07 20:52:50 +00:00
F : 'static + FnMut ( Vec < String > ) ,
2021-05-12 21:16:49 +00:00
{
2024-03-07 20:52:50 +00:00
self . 0. borrow ( ) . platform . on_open_urls ( Box ::new ( callback ) ) ;
2024-01-03 20:59:39 +00:00
self
2021-05-12 21:16:49 +00:00
}
2021-05-12 23:20:03 +00:00
2024-01-09 18:46:43 +00:00
/// Invokes a handler when an already-running application is launched.
/// On macOS, this can occur when the application icon is double-clicked or the app is launched via the dock.
2024-01-03 20:59:39 +00:00
pub fn on_reopen < F > ( & self , mut callback : F ) -> & Self
2022-04-22 09:45:18 +00:00
where
2024-01-03 20:59:39 +00:00
F : 'static + FnMut ( & mut AppContext ) ,
2022-04-22 09:45:18 +00:00
{
2024-01-03 20:59:39 +00:00
let this = Rc ::downgrade ( & self . 0 ) ;
self . 0. borrow_mut ( ) . platform . on_reopen ( Box ::new ( move | | {
if let Some ( app ) = this . upgrade ( ) {
callback ( & mut app . borrow_mut ( ) ) ;
}
} ) ) ;
self
2021-06-11 05:12:04 +00:00
}
2024-01-09 18:46:43 +00:00
/// Returns metadata associated with the application
2024-01-03 20:59:39 +00:00
pub fn metadata ( & self ) -> AppMetadata {
self . 0. borrow ( ) . app_metadata . clone ( )
2021-07-09 23:27:33 +00:00
}
2024-01-09 19:48:48 +00:00
/// Returns a handle to the [`BackgroundExecutor`] associated with this app, which can be used to spawn futures in the background.
2024-01-03 20:59:39 +00:00
pub fn background_executor ( & self ) -> BackgroundExecutor {
self . 0. borrow ( ) . background_executor . clone ( )
2021-05-12 23:20:03 +00:00
}
2021-05-12 21:16:49 +00:00
2024-01-09 19:48:48 +00:00
/// Returns a handle to the [`ForegroundExecutor`] associated with this app, which can be used to spawn futures in the foreground.
2024-01-03 20:59:39 +00:00
pub fn foreground_executor ( & self ) -> ForegroundExecutor {
self . 0. borrow ( ) . foreground_executor . clone ( )
2023-04-21 21:36:52 +00:00
}
2024-01-09 19:48:48 +00:00
/// Returns a reference to the [`TextSystem`] associated with this app.
2024-01-03 20:59:39 +00:00
pub fn text_system ( & self ) -> Arc < TextSystem > {
self . 0. borrow ( ) . text_system . clone ( )
2023-04-21 21:36:52 +00:00
}
}
2024-01-03 20:59:39 +00:00
type Handler = Box < dyn FnMut ( & mut AppContext ) -> bool + 'static > ;
type Listener = Box < dyn FnMut ( & dyn Any , & mut AppContext ) -> bool + 'static > ;
type KeystrokeObserver = Box < dyn FnMut ( & KeystrokeEvent , & mut WindowContext ) + 'static > ;
type QuitHandler = Box < dyn FnOnce ( & mut AppContext ) -> LocalBoxFuture < 'static , ( ) > + 'static > ;
type ReleaseListener = Box < dyn FnOnce ( & mut dyn Any , & mut AppContext ) + 'static > ;
type NewViewListener = Box < dyn FnMut ( AnyView , & mut WindowContext ) + 'static > ;
2023-08-03 23:03:39 +00:00
2024-01-17 18:00:21 +00:00
/// Contains the state of the full application, and passed as a reference to a variety of callbacks.
/// Other contexts such as [ModelContext], [WindowContext], and [ViewContext] deref to this type, making it the most general context type.
/// You need a reference to an `AppContext` to access the state of a [Model].
2023-04-06 21:49:03 +00:00
pub struct AppContext {
2024-01-03 20:59:39 +00:00
pub ( crate ) this : Weak < AppCell > ,
pub ( crate ) platform : Rc < dyn Platform > ,
app_metadata : AppMetadata ,
text_system : Arc < TextSystem > ,
2021-03-10 04:00:51 +00:00
flushing_effects : bool ,
2024-01-03 20:59:39 +00:00
pending_updates : usize ,
pub ( crate ) actions : Rc < ActionRegistry > ,
pub ( crate ) active_drag : Option < AnyDrag > ,
pub ( crate ) background_executor : BackgroundExecutor ,
pub ( crate ) foreground_executor : ForegroundExecutor ,
pub ( crate ) svg_renderer : SvgRenderer ,
asset_source : Arc < dyn AssetSource > ,
pub ( crate ) image_cache : ImageCache ,
pub ( crate ) text_style_stack : Vec < TextStyleRefinement > ,
2024-02-07 12:16:22 +00:00
pub ( crate ) globals_by_type : FxHashMap < TypeId , Box < dyn Any > > ,
2024-01-03 20:59:39 +00:00
pub ( crate ) entities : EntityMap ,
pub ( crate ) new_view_observers : SubscriberSet < TypeId , NewViewListener > ,
pub ( crate ) windows : SlotMap < WindowId , Option < Window > > ,
2024-02-20 20:42:11 +00:00
pub ( crate ) window_handles : FxHashMap < WindowId , AnyWindowHandle > ,
2024-01-21 23:35:47 +00:00
pub ( crate ) keymap : Rc < RefCell < Keymap > > ,
2024-01-03 20:59:39 +00:00
pub ( crate ) global_action_listeners :
2024-02-07 12:16:22 +00:00
FxHashMap < TypeId , Vec < Rc < dyn Fn ( & dyn Any , DispatchPhase , & mut Self ) > > > ,
2024-01-03 20:59:39 +00:00
pending_effects : VecDeque < Effect > ,
2024-02-07 12:16:22 +00:00
pub ( crate ) pending_notifications : FxHashSet < EntityId > ,
pub ( crate ) pending_global_notifications : FxHashSet < TypeId > ,
2024-01-03 20:59:39 +00:00
pub ( crate ) observers : SubscriberSet < EntityId , Handler > ,
// TypeId is the type of the event that the listener callback expects
pub ( crate ) event_listeners : SubscriberSet < EntityId , ( TypeId , Listener ) > ,
pub ( crate ) keystroke_observers : SubscriberSet < ( ) , KeystrokeObserver > ,
pub ( crate ) release_listeners : SubscriberSet < EntityId , ReleaseListener > ,
pub ( crate ) global_observers : SubscriberSet < TypeId , Handler > ,
pub ( crate ) quit_observers : SubscriberSet < ( ) , QuitHandler > ,
pub ( crate ) layout_id_buffer : Vec < LayoutId > , // We recycle this memory across layout requests.
pub ( crate ) propagate_event : bool ,
2024-03-07 02:15:06 +00:00
pub ( crate ) prompt_builder : Option < PromptBuilder > ,
2021-03-10 04:00:51 +00:00
}
2023-04-06 21:49:03 +00:00
impl AppContext {
2024-01-21 23:35:47 +00:00
#[ allow(clippy::new_ret_no_self) ]
2024-01-03 20:59:39 +00:00
pub ( crate ) fn new (
platform : Rc < dyn Platform > ,
asset_source : Arc < dyn AssetSource > ,
2023-09-06 21:22:29 +00:00
http_client : Arc < dyn HttpClient > ,
2024-01-03 20:59:39 +00:00
) -> Rc < AppCell > {
let executor = platform . background_executor ( ) ;
let foreground_executor = platform . foreground_executor ( ) ;
assert! (
executor . is_main_thread ( ) ,
" must construct App on main thread "
) ;
2023-04-07 17:54:08 +00:00
2024-01-03 20:59:39 +00:00
let text_system = Arc ::new ( TextSystem ::new ( platform . text_system ( ) ) ) ;
let entities = EntityMap ::new ( ) ;
2023-04-07 17:54:08 +00:00
2024-01-03 20:59:39 +00:00
let app_metadata = AppMetadata {
os_name : platform . os_name ( ) ,
os_version : platform . os_version ( ) . ok ( ) ,
app_version : platform . app_version ( ) . ok ( ) ,
} ;
2023-04-07 17:54:08 +00:00
2024-01-03 20:59:39 +00:00
let app = Rc ::new_cyclic ( | this | AppCell {
app : RefCell ::new ( AppContext {
this : this . clone ( ) ,
platform : platform . clone ( ) ,
app_metadata ,
text_system ,
actions : Rc ::new ( ActionRegistry ::default ( ) ) ,
flushing_effects : false ,
pending_updates : 0 ,
active_drag : None ,
background_executor : executor ,
foreground_executor ,
svg_renderer : SvgRenderer ::new ( asset_source . clone ( ) ) ,
asset_source ,
image_cache : ImageCache ::new ( http_client ) ,
text_style_stack : Vec ::new ( ) ,
2024-02-07 12:16:22 +00:00
globals_by_type : FxHashMap ::default ( ) ,
2024-01-03 20:59:39 +00:00
entities ,
new_view_observers : SubscriberSet ::new ( ) ,
2024-02-20 20:42:11 +00:00
window_handles : FxHashMap ::default ( ) ,
2024-01-03 20:59:39 +00:00
windows : SlotMap ::with_key ( ) ,
2024-01-21 23:35:47 +00:00
keymap : Rc ::new ( RefCell ::new ( Keymap ::default ( ) ) ) ,
2024-02-07 12:16:22 +00:00
global_action_listeners : FxHashMap ::default ( ) ,
2024-01-03 20:59:39 +00:00
pending_effects : VecDeque ::new ( ) ,
2024-02-07 12:16:22 +00:00
pending_notifications : FxHashSet ::default ( ) ,
pending_global_notifications : FxHashSet ::default ( ) ,
2024-01-03 20:59:39 +00:00
observers : SubscriberSet ::new ( ) ,
event_listeners : SubscriberSet ::new ( ) ,
release_listeners : SubscriberSet ::new ( ) ,
keystroke_observers : SubscriberSet ::new ( ) ,
global_observers : SubscriberSet ::new ( ) ,
quit_observers : SubscriberSet ::new ( ) ,
layout_id_buffer : Default ::default ( ) ,
propagate_event : true ,
2024-03-07 02:15:06 +00:00
prompt_builder : Some ( PromptBuilder ::Default ) ,
2024-01-03 20:59:39 +00:00
} ) ,
} ) ;
2023-04-07 17:54:08 +00:00
2024-01-03 20:59:39 +00:00
init_app_menus ( platform . as_ref ( ) , & mut app . borrow_mut ( ) ) ;
2023-04-07 17:54:08 +00:00
2024-01-03 20:59:39 +00:00
platform . on_quit ( Box ::new ( {
let cx = app . clone ( ) ;
move | | {
cx . borrow_mut ( ) . shutdown ( ) ;
}
} ) ) ;
2023-08-17 02:47:54 +00:00
2024-01-03 20:59:39 +00:00
app
2021-03-21 04:15:04 +00:00
}
2024-01-09 19:48:48 +00:00
/// Quit the application gracefully. Handlers registered with [`ModelContext::on_app_quit`]
2024-01-03 20:59:39 +00:00
/// will be given 100ms to complete before exiting.
pub fn shutdown ( & mut self ) {
2021-11-02 19:16:25 +00:00
let mut futures = Vec ::new ( ) ;
2024-01-03 20:59:39 +00:00
for observer in self . quit_observers . remove ( & ( ) ) {
futures . push ( observer ( self ) ) ;
}
2021-11-02 19:16:25 +00:00
2023-05-02 17:28:58 +00:00
self . windows . clear ( ) ;
2024-02-20 20:42:11 +00:00
self . window_handles . clear ( ) ;
2023-05-02 17:28:58 +00:00
self . flush_effects ( ) ;
2021-11-02 19:16:25 +00:00
let futures = futures ::future ::join_all ( futures ) ;
if self
2024-01-03 20:59:39 +00:00
. background_executor
2024-01-17 18:00:21 +00:00
. block_with_timeout ( SHUTDOWN_TIMEOUT , futures )
2021-11-02 19:16:25 +00:00
. is_err ( )
{
log ::error! ( " timed out waiting on app_will_quit " ) ;
}
}
2024-01-09 18:46:43 +00:00
/// Gracefully quit the application via the platform's standard routine.
2024-01-03 20:59:39 +00:00
pub fn quit ( & mut self ) {
self . platform . quit ( ) ;
2021-04-05 23:45:55 +00:00
}
2024-01-09 18:46:43 +00:00
/// Get metadata about the app and platform.
2024-01-03 20:59:39 +00:00
pub fn app_metadata ( & self ) -> AppMetadata {
self . app_metadata . clone ( )
2022-04-08 22:32:56 +00:00
}
2024-01-03 20:59:39 +00:00
/// Schedules all windows in the application to be redrawn. This can be called
/// multiple times in an update cycle and still result in a single redraw.
pub fn refresh ( & mut self ) {
self . pending_effects . push_back ( Effect ::Refresh ) ;
}
2024-01-04 21:04:17 +00:00
2024-01-03 20:59:39 +00:00
pub ( crate ) fn update < R > ( & mut self , update : impl FnOnce ( & mut Self ) -> R ) -> R {
self . pending_updates + = 1 ;
let result = update ( self ) ;
if ! self . flushing_effects & & self . pending_updates = = 1 {
self . flushing_effects = true ;
self . flush_effects ( ) ;
self . flushing_effects = false ;
}
self . pending_updates - = 1 ;
result
2022-02-27 23:14:40 +00:00
}
2024-01-09 18:46:43 +00:00
/// Arrange a callback to be invoked when the given model or view calls `notify` on its respective context.
2024-01-03 20:59:39 +00:00
pub fn observe < W , E > (
& mut self ,
entity : & E ,
mut on_notify : impl FnMut ( E , & mut AppContext ) + 'static ,
) -> Subscription
2022-02-27 23:14:40 +00:00
where
2024-01-03 20:59:39 +00:00
W : 'static ,
E : Entity < W > ,
2022-02-27 23:14:40 +00:00
{
2024-01-03 20:59:39 +00:00
self . observe_internal ( entity , move | e , cx | {
on_notify ( e , cx ) ;
true
} )
2022-02-27 23:14:40 +00:00
}
2024-02-06 10:10:15 +00:00
pub ( crate ) fn new_observer ( & mut self , key : EntityId , value : Handler ) -> Subscription {
let ( subscription , activate ) = self . observers . insert ( key , value ) ;
self . defer ( move | _ | activate ( ) ) ;
subscription
}
2024-01-09 18:46:43 +00:00
pub ( crate ) fn observe_internal < W , E > (
2024-01-03 20:59:39 +00:00
& mut self ,
entity : & E ,
mut on_notify : impl FnMut ( E , & mut AppContext ) -> bool + 'static ,
) -> Subscription
2021-03-10 04:00:51 +00:00
where
2024-01-03 20:59:39 +00:00
W : 'static ,
E : Entity < W > ,
2021-03-10 04:00:51 +00:00
{
2024-01-03 20:59:39 +00:00
let entity_id = entity . entity_id ( ) ;
let handle = entity . downgrade ( ) ;
2024-02-06 10:10:15 +00:00
self . new_observer (
2024-01-03 20:59:39 +00:00
entity_id ,
Box ::new ( move | cx | {
if let Some ( handle ) = E ::upgrade_from ( & handle ) {
on_notify ( handle , cx )
} else {
false
}
} ) ,
2024-02-06 10:10:15 +00:00
)
2021-03-10 04:00:51 +00:00
}
2024-01-09 18:46:43 +00:00
/// Arrange for the given callback to be invoked whenever the given model or view emits an event of a given type.
/// The callback is provided a handle to the emitting entity and a reference to the emitted event.
pub fn subscribe < T , E , Event > (
2024-01-03 20:59:39 +00:00
& mut self ,
entity : & E ,
2024-01-09 18:46:43 +00:00
mut on_event : impl FnMut ( E , & Event , & mut AppContext ) + 'static ,
2024-01-03 20:59:39 +00:00
) -> Subscription
2022-02-05 19:37:34 +00:00
where
2024-01-09 18:46:43 +00:00
T : 'static + EventEmitter < Event > ,
2024-01-03 20:59:39 +00:00
E : Entity < T > ,
2024-01-09 18:46:43 +00:00
Event : 'static ,
2022-02-05 19:37:34 +00:00
{
2024-01-03 20:59:39 +00:00
self . subscribe_internal ( entity , move | entity , event , cx | {
on_event ( entity , event , cx ) ;
true
2022-02-05 19:37:34 +00:00
} )
}
2024-02-06 10:10:15 +00:00
pub ( crate ) fn new_subscription (
& mut self ,
key : EntityId ,
value : ( TypeId , Listener ) ,
) -> Subscription {
let ( subscription , activate ) = self . event_listeners . insert ( key , value ) ;
self . defer ( move | _ | activate ( ) ) ;
subscription
}
2024-01-03 20:59:39 +00:00
pub ( crate ) fn subscribe_internal < T , E , Evt > (
& mut self ,
entity : & E ,
mut on_event : impl FnMut ( E , & Evt , & mut AppContext ) -> bool + 'static ,
) -> Subscription
2021-03-10 04:00:51 +00:00
where
2024-01-03 20:59:39 +00:00
T : 'static + EventEmitter < Evt > ,
E : Entity < T > ,
Evt : 'static ,
2021-03-10 04:00:51 +00:00
{
2024-01-03 20:59:39 +00:00
let entity_id = entity . entity_id ( ) ;
let entity = entity . downgrade ( ) ;
2024-02-06 10:10:15 +00:00
self . new_subscription (
2024-01-03 20:59:39 +00:00
entity_id ,
(
TypeId ::of ::< Evt > ( ) ,
Box ::new ( move | event , cx | {
let event : & Evt = event . downcast_ref ( ) . expect ( " invalid event type " ) ;
if let Some ( handle ) = E ::upgrade_from ( & entity ) {
on_event ( handle , event , cx )
} else {
false
}
} ) ,
) ,
2024-02-06 10:10:15 +00:00
)
2024-01-03 20:59:39 +00:00
}
2021-03-10 04:00:51 +00:00
2024-01-09 18:46:43 +00:00
/// Returns handles to all open windows in the application.
/// Each handle could be downcast to a handle typed for the root view of that window.
/// To find all windows of a given type, you could filter on
2024-01-03 20:59:39 +00:00
pub fn windows ( & self ) -> Vec < AnyWindowHandle > {
self . windows
2024-02-20 20:42:11 +00:00
. keys ( )
. flat_map ( | window_id | self . window_handles . get ( & window_id ) . copied ( ) )
2024-01-03 20:59:39 +00:00
. collect ( )
}
2022-04-08 22:32:56 +00:00
2024-01-17 18:00:21 +00:00
/// Returns a handle to the window that is currently focused at the platform level, if one exists.
2024-01-03 20:59:39 +00:00
pub fn active_window ( & self ) -> Option < AnyWindowHandle > {
self . platform . active_window ( )
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
/// Opens a new window with the given option and the root view returned by the given function.
/// The function is invoked with a `WindowContext`, which can be used to interact with window-specific
/// functionality.
pub fn open_window < V : 'static + Render > (
& mut self ,
options : crate ::WindowOptions ,
build_root_view : impl FnOnce ( & mut WindowContext ) -> View < V > ,
) -> WindowHandle < V > {
self . update ( | cx | {
let id = cx . windows . insert ( None ) ;
let handle = WindowHandle ::new ( id ) ;
let mut window = Window ::new ( handle . into ( ) , options , cx ) ;
let root_view = build_root_view ( & mut WindowContext ::new ( cx , & mut window ) ) ;
window . root_view . replace ( root_view . into ( ) ) ;
2024-02-20 20:42:11 +00:00
cx . window_handles . insert ( id , window . handle ) ;
2024-01-03 20:59:39 +00:00
cx . windows . get_mut ( id ) . unwrap ( ) . replace ( window ) ;
handle
} )
2023-04-07 17:54:08 +00:00
}
2024-01-03 20:59:39 +00:00
/// Instructs the platform to activate the application by bringing it to the foreground.
pub fn activate ( & self , ignoring_other_apps : bool ) {
self . platform . activate ( ignoring_other_apps ) ;
2023-04-07 17:54:08 +00:00
}
2024-01-17 18:00:21 +00:00
/// Hide the application at the platform level.
2024-01-03 20:59:39 +00:00
pub fn hide ( & self ) {
self . platform . hide ( ) ;
2023-02-20 09:22:08 +00:00
}
2024-01-17 18:00:21 +00:00
/// Hide other applications at the platform level.
2024-01-03 20:59:39 +00:00
pub fn hide_other_apps ( & self ) {
self . platform . hide_other_apps ( ) ;
2022-02-14 22:04:27 +00:00
}
2024-01-17 18:00:21 +00:00
/// Unhide other applications at the platform level.
2024-01-03 20:59:39 +00:00
pub fn unhide_other_apps ( & self ) {
self . platform . unhide_other_apps ( ) ;
2021-04-09 22:58:19 +00:00
}
2024-01-03 20:59:39 +00:00
/// Returns the list of currently active displays.
pub fn displays ( & self ) -> Vec < Rc < dyn PlatformDisplay > > {
self . platform . displays ( )
2023-04-12 13:55:43 +00:00
}
2024-02-07 16:51:18 +00:00
/// Returns the appearance of the application's windows.
pub fn window_appearance ( & self ) -> WindowAppearance {
self . platform . window_appearance ( )
}
2024-01-03 20:59:39 +00:00
/// Writes data to the platform clipboard.
pub fn write_to_clipboard ( & self , item : ClipboardItem ) {
self . platform . write_to_clipboard ( item )
}
/// Reads data from the platform clipboard.
pub fn read_from_clipboard ( & self ) -> Option < ClipboardItem > {
self . platform . read_from_clipboard ( )
}
/// Writes credentials to the platform keychain.
2024-01-24 13:53:05 +00:00
pub fn write_credentials (
& self ,
url : & str ,
username : & str ,
password : & [ u8 ] ,
) -> Task < Result < ( ) > > {
2024-01-03 20:59:39 +00:00
self . platform . write_credentials ( url , username , password )
}
/// Reads credentials from the platform keychain.
2024-01-24 13:53:05 +00:00
pub fn read_credentials ( & self , url : & str ) -> Task < Result < Option < ( String , Vec < u8 > ) > > > {
2024-01-03 20:59:39 +00:00
self . platform . read_credentials ( url )
}
/// Deletes credentials from the platform keychain.
2024-01-24 13:53:05 +00:00
pub fn delete_credentials ( & self , url : & str ) -> Task < Result < ( ) > > {
2024-01-03 20:59:39 +00:00
self . platform . delete_credentials ( url )
}
/// Directs the platform's default browser to open the given URL.
pub fn open_url ( & self , url : & str ) {
self . platform . open_url ( url ) ;
}
2024-03-04 23:08:47 +00:00
/// register_url_scheme requests that the given scheme (e.g. `zed` for `zed://` urls)
/// is opened by the current app.
/// On some platforms (e.g. macOS) you may be able to register URL schemes as part of app
/// distribution, but this method exists to let you register schemes at runtime.
pub fn register_url_scheme ( & self , scheme : & str ) -> Task < Result < ( ) > > {
self . platform . register_url_scheme ( scheme )
}
2024-01-17 18:00:21 +00:00
/// Returns the full pathname of the current app bundle.
/// If the app is not being run from a bundle, returns an error.
2024-01-03 20:59:39 +00:00
pub fn app_path ( & self ) -> Result < PathBuf > {
self . platform . app_path ( )
}
2024-01-17 18:00:21 +00:00
/// Returns the file URL of the executable with the specified name in the application bundle
2024-01-03 20:59:39 +00:00
pub fn path_for_auxiliary_executable ( & self , name : & str ) -> Result < PathBuf > {
self . platform . path_for_auxiliary_executable ( name )
}
2024-01-17 18:00:21 +00:00
/// Returns the maximum duration in which a second mouse click must occur for an event to be a double-click event.
2024-01-03 20:59:39 +00:00
pub fn double_click_interval ( & self ) -> Duration {
self . platform . double_click_interval ( )
2023-04-20 15:13:13 +00:00
}
2024-01-17 18:00:21 +00:00
/// Displays a platform modal for selecting paths.
/// When one or more paths are selected, they'll be relayed asynchronously via the returned oneshot channel.
/// If cancelled, a `None` will be relayed instead.
2022-01-20 08:51:29 +00:00
pub fn prompt_for_paths (
& self ,
options : PathPromptOptions ,
) -> oneshot ::Receiver < Option < Vec < PathBuf > > > {
2024-01-03 20:59:39 +00:00
self . platform . prompt_for_paths ( options )
2021-04-14 14:30:03 +00:00
}
2024-01-17 18:00:21 +00:00
/// Displays a platform modal for selecting a new path where a file can be saved.
2024-01-25 17:32:32 +00:00
/// The provided directory will be used to set the initial location.
2024-01-17 18:00:21 +00:00
/// When a path is selected, it is relayed asynchronously via the returned oneshot channel.
/// If cancelled, a `None` will be relayed instead.
2022-01-20 08:51:29 +00:00
pub fn prompt_for_new_path ( & self , directory : & Path ) -> oneshot ::Receiver < Option < PathBuf > > {
2024-01-03 20:59:39 +00:00
self . platform . prompt_for_new_path ( directory )
2021-05-05 02:04:11 +00:00
}
2024-01-17 18:00:21 +00:00
/// Reveals the specified path at the platform level, such as in Finder on macOS.
2023-02-20 16:57:37 +00:00
pub fn reveal_path ( & self , path : & Path ) {
2024-01-03 20:59:39 +00:00
self . platform . reveal_path ( path )
2022-03-11 04:03:01 +00:00
}
2024-01-17 18:00:21 +00:00
/// Returns whether the user has configured scrollbars to auto-hide at the platform level.
2024-01-03 20:59:39 +00:00
pub fn should_auto_hide_scrollbars ( & self ) -> bool {
self . platform . should_auto_hide_scrollbars ( )
2021-08-23 22:02:30 +00:00
}
2024-01-17 18:00:21 +00:00
/// Restart the application.
2024-01-03 20:59:39 +00:00
pub fn restart ( & self ) {
self . platform . restart ( )
2022-03-11 04:03:01 +00:00
}
2024-01-17 18:00:21 +00:00
/// Returns the local timezone at the platform level.
2024-01-03 20:59:39 +00:00
pub fn local_timezone ( & self ) -> UtcOffset {
self . platform . local_timezone ( )
2021-08-23 22:02:30 +00:00
}
2024-01-03 20:59:39 +00:00
pub ( crate ) fn push_effect ( & mut self , effect : Effect ) {
match & effect {
Effect ::Notify { emitter } = > {
if ! self . pending_notifications . insert ( * emitter ) {
return ;
2022-03-22 14:57:30 +00:00
}
2024-01-03 20:59:39 +00:00
}
Effect ::NotifyGlobalObservers { global_type } = > {
if ! self . pending_global_notifications . insert ( * global_type ) {
return ;
2022-03-22 15:24:48 +00:00
}
2024-01-03 20:59:39 +00:00
}
_ = > { }
} ;
2022-01-21 13:22:06 +00:00
2024-01-03 20:59:39 +00:00
self . pending_effects . push_back ( effect ) ;
2022-04-14 16:22:32 +00:00
}
2024-01-09 19:48:48 +00:00
/// Called at the end of [`AppContext::update`] to complete any side effects
2024-01-03 20:59:39 +00:00
/// such as notifying observers, emitting events, etc. Effects can themselves
/// cause effects, so we continue looping until all effects are processed.
fn flush_effects ( & mut self ) {
loop {
self . release_dropped_entities ( ) ;
self . release_dropped_focus_handles ( ) ;
2022-03-22 23:38:17 +00:00
2024-01-03 20:59:39 +00:00
if let Some ( effect ) = self . pending_effects . pop_front ( ) {
match effect {
Effect ::Notify { emitter } = > {
self . apply_notify_effect ( emitter ) ;
}
2022-03-22 23:38:17 +00:00
2024-01-03 20:59:39 +00:00
Effect ::Emit {
emitter ,
event_type ,
event ,
} = > self . apply_emit_effect ( emitter , event_type , event ) ,
Effect ::Refresh = > {
self . apply_refresh_effect ( ) ;
}
Effect ::NotifyGlobalObservers { global_type } = > {
self . apply_notify_global_observers_effect ( global_type ) ;
}
Effect ::Defer { callback } = > {
self . apply_defer_effect ( callback ) ;
}
}
} else {
#[ cfg(any(test, feature = " test-support " )) ]
for window in self
. windows
. values ( )
. filter_map ( | window | {
let window = window . as_ref ( ) ? ;
2024-02-03 23:33:08 +00:00
window . dirty . get ( ) . then_some ( window . handle )
2024-01-03 20:59:39 +00:00
} )
. collect ::< Vec < _ > > ( )
{
self . update_window ( window , | _ , cx | cx . draw ( ) ) . unwrap ( ) ;
}
if self . pending_effects . is_empty ( ) {
break ;
}
}
2022-09-28 17:02:26 +00:00
}
}
2024-01-03 20:59:39 +00:00
/// Repeatedly called during `flush_effects` to release any entities whose
/// reference count has become zero. We invoke any release observers before dropping
/// each entity.
fn release_dropped_entities ( & mut self ) {
loop {
let dropped = self . entities . take_dropped ( ) ;
if dropped . is_empty ( ) {
break ;
}
for ( entity_id , mut entity ) in dropped {
self . observers . remove ( & entity_id ) ;
self . event_listeners . remove ( & entity_id ) ;
for release_callback in self . release_listeners . remove ( & entity_id ) {
release_callback ( entity . as_mut ( ) , self ) ;
2023-01-06 02:02:53 +00:00
}
2024-01-03 20:59:39 +00:00
}
}
2022-01-21 13:22:06 +00:00
}
2024-01-03 20:59:39 +00:00
/// Repeatedly called during `flush_effects` to handle a focused handle being dropped.
fn release_dropped_focus_handles ( & mut self ) {
for window_handle in self . windows ( ) {
window_handle
. update ( self , | _ , cx | {
let mut blur_window = false ;
let focus = cx . window . focus ;
cx . window . focus_handles . write ( ) . retain ( | handle_id , count | {
if count . load ( SeqCst ) = = 0 {
if focus = = Some ( handle_id ) {
blur_window = true ;
}
false
} else {
true
}
} ) ;
2022-05-30 08:01:23 +00:00
2024-01-03 20:59:39 +00:00
if blur_window {
cx . blur ( ) ;
}
} )
. unwrap ( ) ;
}
2023-02-20 09:22:08 +00:00
}
2024-01-03 20:59:39 +00:00
fn apply_notify_effect ( & mut self , emitter : EntityId ) {
self . pending_notifications . remove ( & emitter ) ;
self . observers
. clone ( )
. retain ( & emitter , | handler | handler ( self ) ) ;
2022-03-23 00:03:24 +00:00
}
2024-01-03 20:59:39 +00:00
fn apply_emit_effect ( & mut self , emitter : EntityId , event_type : TypeId , event : Box < dyn Any > ) {
self . event_listeners
. clone ( )
. retain ( & emitter , | ( stored_type , handler ) | {
if * stored_type = = event_type {
handler ( event . as_ref ( ) , self )
} else {
true
}
} ) ;
2022-01-22 20:14:25 +00:00
}
2024-01-03 20:59:39 +00:00
fn apply_refresh_effect ( & mut self ) {
for window in self . windows . values_mut ( ) {
if let Some ( window ) = window . as_mut ( ) {
2024-02-03 23:33:08 +00:00
window . dirty . set ( true ) ;
2024-01-03 20:59:39 +00:00
}
2021-09-30 21:06:09 +00:00
}
}
2021-08-23 22:02:30 +00:00
2024-01-03 20:59:39 +00:00
fn apply_notify_global_observers_effect ( & mut self , type_id : TypeId ) {
self . pending_global_notifications . remove ( & type_id ) ;
self . global_observers
. clone ( )
. retain ( & type_id , | observer | observer ( self ) ) ;
}
fn apply_defer_effect ( & mut self , callback : Box < dyn FnOnce ( & mut Self ) + 'static > ) {
callback ( self ) ;
2021-04-28 19:02:39 +00:00
}
2024-01-03 20:59:39 +00:00
/// Creates an `AsyncAppContext`, which can be cloned and has a static lifetime
/// so it can be held across `await` points.
pub fn to_async ( & self ) -> AsyncAppContext {
AsyncAppContext {
2024-01-21 23:35:47 +00:00
app : self . this . clone ( ) ,
2024-01-03 20:59:39 +00:00
background_executor : self . background_executor . clone ( ) ,
foreground_executor : self . foreground_executor . clone ( ) ,
2022-03-22 23:38:17 +00:00
}
}
2024-01-03 20:59:39 +00:00
/// Obtains a reference to the executor, which can be used to spawn futures.
pub fn background_executor ( & self ) -> & BackgroundExecutor {
& self . background_executor
2022-04-21 20:33:39 +00:00
}
2024-01-03 20:59:39 +00:00
/// Obtains a reference to the executor, which can be used to spawn futures.
pub fn foreground_executor ( & self ) -> & ForegroundExecutor {
& self . foreground_executor
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
/// Spawns the future returned by the given function on the thread pool. The closure will be invoked
2024-01-17 18:00:21 +00:00
/// with [AsyncAppContext], which allows the application state to be accessed across await points.
2024-01-03 20:59:39 +00:00
pub fn spawn < Fut , R > ( & self , f : impl FnOnce ( AsyncAppContext ) -> Fut ) -> Task < R >
where
Fut : Future < Output = R > + 'static ,
R : 'static ,
{
self . foreground_executor . spawn ( f ( self . to_async ( ) ) )
2022-02-27 23:14:40 +00:00
}
2024-01-03 20:59:39 +00:00
/// Schedules the given function to be run at the end of the current effect cycle, allowing entities
/// that are currently on the stack to be returned to the app.
pub fn defer ( & mut self , f : impl FnOnce ( & mut AppContext ) + 'static ) {
self . push_effect ( Effect ::Defer {
callback : Box ::new ( f ) ,
} ) ;
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
/// Accessor for the application's asset source, which is provided when constructing the `App`.
pub fn asset_source ( & self ) -> & Arc < dyn AssetSource > {
& self . asset_source
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
/// Accessor for the text system.
pub fn text_system ( & self ) -> & Arc < TextSystem > {
& self . text_system
2022-04-11 23:50:44 +00:00
}
2024-01-03 20:59:39 +00:00
/// The current text style. Which is composed of all the style refinements provided to `with_text_style`.
pub fn text_style ( & self ) -> TextStyle {
let mut style = TextStyle ::default ( ) ;
for refinement in & self . text_style_stack {
style . refine ( refinement ) ;
}
style
2023-07-31 13:40:03 +00:00
}
2024-01-03 20:59:39 +00:00
/// Check whether a global of the given type has been assigned.
2024-01-30 19:08:20 +00:00
pub fn has_global < G : Global > ( & self ) -> bool {
2024-01-03 20:59:39 +00:00
self . globals_by_type . contains_key ( & TypeId ::of ::< G > ( ) )
2022-03-17 14:54:34 +00:00
}
2024-01-03 20:59:39 +00:00
/// Access the global of the given type. Panics if a global for that type has not been assigned.
#[ track_caller ]
2024-01-30 19:08:20 +00:00
pub fn global < G : Global > ( & self ) -> & G {
2024-01-03 20:59:39 +00:00
self . globals_by_type
. get ( & TypeId ::of ::< G > ( ) )
. map ( | any_state | any_state . downcast_ref ::< G > ( ) . unwrap ( ) )
. ok_or_else ( | | anyhow! ( " no state of type {} exists " , type_name ::< G > ( ) ) )
. unwrap ( )
2022-02-28 01:07:46 +00:00
}
2024-01-03 20:59:39 +00:00
/// Access the global of the given type if a value has been assigned.
2024-01-30 19:08:20 +00:00
pub fn try_global < G : Global > ( & self ) -> Option < & G > {
2024-01-03 20:59:39 +00:00
self . globals_by_type
. get ( & TypeId ::of ::< G > ( ) )
. map ( | any_state | any_state . downcast_ref ::< G > ( ) . unwrap ( ) )
2022-03-17 14:54:34 +00:00
}
2024-01-03 20:59:39 +00:00
/// Access the global of the given type mutably. Panics if a global for that type has not been assigned.
#[ track_caller ]
2024-01-30 19:08:20 +00:00
pub fn global_mut < G : Global > ( & mut self ) -> & mut G {
2024-01-03 20:59:39 +00:00
let global_type = TypeId ::of ::< G > ( ) ;
self . push_effect ( Effect ::NotifyGlobalObservers { global_type } ) ;
self . globals_by_type
. get_mut ( & global_type )
. and_then ( | any_state | any_state . downcast_mut ::< G > ( ) )
. ok_or_else ( | | anyhow! ( " no state of type {} exists " , type_name ::< G > ( ) ) )
. unwrap ( )
2023-04-20 15:13:13 +00:00
}
2024-01-03 20:59:39 +00:00
/// Access the global of the given type mutably. A default value is assigned if a global of this type has not
/// yet been assigned.
2024-01-30 19:08:20 +00:00
pub fn default_global < G : Global + Default > ( & mut self ) -> & mut G {
2024-01-03 20:59:39 +00:00
let global_type = TypeId ::of ::< G > ( ) ;
self . push_effect ( Effect ::NotifyGlobalObservers { global_type } ) ;
self . globals_by_type
. entry ( global_type )
. or_insert_with ( | | Box ::< G > ::default ( ) )
. downcast_mut ::< G > ( )
. unwrap ( )
2022-02-28 01:07:46 +00:00
}
2024-01-19 16:18:50 +00:00
/// Sets the value of the global of the given type.
2024-01-30 19:08:20 +00:00
pub fn set_global < G : Global > ( & mut self , global : G ) {
2024-01-03 20:59:39 +00:00
let global_type = TypeId ::of ::< G > ( ) ;
self . push_effect ( Effect ::NotifyGlobalObservers { global_type } ) ;
self . globals_by_type . insert ( global_type , Box ::new ( global ) ) ;
2023-04-17 09:17:35 +00:00
}
2024-01-03 20:59:39 +00:00
/// Clear all stored globals. Does not notify global observers.
#[ cfg(any(test, feature = " test-support " )) ]
2022-10-06 07:50:26 +00:00
pub fn clear_globals ( & mut self ) {
2024-01-03 20:59:39 +00:00
self . globals_by_type . drain ( ) ;
2022-10-06 07:50:26 +00:00
}
2024-01-03 20:59:39 +00:00
/// Remove the global of the given type from the app context. Does not notify global observers.
2024-01-30 19:08:20 +00:00
pub fn remove_global < G : Global > ( & mut self ) -> G {
2024-01-03 20:59:39 +00:00
let global_type = TypeId ::of ::< G > ( ) ;
2024-01-16 01:02:20 +00:00
self . push_effect ( Effect ::NotifyGlobalObservers { global_type } ) ;
2023-05-10 23:39:59 +00:00
* self
2024-01-03 20:59:39 +00:00
. globals_by_type
. remove ( & global_type )
. unwrap_or_else ( | | panic! ( " no global added for {} " , std ::any ::type_name ::< G > ( ) ) )
2023-05-10 23:39:59 +00:00
. downcast ( )
. unwrap ( )
}
2024-01-19 16:18:50 +00:00
/// Updates the global of the given type with a closure. Unlike `global_mut`, this method provides
2024-01-03 20:59:39 +00:00
/// your closure with mutable access to the `AppContext` and the global simultaneously.
2024-01-30 19:08:20 +00:00
pub fn update_global < G : Global , R > ( & mut self , f : impl FnOnce ( & mut G , & mut Self ) -> R ) -> R {
2024-01-04 21:04:17 +00:00
self . update ( | cx | {
let mut global = cx . lease_global ::< G > ( ) ;
let result = f ( & mut global , cx ) ;
cx . end_global_lease ( global ) ;
result
} )
2023-04-21 21:05:19 +00:00
}
2024-01-03 20:59:39 +00:00
/// Register a callback to be invoked when a global of the given type is updated.
2024-01-30 19:08:20 +00:00
pub fn observe_global < G : Global > (
2023-04-24 14:52:09 +00:00
& mut self ,
2024-01-03 20:59:39 +00:00
mut f : impl FnMut ( & mut Self ) + 'static ,
) -> Subscription {
let ( subscription , activate ) = self . global_observers . insert (
TypeId ::of ::< G > ( ) ,
Box ::new ( move | cx | {
f ( cx ) ;
true
} ) ,
) ;
self . defer ( move | _ | activate ( ) ) ;
subscription
2023-04-24 14:40:30 +00:00
}
2024-01-03 20:59:39 +00:00
/// Move the global of the given type to the stack.
2024-01-30 19:08:20 +00:00
pub ( crate ) fn lease_global < G : Global > ( & mut self ) -> GlobalLease < G > {
2024-01-03 20:59:39 +00:00
GlobalLease ::new (
self . globals_by_type
. remove ( & TypeId ::of ::< G > ( ) )
. ok_or_else ( | | anyhow! ( " no global registered of type {} " , type_name ::< G > ( ) ) )
. unwrap ( ) ,
)
2023-04-24 14:40:30 +00:00
}
2024-01-03 20:59:39 +00:00
/// Restore the global of the given type after it is moved to the stack.
2024-01-30 19:08:20 +00:00
pub ( crate ) fn end_global_lease < G : Global > ( & mut self , lease : GlobalLease < G > ) {
2024-01-03 20:59:39 +00:00
let global_type = TypeId ::of ::< G > ( ) ;
self . push_effect ( Effect ::NotifyGlobalObservers { global_type } ) ;
self . globals_by_type . insert ( global_type , lease . global ) ;
2023-04-24 14:40:30 +00:00
}
2024-02-06 10:10:15 +00:00
pub ( crate ) fn new_view_observer (
& mut self ,
key : TypeId ,
value : NewViewListener ,
) -> Subscription {
let ( subscription , activate ) = self . new_view_observers . insert ( key , value ) ;
activate ( ) ;
subscription
}
2024-01-17 18:00:21 +00:00
/// Arrange for the given function to be invoked whenever a view of the specified type is created.
/// The function will be passed a mutable reference to the view along with an appropriate context.
2024-01-03 20:59:39 +00:00
pub fn observe_new_views < V : 'static > (
2021-08-05 17:48:35 +00:00
& mut self ,
2024-01-03 20:59:39 +00:00
on_new : impl 'static + Fn ( & mut V , & mut ViewContext < V > ) ,
) -> Subscription {
2024-02-06 10:10:15 +00:00
self . new_view_observer (
2024-01-03 20:59:39 +00:00
TypeId ::of ::< V > ( ) ,
Box ::new ( move | any_view : AnyView , cx : & mut WindowContext | {
any_view
. downcast ::< V > ( )
. unwrap ( )
. update ( cx , | view_state , cx | {
on_new ( view_state , cx ) ;
} )
} ) ,
2024-02-06 10:10:15 +00:00
)
2021-04-06 12:29:42 +00:00
}
2021-03-10 04:00:51 +00:00
2024-01-17 18:00:21 +00:00
/// Observe the release of a model or view. The callback is invoked after the model or view
/// has no more strong references but before it has been dropped.
2024-01-03 20:59:39 +00:00
pub fn observe_release < E , T > (
& mut self ,
handle : & E ,
on_release : impl FnOnce ( & mut T , & mut AppContext ) + 'static ,
) -> Subscription
2022-09-12 10:03:03 +00:00
where
2024-01-03 20:59:39 +00:00
E : Entity < T > ,
T : 'static ,
2022-09-12 10:03:03 +00:00
{
2024-01-03 20:59:39 +00:00
let ( subscription , activate ) = self . release_listeners . insert (
handle . entity_id ( ) ,
Box ::new ( move | entity , cx | {
let entity = entity . downcast_mut ( ) . expect ( " invalid entity type " ) ;
on_release ( entity , cx )
} ) ,
) ;
activate ( ) ;
subscription
2022-09-14 09:58:05 +00:00
}
2024-01-17 18:00:21 +00:00
/// Register a callback to be invoked when a keystroke is received by the application
2024-01-17 22:58:58 +00:00
/// in any window. Note that this fires after all other action and event mechanisms have resolved
/// and that this API will not be invoked if the event's propagation is stopped.
2024-01-03 20:59:39 +00:00
pub fn observe_keystrokes (
2022-09-14 09:58:05 +00:00
& mut self ,
2024-01-03 20:59:39 +00:00
f : impl FnMut ( & KeystrokeEvent , & mut WindowContext ) + 'static ,
) -> Subscription {
2024-02-06 10:10:15 +00:00
fn inner (
keystroke_observers : & mut SubscriberSet < ( ) , KeystrokeObserver > ,
handler : KeystrokeObserver ,
) -> Subscription {
let ( subscription , activate ) = keystroke_observers . insert ( ( ) , handler ) ;
activate ( ) ;
subscription
}
inner ( & mut self . keystroke_observers , Box ::new ( f ) )
2024-01-03 20:59:39 +00:00
}
2022-09-12 10:03:03 +00:00
2024-01-03 20:59:39 +00:00
pub ( crate ) fn push_text_style ( & mut self , text_style : TextStyleRefinement ) {
self . text_style_stack . push ( text_style ) ;
}
2022-09-14 09:58:05 +00:00
2024-01-03 20:59:39 +00:00
pub ( crate ) fn pop_text_style ( & mut self ) {
self . text_style_stack . pop ( ) ;
}
2023-01-20 20:15:21 +00:00
2024-01-03 20:59:39 +00:00
/// Register key bindings.
pub fn bind_keys ( & mut self , bindings : impl IntoIterator < Item = KeyBinding > ) {
2024-01-21 23:35:47 +00:00
self . keymap . borrow_mut ( ) . add_bindings ( bindings ) ;
2024-01-03 20:59:39 +00:00
self . pending_effects . push_back ( Effect ::Refresh ) ;
}
2022-09-14 09:58:05 +00:00
2024-01-17 18:00:21 +00:00
/// Clear all key bindings in the app.
2024-01-04 21:04:17 +00:00
pub fn clear_key_bindings ( & mut self ) {
2024-01-21 23:35:47 +00:00
self . keymap . borrow_mut ( ) . clear ( ) ;
2024-01-04 21:04:17 +00:00
self . pending_effects . push_back ( Effect ::Refresh ) ;
}
2024-01-03 20:59:39 +00:00
/// Register a global listener for actions invoked via the keyboard.
pub fn on_action < A : Action > ( & mut self , listener : impl Fn ( & A , & mut Self ) + 'static ) {
self . global_action_listeners
. entry ( TypeId ::of ::< A > ( ) )
. or_default ( )
. push ( Rc ::new ( move | action , phase , cx | {
if phase = = DispatchPhase ::Bubble {
let action = action . downcast_ref ( ) . unwrap ( ) ;
listener ( action , cx )
}
2022-09-14 09:58:05 +00:00
} ) ) ;
2024-01-03 20:59:39 +00:00
}
2022-09-14 09:58:05 +00:00
2024-01-03 20:59:39 +00:00
/// Event handlers propagate events by default. Call this method to stop dispatching to
/// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is
2024-01-07 13:14:21 +00:00
/// the opposite of [`Self::propagate`]. It's also possible to cancel a call to [`Self::propagate`] by
2024-01-03 20:59:39 +00:00
/// calling this method before effects are flushed.
pub fn stop_propagation ( & mut self ) {
self . propagate_event = false ;
}
2022-09-14 09:58:05 +00:00
2024-01-03 20:59:39 +00:00
/// Action handlers stop propagation by default during the bubble phase of action dispatch
/// dispatching to action handlers higher in the element tree. This is the opposite of
2024-01-07 13:14:21 +00:00
/// [`Self::stop_propagation`]. It's also possible to cancel a call to [`Self::stop_propagation`] by calling
2024-01-03 20:59:39 +00:00
/// this method before effects are flushed.
pub fn propagate ( & mut self ) {
self . propagate_event = true ;
}
2022-09-14 09:58:05 +00:00
2024-01-17 18:00:21 +00:00
/// Build an action from some arbitrary data, typically a keymap entry.
2024-01-03 20:59:39 +00:00
pub fn build_action (
& self ,
name : & str ,
data : Option < serde_json ::Value > ,
) -> Result < Box < dyn Action > > {
self . actions . build_action ( name , data )
2021-08-23 13:20:23 +00:00
}
2024-01-17 18:00:21 +00:00
/// Get a list of all action names that have been registered.
/// in the application. Note that registration only allows for
/// actions to be built dynamically, and is unrelated to binding
/// actions in the element tree.
2024-01-03 20:59:39 +00:00
pub fn all_action_names ( & self ) -> & [ SharedString ] {
self . actions . all_action_names ( )
2023-08-07 00:57:02 +00:00
}
2024-01-17 18:00:21 +00:00
/// Register a callback to be invoked when the application is about to quit.
/// It is not possible to cancel the quit event at this point.
2024-01-03 20:59:39 +00:00
pub fn on_app_quit < Fut > (
& mut self ,
mut on_quit : impl FnMut ( & mut AppContext ) -> Fut + 'static ,
) -> Subscription
where
Fut : 'static + Future < Output = ( ) > ,
{
let ( subscription , activate ) = self . quit_observers . insert (
( ) ,
Box ::new ( move | cx | {
let future = on_quit ( cx ) ;
future . boxed_local ( )
} ) ,
) ;
activate ( ) ;
subscription
2023-04-12 03:56:37 +00:00
}
2024-01-03 20:59:39 +00:00
pub ( crate ) fn clear_pending_keystrokes ( & mut self ) {
for window in self . windows ( ) {
window
. update ( self , | _ , cx | {
cx . window
. rendered_frame
. dispatch_tree
. clear_pending_keystrokes ( ) ;
cx . window
. next_frame
. dispatch_tree
. clear_pending_keystrokes ( ) ;
} )
. ok ( ) ;
2023-04-21 21:03:57 +00:00
}
}
2024-01-17 18:00:21 +00:00
/// Checks if the given action is bound in the current context, as defined by the app's current focus,
/// the bindings in the element tree, and any global action listeners.
2024-01-03 20:59:39 +00:00
pub fn is_action_available ( & mut self , action : & dyn Action ) -> bool {
if let Some ( window ) = self . active_window ( ) {
if let Ok ( window_action_available ) =
window . update ( self , | _ , cx | cx . is_action_available ( action ) )
{
return window_action_available ;
}
2023-04-24 14:33:27 +00:00
}
2024-01-03 20:59:39 +00:00
self . global_action_listeners
. contains_key ( & action . as_any ( ) . type_id ( ) )
2023-04-24 14:33:27 +00:00
}
2024-01-19 16:18:50 +00:00
/// Sets the menu bar for this application. This will replace any existing menu bar.
2024-01-03 20:59:39 +00:00
pub fn set_menus ( & mut self , menus : Vec < Menu > ) {
2024-01-21 23:35:47 +00:00
self . platform . set_menus ( menus , & self . keymap . borrow ( ) ) ;
2023-04-24 14:33:27 +00:00
}
2024-01-17 18:00:21 +00:00
/// Dispatch an action to the currently active window or global action handler
/// See [action::Action] for more information on how actions work
2024-01-03 20:59:39 +00:00
pub fn dispatch_action ( & mut self , action : & dyn Action ) {
if let Some ( active_window ) = self . active_window ( ) {
active_window
. update ( self , | _ , cx | cx . dispatch_action ( action . boxed_clone ( ) ) )
. log_err ( ) ;
} else {
self . propagate_event = true ;
if let Some ( mut global_listeners ) = self
. global_action_listeners
. remove ( & action . as_any ( ) . type_id ( ) )
2021-08-27 16:04:21 +00:00
{
2024-01-03 20:59:39 +00:00
for listener in & global_listeners {
listener ( action . as_any ( ) , DispatchPhase ::Capture , self ) ;
if ! self . propagate_event {
break ;
}
}
global_listeners . extend (
self . global_action_listeners
. remove ( & action . as_any ( ) . type_id ( ) )
. unwrap_or_default ( ) ,
) ;
2021-03-10 04:00:51 +00:00
2024-01-03 20:59:39 +00:00
self . global_action_listeners
. insert ( action . as_any ( ) . type_id ( ) , global_listeners ) ;
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
if self . propagate_event {
if let Some ( mut global_listeners ) = self
. global_action_listeners
. remove ( & action . as_any ( ) . type_id ( ) )
{
for listener in global_listeners . iter ( ) . rev ( ) {
listener ( action . as_any ( ) , DispatchPhase ::Bubble , self ) ;
if ! self . propagate_event {
break ;
}
}
2022-01-21 13:22:06 +00:00
2024-01-03 20:59:39 +00:00
global_listeners . extend (
self . global_action_listeners
. remove ( & action . as_any ( ) . type_id ( ) )
. unwrap_or_default ( ) ,
) ;
2021-04-27 03:24:23 +00:00
2024-01-03 20:59:39 +00:00
self . global_action_listeners
. insert ( action . as_any ( ) . type_id ( ) , global_listeners ) ;
}
2021-04-27 03:24:23 +00:00
}
2021-03-10 04:00:51 +00:00
}
}
2024-01-17 18:00:21 +00:00
/// Is there currently something being dragged?
2024-01-03 20:59:39 +00:00
pub fn has_active_drag ( & self ) -> bool {
self . active_drag . is_some ( )
}
2024-03-07 02:15:06 +00:00
/// Set the prompt renderer for GPUI. This will replace the default or platform specific
/// prompts with this custom implementation.
pub fn set_prompt_builder (
& mut self ,
renderer : impl Fn (
PromptLevel ,
& str ,
Option < & str > ,
& [ & str ] ,
PromptHandle ,
& mut WindowContext ,
) -> RenderablePromptHandle
+ 'static ,
) {
self . prompt_builder = Some ( PromptBuilder ::Custom ( Box ::new ( renderer ) ) )
}
2024-01-03 20:59:39 +00:00
}
2022-08-09 19:34:57 +00:00
2024-01-03 20:59:39 +00:00
impl Context for AppContext {
type Result < T > = T ;
2022-08-09 19:34:57 +00:00
2024-01-03 20:59:39 +00:00
/// Build an entity that is owned by the application. The given function will be invoked with
2024-01-18 04:18:07 +00:00
/// a `ModelContext` and must return an object representing the entity. A `Model` handle will be returned,
2024-01-03 20:59:39 +00:00
/// which can be used to access the entity in a context.
fn new_model < T : 'static > (
2022-12-08 00:39:32 +00:00
& mut self ,
2024-01-03 20:59:39 +00:00
build_model : impl FnOnce ( & mut ModelContext < '_ , T > ) -> T ,
) -> Model < T > {
self . update ( | cx | {
let slot = cx . entities . reserve ( ) ;
let entity = build_model ( & mut ModelContext ::new ( cx , slot . downgrade ( ) ) ) ;
cx . entities . insert ( slot , entity )
2023-05-05 08:47:42 +00:00
} )
2022-05-30 08:01:23 +00:00
}
2024-01-19 16:18:50 +00:00
/// Updates the entity referenced by the given model. The function is passed a mutable reference to the
2024-01-03 20:59:39 +00:00
/// entity along with a `ModelContext` for the entity.
fn update_model < T : 'static , R > (
2022-06-23 09:43:19 +00:00
& mut self ,
2024-01-03 20:59:39 +00:00
model : & Model < T > ,
update : impl FnOnce ( & mut T , & mut ModelContext < '_ , T > ) -> R ,
) -> R {
self . update ( | cx | {
let mut entity = cx . entities . lease ( model ) ;
let result = update ( & mut entity , & mut ModelContext ::new ( cx , model . downgrade ( ) ) ) ;
cx . entities . end_lease ( entity ) ;
result
} )
2022-04-14 14:52:24 +00:00
}
2024-01-03 20:59:39 +00:00
fn update_window < T , F > ( & mut self , handle : AnyWindowHandle , update : F ) -> Result < T >
2021-03-10 04:00:51 +00:00
where
2024-01-03 20:59:39 +00:00
F : FnOnce ( AnyView , & mut WindowContext < '_ > ) -> T ,
2021-03-10 04:00:51 +00:00
{
2024-01-03 20:59:39 +00:00
self . update ( | cx | {
let mut window = cx
. windows
. get_mut ( handle . id )
. ok_or_else ( | | anyhow! ( " window not found " ) ) ?
. take ( )
2024-02-21 05:48:42 +00:00
. ok_or_else ( | | anyhow! ( " window not found " ) ) ? ;
2024-01-03 20:59:39 +00:00
let root_view = window . root_view . clone ( ) . unwrap ( ) ;
let result = update ( root_view , & mut WindowContext ::new ( cx , & mut window ) ) ;
if window . removed {
2024-02-20 20:42:11 +00:00
cx . window_handles . remove ( & handle . id ) ;
2024-01-03 20:59:39 +00:00
cx . windows . remove ( handle . id ) ;
} else {
cx . windows
. get_mut ( handle . id )
. ok_or_else ( | | anyhow! ( " window not found " ) ) ?
. replace ( window ) ;
2023-02-20 09:22:08 +00:00
}
2024-01-03 20:59:39 +00:00
Ok ( result )
2022-01-22 01:43:24 +00:00
} )
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
fn read_model < T , R > (
& self ,
handle : & Model < T > ,
read : impl FnOnce ( & T , & AppContext ) -> R ,
) -> Self ::Result < R >
2023-02-20 09:22:08 +00:00
where
T : 'static ,
{
2024-01-03 20:59:39 +00:00
let entity = self . entities . read ( handle ) ;
read ( entity , self )
2023-02-20 09:22:08 +00:00
}
2024-01-03 20:59:39 +00:00
fn read_window < T , R > (
& self ,
window : & WindowHandle < T > ,
read : impl FnOnce ( View < T > , & AppContext ) -> R ,
) -> Result < R >
2023-02-20 09:22:08 +00:00
where
T : 'static ,
{
2024-01-03 20:59:39 +00:00
let window = self
. windows
. get ( window . id )
. ok_or_else ( | | anyhow! ( " window not found " ) ) ?
. as_ref ( )
. unwrap ( ) ;
2023-05-05 08:47:42 +00:00
2024-01-03 20:59:39 +00:00
let root_view = window . root_view . clone ( ) . unwrap ( ) ;
let view = root_view
. downcast ::< T > ( )
. map_err ( | _ | anyhow! ( " root view's type has changed " ) ) ? ;
2023-05-05 08:47:42 +00:00
2024-01-03 20:59:39 +00:00
Ok ( read ( view , self ) )
2023-05-05 08:47:42 +00:00
}
2023-05-05 08:04:54 +00:00
}
2024-01-03 20:59:39 +00:00
/// These effects are processed at the end of each application update cycle.
pub ( crate ) enum Effect {
Notify {
emitter : EntityId ,
2022-04-14 16:22:32 +00:00
} ,
2024-01-03 20:59:39 +00:00
Emit {
emitter : EntityId ,
event_type : TypeId ,
event : Box < dyn Any > ,
2021-08-27 22:03:37 +00:00
} ,
2024-01-03 20:59:39 +00:00
Refresh ,
NotifyGlobalObservers {
global_type : TypeId ,
2022-08-09 19:34:57 +00:00
} ,
2024-01-03 20:59:39 +00:00
Defer {
callback : Box < dyn FnOnce ( & mut AppContext ) + 'static > ,
2023-02-20 09:22:08 +00:00
} ,
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
/// Wraps a global variable value during `update_global` while the value has been moved to the stack.
2024-01-30 19:08:20 +00:00
pub ( crate ) struct GlobalLease < G : Global > {
2024-01-03 20:59:39 +00:00
global : Box < dyn Any > ,
global_type : PhantomData < G > ,
2021-07-12 15:44:10 +00:00
}
2024-01-30 19:08:20 +00:00
impl < G : Global > GlobalLease < G > {
2024-01-03 20:59:39 +00:00
fn new ( global : Box < dyn Any > ) -> Self {
GlobalLease {
global ,
global_type : PhantomData ,
}
}
2021-03-10 04:00:51 +00:00
}
2024-01-30 19:08:20 +00:00
impl < G : Global > Deref for GlobalLease < G > {
2024-01-03 20:59:39 +00:00
type Target = G ;
2021-03-10 04:00:51 +00:00
2024-01-03 20:59:39 +00:00
fn deref ( & self ) -> & Self ::Target {
self . global . downcast_ref ( ) . unwrap ( )
2021-03-10 04:00:51 +00:00
}
2024-01-03 20:59:39 +00:00
}
2021-06-25 16:35:06 +00:00
2024-01-30 19:08:20 +00:00
impl < G : Global > DerefMut for GlobalLease < G > {
2024-01-03 20:59:39 +00:00
fn deref_mut ( & mut self ) -> & mut Self ::Target {
self . global . downcast_mut ( ) . unwrap ( )
2021-06-25 16:35:06 +00:00
}
2024-01-03 20:59:39 +00:00
}
2021-11-02 19:16:25 +00:00
2024-01-03 20:59:39 +00:00
/// Contains state associated with an active drag operation, started by dragging an element
/// within the window or by dragging into the app from the underlying platform.
pub struct AnyDrag {
2024-01-17 18:00:21 +00:00
/// The view used to render this drag
2024-01-03 20:59:39 +00:00
pub view : AnyView ,
2024-01-17 18:00:21 +00:00
/// The value of the dragged item, to be dropped
2024-01-03 20:59:39 +00:00
pub value : Box < dyn Any > ,
2024-01-17 18:00:21 +00:00
/// This is used to render the dragged item in the same place
/// on the original element that the drag was initiated
2024-01-03 20:59:39 +00:00
pub cursor_offset : Point < Pixels > ,
2021-03-10 04:00:51 +00:00
}
2024-01-15 18:19:27 +00:00
/// Contains state associated with a tooltip. You'll only need this struct if you're implementing
/// tooltip behavior on a custom element. Otherwise, use [Div::tooltip].
2024-01-03 20:59:39 +00:00
#[ derive(Clone) ]
2024-01-15 18:19:27 +00:00
pub struct AnyTooltip {
2024-01-17 18:00:21 +00:00
/// The view used to display the tooltip
2024-01-03 20:59:39 +00:00
pub view : AnyView ,
2024-01-17 18:00:21 +00:00
/// The offset from the cursor to use, relative to the parent view
2024-01-03 20:59:39 +00:00
pub cursor_offset : Point < Pixels > ,
2021-03-10 04:00:51 +00:00
}
2024-01-17 18:00:21 +00:00
/// A keystroke event, and potentially the associated action
2024-01-03 20:59:39 +00:00
#[ derive(Debug) ]
pub struct KeystrokeEvent {
2024-01-17 18:00:21 +00:00
/// The keystroke that occurred
2024-01-03 20:59:39 +00:00
pub keystroke : Keystroke ,
2024-01-17 18:00:21 +00:00
/// The action that was resolved for the keystroke, if any
2024-01-03 20:59:39 +00:00
pub action : Option < Box < dyn Action > > ,
2021-03-10 04:00:51 +00:00
}