// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
priv enum SurfaceHandleSource {
SurfaceSourceAppKit(UInt64)
SurfaceSourceWin32(UInt64, UInt64)
SurfaceSourceWayland(UInt64, UInt64)
SurfaceSourceXlib(UInt64, UInt64)
SurfaceSourceXcb(UInt64, UInt)
}
///|
fn require_nonzero_u64(
value : UInt64?,
error : SurfaceCreateError,
) -> UInt64 raise SurfaceCreateError {
match value {
Some(value) if value != 0UL => value
_ => raise error
}
}
///|
fn surface_handle_source(
window : @windowing.RawWindowHandle,
display : @windowing.RawDisplayHandle,
) -> SurfaceHandleSource raise SurfaceCreateError {
match (window, display) {
(AppKit(window), AppKit(_)) => SurfaceSourceAppKit(window.ns_view())
(Win32(window), Windows(_)) =>
SurfaceSourceWin32(
require_nonzero_u64(
window.hinstance(),
SurfaceWin32HinstanceUnavailable,
),
window.hwnd(),
)
(Wayland(window), Wayland(display)) =>
SurfaceSourceWayland(display.display(), window.surface())
(Xlib(window), Xlib(display)) =>
SurfaceSourceXlib(
require_nonzero_u64(display.display(), SurfaceXlibDisplayUnavailable),
window.window(),
)
(Xcb(window), Xcb(display)) =>
SurfaceSourceXcb(
require_nonzero_u64(
display.connection(),
SurfaceXcbConnectionUnavailable,
),
window.window(),
)
_ => raise SurfaceHandlePairMismatch
}
}
///|
fn window_handle_raw(
handle : @windowing.WindowHandle,
) -> @windowing.RawWindowHandle raise SurfaceCreateError {
handle.as_raw() catch {
_ => raise SurfaceWindowHandleUnavailable
}
}
///|
fn display_handle_raw(
handle : @windowing.DisplayHandle,
) -> @windowing.RawDisplayHandle raise SurfaceCreateError {
handle.as_raw() catch {
_ => raise SurfaceDisplayHandleUnavailable
}
}
///|
/// Create a surface from backend-neutral window and display handles.
///
/// The handles must use the same backend. The returned surface retains both
/// handle providers so their native owners remain reachable for the surface's
/// lifetime.
pub fn Instance::create_surface_from_window_handles(
self : Instance,
window_handle : @windowing.WindowHandle,
display_handle : @windowing.DisplayHandle,
) -> Surface raise SurfaceCreateError {
let source = surface_handle_source(
window_handle_raw(window_handle),
display_handle_raw(display_handle),
)
let surface = match source {
SurfaceSourceAppKit(ns_view) =>
self.create_surface_macos_ns_view_u64(ns_view)
SurfaceSourceWin32(hinstance, hwnd) =>
self.create_surface_windows_hwnd(
@c.opaque_ptr_from_u64(hinstance),
@c.opaque_ptr_from_u64(hwnd),
)
SurfaceSourceWayland(display, surface) =>
self.create_surface_wayland(
@c.opaque_ptr_from_u64(display),
@c.opaque_ptr_from_u64(surface),
)
SurfaceSourceXlib(display, window) =>
self.create_surface_xlib(@c.opaque_ptr_from_u64(display), window)
SurfaceSourceXcb(connection, window) =>
self.create_surface_xcb(@c.opaque_ptr_from_u64(connection), window)
}
guard !@c.surface_is_null(surface.raw) else {
raise SurfaceNativeCreateFailed
}
{
raw: surface.raw,
layer: surface.layer,
layer_owner: surface.layer_owner,
owner_window_handle: Some(window_handle),
owner_display_handle: Some(display_handle),
}
}
///|
/// Create a surface from any window implementing the `Milky2018/windowing`
/// window and display handle contracts.
pub fn[T : @windowing.HasWindowHandle + @windowing.HasDisplayHandle] Instance::create_surface_from_window(
self : Instance,
window : T,
) -> Surface raise SurfaceCreateError {
let window_handle = @windowing.HasWindowHandle::window_handle(window) catch {
_ => raise SurfaceWindowHandleUnavailable
}
let display_handle = @windowing.HasDisplayHandle::display_handle(window) catch {
_ => raise SurfaceDisplayHandleUnavailable
}
self.create_surface_from_window_handles(window_handle, display_handle)
}
///|
/// Synchronize this surface's Metal layer from an AppKit window handle.
pub fn Surface::sync_macos_window_handle(
self : Surface,
window_handle : @windowing.WindowHandle,
) -> Unit raise SurfaceCreateError {
match window_handle_raw(window_handle) {
AppKit(window) => self.sync_macos_ns_view_layer_u64(window.ns_view())
_ => raise SurfaceAppKitWindowHandleRequired
}
}