WIP

Nathan Sobo created

Change summary

crates/gpui2/src/app.rs                  | 15 +++++++-
crates/gpui2/src/platform.rs             |  4 ++
crates/gpui2/src/platform/mac/display.rs | 44 +++++++++++++++++++++++++
crates/workspace2/src/searchable.rs      |  1 
crates/workspace2/src/workspace2.rs      |  3 +
crates/zed2/src/main.rs                  |  2 
crates/zed2/src/zed2.rs                  | 12 +++---
7 files changed, 69 insertions(+), 12 deletions(-)

Detailed changes

crates/gpui2/src/app.rs 🔗

@@ -11,14 +11,15 @@ use refineable::Refineable;
 use smallvec::SmallVec;
 #[cfg(any(test, feature = "test-support"))]
 pub use test_context::*;
+use uuid::Uuid;
 
 use crate::{
     current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle,
     AppMetadata, AssetSource, ClipboardItem, Context, DispatchPhase, DisplayId, Entity, Executor,
     FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly,
-    Pixels, Platform, Point, Render, SharedString, SubscriberSet, Subscription, SvgRenderer, Task,
-    TextStyle, TextStyleRefinement, TextSystem, View, ViewContext, Window, WindowContext,
-    WindowHandle, WindowId,
+    Pixels, Platform, PlatformDisplay, Point, Render, SharedString, SubscriberSet, Subscription,
+    SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, ViewContext, Window,
+    WindowContext, WindowHandle, WindowId,
 };
 use anyhow::{anyhow, Result};
 use collections::{HashMap, HashSet, VecDeque};
@@ -32,6 +33,7 @@ use std::{
     mem,
     ops::{Deref, DerefMut},
     path::PathBuf,
+    rc::Rc,
     sync::{atomic::Ordering::SeqCst, Arc, Weak},
     time::Duration,
 };
@@ -847,6 +849,13 @@ where
     pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
         self.platform().path_for_auxiliary_executable(name)
     }
