873 lines · 27.5 KB · Rust
RawDownload
// todo(linux): remove#![cfg_attr(target_os = "linux", allow(dead_code))]// todo(windows): remove#![cfg_attr(windows, allow(dead_code))] mod app_menu;mod keystroke; #[cfg(not(target_os = "macos"))]mod cosmic_text; #[cfg(target_os = "linux")]mod linux; #[cfg(target_os = "macos")]mod mac; #[cfg(any(target_os = "linux", target_os = "windows", feature = "macos-blade"))]mod blade; #[cfg(any(test, feature = "test-support"))]mod test; #[cfg(target_os = "windows")]mod windows; use crate::{    point, Action, AnyWindowHandle, AsyncWindowContext, BackgroundExecutor, Bounds, DevicePixels,    DispatchEventResult, Font, FontId, FontMetrics, FontRun, ForegroundExecutor, GlyphId, Keymap,    LineLayout, Pixels, PlatformInput, Point, RenderGlyphParams, RenderImageParams,    RenderSvgParams, Scene, SharedString, Size, Task, TaskLabel, WindowContext,    DEFAULT_WINDOW_SIZE,};use anyhow::Result;use async_task::Runnable;use futures::channel::oneshot;use parking::Unparker;use raw_window_handle::{HasDisplayHandle, HasWindowHandle};use seahash::SeaHasher;use serde::{Deserialize, Serialize};use std::borrow::Cow;use std::hash::{Hash, Hasher};use std::time::Duration;use std::{    fmt::{self, Debug},    ops::Range,    path::{Path, PathBuf},    rc::Rc,    sync::Arc,};use uuid::Uuid; pub use app_menu::*;pub use keystroke::*; #[cfg(not(target_os = "macos"))]pub(crate) use cosmic_text::*;#[cfg(target_os = "linux")]pub(crate) use linux::*;#[cfg(target_os = "macos")]pub(crate) use mac::*;pub use semantic_version::SemanticVersion;#[cfg(any(test, feature = "test-support"))]pub(crate) use test::*;use time::UtcOffset;#[cfg(target_os = "windows")]pub(crate) use windows::*; #[cfg(target_os = "macos")]pub(crate) fn current_platform() -> Rc<dyn Platform> {    Rc::new(MacPlatform::new())}#[cfg(target_os = "linux")]pub(crate) fn current_platform() -> Rc<dyn Platform> {    let wayland_display = std::env::var_os("WAYLAND_DISPLAY");    let x11_display = std::env::var_os("DISPLAY");     let use_wayland = wayland_display.is_some_and(|display| !display.is_empty());    let use_x11 = x11_display.is_some_and(|display| !display.is_empty());     if use_wayland {        Rc::new(WaylandClient::new())    } else if use_x11 {        Rc::new(X11Client::new())    } else {        Rc::new(HeadlessClient::new())    }}// todo("windows")#[cfg(target_os = "windows")]pub(crate) fn current_platform() -> Rc<dyn Platform> {    Rc::new(WindowsPlatform::new())} pub(crate) trait Platform: 'static {    fn background_executor(&self) -> BackgroundExecutor;    fn foreground_executor(&self) -> ForegroundExecutor;    fn text_system(&self) -> Arc<dyn PlatformTextSystem>;     fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>);    fn quit(&self);    fn restart(&self, binary_path: Option<PathBuf>);    fn activate(&self, ignoring_other_apps: bool);    fn hide(&self);    fn hide_other_apps(&self);    fn unhide_other_apps(&self);     fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>>;    fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>>;    fn active_window(&self) -> Option<AnyWindowHandle>;    fn can_open_windows(&self) -> anyhow::Result<()> {        Ok(())    }    fn open_window(        &self,        handle: AnyWindowHandle,        options: WindowParams,    ) -> Box<dyn PlatformWindow>;     /// Returns the appearance of the application's windows.    fn window_appearance(&self) -> WindowAppearance;     fn open_url(&self, url: &str);    fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);    fn register_url_scheme(&self, url: &str) -> Task<Result<()>>;     fn prompt_for_paths(        &self,        options: PathPromptOptions,    ) -> oneshot::Receiver<Option<Vec<PathBuf>>>;    fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>>;    fn reveal_path(&self, path: &Path);     fn on_quit(&self, callback: Box<dyn FnMut()>);    fn on_reopen(&self, callback: Box<dyn FnMut()>);     fn set_menus(&self, menus: Vec<Menu>, keymap: &Keymap);    fn set_dock_menu(&self, menu: Vec<MenuItem>, keymap: &Keymap);    fn add_recent_document(&self, _path: &Path) {}    fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>);    fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>);    fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>);     fn os_name(&self) -> &'static str;    fn os_version(&self) -> Result<SemanticVersion>;    fn app_version(&self) -> Result<SemanticVersion>;    fn app_path(&self) -> Result<PathBuf>;    fn local_timezone(&self) -> UtcOffset;    fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;     fn set_cursor_style(&self, style: CursorStyle);    fn should_auto_hide_scrollbars(&self) -> bool;     #[cfg(target_os = "linux")]    fn write_to_primary(&self, item: ClipboardItem);    fn write_to_clipboard(&self, item: ClipboardItem);    #[cfg(target_os = "linux")]    fn read_from_primary(&self) -> Option<ClipboardItem>;    fn read_from_clipboard(&self) -> Option<ClipboardItem>;     fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task<Result<()>>;    fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>>;    fn delete_credentials(&self, url: &str) -> Task<Result<()>>;} /// A handle to a platform's display, e.g. a monitor or laptop screen.pub trait PlatformDisplay: Send + Sync + Debug {    /// Get the ID for this display    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>;     /// Get the bounds for this display    fn bounds(&self) -> Bounds<DevicePixels>;     /// Get the default bounds for this display to place a window    fn default_bounds(&self) -> Bounds<DevicePixels> {        let center = self.bounds().center();        let offset = DEFAULT_WINDOW_SIZE / 2;        let origin = point(center.x - offset.width, center.y - offset.height);        Bounds::new(origin, DEFAULT_WINDOW_SIZE)    }} /// An opaque identifier for a hardware display#[derive(PartialEq, Eq, Hash, Copy, Clone)]pub struct DisplayId(pub(crate) u32); impl Debug for DisplayId {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        write!(f, "DisplayId({})", self.0)    }} unsafe impl Send for DisplayId {} pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {    fn bounds(&self) -> Bounds<DevicePixels>;    fn is_maximized(&self) -> bool;    fn window_bounds(&self) -> WindowBounds;    fn content_size(&self) -> Size<Pixels>;    fn scale_factor(&self) -> f32;    fn appearance(&self) -> WindowAppearance;    fn display(&self) -> Rc<dyn PlatformDisplay>;    fn mouse_position(&self) -> Point<Pixels>;    fn modifiers(&self) -> Modifiers;    fn set_input_handler(&mut self, input_handler: PlatformInputHandler);    fn take_input_handler(&mut self) -> Option<PlatformInputHandler>;    fn prompt(        &self,        level: PromptLevel,        msg: &str,        detail: Option<&str>,        answers: &[&str],    ) -> Option<oneshot::Receiver<usize>>;    fn activate(&self);    fn is_active(&self) -> bool;    fn set_title(&mut self, title: &str);    fn set_app_id(&mut self, app_id: &str);    fn set_background_appearance(&mut self, background_appearance: WindowBackgroundAppearance);    fn set_edited(&mut self, edited: bool);    fn show_character_palette(&self);    fn minimize(&self);    fn zoom(&self);    fn toggle_fullscreen(&self);    fn is_fullscreen(&self) -> bool;    fn on_request_frame(&self, callback: Box<dyn FnMut()>);    fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> DispatchEventResult>);    fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>);    fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>);    fn on_moved(&self, callback: Box<dyn FnMut()>);    fn on_should_close(&self, callback: Box<dyn FnMut() -> bool>);    fn on_close(&self, callback: Box<dyn FnOnce()>);    fn on_appearance_changed(&self, callback: Box<dyn FnMut()>);    fn draw(&self, scene: &Scene);    fn completed_frame(&self) {}    fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas>;     #[cfg(target_os = "windows")]    fn get_raw_handle(&self) -> windows::HWND;     fn show_window_menu(&self, position: Point<Pixels>);    fn start_system_move(&self);    fn should_render_window_controls(&self) -> bool;     #[cfg(any(test, feature = "test-support"))]    fn as_test(&mut self) -> Option<&mut TestWindow> {        None    }} /// This type is public so that our test macro can generate and use it, but it should not/// be considered part of our public API.#[doc(hidden)]pub trait PlatformDispatcher: Send + Sync {    fn is_main_thread(&self) -> bool;    fn dispatch(&self, runnable: Runnable, label: Option<TaskLabel>);    fn dispatch_on_main_thread(&self, runnable: Runnable);    fn dispatch_after(&self, duration: Duration, runnable: Runnable);    fn park(&self, timeout: Option<Duration>) -> bool;    fn unparker(&self) -> Unparker;     #[cfg(any(test, feature = "test-support"))]    fn as_test(&self) -> Option<&TestDispatcher> {        None    }} pub(crate) trait PlatformTextSystem: Send + Sync {    fn add_fonts(&self, fonts: Vec<Cow<'static, [u8]>>) -> Result<()>;    fn all_font_names(&self) -> Vec<String>;    fn all_font_families(&self) -> Vec<String>;    fn font_id(&self, descriptor: &Font) -> Result<FontId>;    fn font_metrics(&self, font_id: FontId) -> FontMetrics;    fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>>;    fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Size<f32>>;    fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId>;    fn glyph_raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>>;    fn rasterize_glyph(        &self,        params: &RenderGlyphParams,        raster_bounds: Bounds<DevicePixels>,    ) -> Result<(Size<DevicePixels>, Vec<u8>)>;    fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> LineLayout;} /// Basic metadata about the current application and operating system.#[derive(Clone, Debug)]pub struct AppMetadata {    /// The name of the current operating system    pub os_name: &'static str,     /// The operating system's version    pub os_version: Option<SemanticVersion>,     /// The current version of the application    pub app_version: Option<SemanticVersion>,} #[derive(PartialEq, Eq, Hash, Clone)]pub(crate) enum AtlasKey {    Glyph(RenderGlyphParams),    Svg(RenderSvgParams),    Image(RenderImageParams),} impl AtlasKey {    pub(crate) fn texture_kind(&self) -> AtlasTextureKind {        match self {            AtlasKey::Glyph(params) => {                if params.is_emoji {                    AtlasTextureKind::Polychrome                } else {                    AtlasTextureKind::Monochrome                }            }            AtlasKey::Svg(_) => AtlasTextureKind::Monochrome,            AtlasKey::Image(_) => AtlasTextureKind::Polychrome,        }    }} impl From<RenderGlyphParams> for AtlasKey {    fn from(params: RenderGlyphParams) -> Self {        Self::Glyph(params)    }} impl From<RenderSvgParams> for AtlasKey {    fn from(params: RenderSvgParams) -> Self {        Self::Svg(params)    }} impl From<RenderImageParams> for AtlasKey {    fn from(params: RenderImageParams) -> Self {        Self::Image(params)    }} pub(crate) trait PlatformAtlas: Send + Sync {    fn get_or_insert_with<'a>(        &self,        key: &AtlasKey,        build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>,    ) -> Result<AtlasTile>;} #[derive(Clone, Debug, PartialEq, Eq)]#[repr(C)]pub(crate) struct AtlasTile {    pub(crate) texture_id: AtlasTextureId,    pub(crate) tile_id: TileId,    pub(crate) padding: u32,    pub(crate) bounds: Bounds<DevicePixels>,} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]#[repr(C)]pub(crate) struct AtlasTextureId {    // We use u32 instead of usize for Metal Shader Language compatibility    pub(crate) index: u32,    pub(crate) kind: AtlasTextureKind,} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]#[repr(C)]pub(crate) enum AtlasTextureKind {    Monochrome = 0,    Polychrome = 1,    Path = 2,} #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]#[repr(C)]pub(crate) struct TileId(pub(crate) u32); impl From<etagere::AllocId> for TileId {    fn from(id: etagere::AllocId) -> Self {        Self(id.serialize())    }} impl From<TileId> for etagere::AllocId {    fn from(id: TileId) -> Self {        Self::deserialize(id.0)    }} pub(crate) struct PlatformInputHandler {    cx: AsyncWindowContext,    handler: Box<dyn InputHandler>,} impl PlatformInputHandler {    pub fn new(cx: AsyncWindowContext, handler: Box<dyn InputHandler>) -> Self {        Self { cx, handler }    }     fn selected_text_range(&mut self) -> Option<Range<usize>> {        self.cx            .update(|cx| self.handler.selected_text_range(cx))            .ok()            .flatten()    }     fn marked_text_range(&mut self) -> Option<Range<usize>> {        self.cx            .update(|cx| self.handler.marked_text_range(cx))            .ok()            .flatten()    }     fn text_for_range(&mut self, range_utf16: Range<usize>) -> Option<String> {        self.cx            .update(|cx| self.handler.text_for_range(range_utf16, cx))            .ok()            .flatten()    }     fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str) {        self.cx            .update(|cx| {                self.handler                    .replace_text_in_range(replacement_range, text, cx);            })            .ok();    }     fn replace_and_mark_text_in_range(        &mut self,        range_utf16: Option<Range<usize>>,        new_text: &str,        new_selected_range: Option<Range<usize>>,    ) {        self.cx            .update(|cx| {                self.handler.replace_and_mark_text_in_range(                    range_utf16,                    new_text,                    new_selected_range,                    cx,                )            })            .ok();    }     fn unmark_text(&mut self) {        self.cx.update(|cx| self.handler.unmark_text(cx)).ok();    }     fn bounds_for_range(&mut self, range_utf16: Range<usize>) -> Option<Bounds<Pixels>> {        self.cx            .update(|cx| self.handler.bounds_for_range(range_utf16, cx))            .ok()            .flatten()    }     pub(crate) fn dispatch_input(&mut self, input: &str, cx: &mut WindowContext) {        self.handler.replace_text_in_range(None, input, cx);    }} /// Zed's interface for handling text input from the platform's IME system/// This is currently a 1:1 exposure of the NSTextInputClient API:////// <https://developer.apple.com/documentation/appkit/nstextinputclient>pub trait InputHandler: 'static {    /// Get the range of the user's currently selected text, if any    /// Corresponds to [selectedRange()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438242-selectedrange)    ///    /// Return value is in terms of UTF-16 characters, from 0 to the length of the document    fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;     /// Get the range of the currently marked text, if any    /// Corresponds to [markedRange()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438250-markedrange)    ///    /// Return value is in terms of UTF-16 characters, from 0 to the length of the document    fn marked_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;     /// Get the text for the given document range in UTF-16 characters    /// Corresponds to [attributedSubstring(forProposedRange: actualRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438238-attributedsubstring)    ///    /// range_utf16 is in terms of UTF-16 characters    fn text_for_range(        &mut self,        range_utf16: Range<usize>,        cx: &mut WindowContext,    ) -> Option<String>;     /// Replace the text in the given document range with the given text    /// Corresponds to [insertText(_:replacementRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438258-inserttext)    ///    /// replacement_range is in terms of UTF-16 characters    fn replace_text_in_range(        &mut self,        replacement_range: Option<Range<usize>>,        text: &str,

Lines 1–500 of 873.