soc.2009.webkitmessageview: 9ce58be3: safely execute JS scripts only after loa...
tdrhq at soc.pidgin.im
tdrhq at soc.pidgin.im
Tue Aug 25 12:03:42 EDT 2009
-----------------------------------------------------------------
Revision: 9ce58be3c321eb4d5785d13edc89a3993aaf921c
Ancestor: c2e72a7e918bf0346ab6b72adbb0b919c6d3d1dd
Author: tdrhq at soc.pidgin.im
Date: 2009-08-10T07:33:21
Branch: im.pidgin.soc.2009.webkitmessageview
URL: http://d.pidgin.im/viewmtn/revision/info/9ce58be3c321eb4d5785d13edc89a3993aaf921c
Modified files:
pidgin/gtkwebview.c pidgin/gtkwebview.h
pidgin/plugins/adiumthemes/webkit.c
ChangeLog:
safely execute JS scripts only after loading is done. Untested code as of now, will test it in next commit.
-------------- next part --------------
============================================================
--- pidgin/gtkwebview.c 12ad35bdbbf95e1efd522a048d1b14a474365fab
+++ pidgin/gtkwebview.c 341d6be43d3db18c70c294a37e6fc70aae7eb034
@@ -41,9 +41,19 @@ static WebKitWebViewClass *parent_class
static WebKitWebViewClass *parent_class = NULL;
+struct GtkWebViewPriv {
+ GHashTable *images; /**< a map from id to temporary file for the image */
+ gboolean empty; /**< whether anything has been appended **/
+
+ /* JS execute queue */
+ GQueue *js_queue;
+ gboolean is_loading;
+};
+
GtkWidget* gtk_webview_new ()
{
- return GTK_WIDGET(g_object_new(gtk_webview_get_type(), NULL));
+ GtkWebView* ret = GTK_WEBVIEW (g_object_new(gtk_webview_get_type(), NULL));
+ return GTK_WIDGET (ret);
}
static char*
@@ -53,10 +63,10 @@ get_image_filename_from_id (GtkWebView*
FILE *file;
PurpleStoredImage* img;
- if (!view->images)
- view->images = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+ if (!view->priv->images)
+ view->priv->images = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
- filename = (char*) g_hash_table_lookup (view->images, GINT_TO_POINTER (id));
+ filename = (char*) g_hash_table_lookup (view->priv->images, GINT_TO_POINTER (id));
if (filename) return filename;
/* else get from img store */
@@ -65,7 +75,7 @@ get_image_filename_from_id (GtkWebView*
img = purple_imgstore_find_by_id (id);
fwrite (purple_imgstore_get_data (img), purple_imgstore_get_size (img), 1, file);
- g_hash_table_insert (view->images, GINT_TO_POINTER (id), filename);
+ g_hash_table_insert (view->priv->images, GINT_TO_POINTER (id), filename);
fclose (file);
return filename;
}
@@ -79,9 +89,9 @@ clear_images (GtkWebView* view)
static void
clear_images (GtkWebView* view)
{
- if (!view->images) return;
- g_hash_table_foreach (view->images, clear_single_image, NULL);
- g_hash_table_unref (view->images);
+ if (!view->priv->images) return;
+ g_hash_table_foreach (view->priv->images, clear_single_image, NULL);
+ g_hash_table_unref (view->priv->images);
}
/*
@@ -146,6 +156,7 @@ gtk_webview_finalize (GObject *view)
gtk_webview_finalize (GObject *view)
{
clear_images (GTK_WEBVIEW (view));
+ g_free (GTK_WEBVIEW(view)->priv);
G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT(view));
}
@@ -173,6 +184,39 @@ webview_link_clicked (WebKitWebView *vie
return TRUE;
}
+static gboolean
+process_js_script_queue (GtkWebView *view)
+{
+ char *script;
+ if (view->priv->is_loading) return FALSE; /* we will be called when loaded */
+ if (!view->priv->js_queue || g_queue_is_empty (view->priv->js_queue))
+ return FALSE; /* nothing to do! */
+
+ script = g_queue_pop_head (view->priv->js_queue);
+ webkit_web_view_execute_script (WEBKIT_WEB_VIEW(view), script);
+ g_free (script);
+
+ return TRUE; /* there may be more for now */
+}
+
+static void
+webview_load_started (WebKitWebView *view,
+ WebKitWebFrame *frame,
+ gpointer userdata)
+{
+ /* is there a better way to test for is_loading? */
+ GTK_WEBVIEW(view)->priv->is_loading = true;
+}
+
+static void
+webview_load_finished (WebKitWebView *view,
+ WebKitWebFrame *frame,
+ gpointer userdata)
+{
+ GTK_WEBVIEW(view)->priv->is_loading = false;
+ g_idle_add ((GSourceFunc) process_js_script_queue, view);
+}
+
char*
gtk_webview_execute_script (GtkWebView *view, const char *script)
{
@@ -192,13 +236,30 @@ gtk_webview_execute_script (GtkWebView *
return cstr;
}
+void
+gtk_webview_safe_execute_script (GtkWebView *view, const char* script)
+{
+ g_queue_push_tail (view->priv->js_queue, g_strdup (script));
+ g_idle_add ((GSourceFunc)process_js_script_queue, view);
+}
+
static void
gtk_webview_init (GtkWebView *view, gpointer userdata)
{
+ view->priv = g_new0 (struct GtkWebViewPriv, 1);
g_signal_connect (view, "navigation-policy-decision-requested",
G_CALLBACK (webview_link_clicked),
view);
- view->empty = TRUE;
+
+ g_signal_connect (view, "load-started",
+ G_CALLBACK (webview_load_started),
+ view);
+
+ g_signal_connect (view, "load-finished",
+ G_CALLBACK (webview_load_finished),
+ view);
+
+ view->priv->empty = TRUE;
}
@@ -254,7 +315,7 @@ gtk_webview_append_html (GtkWebView* vie
char* script = g_strdup_printf ("document.write(%s)", escaped);
printf ("script: %s\n", script);
webkit_web_view_execute_script (WEBKIT_WEB_VIEW (view), script);
- view->empty = FALSE;
+ view->priv->empty = FALSE;
g_free (script);
g_free (escaped);
}
@@ -273,7 +334,7 @@ gboolean gtk_webview_is_empty (GtkWebVie
gboolean gtk_webview_is_empty (GtkWebView *view)
{
- return view->empty;
+ return view->priv->empty;
}
GType gtk_webview_get_type ()
============================================================
--- pidgin/gtkwebview.h 880d9d0c7cebe81016a981c5ff5b0bd90a92dcd8
+++ pidgin/gtkwebview.h 7eff41f8e630dcc136da096d3716aac2147bf8b2
@@ -35,17 +35,17 @@
#define GTK_WEBVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_WEBVIEW, GtkWebView))
#define GTK_WEBVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_WEBVIEW, GtkWebViewClass))
#define GTK_IS_WEBVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_WEBVIEW))
-#define GTK_IS_IMHTML_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_WEBVIEW))
+#define GTK_IS_WEBVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_WEBVIEW))
+struct GtkWebViewPriv;
+
struct _GtkWebView
{
WebKitWebView webkit_web_view;
/*< private >*/
- GHashTable *images; /**< a map from id to temporary file for the image */
- gboolean empty; /**< whether anything has been appended **/
- char *script_return; /**< the last value returned from a script **/
+ struct GtkWebViewPriv* priv;
};
typedef struct _GtkWebView GtkWebView;
@@ -106,7 +106,8 @@ gboolean gtk_webview_is_empty (GtkWebVie
* Executes javascript and returns the answer of the script
* formatted as string. The return value needs to be freed using
* g_free. If the return values is not required you may instead
- * use webkit_web_view_execute_script.
+ * use webkit_web_view_execute_script, or even better
+ * gtk_webview_safe_execute_script.
*
* @param webview The GtkWebView object
* @param script The JavaScript to execute
@@ -116,6 +117,18 @@ char* gtk_webview_execute_script (GtkWeb
char* gtk_webview_execute_script (GtkWebView *webview, const char *script);
/**
+ * Execute the JavaScript only after the webkit_webview_load_string
+ * loads completely. We also guarantee that the scripts are executed
+ * in the order they are called here.This is useful to avoid race
+ * conditions when calls JS functions immediately after opening the
+ * page.
+ *
+ * @param webview the GtkWebView object
+ * @param script the script to execute
+ */
+void gtk_webview_safe_execute_script (GtkWebView *webview, const char* script);
+
+/**
* Get the current contents of the GtkWebView object.
*
* @param webview The GtkWebView object
============================================================
--- pidgin/plugins/adiumthemes/webkit.c af9afabb36a40ef4ea56624f2ca518e6f4cf0159
+++ pidgin/plugins/adiumthemes/webkit.c ebd963b2a5149f5328992628e9fa1ca1fb88e149
@@ -564,7 +564,7 @@ static gboolean webkit_on_displaying_im_
wk_script->script = script;
wk_script->webkit = webkit;
- purple_webkit_execute_script (wk_script);
+ g_idle_add (purple_webkit_execute_script, wk_script);
g_free(smileyed);
g_free(msg);
More information about the Commits
mailing list