summaryrefslogtreecommitdiff
path: root/webhelper/webextensions
diff options
context:
space:
mode:
authorPhilip Chimento <philip@endlessm.com>2016-04-22 13:48:38 -0700
committerPhilip Chimento <philip@endlessm.com>2016-05-03 17:16:22 -0700
commit961325b3d70831e7b10f053340a05dd63cd84d23 (patch)
treee837135aa644813167c7459b213872870fb4a238 /webhelper/webextensions
parent516963eb4fa573c85a4b513fb92bc684c97c6e44 (diff)
Connect to window-object-cleared earlier
If we connect to window-object-cleared only after we own the DBus name, then we risk a race condition where a page is created and its window object is already cleared by the time we connect to the signal, meaning that the signal never fires for that page. However, that on its own would introduce a different race condition, where the JS code would call gettext() before the DBus connection is obtained. Since JSCore doesn't allow you to create JS functions that complete asynchronously, we do the simple but not-very-good thing: if gettext() or ngettext() are called before there is a DBus connection, we spin the main loop until the connection is acquired. https://phabricator.endlessm.com/T11395
Diffstat (limited to 'webhelper/webextensions')
-rw-r--r--webhelper/webextensions/wh2extension.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/webhelper/webextensions/wh2extension.c b/webhelper/webextensions/wh2extension.c
index 8848f2e..c5e281c 100644
--- a/webhelper/webextensions/wh2extension.c
+++ b/webhelper/webextensions/wh2extension.c
@@ -54,11 +54,30 @@ context_free (Context *ctxt)
g_free (ctxt);
}
+/* Spins the main loop until the DBus connection comes up. We need this since we
+define functions in JS, that JS code can potentially call before there is a
+connection. */
+static void
+wait_for_connection_sync (Context *ctxt)
+{
+ g_return_if_fail (ctxt->connection == NULL);
+
+ GMainContext *main = g_main_context_get_thread_default ();
+ while (ctxt->connection == NULL)
+ g_main_context_iteration (main, TRUE /* may block */);
+
+ g_assert (ctxt->connection);
+}
+
static gchar *
translation_function (const gchar *message,
Context *ctxt)
{
GError *error = NULL;
+
+ if (ctxt->connection == NULL)
+ wait_for_connection_sync (ctxt);
+
GVariant *result =
g_dbus_connection_call_sync (ctxt->connection, ctxt->main_program_name,
MAIN_PROGRAM_OBJECT_PATH,
@@ -88,6 +107,10 @@ ngettext_translation_function (const gchar *singular,
Context *ctxt)
{
GError *error = NULL;
+
+ if (ctxt->connection == NULL)
+ wait_for_connection_sync (ctxt);
+
GVariant *result =
g_dbus_connection_call_sync (ctxt->connection, ctxt->main_program_name,
MAIN_PROGRAM_OBJECT_PATH,
@@ -471,11 +494,6 @@ on_bus_acquired (GDBusConnection *connection,
ctxt->connection = connection;
- /* Get a notification when Javascript is ready */
- WebKitScriptWorld *script_world = webkit_script_world_get_default ();
- g_signal_connect (script_world, "window-object-cleared",
- G_CALLBACK (on_window_object_cleared), ctxt);
-
/* Export our interface on the bus */
ctxt->node = g_dbus_node_info_new_for_xml (introspection_xml, &error);
if (ctxt->node == NULL)
@@ -558,4 +576,13 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *extension,
ctxt, (GDestroyNotify) context_free);
g_free (well_known_name);
+
+ /* Get a notification when Javascript is ready. In this callback it's possible
+ that the DBus connection has not been acquired yet, so we have sync waits
+ later if JS tries to call DBus. However, connecting to this signal later
+ doesn't work because it will often already have been fired before the DBus
+ connection is acquired. */
+ WebKitScriptWorld *script_world = webkit_script_world_get_default ();
+ g_signal_connect (script_world, "window-object-cleared",
+ G_CALLBACK (on_window_object_cleared), ctxt);
}