#include "cell.h" #include #include #include #include #include #include #include #include "sdl.h" // SDL Window free function void SDL_Window_free(JSRuntime *rt, SDL_Window *w) { SDL_DestroyWindow(w); } QJSCLASS(SDL_Window,) void SDL_Cursor_free(JSRuntime *rt, SDL_Cursor *c) { SDL_DestroyCursor(c); } QJSCLASS(SDL_Cursor,) // Forward declarations for blend mode helpers static JSValue blendmode2js(JSContext *js, SDL_BlendMode mode); static SDL_BlendMode js2blendmode(JSContext *js, JSValue v); // Window constructor function static JSValue js_SDL_Window_constructor(JSContext *js, JSValueConst new_target, int argc, JSValueConst *argv) { if (argc < 1 || !JS_IsObject(argv[0])) return JS_ThrowTypeError(js, "Window constructor requires an object argument"); JSValue opts = argv[0]; // Get basic properties (defaults are handled in JavaScript) const char *title = NULL; JSValue title_val = JS_GetPropertyStr(js, opts, "title"); if (!JS_IsNull(title_val)) { title = JS_ToCString(js, title_val); } JS_FreeValue(js, title_val); if (!title) { return JS_ThrowTypeError(js, "Window title is required"); } int width = 640; JSValue width_val = JS_GetPropertyStr(js, opts, "width"); if (!JS_IsNull(width_val)) { width = js2number(js, width_val); } JS_FreeValue(js, width_val); int height = 480; JSValue height_val = JS_GetPropertyStr(js, opts, "height"); if (!JS_IsNull(height_val)) { height = js2number(js, height_val); } JS_FreeValue(js, height_val); // Create SDL properties object SDL_PropertiesID props = SDL_CreateProperties(); // Always set basic properties SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, width); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, height); SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title); // Handle window position JSValue x_val = JS_GetPropertyStr(js, opts, "x"); if (!JS_IsNull(x_val)) { if (JS_IsString(x_val)) { const char *pos = JS_ToCString(js, x_val); if (strcmp(pos, "centered") == 0) SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED); else SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_UNDEFINED); JS_FreeCString(js, pos); } else { SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, js2number(js, x_val)); } } JS_FreeValue(js, x_val); JSValue y_val = JS_GetPropertyStr(js, opts, "y"); if (!JS_IsNull(y_val)) { if (JS_IsString(y_val)) { const char *pos = JS_ToCString(js, y_val); if (strcmp(pos, "centered") == 0) SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED); else SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_UNDEFINED); JS_FreeCString(js, pos); } else { SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, js2number(js, y_val)); } } JS_FreeValue(js, y_val); // Helper function to check and set boolean properties #define SET_BOOL_PROP(js_name, sdl_prop) do { \ JSValue val = JS_GetPropertyStr(js, opts, js_name); \ if (!JS_IsNull(val)) { \ SDL_SetBooleanProperty(props, sdl_prop, JS_ToBool(js, val)); \ } \ JS_FreeValue(js, val); \ } while(0) // Set all boolean properties directly on the SDL properties object SET_BOOL_PROP("resizable", SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN); SET_BOOL_PROP("fullscreen", SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN); SET_BOOL_PROP("hidden", SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN); SET_BOOL_PROP("borderless", SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN); SET_BOOL_PROP("alwaysOnTop", SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN); SET_BOOL_PROP("minimized", SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN); SET_BOOL_PROP("maximized", SDL_PROP_WINDOW_CREATE_MAXIMIZED_BOOLEAN); SET_BOOL_PROP("mouseGrabbed", SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN); SET_BOOL_PROP("highPixelDensity", SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN); SET_BOOL_PROP("transparent", SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN); SET_BOOL_PROP("utility", SDL_PROP_WINDOW_CREATE_UTILITY_BOOLEAN); SET_BOOL_PROP("tooltip", SDL_PROP_WINDOW_CREATE_TOOLTIP_BOOLEAN); SET_BOOL_PROP("popupMenu", SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN); SET_BOOL_PROP("opengl", SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN); SET_BOOL_PROP("vulkan", SDL_PROP_WINDOW_CREATE_VULKAN_BOOLEAN); SET_BOOL_PROP("metal", SDL_PROP_WINDOW_CREATE_METAL_BOOLEAN); SET_BOOL_PROP("modal", SDL_PROP_WINDOW_CREATE_MODAL_BOOLEAN); SET_BOOL_PROP("externalGraphicsContext", SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN); // Handle focusable (inverse logic) JSValue focusable_val = JS_GetPropertyStr(js, opts, "focusable"); if (!JS_IsNull(focusable_val)) { SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN, JS_ToBool(js, focusable_val)); } JS_FreeValue(js, focusable_val); // Handle notFocusable (for backwards compatibility) JSValue not_focusable_val = JS_GetPropertyStr(js, opts, "notFocusable"); if (!JS_IsNull(not_focusable_val)) { SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN, !JS_ToBool(js, not_focusable_val)); } JS_FreeValue(js, not_focusable_val); #undef SET_BOOL_PROP // Handle parent window JSValue parent_val = JS_GetPropertyStr(js, opts, "parent"); if (!JS_IsNull(parent_val)) { SDL_Window *parent = js2SDL_Window(js, parent_val); if (parent) { SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_PARENT_POINTER, parent); } } JS_FreeValue(js, parent_val); // Create window with properties SDL_Window *window = SDL_CreateWindowWithProperties(props); SDL_DestroyProperties(props); // Always free the title string since we allocated it if (title) { JS_FreeCString(js, title); } if (!window) { return JS_ThrowReferenceError(js, "Failed to create window: %s", SDL_GetError()); } // Create the window JS object JSValue window_obj = SDL_Window2js(js, window); // Set additional properties that can't be set during creation // These will be applied through the property setters JSValue opacity_val = JS_GetPropertyStr(js, opts, "opacity"); if (!JS_IsNull(opacity_val)) { JS_SetPropertyStr(js, window_obj, "opacity", opacity_val); } JSValue min_size_val = JS_GetPropertyStr(js, opts, "minimumSize"); if (!JS_IsNull(min_size_val)) { JS_SetPropertyStr(js, window_obj, "minimumSize", min_size_val); } JSValue max_size_val = JS_GetPropertyStr(js, opts, "maximumSize"); if (!JS_IsNull(max_size_val)) { JS_SetPropertyStr(js, window_obj, "maximumSize", max_size_val); } JSValue pos_val = JS_GetPropertyStr(js, opts, "position"); if (!JS_IsNull(pos_val)) { JS_SetPropertyStr(js, window_obj, "position", pos_val); } // Handle text input JSValue text_input = JS_GetPropertyStr(js, opts, "textInput"); if (JS_ToBool(js, text_input)) { // SDL_StartTextInput(window); } JS_FreeValue(js, text_input); printf("created window %p\n", window); return window_obj; } JSC_CCALL(SDL_Window_fullscreen, SDL_SetWindowFullscreen(js2SDL_Window(js,self), SDL_WINDOW_FULLSCREEN) ) JSValue js_SDL_Window_keyboard_shown(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *window = js2SDL_Window(js,self); return JS_NewBool(js,SDL_ScreenKeyboardShown(window)); } JSValue js_window_theme(JSContext *js, JSValue self, int argc, JSValue *argv) { return JS_NULL; } JSValue js_window_safe_area(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); SDL_Rect r; SDL_GetWindowSafeArea(w, &r); rect newr; SDL_RectToFRect(&r, &newr); return rect2js(js,newr); } JSValue js_window_bordered(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); SDL_SetWindowBordered(w, JS_ToBool(js,argv[0])); return JS_NULL; } JSValue js_window_get_title(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); const char *title = SDL_GetWindowTitle(w); return JS_NewString(js,title); } JSValue js_window_set_title(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); const char *title = JS_ToCString(js,val); SDL_SetWindowTitle(w,title); JS_FreeCString(js,title); return JS_NULL; } JSValue js_window_get_size(JSContext *js, JSValue self) { SDL_Window *win = js2SDL_Window(js,self); int w, h; SDL_GetWindowSize(win, &w, &h); return vec22js(js, (vec2){w,h}); } JSValue js_window_set_size(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); vec2 size = js2vec2(js,val); SDL_SetWindowSize(w,size.x,size.y); return JS_NULL; } JSValue js_window_set_icon(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); SDL_Surface *s = js2SDL_Surface(js,argv[0]); if (!SDL_SetWindowIcon(w,s)) return JS_ThrowReferenceError(js, "could not set window icon: %s", SDL_GetError()); return JS_NULL; } // Position getter/setter JSValue js_window_get_position(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); int x, y; SDL_GetWindowPosition(w, &x, &y); return vec22js(js, (vec2){x,y}); } JSValue js_window_set_position(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); vec2 pos = js2vec2(js,val); SDL_SetWindowPosition(w,pos.x,pos.y); return JS_NULL; } // Mouse grab getter/setter JSValue js_window_get_mouseGrab(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); return JS_NewBool(js, SDL_GetWindowMouseGrab(w)); } JSValue js_window_set_mouseGrab(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); SDL_SetWindowMouseGrab(w, JS_ToBool(js,val)); return JS_NULL; } // Keyboard grab getter/setter JSValue js_window_get_keyboardGrab(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); return JS_NewBool(js, SDL_GetWindowKeyboardGrab(w)); } JSValue js_window_set_keyboardGrab(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); SDL_SetWindowKeyboardGrab(w, JS_ToBool(js,val)); return JS_NULL; } // Opacity getter/setter JSValue js_window_get_opacity(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); return number2js(js, SDL_GetWindowOpacity(w)); } JSValue js_window_set_opacity(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); float opacity = js2number(js,val); SDL_SetWindowOpacity(w, opacity); return JS_NULL; } // Minimum size getter/setter JSValue js_window_get_minimumSize(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); int width, height; SDL_GetWindowMinimumSize(w, &width, &height); return vec22js(js, (vec2){width,height}); } JSValue js_window_set_minimumSize(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); vec2 size = js2vec2(js,val); SDL_SetWindowMinimumSize(w,size.x,size.y); return JS_NULL; } // Maximum size getter/setter JSValue js_window_get_maximumSize(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); int width, height; SDL_GetWindowMaximumSize(w, &width, &height); return vec22js(js, (vec2){width,height}); } JSValue js_window_set_maximumSize(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); vec2 size = js2vec2(js,val); SDL_SetWindowMaximumSize(w,size.x,size.y); return JS_NULL; } // Resizable setter (read from flags) JSValue js_window_get_resizable(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); return JS_NewBool(js, flags & SDL_WINDOW_RESIZABLE); } JSValue js_window_set_resizable(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); SDL_SetWindowResizable(w, JS_ToBool(js,val)); return JS_NULL; } // Bordered getter/setter JSValue js_window_get_bordered(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); return JS_NewBool(js, !(flags & SDL_WINDOW_BORDERLESS)); } JSValue js_window_set_bordered(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); SDL_SetWindowBordered(w, JS_ToBool(js,val)); return JS_NULL; } // Always on top getter/setter JSValue js_window_get_alwaysOnTop(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); return JS_NewBool(js, flags & SDL_WINDOW_ALWAYS_ON_TOP); } JSValue js_window_set_alwaysOnTop(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); SDL_SetWindowAlwaysOnTop(w, JS_ToBool(js,val)); return JS_NULL; } // Fullscreen getter/setter JSValue js_window_get_fullscreen(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); return JS_NewBool(js, flags & SDL_WINDOW_FULLSCREEN); } JSValue js_window_set_fullscreen(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); SDL_SetWindowFullscreen(w, JS_ToBool(js,val)); return JS_NULL; } // Focusable setter JSValue js_window_get_focusable(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); return JS_NewBool(js, !(flags & SDL_WINDOW_NOT_FOCUSABLE)); } JSValue js_window_set_focusable(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); SDL_SetWindowFocusable(w, JS_ToBool(js,val)); return JS_NULL; } // Modal setter JSValue js_window_get_modal(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); return JS_NewBool(js, flags & SDL_WINDOW_MODAL); } JSValue js_window_set_modal(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); SDL_SetWindowModal(w, JS_ToBool(js,val)); return JS_NULL; } // Hidden/visible state JSValue js_window_get_visible(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); return JS_NewBool(js, !(flags & SDL_WINDOW_HIDDEN)); } JSValue js_window_set_visible(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); if (JS_ToBool(js,val)) SDL_ShowWindow(w); else SDL_HideWindow(w); return JS_NULL; } // Minimized state JSValue js_window_get_minimized(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); return JS_NewBool(js, flags & SDL_WINDOW_MINIMIZED); } JSValue js_window_set_minimized(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); if (JS_ToBool(js,val)) SDL_MinimizeWindow(w); else SDL_RestoreWindow(w); return JS_NULL; } // Maximized state JSValue js_window_get_maximized(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); return JS_NewBool(js, flags & SDL_WINDOW_MAXIMIZED); } JSValue js_window_set_maximized(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); if (JS_ToBool(js,val)) SDL_MaximizeWindow(w); else SDL_RestoreWindow(w); return JS_NULL; } // Other window methods JSValue js_window_raise(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); SDL_RaiseWindow(w); return JS_NULL; } JSValue js_window_restore(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); SDL_RestoreWindow(w); return JS_NULL; } JSValue js_window_flash(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); SDL_FlashOperation op = SDL_FLASH_BRIEFLY; if (argc > 0 && JS_IsString(argv[0])) { const char *operation = JS_ToCString(js,argv[0]); if (strcmp(operation, "cancel") == 0) op = SDL_FLASH_CANCEL; else if (strcmp(operation, "briefly") == 0) op = SDL_FLASH_BRIEFLY; else if (strcmp(operation, "until_focused") == 0) op = SDL_FLASH_UNTIL_FOCUSED; JS_FreeCString(js,operation); } SDL_FlashWindow(w, op); return JS_NULL; } JSValue js_window_destroy(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); SDL_DestroyWindow(w); return JS_NULL; } JSValue js_window_get_id(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); return number2js(js, SDL_GetWindowID(w)); } JSValue js_window_get_parent(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_Window *parent = SDL_GetWindowParent(w); if (!parent) return JS_NULL; return SDL_Window2js(js, parent); } JSValue js_window_set_parent(JSContext *js, JSValue self, JSValue val) { SDL_Window *w = js2SDL_Window(js,self); SDL_Window *parent = NULL; if (!JS_IsNull(val)) parent = js2SDL_Window(js,val); SDL_SetWindowParent(w, parent); return JS_NULL; } JSValue js_window_get_pixelDensity(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); return number2js(js, SDL_GetWindowPixelDensity(w)); } JSValue js_window_get_displayScale(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); return number2js(js, SDL_GetWindowDisplayScale(w)); } JSValue js_window_get_sizeInPixels(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); int width, height; SDL_GetWindowSizeInPixels(w, &width, &height); return vec22js(js, (vec2){width,height}); } // Surface related JSValue js_window_get_surface(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_Surface *surf = SDL_GetWindowSurface(w); if (!surf) return JS_NULL; return SDL_Surface2js(js, surf); } JSValue js_window_updateSurface(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); if (!SDL_UpdateWindowSurface(w)) return JS_ThrowReferenceError(js, "Failed to update window surface: %s", SDL_GetError()); return JS_NULL; } JSValue js_window_updateSurfaceRects(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); if (!JS_IsArray(js, argv[0])) return JS_ThrowTypeError(js, "Expected array of rectangles"); int len = JS_ArrayLength(js, argv[0]); SDL_Rect rects[len]; for (int i = 0; i < len; i++) { JSValue val = JS_GetPropertyUint32(js, argv[0], i); rect r = js2rect(js, val); rects[i] = (SDL_Rect){r.x, r.y, r.w, r.h}; JS_FreeValue(js, val); } if (!SDL_UpdateWindowSurfaceRects(w, rects, len)) return JS_ThrowReferenceError(js, "Failed to update window surface rects: %s", SDL_GetError()); return JS_NULL; } JSValue js_window_get_flags(JSContext *js, JSValue self) { SDL_Window *w = js2SDL_Window(js,self); SDL_WindowFlags flags = SDL_GetWindowFlags(w); JSValue ret = JS_NewObject(js); JS_SetPropertyStr(js, ret, "fullscreen", JS_NewBool(js, flags & SDL_WINDOW_FULLSCREEN)); JS_SetPropertyStr(js, ret, "opengl", JS_NewBool(js, flags & SDL_WINDOW_OPENGL)); JS_SetPropertyStr(js, ret, "occluded", JS_NewBool(js, flags & SDL_WINDOW_OCCLUDED)); JS_SetPropertyStr(js, ret, "hidden", JS_NewBool(js, flags & SDL_WINDOW_HIDDEN)); JS_SetPropertyStr(js, ret, "borderless", JS_NewBool(js, flags & SDL_WINDOW_BORDERLESS)); JS_SetPropertyStr(js, ret, "resizable", JS_NewBool(js, flags & SDL_WINDOW_RESIZABLE)); JS_SetPropertyStr(js, ret, "minimized", JS_NewBool(js, flags & SDL_WINDOW_MINIMIZED)); JS_SetPropertyStr(js, ret, "maximized", JS_NewBool(js, flags & SDL_WINDOW_MAXIMIZED)); JS_SetPropertyStr(js, ret, "mouseGrabbed", JS_NewBool(js, flags & SDL_WINDOW_MOUSE_GRABBED)); JS_SetPropertyStr(js, ret, "inputFocus", JS_NewBool(js, flags & SDL_WINDOW_INPUT_FOCUS)); JS_SetPropertyStr(js, ret, "mouseFocus", JS_NewBool(js, flags & SDL_WINDOW_MOUSE_FOCUS)); JS_SetPropertyStr(js, ret, "external", JS_NewBool(js, flags & SDL_WINDOW_EXTERNAL)); JS_SetPropertyStr(js, ret, "modal", JS_NewBool(js, flags & SDL_WINDOW_MODAL)); JS_SetPropertyStr(js, ret, "highPixelDensity", JS_NewBool(js, flags & SDL_WINDOW_HIGH_PIXEL_DENSITY)); JS_SetPropertyStr(js, ret, "mouseCapture", JS_NewBool(js, flags & SDL_WINDOW_MOUSE_CAPTURE)); JS_SetPropertyStr(js, ret, "mouseRelativeMode", JS_NewBool(js, flags & SDL_WINDOW_MOUSE_RELATIVE_MODE)); JS_SetPropertyStr(js, ret, "alwaysOnTop", JS_NewBool(js, flags & SDL_WINDOW_ALWAYS_ON_TOP)); JS_SetPropertyStr(js, ret, "utility", JS_NewBool(js, flags & SDL_WINDOW_UTILITY)); JS_SetPropertyStr(js, ret, "tooltip", JS_NewBool(js, flags & SDL_WINDOW_TOOLTIP)); JS_SetPropertyStr(js, ret, "popupMenu", JS_NewBool(js, flags & SDL_WINDOW_POPUP_MENU)); JS_SetPropertyStr(js, ret, "keyboardGrabbed", JS_NewBool(js, flags & SDL_WINDOW_KEYBOARD_GRABBED)); JS_SetPropertyStr(js, ret, "vulkan", JS_NewBool(js, flags & SDL_WINDOW_VULKAN)); JS_SetPropertyStr(js, ret, "metal", JS_NewBool(js, flags & SDL_WINDOW_METAL)); JS_SetPropertyStr(js, ret, "transparent", JS_NewBool(js, flags & SDL_WINDOW_TRANSPARENT)); JS_SetPropertyStr(js, ret, "notFocusable", JS_NewBool(js, flags & SDL_WINDOW_NOT_FOCUSABLE)); return ret; } JSValue js_window_sync(JSContext *js, JSValue self, int argc, JSValue *argv) { SDL_Window *w = js2SDL_Window(js,self); SDL_SyncWindow(w); return JS_NULL; } static const JSCFunctionListEntry js_SDL_Window_funcs[] = { MIST_FUNC_DEF(SDL_Window, fullscreen, 0), MIST_FUNC_DEF(SDL_Window, keyboard_shown, 0), MIST_FUNC_DEF(window, theme, 0), MIST_FUNC_DEF(window, safe_area, 0), MIST_FUNC_DEF(window, set_icon, 1), MIST_FUNC_DEF(window, raise, 0), MIST_FUNC_DEF(window, restore, 0), MIST_FUNC_DEF(window, flash, 1), MIST_FUNC_DEF(window, destroy, 0), MIST_FUNC_DEF(window, sync, 0), CGETSET_ADD(window, title), CGETSET_ADD(window, size), CGETSET_ADD(window, position), CGETSET_ADD(window, mouseGrab), CGETSET_ADD(window, keyboardGrab), CGETSET_ADD(window, opacity), CGETSET_ADD(window, minimumSize), CGETSET_ADD(window, maximumSize), CGETSET_ADD(window, resizable), CGETSET_ADD(window, bordered), CGETSET_ADD(window, alwaysOnTop), CGETSET_ADD(window, fullscreen), CGETSET_ADD(window, focusable), CGETSET_ADD(window, modal), CGETSET_ADD(window, visible), CGETSET_ADD(window, minimized), CGETSET_ADD(window, maximized), CGETSET_ADD(window, parent), JS_CGETSET_DEF("id", js_window_get_id, NULL), JS_CGETSET_DEF("pixelDensity", js_window_get_pixelDensity, NULL), JS_CGETSET_DEF("displayScale", js_window_get_displayScale, NULL), JS_CGETSET_DEF("sizeInPixels", js_window_get_sizeInPixels, NULL), JS_CGETSET_DEF("flags", js_window_get_flags, NULL), JS_CGETSET_DEF("surface", js_window_get_surface, NULL), MIST_FUNC_DEF(window, updateSurface, 0), MIST_FUNC_DEF(window, updateSurfaceRects, 1), }; // Cursor creation function JSC_CCALL(sdl_create_cursor, SDL_Surface *surf = js2SDL_Surface(js, argv[0]); if (!surf) return JS_ThrowReferenceError(js, "Invalid surface"); vec2 hot = {0, 0}; if (argc > 1) hot = js2vec2(js, argv[1]); SDL_Cursor *cursor = SDL_CreateColorCursor(surf, hot.x, hot.y); if (!cursor) return JS_ThrowReferenceError(js, "Failed to create cursor: %s", SDL_GetError()); return SDL_Cursor2js(js, cursor); ) // Set cursor function JSC_CCALL(sdl_set_cursor, SDL_Cursor *cursor = js2SDL_Cursor(js, argv[0]); if (!cursor) return JS_ThrowReferenceError(js, "Invalid cursor"); SDL_SetCursor(cursor); ) CELL_USE_INIT( if (!SDL_Init(SDL_INIT_VIDEO)) return JS_ThrowInternalError(js, "Unable to initialize video subsystem: %s", SDL_GetError()); JSValue ret = JS_NewObject(js); JS_SetPropertyStr(js, ret, "window", QJSCLASSPREP_FUNCS_CTOR(SDL_Window, 1)); QJSCLASSPREP_NO_FUNCS(SDL_Cursor); // Add cursor functions JS_SetPropertyStr(js, ret, "createCursor", JS_NewCFunction(js, js_sdl_create_cursor, "createCursor", 2)); JS_SetPropertyStr(js, ret, "setCursor", JS_NewCFunction(js, js_sdl_set_cursor, "setCursor", 1)); return ret; )