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. Load more
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/nsdragoperation type 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()