mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 13:23:56 -07:00
Attempt to fix GUI script interaction with JITs.
Simplify some other GUI script interface code. This was SVN commit r8657.
This commit is contained in:
parent
2c8e683214
commit
64bd264fc0
3 changed files with 81 additions and 29 deletions
|
|
@ -343,20 +343,84 @@ void CGUI::SendEventToAll(const CStr& EventName)
|
|||
//-------------------------------------------------------------------
|
||||
// Constructor / Destructor
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
// To isolate the vars declared by each GUI page, we need to create
|
||||
// a pseudo-global object to declare them in. In particular, it must
|
||||
// have no parent object, so it must be declared with JS_NewGlobalObject.
|
||||
// But GUI scripts should have access to the real global's properties
|
||||
// (Array, undefined, getGUIObjectByName, etc), so we add a custom resolver
|
||||
// that defers to the real global object when necessary.
|
||||
|
||||
static JSBool GetGlobalProperty(JSContext* cx, JSObject* UNUSED(obj), jsid id, jsval* vp)
|
||||
{
|
||||
return JS_GetPropertyById(cx, g_ScriptingHost.GetGlobalObject(), id, vp);
|
||||
}
|
||||
|
||||
static JSBool SetGlobalProperty(JSContext* cx, JSObject* UNUSED(obj), jsid id, jsval* vp)
|
||||
{
|
||||
return JS_SetPropertyById(cx, g_ScriptingHost.GetGlobalObject(), id, vp);
|
||||
}
|
||||
|
||||
static JSBool ResolveGlobalProperty(JSContext* cx, JSObject* obj, jsid id, uintN flags, JSObject** objp)
|
||||
{
|
||||
// This gets called when the property can't be resolved in the page_global object.
|
||||
|
||||
// Warning: The interaction between this resolution stuff and the JITs appears
|
||||
// to be quite fragile, and I don't quite understand what the constraints are.
|
||||
// If changing it, be careful to test with each JIT to make sure it works.
|
||||
// (This code is somewhat based on GPSEE's module system.)
|
||||
|
||||
// Declarations and assignments shouldn't affect the real global
|
||||
if (flags & (JSRESOLVE_DECLARING | JSRESOLVE_ASSIGNING))
|
||||
{
|
||||
// Can't be resolved - return NULL
|
||||
*objp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
// Check whether the real global object defined this property
|
||||
uintN attrs;
|
||||
JSBool found;
|
||||
if (!JS_GetPropertyAttrsGetterAndSetterById(cx, g_ScriptingHost.GetGlobalObject(), id, &attrs, &found, NULL, NULL))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!found)
|
||||
{
|
||||
// Not found on real global, so can't be resolved - return NULL
|
||||
*objp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
// Retrieve the property value from the global
|
||||
jsval v;
|
||||
if (!JS_GetPropertyById(cx, g_ScriptingHost.GetGlobalObject(), id, &v))
|
||||
return JS_FALSE;
|
||||
|
||||
// Add the global's property value onto this object, with getter/setter that will
|
||||
// update the global's copy instead of this copy, and then return this object
|
||||
if (!JS_DefinePropertyById(cx, obj, id, v, GetGlobalProperty, SetGlobalProperty, attrs))
|
||||
return JS_FALSE;
|
||||
|
||||
*objp = obj;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSClass page_global_class = {
|
||||
"page_global", JSCLASS_GLOBAL_FLAGS | JSCLASS_NEW_RESOLVE,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, (JSResolveOp)ResolveGlobalProperty, JS_ConvertStub, JS_FinalizeStub,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
CGUI::CGUI() : m_MouseButtons(0), m_FocusedObject(NULL), m_InternalNameNumber(0)
|
||||
{
|
||||
m_BaseObject = new CGUIDummyObject;
|
||||
m_BaseObject->SetGUI(this);
|
||||
|
||||
// Construct the root object for all GUI JavaScript things.
|
||||
// (We need an object with no parent, so functions defined by scripts get
|
||||
// put onto this object and not its parent. In the current version of SpiderMonkey
|
||||
// that means it must be a global object. Then we adjust its prototype so it
|
||||
// can still read standard properties from the context's standard global object.)
|
||||
m_ScriptObject = JS_NewGlobalObject(g_ScriptingHost.getContext(), g_ScriptingHost.GetScriptInterface().GetGlobalClass());
|
||||
// Construct the root object for all GUI JavaScript things
|
||||
m_ScriptObject = JS_NewGlobalObject(g_ScriptingHost.getContext(), &page_global_class);
|
||||
JS_AddObjectRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
|
||||
|
||||
JS_SetPrototype(g_ScriptingHost.getContext(), m_ScriptObject, g_ScriptingHost.GetGlobalObject());
|
||||
}
|
||||
|
||||
CGUI::~CGUI()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ IGUIObject
|
|||
|
||||
#include "gui/scripting/JSInterface_IGUIObject.h"
|
||||
#include "gui/scripting/JSInterface_GUITypes.h"
|
||||
#include "scriptinterface/ScriptVal.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#define LOG_CATEGORY L"gui"
|
||||
|
|
@ -504,27 +504,17 @@ void IGUIObject::ScriptEvent(const CStr& Action)
|
|||
if (it == m_ScriptHandlers.end())
|
||||
return;
|
||||
|
||||
// The IGUIObject needs to be stored inside the script's object
|
||||
jsval guiObject = PRIVATE_TO_JSVAL(this);
|
||||
|
||||
// Make a 'this', allowing access to the IGUIObject
|
||||
JSObject* jsGuiObject = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_IGUIObject::JSI_class, m_pGUI->m_ScriptObject, NULL, 1, &guiObject);
|
||||
debug_assert(jsGuiObject); // TODO: Handle errors
|
||||
|
||||
// TODO: why don't we use GetJSObject here?
|
||||
|
||||
// Set up the 'mouse' parameter
|
||||
jsval mouseParams[3];
|
||||
mouseParams[0] = INT_TO_JSVAL(m_pGUI->m_MousePos.x);
|
||||
mouseParams[1] = INT_TO_JSVAL(m_pGUI->m_MousePos.y);
|
||||
mouseParams[2] = INT_TO_JSVAL(m_pGUI->m_MouseButtons);
|
||||
JSObject* mouseObj = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_GUIMouse::JSI_class, m_pGUI->m_ScriptObject, NULL, 3, mouseParams);
|
||||
debug_assert(mouseObj); // TODO: Handle errors
|
||||
CScriptVal mouse;
|
||||
g_ScriptingHost.GetScriptInterface().Eval("({})", mouse);
|
||||
g_ScriptingHost.GetScriptInterface().SetProperty(mouse.get(), "x", m_pGUI->m_MousePos.x, false);
|
||||
g_ScriptingHost.GetScriptInterface().SetProperty(mouse.get(), "y", m_pGUI->m_MousePos.y, false);
|
||||
g_ScriptingHost.GetScriptInterface().SetProperty(mouse.get(), "buttons", m_pGUI->m_MouseButtons, false);
|
||||
|
||||
jsval paramData[] = { OBJECT_TO_JSVAL(mouseObj) };
|
||||
jsval paramData[] = { mouse.get() };
|
||||
|
||||
jsval result;
|
||||
JSBool ok = JS_CallFunctionValue(g_ScriptingHost.getContext(), jsGuiObject, OBJECT_TO_JSVAL(*it->second), ARRAY_SIZE(paramData), paramData, &result);
|
||||
JSBool ok = JS_CallFunctionValue(g_ScriptingHost.getContext(), GetJSObject(), OBJECT_TO_JSVAL(*it->second), ARRAY_SIZE(paramData), paramData, &result);
|
||||
if (!ok)
|
||||
{
|
||||
JS_ReportError(g_ScriptingHost.getContext(), "Errors executing script action \"%s\"", Action.c_str());
|
||||
|
|
|
|||
|
|
@ -99,9 +99,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval*
|
|||
if (parent)
|
||||
{
|
||||
// If the object isn't parentless, return a new object
|
||||
JSObject* entity = JS_NewObject(cx, &JSI_IGUIObject::JSI_class, NULL, NULL);
|
||||
JS_SetPrivate(cx, entity, parent);
|
||||
*vp = OBJECT_TO_JSVAL(entity);
|
||||
*vp = OBJECT_TO_JSVAL(parent->GetJSObject());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue