update
This commit is contained in:
Vendored
+2
@@ -6,6 +6,7 @@ mod div;
|
||||
mod image_cache;
|
||||
mod img;
|
||||
mod list;
|
||||
mod native_surface;
|
||||
mod surface;
|
||||
mod svg;
|
||||
mod text;
|
||||
@@ -19,6 +20,7 @@ pub use div::*;
|
||||
pub use image_cache::*;
|
||||
pub use img::*;
|
||||
pub use list::*;
|
||||
pub use native_surface::*;
|
||||
pub use surface::*;
|
||||
pub use svg::*;
|
||||
pub use text::*;
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
use crate::{
|
||||
App, Bounds, Element, ElementId, GlobalElementId, InspectorElementId, IntoElement, LayoutId,
|
||||
NativeSurfaceHandle, Pixels, Style, StyleRefinement, Styled, Window,
|
||||
};
|
||||
use refineable::Refineable;
|
||||
|
||||
/// A native platform surface hosted inside a GPUI layout box.
|
||||
pub struct NativeSurface {
|
||||
id: ElementId,
|
||||
on_surface: Option<Box<dyn FnMut(NativeSurfaceHandle, Bounds<Pixels>, &mut Window, &mut App)>>,
|
||||
style: StyleRefinement,
|
||||
}
|
||||
|
||||
/// Create a native platform surface element.
|
||||
pub fn native_surface(
|
||||
id: impl Into<ElementId>,
|
||||
on_surface: impl FnMut(NativeSurfaceHandle, Bounds<Pixels>, &mut Window, &mut App) + 'static,
|
||||
) -> NativeSurface {
|
||||
NativeSurface { id: id.into(), on_surface: Some(Box::new(on_surface)), style: Default::default() }
|
||||
}
|
||||
|
||||
impl Element for NativeSurface {
|
||||
type RequestLayoutState = ();
|
||||
type PrepaintState = ();
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
Some(self.id.clone())
|
||||
}
|
||||
|
||||
fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn request_layout(
|
||||
&mut self,
|
||||
_global_id: Option<&GlobalElementId>,
|
||||
_inspector_id: Option<&InspectorElementId>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> (LayoutId, Self::RequestLayoutState) {
|
||||
let mut style = Style::default();
|
||||
style.refine(&self.style);
|
||||
let layout_id = window.request_layout(style, [], cx);
|
||||
(layout_id, ())
|
||||
}
|
||||
|
||||
fn prepaint(
|
||||
&mut self,
|
||||
_global_id: Option<&GlobalElementId>,
|
||||
_inspector_id: Option<&InspectorElementId>,
|
||||
_bounds: Bounds<Pixels>,
|
||||
_request_layout: &mut Self::RequestLayoutState,
|
||||
_window: &mut Window,
|
||||
_cx: &mut App,
|
||||
) -> Self::PrepaintState {
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
global_id: Option<&GlobalElementId>,
|
||||
_inspector_id: Option<&InspectorElementId>,
|
||||
bounds: Bounds<Pixels>,
|
||||
_: &mut Self::RequestLayoutState,
|
||||
_: &mut Self::PrepaintState,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) {
|
||||
let Some(global_id) = global_id else {
|
||||
return;
|
||||
};
|
||||
let Some(on_surface) = self.on_surface.as_mut() else {
|
||||
return;
|
||||
};
|
||||
let Some(surface) = window.with_element_state::<NativeSurfaceState, _>(
|
||||
global_id,
|
||||
|state, window| {
|
||||
let surface = state
|
||||
.and_then(|state| state.surface)
|
||||
.or_else(|| window.create_native_surface());
|
||||
if let Some(surface) = surface {
|
||||
window.sync_native_surface(&surface, bounds);
|
||||
return (Some(surface.clone()), NativeSurfaceState { surface: Some(surface) });
|
||||
}
|
||||
(None, NativeSurfaceState { surface: None })
|
||||
},
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
on_surface(surface, bounds, window, cx);
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoElement for NativeSurface {
|
||||
type Element = Self;
|
||||
|
||||
fn into_element(self) -> Self::Element {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Styled for NativeSurface {
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
&mut self.style
|
||||
}
|
||||
}
|
||||
|
||||
struct NativeSurfaceState {
|
||||
surface: Option<NativeSurfaceHandle>,
|
||||
}
|
||||
Vendored
+249
-1
@@ -48,15 +48,25 @@ use async_task::Runnable;
|
||||
use futures::channel::oneshot;
|
||||
use image::codecs::gif::GifDecoder;
|
||||
use image::{AnimationDecoder as _, Frame};
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||
#[cfg(target_os = "macos")]
|
||||
use objc::sel;
|
||||
#[cfg(target_os = "macos")]
|
||||
use objc::sel_impl;
|
||||
use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
|
||||
use schemars::JsonSchema;
|
||||
use seahash::SeaHasher;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::Cow;
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux", target_os = "freebsd"))]
|
||||
use std::ffi::c_void;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::Cursor;
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::num::NonZeroIsize;
|
||||
use std::ops;
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "freebsd"))]
|
||||
use std::ptr::NonNull;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
@@ -457,6 +467,240 @@ pub(crate) struct RequestFrameOptions {
|
||||
pub(crate) force_render: bool,
|
||||
}
|
||||
|
||||
/// A platform child surface that can be handed to an embedded renderer.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NativeSurfaceHandle {
|
||||
inner: Arc<NativeSurfaceHandleInner>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum NativeSurfaceHandleInner {
|
||||
#[cfg(target_os = "macos")]
|
||||
MacOS { appkit_ns_view: NonNull<c_void> },
|
||||
#[cfg(target_os = "windows")]
|
||||
Windows { hwnd: isize },
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "x11"))]
|
||||
X11 {
|
||||
connection: usize,
|
||||
screen_id: i32,
|
||||
window_id: u32,
|
||||
visual_id: u32,
|
||||
},
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "wayland"))]
|
||||
Wayland { surface: usize, display: usize },
|
||||
}
|
||||
|
||||
impl NativeSurfaceHandle {
|
||||
#[cfg(target_os = "macos")]
|
||||
pub(crate) fn from_appkit_ns_view(appkit_ns_view: NonNull<c_void>) -> Self {
|
||||
Self { inner: Arc::new(NativeSurfaceHandleInner::MacOS { appkit_ns_view }) }
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) fn from_win32_hwnd(hwnd: isize) -> Self {
|
||||
Self { inner: Arc::new(NativeSurfaceHandleInner::Windows { hwnd }) }
|
||||
}
|
||||
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "x11"))]
|
||||
pub(crate) fn from_xcb_window(
|
||||
connection: usize,
|
||||
screen_id: i32,
|
||||
window_id: u32,
|
||||
visual_id: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(NativeSurfaceHandleInner::X11 {
|
||||
connection,
|
||||
screen_id,
|
||||
window_id,
|
||||
visual_id,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "wayland"))]
|
||||
pub(crate) fn from_wayland_surface(surface: usize, display: usize) -> Self {
|
||||
Self { inner: Arc::new(NativeSurfaceHandleInner::Wayland { surface, display }) }
|
||||
}
|
||||
|
||||
/// Returns the backing `NSView` pointer on macOS.
|
||||
#[cfg(target_os = "macos")]
|
||||
#[must_use]
|
||||
pub fn appkit_ns_view(&self) -> NonNull<c_void> {
|
||||
match self.inner.as_ref() {
|
||||
NativeSurfaceHandleInner::MacOS { appkit_ns_view } => *appkit_ns_view,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the backing Win32 `HWND` value on Windows.
|
||||
#[cfg(target_os = "windows")]
|
||||
#[must_use]
|
||||
pub fn win32_hwnd(&self) -> isize {
|
||||
match self.inner.as_ref() {
|
||||
NativeSurfaceHandleInner::Windows { hwnd } => *hwnd,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the backing XCB window id on X11.
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "x11"))]
|
||||
#[must_use]
|
||||
pub(crate) fn xcb_window_id(&self) -> u32 {
|
||||
match self.inner.as_ref() {
|
||||
NativeSurfaceHandleInner::X11 { window_id, .. } => *window_id,
|
||||
#[cfg(feature = "wayland")]
|
||||
NativeSurfaceHandleInner::Wayland { .. } => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a stable identity for the lifetime of this native surface.
|
||||
#[must_use]
|
||||
pub fn identity(&self) -> usize {
|
||||
match self.inner.as_ref() {
|
||||
#[cfg(target_os = "macos")]
|
||||
NativeSurfaceHandleInner::MacOS { appkit_ns_view } => appkit_ns_view.as_ptr() as usize,
|
||||
#[cfg(target_os = "windows")]
|
||||
NativeSurfaceHandleInner::Windows { hwnd } => *hwnd as usize,
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "x11"))]
|
||||
NativeSurfaceHandleInner::X11 { window_id, .. } => *window_id as usize,
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "wayland"))]
|
||||
NativeSurfaceHandleInner::Wayland { surface, .. } => *surface,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for NativeSurfaceHandleInner {
|
||||
fn drop(&mut self) {
|
||||
match self {
|
||||
#[cfg(target_os = "macos")]
|
||||
Self::MacOS { appkit_ns_view } => unsafe {
|
||||
let view = appkit_ns_view.as_ptr() as *mut objc::runtime::Object;
|
||||
let _: () = objc::msg_send![view, removeFromSuperview];
|
||||
let _: () = objc::msg_send![view, release];
|
||||
},
|
||||
#[cfg(target_os = "windows")]
|
||||
Self::Windows { hwnd } => unsafe {
|
||||
let _ = ::windows::Win32::UI::WindowsAndMessaging::DestroyWindow(
|
||||
::windows::Win32::Foundation::HWND(*hwnd as *mut c_void),
|
||||
);
|
||||
},
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "x11"))]
|
||||
Self::X11 { connection, window_id, .. } => {
|
||||
if let Some(connection) = NonNull::new(*connection as *mut c_void) {
|
||||
use x11rb::connection::Connection as _;
|
||||
use x11rb::protocol::xproto::ConnectionExt as _;
|
||||
|
||||
if let Ok(xcb) = unsafe {
|
||||
x11rb::xcb_ffi::XCBConnection::from_raw_xcb_connection(
|
||||
connection.as_ptr(),
|
||||
false,
|
||||
)
|
||||
} {
|
||||
let _ = xcb.destroy_window(*window_id);
|
||||
let _ = xcb.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "wayland"))]
|
||||
Self::Wayland { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for NativeSurfaceHandle {}
|
||||
|
||||
unsafe impl Sync for NativeSurfaceHandle {}
|
||||
|
||||
impl HasWindowHandle for NativeSurfaceHandle {
|
||||
fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
|
||||
match self.inner.as_ref() {
|
||||
#[cfg(target_os = "macos")]
|
||||
NativeSurfaceHandleInner::MacOS { appkit_ns_view } => unsafe {
|
||||
Ok(raw_window_handle::WindowHandle::borrow_raw(
|
||||
raw_window_handle::RawWindowHandle::AppKit(
|
||||
raw_window_handle::AppKitWindowHandle::new(*appkit_ns_view),
|
||||
),
|
||||
))
|
||||
},
|
||||
#[cfg(target_os = "windows")]
|
||||
NativeSurfaceHandleInner::Windows { hwnd } => {
|
||||
let Some(hwnd) = NonZeroIsize::new(*hwnd) else {
|
||||
return Err(HandleError::Unavailable);
|
||||
};
|
||||
let handle = raw_window_handle::Win32WindowHandle::new(hwnd);
|
||||
unsafe {
|
||||
Ok(raw_window_handle::WindowHandle::borrow_raw(
|
||||
raw_window_handle::RawWindowHandle::Win32(handle),
|
||||
))
|
||||
}
|
||||
}
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "x11"))]
|
||||
NativeSurfaceHandleInner::X11 { window_id, visual_id, .. } => {
|
||||
let Some(window_id) = std::num::NonZeroU32::new(*window_id) else {
|
||||
return Err(HandleError::Unavailable);
|
||||
};
|
||||
let mut handle = raw_window_handle::XcbWindowHandle::new(window_id);
|
||||
handle.visual_id = std::num::NonZeroU32::new(*visual_id);
|
||||
unsafe {
|
||||
Ok(raw_window_handle::WindowHandle::borrow_raw(
|
||||
raw_window_handle::RawWindowHandle::Xcb(handle),
|
||||
))
|
||||
}
|
||||
}
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "wayland"))]
|
||||
NativeSurfaceHandleInner::Wayland { surface, .. } => {
|
||||
let Some(surface) = NonNull::new(*surface as *mut c_void) else {
|
||||
return Err(HandleError::Unavailable);
|
||||
};
|
||||
let handle = raw_window_handle::WaylandWindowHandle::new(surface);
|
||||
unsafe {
|
||||
Ok(raw_window_handle::WindowHandle::borrow_raw(
|
||||
raw_window_handle::RawWindowHandle::Wayland(handle),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDisplayHandle for NativeSurfaceHandle {
|
||||
fn display_handle(&self) -> Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
|
||||
match self.inner.as_ref() {
|
||||
#[cfg(target_os = "macos")]
|
||||
NativeSurfaceHandleInner::MacOS { .. } => unsafe {
|
||||
Ok(raw_window_handle::DisplayHandle::borrow_raw(
|
||||
raw_window_handle::AppKitDisplayHandle::new().into(),
|
||||
))
|
||||
},
|
||||
#[cfg(target_os = "windows")]
|
||||
NativeSurfaceHandleInner::Windows { .. } => Ok(raw_window_handle::DisplayHandle::windows()),
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "x11"))]
|
||||
NativeSurfaceHandleInner::X11 { connection, screen_id, .. } => {
|
||||
let Some(connection) = NonNull::new(*connection as *mut c_void) else {
|
||||
return Err(HandleError::Unavailable);
|
||||
};
|
||||
let handle = raw_window_handle::XcbDisplayHandle::new(Some(connection), *screen_id);
|
||||
unsafe {
|
||||
Ok(raw_window_handle::DisplayHandle::borrow_raw(
|
||||
raw_window_handle::RawDisplayHandle::Xcb(handle),
|
||||
))
|
||||
}
|
||||
}
|
||||
#[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "wayland"))]
|
||||
NativeSurfaceHandleInner::Wayland { display, .. } => {
|
||||
let Some(display) = NonNull::new(*display as *mut c_void) else {
|
||||
return Err(HandleError::Unavailable);
|
||||
};
|
||||
let handle = raw_window_handle::WaylandDisplayHandle::new(display);
|
||||
unsafe {
|
||||
Ok(raw_window_handle::DisplayHandle::borrow_raw(
|
||||
raw_window_handle::RawDisplayHandle::Wayland(handle),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
|
||||
fn bounds(&self) -> Bounds<Pixels>;
|
||||
fn is_maximized(&self) -> bool;
|
||||
@@ -500,6 +744,10 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
|
||||
fn draw(&self, scene: &Scene);
|
||||
fn completed_frame(&self) {}
|
||||
fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas>;
|
||||
fn create_native_surface(&self) -> Option<NativeSurfaceHandle> {
|
||||
None
|
||||
}
|
||||
fn sync_native_surface(&self, _surface: &NativeSurfaceHandle, _bounds: Bounds<Pixels>) {}
|
||||
|
||||
// macOS specific methods
|
||||
fn get_title(&self) -> String {
|
||||
|
||||
+5
-1
@@ -33,7 +33,7 @@ use wayland_client::{
|
||||
Connection, Dispatch, Proxy, QueueHandle, delegate_noop,
|
||||
protocol::{
|
||||
wl_buffer, wl_compositor, wl_keyboard, wl_pointer, wl_registry, wl_seat, wl_shm,
|
||||
wl_shm_pool, wl_surface,
|
||||
wl_shm_pool, wl_subcompositor, wl_subsurface, wl_surface,
|
||||
},
|
||||
};
|
||||
use wayland_protocols::wp::cursor_shape::v1::client::{
|
||||
@@ -111,6 +111,7 @@ pub struct Globals {
|
||||
pub wm_base: xdg_wm_base::XdgWmBase,
|
||||
pub shm: wl_shm::WlShm,
|
||||
pub seat: wl_seat::WlSeat,
|
||||
pub subcompositor: Option<wl_subcompositor::WlSubcompositor>,
|
||||
pub viewporter: Option<wp_viewporter::WpViewporter>,
|
||||
pub fractional_scale_manager:
|
||||
Option<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1>,
|
||||
@@ -149,6 +150,7 @@ impl Globals {
|
||||
shm: globals.bind(&qh, 1..=1, ()).unwrap(),
|
||||
seat,
|
||||
wm_base: globals.bind(&qh, 2..=5, ()).unwrap(),
|
||||
subcompositor: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
viewporter: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
fractional_scale_manager: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
decoration_manager: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
@@ -943,6 +945,8 @@ delegate_noop!(WaylandClientStatePtr: ignore wl_shm::WlShm);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore wl_shm_pool::WlShmPool);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore wl_buffer::WlBuffer);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore wl_region::WlRegion);
|
||||
delegate_noop!(WaylandClientStatePtr: wl_subcompositor::WlSubcompositor);
|
||||
delegate_noop!(WaylandClientStatePtr: wl_subsurface::WlSubsurface);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore zxdg_decoration_manager_v1::ZxdgDecorationManagerV1);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore org_kde_kwin_blur_manager::OrgKdeKwinBlurManager);
|
||||
|
||||
+71
-1
@@ -13,7 +13,10 @@ use futures::channel::oneshot::Receiver;
|
||||
use raw_window_handle as rwh;
|
||||
use wayland_backend::client::ObjectId;
|
||||
use wayland_client::WEnum;
|
||||
use wayland_client::{Proxy, protocol::wl_surface};
|
||||
use wayland_client::{
|
||||
Proxy,
|
||||
protocol::{wl_subsurface, wl_surface},
|
||||
};
|
||||
use wayland_protocols::wp::viewporter::client::wp_viewport;
|
||||
use wayland_protocols::xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1;
|
||||
use wayland_protocols::xdg::shell::client::xdg_surface;
|
||||
@@ -92,6 +95,7 @@ pub struct WaylandWindowState {
|
||||
blur: Option<org_kde_kwin_blur::OrgKdeKwinBlur>,
|
||||
toplevel: xdg_toplevel::XdgToplevel,
|
||||
viewport: Option<wp_viewport::WpViewport>,
|
||||
native_surfaces: HashMap<usize, WaylandNativeSurface>,
|
||||
outputs: HashMap<ObjectId, Output>,
|
||||
display: Option<(ObjectId, Output)>,
|
||||
globals: Globals,
|
||||
@@ -166,6 +170,7 @@ impl WaylandWindowState {
|
||||
blur: None,
|
||||
toplevel,
|
||||
viewport,
|
||||
native_surfaces: HashMap::default(),
|
||||
globals,
|
||||
outputs: HashMap::default(),
|
||||
display: None,
|
||||
@@ -222,6 +227,22 @@ impl WaylandWindowState {
|
||||
}
|
||||
}
|
||||
|
||||
struct WaylandNativeSurface {
|
||||
surface: wl_surface::WlSurface,
|
||||
subsurface: wl_subsurface::WlSubsurface,
|
||||
viewport: Option<wp_viewport::WpViewport>,
|
||||
}
|
||||
|
||||
impl WaylandNativeSurface {
|
||||
fn destroy(self) {
|
||||
if let Some(viewport) = self.viewport {
|
||||
viewport.destroy();
|
||||
}
|
||||
self.subsurface.destroy();
|
||||
self.surface.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WaylandWindow(pub WaylandWindowStatePtr);
|
||||
pub enum ImeInput {
|
||||
InsertText(String),
|
||||
@@ -247,6 +268,9 @@ impl Drop for WaylandWindow {
|
||||
if let Some(viewport) = &state.viewport {
|
||||
viewport.destroy();
|
||||
}
|
||||
for (_, native_surface) in state.native_surfaces.drain() {
|
||||
native_surface.destroy();
|
||||
}
|
||||
state.xdg_surface.destroy();
|
||||
state.surface.destroy();
|
||||
|
||||
@@ -1032,6 +1056,52 @@ impl PlatformWindow for WaylandWindow {
|
||||
state.renderer.sprite_atlas().clone()
|
||||
}
|
||||
|
||||
fn create_native_surface(&self) -> Option<crate::NativeSurfaceHandle> {
|
||||
let mut state = self.borrow_mut();
|
||||
let subcompositor = state.globals.subcompositor.as_ref()?;
|
||||
let surface = state.globals.compositor.create_surface(&state.globals.qh, ());
|
||||
let subsurface =
|
||||
subcompositor.get_subsurface(&surface, &state.surface, &state.globals.qh, ());
|
||||
subsurface.set_desync();
|
||||
let viewport = state
|
||||
.globals
|
||||
.viewporter
|
||||
.as_ref()
|
||||
.map(|viewporter| viewporter.get_viewport(&surface, &state.globals.qh, ()));
|
||||
let display = surface.backend().upgrade()?.display_ptr().cast::<c_void>() as usize;
|
||||
let surface_id = surface.id().as_ptr().cast::<c_void>() as usize;
|
||||
surface.commit();
|
||||
state.native_surfaces.insert(
|
||||
surface_id,
|
||||
WaylandNativeSurface {
|
||||
surface,
|
||||
subsurface,
|
||||
viewport,
|
||||
},
|
||||
);
|
||||
Some(crate::NativeSurfaceHandle::from_wayland_surface(
|
||||
surface_id, display,
|
||||
))
|
||||
}
|
||||
|
||||
fn sync_native_surface(&self, surface: &crate::NativeSurfaceHandle, bounds: Bounds<Pixels>) {
|
||||
let state = self.borrow();
|
||||
let bounds = bounds.to_device_pixels(state.scale);
|
||||
if let Some(native_surface) = state.native_surfaces.get(&surface.identity()) {
|
||||
native_surface
|
||||
.subsurface
|
||||
.set_position(bounds.origin.x.0, bounds.origin.y.0);
|
||||
if let Some(viewport) = native_surface.viewport.as_ref() {
|
||||
viewport.set_destination(
|
||||
bounds.size.width.0.max(1),
|
||||
bounds.size.height.0.max(1),
|
||||
);
|
||||
}
|
||||
native_surface.surface.commit();
|
||||
state.surface.commit();
|
||||
}
|
||||
}
|
||||
|
||||
fn show_window_menu(&self, position: Point<Pixels>) {
|
||||
let state = self.borrow();
|
||||
let serial = state.client.get_serial(SerialKind::MousePress);
|
||||
|
||||
+64
-4
@@ -4,10 +4,11 @@ use x11rb::connection::RequestConnection;
|
||||
use crate::platform::blade::{BladeContext, BladeRenderer, BladeSurfaceConfig};
|
||||
use crate::{
|
||||
AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, GpuSpecs, Modifiers,
|
||||
Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow,
|
||||
Point, PromptButton, PromptLevel, RequestFrameOptions, ResizeEdge, ScaledPixels, Scene, Size,
|
||||
Tiling, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControlArea,
|
||||
WindowDecorations, WindowKind, WindowParams, X11ClientStatePtr, px, size,
|
||||
NativeSurfaceHandle, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
|
||||
PlatformInputHandler, PlatformWindow, Point, PromptButton, PromptLevel, RequestFrameOptions,
|
||||
ResizeEdge, ScaledPixels, Scene, Size, Tiling, WindowAppearance, WindowBackgroundAppearance,
|
||||
WindowBounds, WindowControlArea, WindowDecorations, WindowKind, WindowParams,
|
||||
X11ClientStatePtr, px, size,
|
||||
};
|
||||
|
||||
use blade_graphics as gpu;
|
||||
@@ -253,6 +254,8 @@ pub struct X11WindowState {
|
||||
executor: ForegroundExecutor,
|
||||
atoms: XcbAtoms,
|
||||
x_root_window: xproto::Window,
|
||||
x_screen_id: usize,
|
||||
x_visual_id: u32,
|
||||
pub(crate) counter_id: sync::Counter,
|
||||
pub(crate) last_sync_counter: Option<sync::Int64>,
|
||||
bounds: Bounds<Pixels>,
|
||||
@@ -671,6 +674,8 @@ impl X11WindowState {
|
||||
executor,
|
||||
display,
|
||||
x_root_window: visual_set.root,
|
||||
x_screen_id: x_screen_index,
|
||||
x_visual_id: visual.id,
|
||||
bounds: bounds.to_pixels(scale_factor),
|
||||
scale_factor,
|
||||
renderer,
|
||||
@@ -1480,6 +1485,61 @@ impl PlatformWindow for X11Window {
|
||||
inner.renderer.sprite_atlas().clone()
|
||||
}
|
||||
|
||||
fn create_native_surface(&self) -> Option<NativeSurfaceHandle> {
|
||||
let state = self.0.state.borrow();
|
||||
let window_id = self.0.xcb.generate_id().log_err()?;
|
||||
let aux = xproto::CreateWindowAux::new().event_mask(xproto::EventMask::NO_EVENT);
|
||||
check_reply(
|
||||
|| "X11 CreateWindow failed for native surface.",
|
||||
self.0.xcb.create_window(
|
||||
0,
|
||||
window_id,
|
||||
self.0.x_window,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
xproto::WindowClass::INPUT_OUTPUT,
|
||||
0,
|
||||
&aux,
|
||||
),
|
||||
)
|
||||
.log_err()?;
|
||||
check_reply(
|
||||
|| "X11 MapWindow failed for native surface.",
|
||||
self.0.xcb.map_window(window_id),
|
||||
)
|
||||
.log_err()?;
|
||||
xcb_flush(&self.0.xcb);
|
||||
Some(NativeSurfaceHandle::from_xcb_window(
|
||||
as_raw_xcb_connection::AsRawXcbConnection::as_raw_xcb_connection(&*self.0.xcb)
|
||||
as usize,
|
||||
state.x_screen_id as i32,
|
||||
window_id,
|
||||
state.x_visual_id,
|
||||
))
|
||||
}
|
||||
|
||||
fn sync_native_surface(&self, surface: &NativeSurfaceHandle, bounds: Bounds<Pixels>) {
|
||||
let state = self.0.state.borrow();
|
||||
let bounds = bounds.to_device_pixels(state.scale_factor);
|
||||
drop(state);
|
||||
check_reply(
|
||||
|| "X11 ConfigureWindow failed for native surface.",
|
||||
self.0.xcb.configure_window(
|
||||
surface.xcb_window_id(),
|
||||
&xproto::ConfigureWindowAux::new()
|
||||
.x(bounds.origin.x.0)
|
||||
.y(bounds.origin.y.0)
|
||||
.width(bounds.size.width.0.max(1) as u32)
|
||||
.height(bounds.size.height.0.max(1) as u32),
|
||||
),
|
||||
)
|
||||
.log_err();
|
||||
xcb_flush(&self.0.xcb);
|
||||
}
|
||||
|
||||
fn show_window_menu(&self, position: Point<Pixels>) {
|
||||
let state = self.0.state.borrow();
|
||||
|
||||
|
||||
+60
-5
@@ -2,11 +2,12 @@ use super::{BoolExt, MacDisplay, NSRange, NSStringExt, ns_string, renderer};
|
||||
use crate::{
|
||||
AnyWindowHandle, Bounds, Capslock, DisplayLink, ExternalPaths, FileDropEvent,
|
||||
ForegroundExecutor, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton,
|
||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay,
|
||||
PlatformInput, PlatformWindow, Point, PromptButton, PromptLevel, RequestFrameOptions,
|
||||
SharedString, Size, SystemWindowTab, Timer, WindowAppearance, WindowBackgroundAppearance,
|
||||
WindowBounds, WindowControlArea, WindowKind, WindowParams, dispatch_get_main_queue,
|
||||
dispatch_sys::dispatch_async_f, platform::PlatformInputHandler, point, px, size,
|
||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, NativeSurfaceHandle, Pixels, PlatformAtlas,
|
||||
PlatformDisplay, PlatformInput, PlatformWindow, Point, PromptButton, PromptLevel,
|
||||
RequestFrameOptions, SharedString, Size, SystemWindowTab, Timer, WindowAppearance,
|
||||
WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowKind, WindowParams,
|
||||
dispatch_get_main_queue, dispatch_sys::dispatch_async_f, platform::PlatformInputHandler, point,
|
||||
px, size,
|
||||
};
|
||||
use block::ConcreteBlock;
|
||||
use cocoa::{
|
||||
@@ -57,6 +58,7 @@ 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 NATIVE_SURFACE_VIEW_CLASS: *const Class = ptr::null();
|
||||
static mut BLURRED_VIEW_CLASS: *const Class = ptr::null();
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
@@ -252,6 +254,16 @@ unsafe fn build_classes() {
|
||||
}
|
||||
decl.register()
|
||||
};
|
||||
NATIVE_SURFACE_VIEW_CLASS = {
|
||||
let mut decl = ClassDecl::new("GPUINativeSurfaceView", class!(NSView)).unwrap();
|
||||
unsafe {
|
||||
decl.add_method(
|
||||
sel!(hitTest:),
|
||||
native_surface_hit_test as extern "C" fn(&Object, Sel, NSPoint) -> id,
|
||||
);
|
||||
decl.register()
|
||||
}
|
||||
};
|
||||
BLURRED_VIEW_CLASS = {
|
||||
let mut decl = ClassDecl::new("BlurredView", class!(NSVisualEffectView)).unwrap();
|
||||
unsafe {
|
||||
@@ -1504,6 +1516,45 @@ impl PlatformWindow for MacWindow {
|
||||
self.0.lock().renderer.sprite_atlas().clone()
|
||||
}
|
||||
|
||||
fn create_native_surface(&self) -> Option<NativeSurfaceHandle> {
|
||||
let this = self.0.lock();
|
||||
unsafe {
|
||||
let parent = this.native_view.as_ptr() as id;
|
||||
let native_surface: id = msg_send![NATIVE_SURFACE_VIEW_CLASS, alloc];
|
||||
let native_surface = NSView::initWithFrame_(
|
||||
native_surface,
|
||||
NSRect::new(NSPoint::new(0.0, 0.0), NSSize::new(1.0, 1.0)),
|
||||
);
|
||||
if native_surface.is_null() {
|
||||
return None;
|
||||
}
|
||||
native_surface.setWantsBestResolutionOpenGLSurface_(YES);
|
||||
native_surface.setWantsLayer(YES);
|
||||
let _: () = msg_send![
|
||||
native_surface,
|
||||
setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize
|
||||
];
|
||||
let _: () = msg_send![parent, addSubview: native_surface];
|
||||
NonNull::new(native_surface as *mut c_void).map(NativeSurfaceHandle::from_appkit_ns_view)
|
||||
}
|
||||
}
|
||||
|
||||
fn sync_native_surface(&self, surface: &NativeSurfaceHandle, bounds: Bounds<Pixels>) {
|
||||
let this = self.0.lock();
|
||||
unsafe {
|
||||
let parent = this.native_view.as_ptr() as id;
|
||||
let parent_frame: NSRect = msg_send![parent, frame];
|
||||
let view = surface.appkit_ns_view().as_ptr() as id;
|
||||
let width = bounds.size.width.0.max(1.0) as f64;
|
||||
let height = bounds.size.height.0.max(1.0) as f64;
|
||||
let x = bounds.origin.x.0 as f64;
|
||||
let y = (parent_frame.size.height - bounds.origin.y.0 as f64 - height).max(0.0);
|
||||
let frame = NSRect::new(NSPoint::new(x, y), NSSize::new(width, height));
|
||||
let _: () = msg_send![view, setFrame: frame];
|
||||
let _: () = msg_send![view, setHidden: NO];
|
||||
}
|
||||
}
|
||||
|
||||
fn gpu_specs(&self) -> Option<crate::GpuSpecs> {
|
||||
None
|
||||
}
|
||||
@@ -1632,6 +1683,10 @@ extern "C" fn yes(_: &Object, _: Sel) -> BOOL {
|
||||
YES
|
||||
}
|
||||
|
||||
extern "C" fn native_surface_hit_test(_: &Object, _: Sel, _: NSPoint) -> id {
|
||||
nil
|
||||
}
|
||||
|
||||
extern "C" fn dealloc_window(this: &Object, _: Sel) {
|
||||
unsafe {
|
||||
drop_window_state(this);
|
||||
|
||||
+65
@@ -849,6 +849,46 @@ impl PlatformWindow for WindowsWindow {
|
||||
self.0.state.borrow().renderer.sprite_atlas()
|
||||
}
|
||||
|
||||
fn create_native_surface(&self) -> Option<NativeSurfaceHandle> {
|
||||
register_native_surface_window_class();
|
||||
let hwnd = unsafe {
|
||||
CreateWindowExW(
|
||||
WS_EX_NOACTIVATE,
|
||||
NATIVE_SURFACE_CLASS_NAME,
|
||||
w!(""),
|
||||
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
Some(self.0.hwnd),
|
||||
None,
|
||||
Some(get_module_handle().into()),
|
||||
None,
|
||||
)
|
||||
}
|
||||
.ok()?;
|
||||
Some(NativeSurfaceHandle::from_win32_hwnd(hwnd.0 as isize))
|
||||
}
|
||||
|
||||
fn sync_native_surface(&self, surface: &NativeSurfaceHandle, bounds: Bounds<Pixels>) {
|
||||
let bounds = bounds.to_device_pixels(self.scale_factor());
|
||||
let hwnd = HWND(surface.win32_hwnd() as _);
|
||||
unsafe {
|
||||
SetWindowPos(
|
||||
hwnd,
|
||||
None,
|
||||
bounds.origin.x.0,
|
||||
bounds.origin.y.0,
|
||||
bounds.size.width.0.max(1),
|
||||
bounds.size.height.0.max(1),
|
||||
SWP_NOZORDER | SWP_NOACTIVATE,
|
||||
)
|
||||
.log_err();
|
||||
ShowWindow(hwnd, SW_SHOW).ok().log_err();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_raw_handle(&self) -> HWND {
|
||||
self.0.hwnd
|
||||
}
|
||||
@@ -1145,6 +1185,7 @@ enum WindowOpenState {
|
||||
}
|
||||
|
||||
const WINDOW_CLASS_NAME: PCWSTR = w!("Zed::Window");
|
||||
const NATIVE_SURFACE_CLASS_NAME: PCWSTR = w!("Zed::NativeSurface");
|
||||
|
||||
fn register_window_class(icon_handle: HICON) {
|
||||
static ONCE: Once = Once::new();
|
||||
@@ -1162,6 +1203,30 @@ fn register_window_class(icon_handle: HICON) {
|
||||
});
|
||||
}
|
||||
|
||||
fn register_native_surface_window_class() {
|
||||
static ONCE: Once = Once::new();
|
||||
ONCE.call_once(|| {
|
||||
let wc = WNDCLASSW {
|
||||
lpfnWndProc: Some(native_surface_window_procedure),
|
||||
lpszClassName: PCWSTR(NATIVE_SURFACE_CLASS_NAME.as_ptr()),
|
||||
style: CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
|
||||
hInstance: get_module_handle().into(),
|
||||
hbrBackground: unsafe { CreateSolidBrush(COLORREF(0x00000000)) },
|
||||
..Default::default()
|
||||
};
|
||||
unsafe { RegisterClassW(&wc) };
|
||||
});
|
||||
}
|
||||
|
||||
unsafe extern "system" fn native_surface_window_procedure(
|
||||
hwnd: HWND,
|
||||
msg: u32,
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> LRESULT {
|
||||
unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }
|
||||
}
|
||||
|
||||
unsafe extern "system" fn window_procedure(
|
||||
hwnd: HWND,
|
||||
msg: u32,
|
||||
|
||||
Vendored
+18
-7
@@ -10,13 +10,14 @@ use crate::{
|
||||
LineLayoutIndex, Modifiers, ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent,
|
||||
MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
|
||||
PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptButton, PromptLevel, Quad,
|
||||
Render, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge,
|
||||
SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, ScaledPixels, Scene, Shadow,
|
||||
SharedString, Size, StrikethroughStyle, Style, SubscriberSet, Subscription, SystemWindowTab,
|
||||
SystemWindowTabController, TabStopMap, TaffyLayoutEngine, Task, TextStyle, TextStyleRefinement,
|
||||
TransformationMatrix, Underline, UnderlineStyle, WindowAppearance, WindowBackgroundAppearance,
|
||||
WindowBounds, WindowControls, WindowDecorations, WindowOptions, WindowParams, WindowTextSystem,
|
||||
point, prelude::*, px, rems, size, transparent_black,
|
||||
NativeSurfaceHandle, Render, RenderGlyphParams, RenderImage, RenderImageParams,
|
||||
RenderSvgParams, Replay, ResizeEdge, SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS_X,
|
||||
SUBPIXEL_VARIANTS_Y, ScaledPixels, Scene, Shadow, SharedString, Size, StrikethroughStyle,
|
||||
Style, SubscriberSet, Subscription, SystemWindowTab, SystemWindowTabController, TabStopMap,
|
||||
TaffyLayoutEngine, Task, TextStyle, TextStyleRefinement, TransformationMatrix, Underline,
|
||||
UnderlineStyle, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControls,
|
||||
WindowDecorations, WindowOptions, WindowParams, WindowTextSystem, point, prelude::*, px, rems,
|
||||
size, transparent_black,
|
||||
};
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use collections::{FxHashMap, FxHashSet};
|
||||
@@ -3201,6 +3202,16 @@ impl Window {
|
||||
});
|
||||
}
|
||||
|
||||
/// Creates a native child surface hosted by this window.
|
||||
pub fn create_native_surface(&self) -> Option<NativeSurfaceHandle> {
|
||||
self.platform_window.create_native_surface()
|
||||
}
|
||||
|
||||
/// Synchronizes a native child surface to a GPUI layout box.
|
||||
pub fn sync_native_surface(&self, surface: &NativeSurfaceHandle, bounds: Bounds<Pixels>) {
|
||||
self.platform_window.sync_native_surface(surface, bounds);
|
||||
}
|
||||
|
||||
/// Removes an image from the sprite atlas.
|
||||
pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
|
||||
for frame_index in 0..data.frame_count() {
|
||||
|
||||
Reference in New Issue
Block a user