+
+    pub fn display_for_uuid(&self, uuid: Uuid) -> Option<Rc<dyn PlatformDisplay>> {
+        self.platform()
+            .displays()
+            .into_iter()
+            .find(|display| display.uuid().ok() == Some(uuid))
+    }
 }
 
 impl MainThread<AppContext> {

crates/gpui2/src/platform.rs 🔗

@@ -28,6 +28,7 @@ use std::{
     str::FromStr,
     sync::Arc,
 };
+use uuid::Uuid;
 
 pub use keystroke::*;
 #[cfg(target_os = "macos")]
@@ -106,6 +107,9 @@ pub(crate) trait Platform: 'static {
 
 pub trait PlatformDisplay: Send + Sync + Debug {
     fn id(&self) -> DisplayId;
+    /// Returns a stable identifier for this display that can be persisted and used
+    /// across system restarts.
+    fn uuid(&self) -> Result<Uuid>;
     fn as_any(&self) -> &dyn Any;
     fn bounds(&self) -> Bounds<GlobalPixels>;
 }

crates/gpui2/src/platform/mac/display.rs 🔗

@@ -1,9 +1,12 @@
 use crate::{point, size, Bounds, DisplayId, GlobalPixels, PlatformDisplay};
+use anyhow::Result;
+use core_foundation::uuid::{CFUUIDGetUUIDBytes, CFUUIDRef};
 use core_graphics::{
     display::{CGDirectDisplayID, CGDisplayBounds, CGGetActiveDisplayList},
     geometry::{CGPoint, CGRect, CGSize},
 };
 use std::any::Any;
+use uuid::Uuid;
 
 #[derive(Debug)]
 pub struct MacDisplay(pub(crate) CGDirectDisplayID);
@@ -11,17 +14,23 @@ pub struct MacDisplay(pub(crate) CGDirectDisplayID);
 unsafe impl Send for MacDisplay {}
 
 impl MacDisplay {
-    /// Get the screen with the given UUID.
+    /// Get the screen with the given [DisplayId].
     pub fn find_by_id(id: DisplayId) -> Option<Self> {
         Self::all().find(|screen| screen.id() == id)
     }
 
+    /// Get the screen with the given persistent [Uuid].
+    pub fn find_by_uuid(uuid: Uuid) -> Option<Self> {
+        Self::all().find(|screen| screen.uuid().ok() == Some(uuid))
+    }
+
     /// Get the primary screen - the one with the menu bar, and whose bottom left
     /// corner is at the origin of the AppKit coordinate system.
     pub fn primary() -> Self {
         Self::all().next().unwrap()
     }
 
+    /// Obtains an iterator over all currently active system displays.
     pub fn all() -> impl Iterator<Item = Self> {
         unsafe {
             let mut display_count: u32 = 0;
@@ -40,6 +49,11 @@ impl MacDisplay {
     }
 }
 
+#[link(name = "ApplicationServices", kind = "framework")]
+extern "C" {
+    pub fn CGDisplayCreateUUIDFromDisplayID(display: CGDirectDisplayID) -> CFUUIDRef;
+}
+
 /// Convert the given rectangle from CoreGraphics' native coordinate space to GPUI's coordinate space.
 ///
 /// CoreGraphics' coordinate space has its origin at the bottom left of the primary screen,
@@ -88,6 +102,34 @@ impl PlatformDisplay for MacDisplay {
         DisplayId(self.0)
     }
 
+    fn uuid(&self) -> Result<Uuid> {
+        let cfuuid = unsafe { CGDisplayCreateUUIDFromDisplayID(self.0 as CGDirectDisplayID) };
+        anyhow::ensure!(
+            !cfuuid.is_null(),
+            "AppKit returned a null from CGDisplayCreateUUIDFromDisplayID"
+        );
+
+        let bytes = unsafe { CFUUIDGetUUIDBytes(cfuuid) };
+        Ok(Uuid::from_bytes([
+            bytes.byte0,
+            bytes.byte1,
+            bytes.byte2,
+            bytes.byte3,
+            bytes.byte4,
+            bytes.byte5,
+            bytes.byte6,
+            bytes.byte7,
+            bytes.byte8,
+            bytes.byte9,
+            bytes.byte10,
+            bytes.byte11,
+            bytes.byte12,
+            bytes.byte13,
+            bytes.byte14,
+            bytes.byte15,
+        ]))
+    }
+
     fn as_any(&self) -> &dyn Any {
         self
     }

crates/workspace2/src/searchable.rs 🔗

@@ -128,6 +128,7 @@ pub trait SearchableItemHandle: ItemHandle {
     ) -> Option<usize>;
 }
 
+// todo!("here is where we need to use AnyWeakView");
 impl<T: SearchableItem> SearchableItemHandle for View<T> {
     fn downgrade(&self) -> Box<dyn WeakSearchableItemHandle> {
         // Box::new(self.downgrade())

crates/workspace2/src/workspace2.rs 🔗

@@ -42,6 +42,7 @@ use std::{
 };
 pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
 use util::ResultExt;
+use uuid::Uuid;
 
 use crate::persistence::model::{
     DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup,
@@ -414,7 +415,7 @@ pub struct AppState {
     pub workspace_store: Model<WorkspaceStore>,
     pub fs: Arc<dyn fs2::Fs>,
     pub build_window_options:
-        fn(Option<WindowBounds>, Option<DisplayId>, &MainThread<AppContext>) -> WindowOptions,
+        fn(Option<WindowBounds>, Option<Uuid>, MainThread<AppContext>) -> WindowOptions,
     pub initialize_workspace:
         fn(WeakModel<Workspace>, bool, Arc<AppState>, AsyncAppContext) -> Task<anyhow::Result<()>>,
     pub node_runtime: Arc<dyn NodeRuntime>,

crates/zed2/src/main.rs 🔗

@@ -46,7 +46,7 @@ use util::{
 };
 use uuid::Uuid;
 use workspace2::{AppState, WorkspaceStore};
-use zed2::languages;
+use zed2::{build_window_options, languages};
 use zed2::{ensure_only_instance, Assets, IsOnlyInstance};
 
 mod open_listener;

crates/zed2/src/zed2.rs 🔗

@@ -6,8 +6,8 @@ mod open_listener;
 pub use assets::*;
 use collections::HashMap;
 use gpui2::{
-    point, px, AsyncAppContext, Point, Styled, TitlebarOptions, WindowBounds, WindowKind,
-    WindowOptions,
+    point, px, AppContext, AsyncAppContext, MainThread, Point, TitlebarOptions, WindowBounds,
+    WindowKind, WindowOptions,
 };
 pub use only_instance::*;
 pub use open_listener::*;
@@ -218,11 +218,11 @@ pub async fn handle_cli_connection(
 
 pub fn build_window_options(
     bounds: Option<WindowBounds>,
-    display: Option<Uuid>,
-    platform: &dyn Platform,
+    display_uuid: Option<Uuid>,
+    cx: MainThread<AppContext>,
 ) -> WindowOptions {
     let bounds = bounds.unwrap_or(WindowBounds::Maximized);
-    let display_id = display.and_then(|display| platform.screen_by_id(display));
+    let display = display_uuid.and_then(|uuid| cx.display_for_uuid(uuid));
 
     WindowOptions {
         bounds,
@@ -236,6 +236,6 @@ pub fn build_window_options(
         show: false,
         kind: WindowKind::Normal,
         is_movable: false,
-        display_id,
+        display_id: display.map(|display| display.id()),
     }
 }