1678 lines · 57.2 KB · Rust
RawDownload
#![deny(unsafe_op_in_unsafe_fn)] use std::{    cell::{Cell, RefCell},    num::NonZeroIsize,    path::PathBuf,    rc::{Rc, Weak},    str::FromStr,    sync::{Arc, Once, atomic::AtomicBool},    time::{Duration, Instant},}; use anyhow::{Context as _, Result};use futures::channel::oneshot::{self, Receiver};use gpui_util::ResultExt;use raw_window_handle as rwh;use smallvec::SmallVec;use windows::{    Win32::{        Foundation::*,        Graphics::Dwm::*,        Graphics::Gdi::*,        System::{            Com::*, Diagnostics::Debug::MessageBeep, LibraryLoader::*, Ole::*, SystemServices::*,        },        UI::{Controls::*, HiDpi::*, Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},    },    core::*,}; use crate::direct_manipulation::DirectManipulationHandler;use crate::*;use gpui::*; pub(crate) struct WindowsWindow(pub Rc<WindowsWindowInner>); impl std::ops::Deref for WindowsWindow {    type Target = WindowsWindowInner;     fn deref(&self) -> &Self::Target {        &self.0    }} pub struct WindowsWindowState {    pub origin: Cell<Point<Pixels>>,    pub logical_size: Cell<Size<Pixels>>,    pub min_size: Option<Size<Pixels>>,    pub fullscreen_restore_bounds: Cell<Bounds<Pixels>>,    pub border_offset: WindowBorderOffset,    pub appearance: Cell<WindowAppearance>,    pub background_appearance: Cell<WindowBackgroundAppearance>,    pub scale_factor: Cell<f32>,    pub restore_from_minimized: Cell<Option<Box<dyn FnMut(RequestFrameOptions)>>>,     pub callbacks: Callbacks,    pub input_handler: Cell<Option<PlatformInputHandler>>,    pub ime_enabled: Cell<bool>,    pub pending_surrogate: Cell<Option<u16>>,    pub last_reported_modifiers: Cell<Option<Modifiers>>,    pub last_reported_capslock: Cell<Option<Capslock>>,    pub hovered: Cell<bool>,    pub direct_manipulation: DirectManipulationHandler,     pub renderer: RefCell<DirectXRenderer>,    /// Set when the next `draw_window` call must be treated as a forced    /// render. Used after a GPU device-lost recovery, where the next frame    /// must both re-enable drawing (via `mark_drawable`) and bypass the GPUI    /// view cache (which would otherwise replay stale atlas tile references    /// from the previous frame and panic in `DirectXAtlasState::texture`),    /// and when a forced render was requested while another draw was in    /// progress and had to be deferred.    pub force_render_pending: Cell<bool>,     pub click_state: ClickState,    pub current_cursor: Cell<Option<HCURSOR>>,    /// Shared with [`WindowsPlatformState::cursor_visible`].    pub cursor_visible: Arc<AtomicBool>,    pub nc_button_pressed: Cell<Option<u32>>,     pub display: Cell<WindowsDisplay>,    /// Flag to instruct the `VSyncProvider` thread to invalidate the directx devices    /// as resizing them has failed, causing us to have lost at least the render target.    pub invalidate_devices: Arc<AtomicBool>,    /// Shared with [`WindowsPlatformState::draw_coordinator`] and every other window.    pub(crate) draw_coordinator: Rc<DrawCoordinator>,    fullscreen: Cell<Option<StyleAndBounds>>,    initial_placement: Cell<Option<WindowOpenStatus>>,    hwnd: HWND,    pub(crate) a11y: RefCell<Option<A11yState>>,} pub(crate) struct WindowsWindowInner {    hwnd: HWND,    drop_target_helper: IDropTargetHelper,    pub(crate) state: WindowsWindowState,    system_settings: WindowsSystemSettings,    pub(crate) handle: AnyWindowHandle,    pub(crate) hide_title_bar: bool,    pub(crate) is_movable: bool,    pub(crate) is_resizable: bool,    pub(crate) is_minimizable: bool,    pub(crate) executor: ForegroundExecutor,    pub(crate) validation_number: usize,    pub(crate) main_receiver: PriorityQueueReceiver<RunnableVariant>,    pub(crate) platform_window_handle: HWND,    pub(crate) parent_hwnd: Option<HWND>,} impl WindowsWindowState {    fn new(        hwnd: HWND,        directx_devices: &DirectXDevices,        window_params: &CREATESTRUCTW,        current_cursor: Option<HCURSOR>,        cursor_visible: Arc<AtomicBool>,        display: WindowsDisplay,        min_size: Option<Size<Pixels>>,        appearance: WindowAppearance,        disable_direct_composition: bool,        invalidate_devices: Arc<AtomicBool>,        draw_coordinator: Rc<DrawCoordinator>,    ) -> Result<Self> {        let scale_factor = {            let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;            monitor_dpi / USER_DEFAULT_SCREEN_DPI as f32        };        let origin = logical_point(window_params.x as f32, window_params.y as f32, scale_factor);        let logical_size = {            let physical_size = size(                DevicePixels(window_params.cx),                DevicePixels(window_params.cy),            );            physical_size.to_pixels(scale_factor)        };        let fullscreen_restore_bounds = Bounds {            origin,            size: logical_size,        };        let border_offset = WindowBorderOffset::default();        let restore_from_minimized = None;        let renderer = DirectXRenderer::new(hwnd, directx_devices, disable_direct_composition)            .context("Creating DirectX renderer")?;        let callbacks = Callbacks::default();        let input_handler = None;        let pending_surrogate = None;        let last_reported_modifiers = None;        let last_reported_capslock = None;        let hovered = false;        let click_state = ClickState::new();        let nc_button_pressed = None;        let fullscreen = None;        let initial_placement = None;         let direct_manipulation = DirectManipulationHandler::new(hwnd, scale_factor)            .context("initializing Direct Manipulation")?;         Ok(Self {            origin: Cell::new(origin),            logical_size: Cell::new(logical_size),            fullscreen_restore_bounds: Cell::new(fullscreen_restore_bounds),            border_offset,            appearance: Cell::new(appearance),            background_appearance: Cell::new(WindowBackgroundAppearance::Opaque),            scale_factor: Cell::new(scale_factor),            restore_from_minimized: Cell::new(restore_from_minimized),            min_size,            callbacks,            input_handler: Cell::new(input_handler),            ime_enabled: Cell::new(true),            pending_surrogate: Cell::new(pending_surrogate),            last_reported_modifiers: Cell::new(last_reported_modifiers),            last_reported_capslock: Cell::new(last_reported_capslock),            hovered: Cell::new(hovered),            renderer: RefCell::new(renderer),            force_render_pending: Cell::new(false),            click_state,            current_cursor: Cell::new(current_cursor),            cursor_visible,            nc_button_pressed: Cell::new(nc_button_pressed),            display: Cell::new(display),            fullscreen: Cell::new(fullscreen),            initial_placement: Cell::new(initial_placement),            hwnd,            invalidate_devices,            draw_coordinator,            direct_manipulation,            a11y: RefCell::new(None),        })    }     #[inline]    pub(crate) fn is_fullscreen(&self) -> bool {        self.fullscreen.get().is_some()    }     pub(crate) fn is_maximized(&self) -> bool {        !self.is_fullscreen() && unsafe { IsZoomed(self.hwnd) }.as_bool()    }     fn bounds(&self) -> Bounds<Pixels> {        Bounds {            origin: self.origin.get(),            size: self.logical_size.get(),        }    }     // Calculate the bounds used for saving and whether the window is maximized.    fn calculate_window_bounds(&self) -> (Bounds<Pixels>, bool) {        let placement = unsafe {            let mut placement = WINDOWPLACEMENT {                length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,                ..Default::default()            };            GetWindowPlacement(self.hwnd, &mut placement)                .context("failed to get window placement")                .log_err();            placement        };        (            calculate_client_rect(                placement.rcNormalPosition,                &self.border_offset,                self.scale_factor.get(),            ),            placement.showCmd == SW_SHOWMAXIMIZED.0 as u32,        )    }     fn window_bounds(&self) -> WindowBounds {        let (bounds, maximized) = self.calculate_window_bounds();         if self.is_fullscreen() {            WindowBounds::Fullscreen(self.fullscreen_restore_bounds.get())        } else if maximized {            WindowBounds::Maximized(bounds)        } else {            WindowBounds::Windowed(bounds)        }    }     /// get the logical size of the app's drawable area.    ///    /// Currently, GPUI uses the logical size of the app to handle mouse interactions (such as    /// whether the mouse collides with other elements of GPUI).    fn content_size(&self) -> Size<Pixels> {        self.logical_size.get()    }} impl WindowsWindowInner {    fn new(context: &mut WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result<Rc<Self>> {        let state = WindowsWindowState::new(            hwnd,            &context.directx_devices,            cs,            context.current_cursor,            context.cursor_visible.clone(),            context.display,            context.min_size,            context.appearance,            context.disable_direct_composition,            context.invalidate_devices.clone(),            context.draw_coordinator.clone(),        )?;         Ok(Rc::new(Self {            hwnd,            drop_target_helper: context.drop_target_helper.clone(),            state,            handle: context.handle,            hide_title_bar: context.hide_title_bar,            is_movable: context.is_movable,            is_resizable: context.is_resizable,            is_minimizable: context.is_minimizable,            executor: context.executor.clone(),            validation_number: context.validation_number,            main_receiver: context.main_receiver.clone(),            platform_window_handle: context.platform_window_handle,            system_settings: WindowsSystemSettings::new(),            parent_hwnd: context.parent_hwnd,        }))    }     fn toggle_fullscreen(self: &Rc<Self>) {        let this = self.clone();        self.executor            .spawn(async move {                let StyleAndBounds {                    style,                    x,                    y,                    cx,                    cy,                } = match this.state.fullscreen.take() {                    Some(state) => state,                    None => {                        let (window_bounds, _) = this.state.calculate_window_bounds();                        this.state.fullscreen_restore_bounds.set(window_bounds);                         let style =                            WINDOW_STYLE(unsafe { get_window_long(this.hwnd, GWL_STYLE) } as _);                        let mut rc = RECT::default();                        unsafe { GetWindowRect(this.hwnd, &mut rc) }                            .context("failed to get window rect")                            .log_err();                        let _ = this.state.fullscreen.set(Some(StyleAndBounds {                            style,                            x: rc.left,                            y: rc.top,                            cx: rc.right - rc.left,                            cy: rc.bottom - rc.top,                        }));                        let style = style                            & !(WS_THICKFRAME                                | WS_SYSMENU                                | WS_MAXIMIZEBOX                                | WS_MINIMIZEBOX                                | WS_CAPTION);                        let physical_bounds = this.state.display.get().physical_bounds();                        StyleAndBounds {                            style,                            x: physical_bounds.left().0,                            y: physical_bounds.top().0,                            cx: physical_bounds.size.width.0,                            cy: physical_bounds.size.height.0,                        }                    }                };                set_non_rude_hwnd(this.hwnd, !this.state.is_fullscreen());                unsafe { set_window_long(this.hwnd, GWL_STYLE, style.0 as isize) };                unsafe {                    SetWindowPos(                        this.hwnd,                        None,                        x,                        y,                        cx,                        cy,                        SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER,                    )                }                .log_err();            })            .detach();    }     fn set_window_placement(self: &Rc<Self>) -> Result<()> {        let Some(open_status) = self.state.initial_placement.take() else {            return Ok(());        };        match open_status.state {            WindowOpenState::Maximized => unsafe {                SetWindowPlacement(self.hwnd, &open_status.placement)                    .context("failed to set window placement")?;                ShowWindowAsync(self.hwnd, SW_MAXIMIZE).ok()?;            },            WindowOpenState::Fullscreen => {                unsafe {                    SetWindowPlacement(self.hwnd, &open_status.placement)                        .context("failed to set window placement")?                };                self.toggle_fullscreen();            }            WindowOpenState::Windowed => unsafe {                SetWindowPlacement(self.hwnd, &open_status.placement)                    .context("failed to set window placement")?;            },        }        Ok(())    }     pub(crate) fn system_settings(&self) -> &WindowsSystemSettings {        &self.system_settings    }} #[derive(Default)]pub(crate) struct Callbacks {    pub(crate) request_frame: Cell<Option<Box<dyn FnMut(RequestFrameOptions)>>>,    pub(crate) input: Cell<Option<Box<dyn FnMut(PlatformInput) -> DispatchEventResult>>>,    pub(crate) active_status_change: Cell<Option<Box<dyn FnMut(bool)>>>,    pub(crate) hovered_status_change: Cell<Option<Box<dyn FnMut(bool)>>>,    pub(crate) resize: Cell<Option<Box<dyn FnMut(Size<Pixels>, f32)>>>,    pub(crate) moved: Cell<Option<Box<dyn FnMut()>>>,    pub(crate) should_close: Cell<Option<Box<dyn FnMut() -> bool>>>,    pub(crate) close: Cell<Option<Box<dyn FnOnce()>>>,    pub(crate) hit_test_window_control: Cell<Option<Box<dyn FnMut() -> Option<WindowControlArea>>>>,    pub(crate) appearance_changed: Cell<Option<Box<dyn FnMut()>>>,} struct WindowCreateContext {    inner: Option<Result<Rc<WindowsWindowInner>>>,    handle: AnyWindowHandle,    hide_title_bar: bool,    display: WindowsDisplay,    is_movable: bool,    is_resizable: bool,    is_minimizable: bool,    min_size: Option<Size<Pixels>>,    executor: ForegroundExecutor,    current_cursor: Option<HCURSOR>,    cursor_visible: Arc<AtomicBool>,    drop_target_helper: IDropTargetHelper,    validation_number: usize,    main_receiver: PriorityQueueReceiver<RunnableVariant>,    platform_window_handle: HWND,    appearance: WindowAppearance,    disable_direct_composition: bool,    directx_devices: DirectXDevices,    invalidate_devices: Arc<AtomicBool>,    draw_coordinator: Rc<DrawCoordinator>,    parent_hwnd: Option<HWND>,} impl WindowsWindow {    pub(crate) fn new(        handle: AnyWindowHandle,        params: WindowParams,        creation_info: WindowCreationInfo,    ) -> Result<Self> {        // Native popups are not implemented on Windows yet. Rejecting lets callers fall back to        // gpui's in-window popovers.        if let WindowKind::AnchoredPopup(_) = params.kind {            return Err(popup::PopupNotSupportedError.into());        }         let WindowCreationInfo {            icon,            executor,            current_cursor,            cursor_visible,            drop_target_helper,            validation_number,            main_receiver,            platform_window_handle,            disable_direct_composition,            directx_devices,            invalidate_devices,            draw_coordinator,        } = creation_info;        register_window_class(icon);        let parent_hwnd = if params.kind == WindowKind::Dialog {            let parent_window = unsafe { GetActiveWindow() };            if parent_window.is_invalid() {                None            } else {                // Disable the parent window to make this dialog modal                unsafe {                    EnableWindow(parent_window, false).as_bool();                };                Some(parent_window)            }        } else {            None        };        let hide_title_bar = params            .titlebar            .as_ref()            .map(|titlebar| titlebar.appears_transparent)            .unwrap_or(true);        let window_name = HSTRING::from(            params                .titlebar                .as_ref()                .and_then(|titlebar| titlebar.title.as_ref())                .map(|title| title.as_ref())                .unwrap_or(""),        );         let (mut dwexstyle, dwstyle) = if params.kind == WindowKind::PopUp {            (WS_EX_TOOLWINDOW | WS_EX_TOPMOST, WINDOW_STYLE(0x0))        } else {            let mut dwstyle = WS_SYSMENU;             if params.is_resizable {                dwstyle |= WS_THICKFRAME | WS_MAXIMIZEBOX;            }             if params.is_minimizable {                dwstyle |= WS_MINIMIZEBOX;            }            let dwexstyle = if params.kind == WindowKind::Dialog {                dwstyle |= WS_POPUP | WS_CAPTION;                WS_EX_DLGMODALFRAME            } else {                WS_EX_APPWINDOW            };             (dwexstyle, dwstyle)        };        if !disable_direct_composition {            dwexstyle |= WS_EX_NOREDIRECTIONBITMAP;        }         let hinstance = get_module_handle();        let display = if let Some(display_id) = params.display_id {            WindowsDisplay::new(display_id)        } else {            None

Lines 1–500 of 1678.