Hi Alistair,
Looking at this again, it seems to me like it would be very difficult
to cleanly pass control to the plugin thread via
NPN_PluginThreadAsyncCall without making changes to nixysa. Are such
changes out of the question for the official codebase?
From what I can imagine, the 80-90% use-case for using callbacks (and
the basis for my initial misunderstanding) is where a worker thread
wants to call a JavaScript function.
Heres another quick and ugly patch that changes RunCallback() such
that all arguments are copied and the NPAPI code is deferred to the
plugin thread.
- Aaron
--- nixysa/npapi_generator.py (revision 57)
+++ nixysa/npapi_generator.py (working copy)
@@ -818,8 +818,11 @@
_namespace_glue_cpp_tail]))
_callback_glue_cpp_template = string.Template("""
-${RunCallback} {
+${AsyncCallbackStruct}
+
+${AsyncRunCallback} {
${StartException}
+ ${AsyncCallbackStructToParams}
const char *error=NULL;
const char **error_handle = &error;
bool success = true;
@@ -861,6 +861,17 @@
return ${ReturnValue};
${EndException}
}
+
+${RunCallback} {
+ ${ParamsToAsyncCallbackStruct}
+ if (async && NPCallback::SupportsAsync()) {
+ NPN_PluginThreadAsyncCall(npp, &AsyncRunCallback, asyncargs);
+ } else {
+ AsyncRunCallback(asyncargs);
+ }
+ return ${ReturnValue};
+}
+
""")
_callback_no_param_glue_cpp_template = string.Template("""
@@ -1843,6 +1847,30 @@
run_callback = ('%s RunCallback(NPP npp, NPObject *npobject, bool
async%s)'
% (return_type_string, ', '.join(param_strings)))
+ async_run_callback = '%s AsyncRunCallback(void *data)' %
(return_type_string)
+ async_callback_struct = "struct AsyncArgs { \n"
+ async_callback_struct+= " AsyncArgs() {};\n"
+ async_callback_struct+= " NPP npp;\n"
+ async_callback_struct+= " NPObject *npobject;\n"
+ async_callback_struct+= " bool async;\n"
+ for i in obj.params:
+ async_callback_struct += " %s %s;\n" %
(i.type_defn.binding_model.CppMemberString(scope, i.type_defn)[0],
i.name)
+
+ async_callback_struct += "};"
+ async_callback_struct_to_params = "AsyncArgs *asyncargs =
(AsyncArgs *)data;\n"
+ async_callback_struct_to_params+= " NPP npp = asyncargs->npp;\n"
+ async_callback_struct_to_params+= " NPObject *npobject =
asyncargs->npobject;\n"
+ async_callback_struct_to_params+= " bool async = asyncargs-
>async;\n"
+ for i in obj.params:
+ async_callback_struct_to_params += " %s %s = asyncargs->%s;\n"
% (i.type_defn.binding_model.CppMemberString(scope, i.type_defn)[0],
i.name,
i.name)
+ async_callback_struct_to_params += "delete asyncargs;"
+
+ params_to_async_callback_struct = "AsyncArgs *asyncargs = new
AsyncArgs();\n"
+ params_to_async_callback_struct+= " asyncargs->npp = npp;\n"
+ params_to_async_callback_struct+= " asyncargs->npobject =
npobject;\n"
+ params_to_async_callback_struct+= " asyncargs->async = async;\n"
+ params_to_async_callback_struct+= "%s" % "\n".join([" asyncargs->
%s = %s;" % (
i.name,
i.name) for i in obj.params])
+
return_eval, return_value = bm.NpapiFromNPVariant(scope,
return_type,
'result',
'retval',
'success',
@@ -1851,6 +1879,10 @@
start_exception, end_exception = GenExceptionContext(
_exception_macro_name, "callback return value", "<no name>")
subst_dict = {'RunCallback': run_callback,
+ 'AsyncRunCallback': async_run_callback,
+ 'AsyncCallbackStruct': async_callback_struct,
+ 'ParamsToAsyncCallbackStruct':
params_to_async_callback_struct,
+ 'AsyncCallbackStructToParams':
async_callback_struct_to_params,
'ArgCount': str(len(obj.params)),
'ParamsToVariantsPre': '\n'.join
(param_to_variant_pre),
'ParamsToVariantsPost': '\n'.join
(param_to_variant_post),