diff --git a/cmake/platforms/emscripten.cmake b/cmake/platforms/emscripten.cmake
index 3cbcab4..70aa5c9 100644
--- a/cmake/platforms/emscripten.cmake
+++ b/cmake/platforms/emscripten.cmake
@@ -42,7 +42,7 @@ string(JOIN "," emcc_export_string ${emcc_export_list})
set(CMAKE_C_LINK_FLAGS "\
-s ALLOW_MEMORY_GROWTH=1 \
-s EXPORTED_FUNCTIONS='[${emcc_export_string}]' \
--s EXTRA_EXPORTED_RUNTIME_METHODS='[cwrap,callMain]' \
+-s EXTRA_EXPORTED_RUNTIME_METHODS='[cwrap]' \
-s STRICT_JS=1")
if(WASM)
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -s WASM=1")
@@ -63,7 +63,6 @@ endfunction()
function(set_platform_puzzle_target_properties NAME TARGET)
em_link_pre_js(${TARGET} ${CMAKE_SOURCE_DIR}/emccpre.js)
em_link_js_library(${TARGET} ${CMAKE_SOURCE_DIR}/emcclib.js)
- em_link_post_js(${TARGET} ${CMAKE_SOURCE_DIR}/emccpost.js)
endfunction()
function(build_platform_extras)
diff --git a/emcc.c b/emcc.c
index def12ac..393b28c 100644
--- a/emcc.c
+++ b/emcc.c
@@ -43,6 +43,8 @@
/*
* Extern references to Javascript functions provided in emcclib.js.
*/
+extern void js_init_puzzle(void);
+extern void js_post_init(void);
extern void js_debug(const char *);
extern void js_error_box(const char *message);
extern void js_remove_type_dropdown(void);
@@ -936,6 +938,11 @@ int main(int argc, char **argv)
float *colours;
int i;
+ /*
+ * Initialise JavaScript event handlers.
+ */
+ js_init_puzzle();
+
/*
* Instantiate a midend.
*/
@@ -1040,6 +1047,11 @@ int main(int argc, char **argv)
if (param_err)
js_error_box(param_err);
+ /*
+ * Reveal the puzzle!
+ */
+ js_post_init();
+
/*
* Done. Return to JS, and await callbacks!
*/
diff --git a/emcclib.js b/emcclib.js
index 98c20f6..676c429 100644
--- a/emcclib.js
+++ b/emcclib.js
@@ -16,6 +16,23 @@
*/
mergeInto(LibraryManager.library, {
+ /*
+ * void js_init_puzzle(void);
+ *
+ * Called at the start of main() to set up event handlers.
+ */
+ js_init_puzzle: function() {
+ initPuzzle();
+ },
+ /*
+ * void js_post_init(void);
+ *
+ * Called at the end of main() once the initial puzzle has been
+ * started.
+ */
+ js_post_init: function() {
+ post_init();
+ },
/*
* void js_debug(const char *message);
*
diff --git a/emccpost.js b/emccpost.js
deleted file mode 100644
index b12b0af..0000000
--- a/emccpost.js
+++ /dev/null
@@ -1 +0,0 @@
-initPuzzle();
diff --git a/emccpre.js b/emccpre.js
index 240cb98..38e0a4a 100644
--- a/emccpre.js
+++ b/emccpre.js
@@ -31,11 +31,8 @@ var ctx;
var update_xmin, update_xmax, update_ymin, update_ymax;
// Module object for Emscripten. We fill in these parameters to ensure
-// that Module.run() won't be called until we're ready (we want to do
-// our own init stuff first), and that when main() returns nothing
-// will get cleaned up so we remain able to call the puzzle's various
-// callbacks.
-//
+// that when main() returns nothing will get cleaned up so we remain
+// able to call the puzzle's various callbacks.
//
// Page loading order:
//
@@ -49,39 +46,45 @@ var update_xmin, update_xmax, update_ymin, update_ymax;
//
// 3. The HTML finishes loading. The browser is about to fire the
// `DOMContentLoaded` event (ie `onload`) but before that, it
-// actually runs the deferred JS. THis consists of
+// actually runs the deferred JS. This consists of
//
// (i) emccpre.js (this file). This sets up various JS variables
-// including the emscripten Module object.
+// including the emscripten Module object, which includes the
+// environment variables and argv seen by main().
//
// (ii) emscripten's JS. This starts the WASM loading.
//
-// (iii) emccpost.js. This calls initPuzzle, which is defined here
-// in this file. initPuzzle:
-//
-// (a) finds various DOM elements and bind them to variables,
-// which depend on the HTML having loaded (it has).
-//
-// (b) makes various `cwrap` calls into the emscripten module to
-// set up hooks; this depends on the emscripten JS having been
-// loaded (it has).
-//
-// (c) Makes the call to emscripten's
-// Module.onRuntimeInitialized, which sets the callback for when
-// the WASM has finished loading and initialising. This has to
-// come before the WASM finishes loading, or we'll miss the
-// callback. We are executing synchronously here in the same JS
-// file as started the WASM loading, so that is guaranteed.
-//
// When this JS execution is complete, the browser fires the `onload`
// event. This is ignored. It continues loading the WASM.
//
-// 4. The WASM loading and initialisation completes. The
-// onRuntimeInitialised callback calls into emscripten-generated
-// WASM to call the C `main`, to actually start the puzzle.
+// 4. The WASM loading and initialisation completes. Emscripten's
+// runtime calls the C `main` to actually start the puzzle. It
+// then calls initPuzzle, which:
+//
+// (a) finds various DOM elements and bind them to variables,
+// which depends on the HTML having loaded (it has).
+//
+// (b) makes various `cwrap` calls into the emscripten module to
+// set up hooks; this depends on the emscripten JS having been
+// loaded (it has).
var Module = {
- 'noInitialRun': true,
+ 'preRun': function() {
+ // Merge environment variables from HTML script element.
+ // This means you can add something like this to the HTML:
+ //
+ var envscript = document.getElementById("environment");
+ var k, v;
+ if (envscript !== null)
+ for ([k, v] of
+ Object.entries(JSON.parse(envscript.textContent)))
+ ENV[k] = v;
+ },
+ // Pass argv[1] as the fragment identifier (so that permalinks of
+ // the form puzzle.html#game-id can launch the specified id).
+ 'arguments': [decodeURIComponent(location.hash)],
'noExitRuntime': true
};
@@ -261,7 +264,7 @@ function dialog_cleanup() {
onscreen_canvas.focus();
}
-// Init function called from body.onload.
+// Init function called early in main().
function initPuzzle() {
// Construct the off-screen canvas used for double buffering.
onscreen_canvas = document.getElementById("puzzlecanvas");
@@ -686,22 +689,7 @@ function initPuzzle() {
});
}
- /*
- * Arrange to detect changes of device pixel ratio. Adapted from
- * (CC0) to work on older browsers.
- */
var rescale_puzzle = Module.cwrap('rescale_puzzle', 'void', []);
- var mql = null;
- var update_pixel_ratio = function() {
- var dpr = window.devicePixelRatio;
- if (mql !== null)
- mql.removeListener(update_pixel_ratio);
- mql = window.matchMedia(`(resolution: ${dpr}dppx)`);
- mql.addListener(update_pixel_ratio);
- rescale_puzzle();
- }
-
/*
* If the puzzle is sized to fit the page, try to detect changes
* of size of the containing element. Ideally this would use a
@@ -720,36 +708,34 @@ function initPuzzle() {
window.addEventListener("load", resize_handler);
}
- Module.preRun = function() {
- // Merge environment variables from HTML script element.
- // This means you can add something like this to the HTML:
- //
- var envscript = document.getElementById("environment");
- var k, v;
- if (envscript !== null)
- for ([k, v] of
- Object.entries(JSON.parse(envscript.textContent)))
- ENV[k] = v;
- };
-
- Module.onRuntimeInitialized = function() {
- // Run the C setup function, passing argv[1] as the fragment
- // identifier (so that permalinks of the form puzzle.html#game-id
- // can launch the specified id).
- Module.callMain([decodeURIComponent(location.hash)]);
-
- update_pixel_ratio();
- // And if we get here with everything having gone smoothly, i.e.
- // we haven't crashed for one reason or another during setup, then
- // it's probably safe to hide the 'sorry, no puzzle here' div and
- // show the div containing the actual puzzle.
- var apology = document.getElementById("apology");
- if (apology !== null) apology.style.display = "none";
- document.getElementById("puzzle").style.display = "";
-
- // Default to giving keyboard focus to the puzzle.
- onscreen_canvas.focus();
- };
+}
+
+function post_init() {
+ /*
+ * Arrange to detect changes of device pixel ratio. Adapted from
+ * (CC0) to work on older browsers.
+ */
+ var rescale_puzzle = Module.cwrap('rescale_puzzle', 'void', []);
+ var mql = null;
+ var update_pixel_ratio = function() {
+ var dpr = window.devicePixelRatio;
+ if (mql !== null)
+ mql.removeListener(update_pixel_ratio);
+ mql = window.matchMedia(`(resolution: ${dpr}dppx)`);
+ mql.addListener(update_pixel_ratio);
+ rescale_puzzle();
+ }
+
+ update_pixel_ratio();
+ // If we get here with everything having gone smoothly, i.e.
+ // we haven't crashed for one reason or another during setup, then
+ // it's probably safe to hide the 'sorry, no puzzle here' div and
+ // show the div containing the actual puzzle.
+ var apology = document.getElementById("apology");
+ if (apology !== null) apology.style.display = "none";
+ document.getElementById("puzzle").style.display = "";
+
+ // Default to giving keyboard focus to the puzzle.
+ onscreen_canvas.focus();
}