1544 lines · 52.4 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 ::util::ResultExt;use anyhow::{Context as _, Result};use futures::channel::oneshot::{self, Receiver};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>,     pub click_state: ClickState,    pub current_cursor: Cell<Option<HCURSOR>>,    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>,    fullscreen: Cell<Option<StyleAndBounds>>,    initial_placement: Cell<Option<WindowOpenStatus>>,    hwnd: HWND,} 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) 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>,        display: WindowsDisplay,        min_size: Option<Size<Pixels>>,        appearance: WindowAppearance,        disable_direct_composition: bool,        invalidate_devices: Arc<AtomicBool>,    ) -> 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),            click_state,            current_cursor: Cell::new(current_cursor),            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,            direct_manipulation,        })    }     #[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.display,            context.min_size,            context.appearance,            context.disable_direct_composition,            context.invalidate_devices.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,            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,    min_size: Option<Size<Pixels>>,    executor: ForegroundExecutor,    current_cursor: Option<HCURSOR>,    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>,    parent_hwnd: Option<HWND>,} impl WindowsWindow {    pub(crate) fn new(        handle: AnyWindowHandle,        params: WindowParams,        creation_info: WindowCreationInfo,    ) -> Result<Self> {        let WindowCreationInfo {            icon,            executor,            current_cursor,            drop_target_helper,            validation_number,            main_receiver,            platform_window_handle,            disable_direct_composition,            directx_devices,            invalidate_devices,        } = 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, 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 {            // if we obtain a display_id, then this ID must be valid.            WindowsDisplay::new(display_id).unwrap()        } else {            WindowsDisplay::primary_monitor().unwrap()        };        let appearance = system_appearance().unwrap_or_default();        let mut context = WindowCreateContext {            inner: None,            handle,            hide_title_bar,            display,            is_movable: params.is_movable,            min_size: params.window_min_size,            executor,            current_cursor,            drop_target_helper,            validation_number,            main_receiver,            platform_window_handle,            appearance,            disable_direct_composition,            directx_devices,            invalidate_devices,            parent_hwnd,        };        let creation_result = unsafe {            CreateWindowExW(                dwexstyle,                WINDOW_CLASS_NAME,                &window_name,                dwstyle,                CW_USEDEFAULT,                CW_USEDEFAULT,                CW_USEDEFAULT,                CW_USEDEFAULT,                parent_hwnd,                None,                Some(hinstance.into()),                Some(&context as *const _ as *const _),            )

Lines 1–500 of 1544.