2752 lines · 101.3 KB · Rust
RawDownload
use crate::{    BoolExt, DisplayLink, MacDisplay, NSRange, NSStringExt, dispatch_get_main_queue,    dispatcher::dispatch_sys::dispatch_async_f, events::platform_input_from_native, ns_string,    renderer,};#[cfg(any(test, feature = "test-support"))]use anyhow::Result;use block::ConcreteBlock;use cocoa::{    appkit::{        NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered,        NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen,        NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial,        NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton,        NSWindowCollectionBehavior, NSWindowOcclusionState, NSWindowOrderingMode,        NSWindowStyleMask, NSWindowTitleVisibility,    },    base::{id, nil},    foundation::{        NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound,        NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger,        NSUserDefaults,    },};use gpui::{    AnyWindowHandle, BackgroundExecutor, Bounds, Capslock, ExternalPaths, FileDropEvent,    ForegroundExecutor, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton,    MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay,    PlatformInput, PlatformInputHandler, PlatformWindow, Point, PromptButton, PromptLevel,    RequestFrameOptions, SharedString, Size, SystemWindowTab, WindowAppearance,    WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowKind, WindowParams, point,    px, size,};#[cfg(any(test, feature = "test-support"))]use image::RgbaImage; use core_graphics::display::{CGDirectDisplayID, CGPoint, CGRect};use ctor::ctor;use futures::channel::oneshot;use objc::{    class,    declare::ClassDecl,    msg_send,    runtime::{BOOL, Class, NO, Object, Protocol, Sel, YES},    sel, sel_impl,};use parking_lot::Mutex;use raw_window_handle as rwh;use smallvec::SmallVec;use std::{    cell::Cell,    ffi::{CStr, c_void},    mem,    ops::Range,    path::PathBuf,    ptr::{self, NonNull},    rc::Rc,    sync::{Arc, Weak},    time::Duration,};use util::ResultExt; const WINDOW_STATE_IVAR: &str = "windowState"; static mut WINDOW_CLASS: *const Class = ptr::null();static mut PANEL_CLASS: *const Class = ptr::null();static mut VIEW_CLASS: *const Class = ptr::null();static mut BLURRED_VIEW_CLASS: *const Class = ptr::null(); #[allow(non_upper_case_globals)]const NSWindowStyleMaskNonactivatingPanel: NSWindowStyleMask =    NSWindowStyleMask::from_bits_retain(1 << 7);// WindowLevel const value ref: https://docs.rs/core-graphics2/0.4.1/src/core_graphics2/window_level.rs.html#[allow(non_upper_case_globals)]const NSNormalWindowLevel: NSInteger = 0;#[allow(non_upper_case_globals)]const NSFloatingWindowLevel: NSInteger = 3;#[allow(non_upper_case_globals)]const NSPopUpWindowLevel: NSInteger = 101;#[allow(non_upper_case_globals)]const NSTrackingMouseEnteredAndExited: NSUInteger = 0x01;#[allow(non_upper_case_globals)]const NSTrackingMouseMoved: NSUInteger = 0x02;#[allow(non_upper_case_globals)]const NSTrackingActiveAlways: NSUInteger = 0x80;#[allow(non_upper_case_globals)]const NSTrackingInVisibleRect: NSUInteger = 0x200;#[allow(non_upper_case_globals)]const NSWindowAnimationBehaviorUtilityWindow: NSInteger = 4;#[allow(non_upper_case_globals)]const NSViewLayerContentsRedrawDuringViewResize: NSInteger = 2;// https://developer.apple.com/documentation/appkit/nsdragoperationtype NSDragOperation = NSUInteger;#[allow(non_upper_case_globals)]const NSDragOperationNone: NSDragOperation = 0;#[allow(non_upper_case_globals)]const NSDragOperationCopy: NSDragOperation = 1;#[derive(PartialEq)]pub enum UserTabbingPreference {    Never,    Always,    InFullScreen,} #[link(name = "CoreGraphics", kind = "framework")]unsafe extern "C" {    // Widely used private APIs; Apple uses them for their Terminal.app.    fn CGSMainConnectionID() -> id;    fn CGSSetWindowBackgroundBlurRadius(        connection_id: id,        window_id: NSInteger,        radius: i64,    ) -> i32;} #[ctor]unsafe fn build_classes() {    unsafe {        WINDOW_CLASS = build_window_class("GPUIWindow", class!(NSWindow));        PANEL_CLASS = build_window_class("GPUIPanel", class!(NSPanel));        VIEW_CLASS = {            let mut decl = ClassDecl::new("GPUIView", class!(NSView)).unwrap();            decl.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR);            unsafe {                decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel));                 decl.add_method(                    sel!(performKeyEquivalent:),                    handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL,                );                decl.add_method(                    sel!(keyDown:),                    handle_key_down as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(keyUp:),                    handle_key_up as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(mouseDown:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(mouseUp:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(rightMouseDown:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(rightMouseUp:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(otherMouseDown:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(otherMouseUp:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(mouseMoved:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(pressureChangeWithEvent:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(mouseExited:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(mouseDragged:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(scrollWheel:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(swipeWithEvent:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                decl.add_method(                    sel!(flagsChanged:),                    handle_view_event as extern "C" fn(&Object, Sel, id),                );                 decl.add_method(                    sel!(makeBackingLayer),                    make_backing_layer as extern "C" fn(&Object, Sel) -> id,                );                 decl.add_protocol(Protocol::get("CALayerDelegate").unwrap());                decl.add_method(                    sel!(viewDidChangeBackingProperties),                    view_did_change_backing_properties as extern "C" fn(&Object, Sel),                );                decl.add_method(                    sel!(setFrameSize:),                    set_frame_size as extern "C" fn(&Object, Sel, NSSize),                );                decl.add_method(                    sel!(displayLayer:),                    display_layer as extern "C" fn(&Object, Sel, id),                );                 decl.add_protocol(Protocol::get("NSTextInputClient").unwrap());                decl.add_method(                    sel!(validAttributesForMarkedText),                    valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id,                );                decl.add_method(                    sel!(hasMarkedText),                    has_marked_text as extern "C" fn(&Object, Sel) -> BOOL,                );                decl.add_method(                    sel!(markedRange),                    marked_range as extern "C" fn(&Object, Sel) -> NSRange,                );                decl.add_method(                    sel!(selectedRange),                    selected_range as extern "C" fn(&Object, Sel) -> NSRange,                );                decl.add_method(                    sel!(firstRectForCharacterRange:actualRange:),                    first_rect_for_character_range                        as extern "C" fn(&Object, Sel, NSRange, id) -> NSRect,                );                decl.add_method(                    sel!(insertText:replacementRange:),                    insert_text as extern "C" fn(&Object, Sel, id, NSRange),                );                decl.add_method(                    sel!(setMarkedText:selectedRange:replacementRange:),                    set_marked_text as extern "C" fn(&Object, Sel, id, NSRange, NSRange),                );                decl.add_method(sel!(unmarkText), unmark_text as extern "C" fn(&Object, Sel));                decl.add_method(                    sel!(attributedSubstringForProposedRange:actualRange:),                    attributed_substring_for_proposed_range                        as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> id,                );                decl.add_method(                    sel!(viewDidChangeEffectiveAppearance),                    view_did_change_effective_appearance as extern "C" fn(&Object, Sel),                );                 // Suppress beep on keystrokes with modifier keys.                decl.add_method(                    sel!(doCommandBySelector:),                    do_command_by_selector as extern "C" fn(&Object, Sel, Sel),                );                 decl.add_method(                    sel!(acceptsFirstMouse:),                    accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL,                );                 decl.add_method(                    sel!(characterIndexForPoint:),                    character_index_for_point as extern "C" fn(&Object, Sel, NSPoint) -> u64,                );            }            decl.register()        };        BLURRED_VIEW_CLASS = {            let mut decl = ClassDecl::new("BlurredView", class!(NSVisualEffectView)).unwrap();            unsafe {                decl.add_method(                    sel!(initWithFrame:),                    blurred_view_init_with_frame as extern "C" fn(&Object, Sel, NSRect) -> id,                );                decl.add_method(                    sel!(updateLayer),                    blurred_view_update_layer as extern "C" fn(&Object, Sel),                );                decl.register()            }        };    }} pub(crate) fn convert_mouse_position(position: NSPoint, window_height: Pixels) -> Point<Pixels> {    point(        px(position.x as f32),        // macOS screen coordinates are relative to bottom left        window_height - px(position.y as f32),    )} unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const Class {    unsafe {        let mut decl = ClassDecl::new(name, superclass).unwrap();        decl.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR);        decl.add_method(sel!(dealloc), dealloc_window as extern "C" fn(&Object, Sel));         decl.add_method(            sel!(canBecomeMainWindow),            yes as extern "C" fn(&Object, Sel) -> BOOL,        );        decl.add_method(            sel!(canBecomeKeyWindow),            yes as extern "C" fn(&Object, Sel) -> BOOL,        );        decl.add_method(            sel!(windowDidResize:),            window_did_resize as extern "C" fn(&Object, Sel, id),        );        decl.add_method(            sel!(windowDidChangeOcclusionState:),            window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id),        );        decl.add_method(            sel!(windowWillEnterFullScreen:),            window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id),        );        decl.add_method(            sel!(windowWillExitFullScreen:),            window_will_exit_fullscreen as extern "C" fn(&Object, Sel, id),        );        decl.add_method(            sel!(windowDidMove:),            window_did_move as extern "C" fn(&Object, Sel, id),        );        decl.add_method(            sel!(windowDidChangeScreen:),            window_did_change_screen as extern "C" fn(&Object, Sel, id),        );        decl.add_method(            sel!(windowDidBecomeKey:),            window_did_change_key_status as extern "C" fn(&Object, Sel, id),        );        decl.add_method(            sel!(windowDidResignKey:),            window_did_change_key_status as extern "C" fn(&Object, Sel, id),        );        decl.add_method(            sel!(windowShouldClose:),            window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL,        );         decl.add_method(sel!(close), close_window as extern "C" fn(&Object, Sel));         decl.add_method(            sel!(draggingEntered:),            dragging_entered as extern "C" fn(&Object, Sel, id) -> NSDragOperation,        );        decl.add_method(            sel!(draggingUpdated:),            dragging_updated as extern "C" fn(&Object, Sel, id) -> NSDragOperation,        );        decl.add_method(            sel!(draggingExited:),            dragging_exited as extern "C" fn(&Object, Sel, id),        );        decl.add_method(            sel!(performDragOperation:),            perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL,        );        decl.add_method(            sel!(concludeDragOperation:),            conclude_drag_operation as extern "C" fn(&Object, Sel, id),        );         decl.add_method(            sel!(addTitlebarAccessoryViewController:),            add_titlebar_accessory_view_controller as extern "C" fn(&Object, Sel, id),        );         decl.add_method(            sel!(moveTabToNewWindow:),            move_tab_to_new_window as extern "C" fn(&Object, Sel, id),        );         decl.add_method(            sel!(mergeAllWindows:),            merge_all_windows as extern "C" fn(&Object, Sel, id),        );         decl.add_method(            sel!(selectNextTab:),            select_next_tab as extern "C" fn(&Object, Sel, id),        );         decl.add_method(            sel!(selectPreviousTab:),            select_previous_tab as extern "C" fn(&Object, Sel, id),        );         decl.add_method(            sel!(toggleTabBar:),            toggle_tab_bar as extern "C" fn(&Object, Sel, id),        );         decl.register()    }} struct MacWindowState {    handle: AnyWindowHandle,    foreground_executor: ForegroundExecutor,    background_executor: BackgroundExecutor,    native_window: id,    native_view: NonNull<Object>,    blurred_view: Option<id>,    background_appearance: WindowBackgroundAppearance,    display_link: Option<DisplayLink>,    renderer: renderer::Renderer,    request_frame_callback: Option<Box<dyn FnMut(RequestFrameOptions)>>,    event_callback: Option<Box<dyn FnMut(PlatformInput) -> gpui::DispatchEventResult>>,    activate_callback: Option<Box<dyn FnMut(bool)>>,    resize_callback: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,    moved_callback: Option<Box<dyn FnMut()>>,    should_close_callback: Option<Box<dyn FnMut() -> bool>>,    close_callback: Option<Box<dyn FnOnce()>>,    appearance_changed_callback: Option<Box<dyn FnMut()>>,    input_handler: Option<PlatformInputHandler>,    last_key_equivalent: Option<KeyDownEvent>,    synthetic_drag_counter: usize,    traffic_light_position: Option<Point<Pixels>>,    transparent_titlebar: bool,    previous_modifiers_changed_event: Option<PlatformInput>,    keystroke_for_do_command: Option<Keystroke>,    do_command_handled: Option<bool>,    external_files_dragged: bool,    // Whether the next left-mouse click is also the focusing click.    first_mouse: bool,    fullscreen_restore_bounds: Bounds<Pixels>,    move_tab_to_new_window_callback: Option<Box<dyn FnMut()>>,    merge_all_windows_callback: Option<Box<dyn FnMut()>>,    select_next_tab_callback: Option<Box<dyn FnMut()>>,    select_previous_tab_callback: Option<Box<dyn FnMut()>>,    toggle_tab_bar_callback: Option<Box<dyn FnMut()>>,    activated_least_once: bool,    // The parent window if this window is a sheet (Dialog kind)    sheet_parent: Option<id>,} impl MacWindowState {    fn move_traffic_light(&self) {        if let Some(traffic_light_position) = self.traffic_light_position {            if self.is_fullscreen() {                // Moving traffic lights while fullscreen doesn't work,                // see https://github.com/zed-industries/zed/issues/4712                return;            }             let titlebar_height = self.titlebar_height();             unsafe {                let close_button: id = msg_send![                    self.native_window,                    standardWindowButton: NSWindowButton::NSWindowCloseButton                ];                let min_button: id = msg_send![                    self.native_window,                    standardWindowButton: NSWindowButton::NSWindowMiniaturizeButton                ];                let zoom_button: id = msg_send![                    self.native_window,                    standardWindowButton: NSWindowButton::NSWindowZoomButton                ];                 let mut close_button_frame: CGRect = msg_send![close_button, frame];                let mut min_button_frame: CGRect = msg_send![min_button, frame];                let mut zoom_button_frame: CGRect = msg_send![zoom_button, frame];                let mut origin = point(                    traffic_light_position.x,                    titlebar_height                        - traffic_light_position.y                        - px(close_button_frame.size.height as f32),                );                let button_spacing =                    px((min_button_frame.origin.x - close_button_frame.origin.x) as f32);                 close_button_frame.origin = CGPoint::new(origin.x.into(), origin.y.into());                let _: () = msg_send![close_button, setFrame: close_button_frame];                origin.x += button_spacing;                 min_button_frame.origin = CGPoint::new(origin.x.into(), origin.y.into());                let _: () = msg_send![min_button, setFrame: min_button_frame];                origin.x += button_spacing;                 zoom_button_frame.origin = CGPoint::new(origin.x.into(), origin.y.into());                let _: () = msg_send![zoom_button, setFrame: zoom_button_frame];                origin.x += button_spacing;            }        }    }     fn start_display_link(&mut self) {        self.stop_display_link();        unsafe {            if !self                .native_window                .occlusionState()

Lines 1–500 of 2752.