[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Gnash-commit] gnash ChangeLog doc/C/extensions.xml
From: |
strk |
Subject: |
Re: [Gnash-commit] gnash ChangeLog doc/C/extensions.xml |
Date: |
Fri, 16 Feb 2007 09:29:35 +0100 |
On Fri, Feb 16, 2007 at 04:16:49AM +0000, Rob Savoye wrote:
> Added files:
> doc/C : extensions.xml
>
> + // setup so DummyClass.func1() and DummyClass.func2() work from Flash.
> + static void
> + attachInterface(as_object *obj)
> + {
> + obj->set_member("func1", &ext_func1);
> + obj->set_member("func2", &ext_func2);
> + }
> + </programlisting>
In latest changes we're using 'init_member', rather then 'set_member'.
The difference is thats are:
- init_member will convert the function name to lowercase
if target SWF is < 7
- init_member will *not* seek for getter-setter properties
in the inheritance chain to set any of them instead
- init_member will *not* specially thread __proto__
- init_member will automatically set member flags to
dontDelete|dontEnum
Also, if NULL is an invalid argument I prefer to get an as_object& (reference)
rather then a pointer. This is already implemented in new classes (see
xmlnode.cpp).
> + static as_object*
> + getInterface()
> + {
> + static boost::intrusive_ptr<as_object> o;
> + if (o == NULL) {
> + o = new as_object();
> + }
> + return o.get();
> + }
Remember to call attachInterface(*o) right after creation, or
the interface will be empty.
> + static void
> + dummyext_ctor(const fn_call& fn)
> + {
> + DummyExt *obj = new DummyExt();
> +
> + attachInterface(obj);
> + fn.result->set_as_object(obj); // will keep alive
> + }
> + </programlisting>
Here you're attaching the interface to the newly created object, while
it's usually more appropriate to let the interface be inherited from
the class. To do so, the DummyExt() class would derive from as_object
constructing it with the single parameter being the exported interface:
class DummyExt: public as_object {
DummyExt()
:
as_object(getInterface)
{}
}
This allows programmers to override a method, or to add a method
to the AS class which is automatically inherited by all instances of
that AS class.
> + // Creates a new button with the label as the text.
> + void func1(const fn_call& fn)
> + {
> + DummyExt *ptr = dynamic_cast<DummyExt *>(fn.this_ptr);
> + assert(ptr);
> +
> + if (fn.nargs > 0) {
> + const char *label = fn.arg(0).to_string();
> + bool ret = ptr->dummy_text_label(label);
> + fn.result->set_bool(ret);
> + }
> + }
Assertign that the 'this' pointer of func1 call is a DummyExt is azardous.
Consider this:
var dummy = new DummyExt;
var str = new String;
str.myFunc = dummy.func1;
str.myFunc('Feel free to abort') ;
In the above example, the 'func1' member will be called with a string_as_object
as 'this' pointer. In order to have a common handling of these cases, new
developments
are settling up to this kind of implementation:
void func1(const fn_call& fn)
{
DummyExt *ptr = ensureDummyExt(fn.this_ptr);
assert(ptr);
...
}
The ensureDummyExt will throw an ActionException if the 'this' ptr is
NOT a DummyExt:
static DummyExt*
ensure_sound(as_object* obj)
{
DummyExt* ret = dynamic_cast<DummyExt*>(obj);
if ( ! ret )
{
throw ActionException("builtin method or gettersetter for
DummyExt objects called against non-DummyExt instance");
}
return ret;
}
--strk;