31 #include <string_view> 41 #define DECLARE_GUIPROXY(Type) \ 42 void Type::CreateJSObject() \ 44 ScriptRequest rq(m_pGUI.GetScriptInterface()); \ 45 using ProxyHandler = JSI_GUIProxy<std::remove_pointer_t<decltype(this)>>; \ 46 m_JSObject = ProxyHandler::CreateJSObject(rq, this, GetGUI().GetProxyData(&ProxyHandler::Singleton())); \ 48 template class JSI_GUIProxy<Type>; 56 static JSClass c = PROXY_CLASS_DEF(
"GUIObjectProxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy) | JSCLASS_HAS_RESERVED_SLOTS(1));
66 virtual bool has(
const std::string& name)
const override 71 virtual JSObject*
get(
const std::string& name)
const override 78 m_Functions[name].init(rq.
cx, JS_GetFunctionObject(
function));
83 std::unordered_map<std::string, JS::PersistentRootedObject>
m_Functions;
88 IGUIObject* IGUIProxyObject::FromPrivateSlot<IGUIObject>(JSObject* obj)
94 return UnsafeFromPrivateSlot<IGUIObject>(obj);
104 template <
typename T>
108 return IGUIProxyObject::UnsafeFromPrivateSlot<T>(args.thisv().toObjectOrNull());
111 template <
typename T>
116 const PropertyCache* data =
static_cast<const PropertyCache*
>(
static_cast<const GUIProxyProps*
>(js::GetProxyReservedSlot(proxy, 0).toPrivate()));
117 if (data->has(propName))
119 vp.setObjectOrNull(data->get(propName));
125 template <
typename T>
129 PropertyCache* data =
new PropertyCache();
136 if constexpr (!std::is_same_v<T, IGUIObject>)
137 CreateFunctions(rq, data);
142 template<auto callable>
145 cache->
setFunction(rq, name, ScriptFunction::Create<callable, FromPrivateSlot>(rq, name.c_str()));
151 js::ProxyOptions options;
154 auto ret = std::make_unique<IGUIProxyObject>();
157 JS::RootedValue cppObj(rq.
cx), data(rq.
cx);
158 cppObj.get().setPrivate(ret->m_Ptr);
159 data.get().setPrivate(static_cast<void*>(dataPtr));
160 ret->m_Object.init(rq.
cx, js::NewProxyObject(rq.
cx, &
Singleton(), cppObj,
nullptr, options));
161 js::SetProxyReservedSlot(ret->m_Object, 0, data);
165 template <
typename T>
166 bool JSI_GUIProxy<T>::get(JSContext* cx, JS::HandleObject proxy, JS::HandleValue
UNUSED(receiver), JS::HandleId
id, JS::MutableHandleValue vp)
const 170 T* e = IGUIProxyObject::FromPrivateSlot<T>(proxy.get());
174 JS::RootedValue idval(rq.
cx);
175 if (!JS_IdToValue(rq.
cx,
id, &idval))
178 std::string propName;
183 if (PropGetter(proxy, propName, vp))
187 if (propName.substr(0, 2) ==
"on")
189 CStr eventName(propName.substr(2));
190 std::map<CStr, JS::Heap<JSObject*>>::iterator it = e->m_ScriptHandlers.find(eventName);
191 if (it == e->m_ScriptHandlers.end())
194 vp.setObject(*it->second.get());
198 if (propName ==
"parent")
205 vp.set(JS::NullValue());
209 else if (propName ==
"children")
213 for (
size_t i = 0; i < e->m_Children.size(); ++i)
218 else if (propName ==
"name")
223 else if (e->SettingExists(propName))
225 e->m_Settings[propName]->ToJSVal(rq, vp);
229 LOGERROR(
"Property '%s' does not exist!", propName.c_str());
234 template <
typename T>
236 JS::HandleValue
UNUSED(receiver), JS::ObjectOpResult& result)
const 238 T* e = IGUIProxyObject::FromPrivateSlot<T>(proxy.get());
241 LOGERROR(
"C++ GUI Object could not be found");
242 return result.fail(JSMSG_OBJECT_REQUIRED);
247 JS::RootedValue idval(rq.
cx);
248 if (!JS_IdToValue(rq.
cx,
id, &idval))
249 return result.fail(JSMSG_BAD_PROP_ID);
251 std::string propName;
253 return result.fail(JSMSG_BAD_PROP_ID);
255 if (propName ==
"name")
259 return result.fail(JSMSG_BAD_PROP_ID);
261 return result.succeed();
264 JS::RootedObject vpObj(cx);
266 vpObj = &vp.toObject();
269 if (propName.substr(0, 2) ==
"on")
271 if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(&vp.toObject()))
273 LOGERROR(
"on- event-handlers must be functions");
274 return result.fail(JSMSG_NOT_FUNCTION);
277 CStr eventName(propName.substr(2));
278 e->SetScriptHandler(eventName, vpObj);
280 return result.succeed();
283 if (e->SettingExists(propName))
284 return e->m_Settings[propName]->FromJSVal(rq, vp,
true) ? result.succeed() : result.fail(JSMSG_USER_DEFINED_ERROR);
286 LOGERROR(
"Property '%s' does not exist!", propName.c_str());
287 return result.fail(JSMSG_BAD_PROP_ID);
293 T* e = IGUIProxyObject::FromPrivateSlot<T>(proxy.get());
296 LOGERROR(
"C++ GUI Object could not be found");
297 return result.fail(JSMSG_OBJECT_REQUIRED);
302 JS::RootedValue idval(rq.
cx);
303 if (!JS_IdToValue(rq.
cx,
id, &idval))
304 return result.fail(JSMSG_BAD_PROP_ID);
306 std::string propName;
308 return result.fail(JSMSG_BAD_PROP_ID);
311 if (std::string_view{propName}.substr(0, 2) ==
"on")
313 CStr eventName(propName.substr(2));
314 e->UnsetScriptHandler(eventName);
315 return result.succeed();
318 LOGERROR(
"Only event handlers can be deleted from GUI objects!");
319 return result.fail(JSMSG_BAD_PROP_ID);
virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue vp, JS::HandleValue receiver, JS::ObjectOpResult &result) const final
Definition: JSInterface_GUIProxy_impl.h:235
bool PropGetter(JS::HandleObject proxy, const std::string &propName, JS::MutableHandleValue vp) const
Definition: JSInterface_GUIProxy_impl.h:112
JSContext * cx
Definition: ScriptRequest.h:92
virtual bool setFunction(const ScriptRequest &rq, const std::string &name, JSFunction *function) override
Definition: JSInterface_GUIProxy_impl.h:76
#define LOGERROR(...)
Definition: CLogger.h:36
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
Definition: code_annotation.h:38
static void CreateFunctions(const ScriptRequest &rq, GUIProxyProps *cache)
Definition: JSInterface_GUIProxy_impl.h:51
Definition: JSInterface_GUIProxy_impl.h:99
static std::unique_ptr< IGUIProxyObject > CreateJSObject(const ScriptRequest &rq, GUIObjectType *ptr, GUIProxyProps *data)
Definition: JSInterface_GUIProxy_impl.h:149
virtual bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleValue receiver, JS::HandleId id, JS::MutableHandleValue vp) const override final
Definition: JSInterface_GUIProxy_impl.h:166
GUI object such as a button or an input-box.
Definition: IGUIObject.h:59
IGUIObject * GetParent() const
NOTE! This will not just return m_pParent, when that is need use it! There is one exception to it...
Definition: IGUIObject.cpp:187
virtual ~MapCache()
Definition: JSInterface_GUIProxy_impl.h:64
static std::pair< const js::BaseProxyHandler *, GUIProxyProps * > CreateData(ScriptInterface &scriptInterface)
Definition: JSInterface_GUIProxy_impl.h:126
Proxies need to store some data whose lifetime is tied to an interface.
Definition: JSInterface_GUIProxy.h:85
static GUIObjectType * FromPrivateSlot(const ScriptRequest &, JS::CallArgs &args)
Definition: JSInterface_GUIProxy_impl.h:105
JSObject * GetJSObject()
Retrieves the JSObject representing this GUI object.
Definition: IGUIObject.cpp:427
void ToJSVal(const ScriptRequest &rq, JS::MutableHandleValue ret, T const &val)
Convert a C++ type to a JS::Value.
static void CreateFunction(const ScriptRequest &rq, GUIProxyProps *cache, const std::string &name)
Definition: JSInterface_GUIProxy_impl.h:143
#define T(string_literal)
Definition: secure_crt.cpp:77
Definition: JSInterface_GUIProxy_impl.h:61
Handles the js interface with C++ GUI objects.
Definition: IGUIObject.h:48
virtual bool has(const std::string &name) const override
Definition: JSInterface_GUIProxy_impl.h:66
bool SetPropertyInt(const ScriptRequest &rq, JS::HandleValue obj, int name, const T &value, bool constant=false, bool enumerable=true)
Definition: Object.h:129
bool CreateArray(const ScriptRequest &rq, JS::MutableHandleValue objectValue, size_t length=0)
Sets the given value to a new JS object or Null Value in case of out-of-memory.
Definition: Object.h:244
Template base class for singletons.
Definition: Singleton.h:33
Abstraction around a SpiderMonkey JS::Realm.
Definition: ScriptInterface.h:71
virtual bool setFunction(const ScriptRequest &rq, const std::string &name, JSFunction *function)=0
static JSI_GUIProxy & Singleton()
Definition: JSInterface_GUIProxy_impl.h:34
Spidermonkey maintains some 'local' state via the JSContext* object.
Definition: ScriptRequest.h:59
JSClass & ClassDefinition()
Definition: JSInterface_GUIProxy_impl.h:54
std::unordered_map< std::string, JS::PersistentRootedObject > m_Functions
Definition: JSInterface_GUIProxy_impl.h:83
virtual bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::ObjectOpResult &result) const override final
Definition: JSInterface_GUIProxy_impl.h:291
bool FromJSVal(const ScriptRequest &rq, const JS::HandleValue val, T &ret)
Convert a JS::Value to a C++ type.