This commit is contained in:
2026-05-18 13:58:36 -04:00
parent d076dad356
commit 68a4507dbe
143 changed files with 15715 additions and 7204 deletions
+5 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,