/// PlatformLinux - Linux platform abstraction layer /// This module provides window management and input handling for Linux /// Uses X11/Wayland via GLFW or SDL bindings import Foundation import RendererAPI // Note: In a real implementation, this would import GLFW or SDL bindings // import CGLFW or import CSDL2 // MARK: - Linux Window Manager public final class LinuxWindowManager: WindowManager, @unchecked Sendable { private var window: UnsafeMutableRawPointer? private var config: WindowConfig? private var shouldCloseFlag: Bool = false private var currentWidth: Int = 0 private var currentHeight: Int = 0 public init() { print(" 🐧 LinuxWindowManager created") } public func createWindow(config: WindowConfig) async throws { print(" → Creating Linux window...") self.config = config self.currentWidth = config.width self.currentHeight = config.height // Initialize GLFW or SDL // glfwInit() or SDL_Init(SDL_INIT_VIDEO) // Set window hints for Vulkan (no OpenGL context) // glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API) // glfwWindowHint(GLFW_RESIZABLE, config.resizable ? GLFW_TRUE : GLFW_FALSE) // Create window // window = glfwCreateWindow(width, height, title, monitor, share) // or // window = SDL_CreateWindow(title, x, y, width, height, SDL_WINDOW_VULKAN) // Set up event callbacks // glfwSetWindowSizeCallback(window, sizeCallback) // glfwSetWindowCloseCallback(window, closeCallback) print(" ✓ Linux window created: \(config.title) (\(config.width)x\(config.height))") } public func shouldClose() -> Bool { // return glfwWindowShouldClose(window) != 0 // or check SDL event queue for SDL_QUIT return shouldCloseFlag } public func processEvents() -> [WindowEvent] { var events: [WindowEvent] = [] // Poll events from GLFW or SDL // glfwPollEvents() // or // while SDL_PollEvent(&event) { // switch event.type { // case SDL_QUIT: events.append(.close) // case SDL_WINDOWEVENT: ... // } // } return events } public func getSize() -> (width: Int, height: Int) { // glfwGetWindowSize(window, &width, &height) // or SDL_GetWindowSize(window, &width, &height) return (currentWidth, currentHeight) } public func setSize(width: Int, height: Int) throws { currentWidth = width currentHeight = height // glfwSetWindowSize(window, width, height) // or SDL_SetWindowSize(window, width, height) } public func setTitle(_ title: String) throws { // glfwSetWindowTitle(window, title) // or SDL_SetWindowTitle(window, title) } public func setFullscreen(_ fullscreen: Bool) throws { // glfwSetWindowMonitor(...) for GLFW // or SDL_SetWindowFullscreen(window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0) } public func getNativeHandle() -> UnsafeMutableRawPointer? { // For Vulkan surface creation on Linux: // X11: glfwGetX11Window(window) or SDL_GetProperty(window, SDL_PROP_WINDOW_X11_WINDOW_POINTER) // Wayland: glfwGetWaylandWindow(window) or SDL_GetProperty(window, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER) return window } public func swapBuffers() throws { // Not needed for Vulkan (presentation is handled by renderer) // For OpenGL: glfwSwapBuffers(window) or SDL_GL_SwapWindow(window) } public func destroyWindow() async { print(" → Destroying Linux window...") // glfwDestroyWindow(window) // glfwTerminate() // or // SDL_DestroyWindow(window) // SDL_Quit() window = nil print(" ✓ Linux window destroyed") } } // MARK: - Linux Input Handler public final class LinuxInputHandler: InputHandler, @unchecked Sendable { private var window: UnsafeMutableRawPointer? private var keyStates: [KeyCode: Bool] = [:] private var mouseButtonStates: [MouseButton: Bool] = [:] private var mousePosition: (x: Double, y: Double) = (0, 0) private var eventQueue: [InputEvent] = [] public init() { print(" 🐧 LinuxInputHandler created") } public func initialize() async throws { print(" → Initializing Linux input system...") // Set up GLFW or SDL input callbacks // glfwSetKeyCallback(window, keyCallback) // glfwSetMouseButtonCallback(window, mouseButtonCallback) // glfwSetCursorPosCallback(window, cursorPosCallback) // glfwSetScrollCallback(window, scrollCallback) // glfwSetJoystickCallback(joystickCallback) print(" ✓ Linux input system initialized") } public func pollEvents() -> [InputEvent] { // Events are accumulated in callbacks, return and clear the queue let events = eventQueue eventQueue.removeAll() return events } public func isKeyPressed(_ key: KeyCode) -> Bool { return keyStates[key] ?? false } public func isMouseButtonPressed(_ button: MouseButton) -> Bool { return mouseButtonStates[button] ?? false } public func getMousePosition() -> (x: Double, y: Double) { // glfwGetCursorPos(window, &xpos, &ypos) // or SDL_GetMouseState(&x, &y) return mousePosition } public func setCursorVisible(_ visible: Bool) { // glfwSetInputMode(window, GLFW_CURSOR, visible ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN) // or SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE) } public func setCursorMode(_ mode: CursorMode) { // switch mode { // case .normal: // glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL) // case .hidden: // glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN) // case .locked: // glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED) // } } public func getGamepadCount() -> Int { // Check for connected joysticks // glfwJoystickPresent(GLFW_JOYSTICK_1) through GLFW_JOYSTICK_16 // or SDL_NumJoysticks() return 0 } public func isGamepadConnected(_ gamepadId: Int) -> Bool { // glfwJoystickPresent(gamepadId) != 0 // or SDL_JoystickGetAttached(joystick) return false } public func getGamepadName(_ gamepadId: Int) -> String? { // glfwGetJoystickName(gamepadId) // or SDL_JoystickName(joystick) return nil } public func shutdown() async { print(" → Shutting down Linux input system...") keyStates.removeAll() mouseButtonStates.removeAll() eventQueue.removeAll() print(" ✓ Linux input system shutdown") } // MARK: - Event Processing Helpers internal func handleKeyEvent(key: KeyCode, action: InputAction) { keyStates[key] = (action == .press || action == .repeat_) eventQueue.append(.keyEvent(key: key, action: action)) } internal func handleMouseButton(button: MouseButton, action: InputAction) { mouseButtonStates[button] = (action == .press) eventQueue.append(.mouseButton(button: button, action: action)) } internal func handleMouseMove(x: Double, y: Double) { mousePosition = (x, y) eventQueue.append(.mouseMove(x: x, y: y)) } internal func handleMouseScroll(xOffset: Double, yOffset: Double) { eventQueue.append(.mouseScroll(xOffset: xOffset, yOffset: yOffset)) } } // MARK: - Linux Audio Engine (Stub) public final class LinuxAudioEngine: AudioEngine, @unchecked Sendable { public init() { print(" 🐧 LinuxAudioEngine created") } public func initialize(config: AudioConfig) async throws { print(" → Initializing Linux audio (ALSA/PulseAudio/PipeWire)...") // Initialize audio backend (ALSA, PulseAudio, PipeWire, or OpenAL) print(" ✓ Linux audio initialized") } public func loadAudio(path: String) async throws -> AudioHandle { // Load audio file (WAV, OGG, MP3) return AudioHandle() } public func loadAudioFromData(data: Data, sampleRate: Int, channels: Int) async throws -> AudioHandle { return AudioHandle() } public func play(handle: AudioHandle, source: AudioSource3D) throws { // Play audio source } public func stop(handle: AudioHandle) throws { // Stop audio source } public func pause(handle: AudioHandle) throws { // Pause audio source } public func resume(handle: AudioHandle) throws { // Resume audio source } public func updateSource(handle: AudioHandle, source: AudioSource3D) throws { // Update 3D audio properties } public func setListener(listener: AudioListener) throws { // Set listener (camera) position and orientation } public func setMasterVolume(_ volume: Float) throws { // Set master volume } public func update(deltaTime: Float) throws { // Update audio system } public func shutdown() async { print(" → Shutting down Linux audio...") print(" ✓ Linux audio shutdown") } }