// SDL Video Actor // This actor runs on the main thread and handles all SDL video operations // Default window configuration - documents all available window options var default_window = { // Basic properties title: "Prosperon Window", width: 640, height: 480, // Position - can be numbers or "centered" x: undefined, // SDL_WINDOWPOS_UNDEFINED by default y: undefined, // SDL_WINDOWPOS_UNDEFINED by default // Window behavior flags resizable: true, fullscreen: false, hidden: false, borderless: false, alwaysOnTop: false, minimized: false, maximized: false, // Input grabbing mouseGrabbed: false, keyboardGrabbed: false, // Display properties highPixelDensity: false, transparent: false, opacity: 1.0, // 0.0 to 1.0 // Focus behavior notFocusable: false, // Special window types (mutually exclusive) utility: false, // Utility window (not in taskbar) tooltip: false, // Tooltip window (requires parent) popupMenu: false, // Popup menu window (requires parent) // Graphics API flags (let SDL choose if not specified) opengl: false, // Force OpenGL context vulkan: false, // Force Vulkan context metal: false, // Force Metal context (macOS) // Advanced properties parent: undefined, // Parent window for tooltips/popups/modal modal: false, // Modal to parent window (requires parent) externalGraphicsContext: false, // Use external graphics context // Input handling textInput: true, // Enable text input on creation }; // Resource tracking var resources = { window: {}, renderer: {}, texture: {}, surface: {} }; // ID counter for resource allocation var next_id = 1; // Helper to allocate new ID function allocate_id() { return next_id++; } // Message handler $_.receiver(function(msg) { if (!msg.kind || !msg.op) { send(msg, {error: "Message must have 'kind' and 'op' fields"}); return; } var response = {}; try { switch (msg.kind) { case 'window': response = handle_window(msg); break; case 'renderer': response = handle_renderer(msg); break; case 'texture': response = handle_texture(msg); break; default: response = {error: "Unknown kind: " + msg.kind}; } } catch (e) { response = {error: e.toString()}; } // Send response back send(msg, response); }); // Window operations function handle_window(msg) { switch (msg.op) { case 'create': var config = Object.assign({}, default_window, msg.data || {}); var id = allocate_id(); var window = new prosperon.endowments.window(config); resources.window[id] = window; return {id: id, data: {width: window.width, height: window.height}}; case 'destroy': if (!msg.id || !resources.window[msg.id]) { return {error: "Invalid window id: " + msg.id}; } resources.window[msg.id].destroy(); delete resources.window[msg.id]; return {success: true}; case 'show': if (!msg.id || !resources.window[msg.id]) { return {error: "Invalid window id: " + msg.id}; } resources.window[msg.id].show(); return {success: true}; case 'hide': if (!msg.id || !resources.window[msg.id]) { return {error: "Invalid window id: " + msg.id}; } resources.window[msg.id].hide(); return {success: true}; case 'set_title': if (!msg.id || !resources.window[msg.id]) { return {error: "Invalid window id: " + msg.id}; } if (!msg.data || !msg.data.title) { return {error: "Missing title in data"}; } resources.window[msg.id].title = msg.data.title; return {success: true}; case 'get_size': if (!msg.id || !resources.window[msg.id]) { return {error: "Invalid window id: " + msg.id}; } var win = resources.window[msg.id]; return {data: {width: win.width, height: win.height}}; case 'set_size': if (!msg.id || !resources.window[msg.id]) { return {error: "Invalid window id: " + msg.id}; } if (!msg.data || typeof msg.data.width !== 'number' || typeof msg.data.height !== 'number') { return {error: "Missing or invalid width/height in data"}; } var win = resources.window[msg.id]; win.width = msg.data.width; win.height = msg.data.height; return {success: true}; default: return {error: "Unknown window operation: " + msg.op}; } } // Renderer operations function handle_renderer(msg) { switch (msg.op) { case 'create': if (!msg.data || !msg.data.window_id) { return {error: "Missing window_id in data"}; } if (!resources.window[msg.data.window_id]) { return {error: "Invalid window id: " + msg.data.window_id}; } var id = allocate_id(); var renderer = prosperon.endowments.renderer.create(resources.window[msg.data.window_id]); resources.renderer[id] = renderer; return {id: id}; case 'destroy': if (!msg.id || !resources.renderer[msg.id]) { return {error: "Invalid renderer id: " + msg.id}; } resources.renderer[msg.id].destroy(); delete resources.renderer[msg.id]; return {success: true}; case 'clear': if (!msg.id || !resources.renderer[msg.id]) { return {error: "Invalid renderer id: " + msg.id}; } resources.renderer[msg.id].clear(); return {success: true}; case 'present': if (!msg.id || !resources.renderer[msg.id]) { return {error: "Invalid renderer id: " + msg.id}; } resources.renderer[msg.id].present(); return {success: true}; default: return {error: "Unknown renderer operation: " + msg.op}; } } // Texture operations function handle_texture(msg) { switch (msg.op) { case 'create': // TODO: Implement texture creation return {error: "Texture operations not yet implemented"}; default: return {error: "Unknown texture operation: " + msg.op}; } }