changeset 2006:6f1adc77de02

GTK: Added DW_SIGNAL_HTML_CHANGED and DW_SIGNAL_HTML_RESULT. Added dw_html_javascript_run(). Full support on GTK3 using WebKit2 and partial support for WebKit1. Will port to GTK2 when WebKit1 support is complete. Mac and Windows versions coming soon.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Wed, 06 Nov 2019 13:09:31 +0000
parents a17cc1958369
children 3a26e6f6691d
files dw.h gtk3/dw.c
diffstat 2 files changed, 194 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/dw.h	Wed Nov 06 08:48:49 2019 +0000
+++ b/dw.h	Wed Nov 06 13:09:31 2019 +0000
@@ -56,6 +56,8 @@
 #define DW_SIGNAL_SWITCH_PAGE    "switch-page"
 #define DW_SIGNAL_COLUMN_CLICK   "click-column"
 #define DW_SIGNAL_TREE_EXPAND    "tree-expand"
+#define DW_SIGNAL_HTML_CHANGED   "html-changed"
+#define DW_SIGNAL_HTML_RESULT    "html-result"
 
 /* status of menu items */
 #define DW_MIS_ENABLED           1
@@ -1443,6 +1445,12 @@
 #define DW_HTML_STOP       5
 #define DW_HTML_PRINT      6
 
+/* Embedded HTML notifcations */
+#define DW_HTML_CHANGE_STARTED  1
+#define DW_HTML_CHANGE_REDIRECT 2
+#define DW_HTML_CHANGE_LOADING  3
+#define DW_HTML_CHANGE_COMPLETE 4
+
 /* Drawing flags  */
 #define DW_DRAW_DEFAULT    0
 #define DW_DRAW_FILL       1
@@ -1809,6 +1817,7 @@
 void API dw_html_action(HWND hwnd, int action);
 int API dw_html_raw(HWND hwnd, char *string);
 int API dw_html_url(HWND hwnd, char *url);
+int API dw_html_javascript_run(HWND hwnd, char *script, void *scriptdata);
 HWND API dw_html_new(unsigned long id);
 char * API dw_clipboard_get_text(void);
 void API dw_clipboard_set_text( char *str, int len );
--- a/gtk3/dw.c	Wed Nov 06 08:48:49 2019 +0000
+++ b/gtk3/dw.c	Wed Nov 06 13:09:31 2019 +0000
@@ -160,6 +160,14 @@
 static gint _tree_expand_event(GtkTreeView *treeview, GtkTreeIter *arg1, GtkTreePath *arg2, gpointer data);
 static gint _switch_page_event(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer data);
 static gint _column_click_event(GtkWidget *widget, gpointer data);
+static void _html_result_event(GObject *object, GAsyncResult *result, gpointer script_data);
+#ifdef USE_WEBKIT
+#ifdef USE_WEBKIT2
+static void _html_changed_event(WebKitWebView  *web_view, WebKitLoadEvent load_event, gpointer data);
+#else
+static void _html_changed_event(WebKitWebView  *web_view, WebKitWebFrame *frame, gpointer user_data);
+#endif
+#endif
 static void _dw_signal_disconnect(gpointer data, GClosure *closure);
 
 GObject *_DWObject = NULL;
@@ -183,7 +191,7 @@
 
 } SignalHandler;
 
-#define SIGNALMAX 18
+#define SIGNALMAX 20
 
 /* A list of signal forwarders, to account for paramater differences. */
 static SignalList SignalTranslate[SIGNALMAX] = {
@@ -204,7 +212,13 @@
    { _value_changed_event,     DW_SIGNAL_VALUE_CHANGED },
    { _switch_page_event,       DW_SIGNAL_SWITCH_PAGE },
    { _column_click_event,      DW_SIGNAL_COLUMN_CLICK },
-   { _tree_expand_event,       DW_SIGNAL_TREE_EXPAND }
+   { _tree_expand_event,       DW_SIGNAL_TREE_EXPAND },
+#ifdef USE_WEBKIT
+   { _html_changed_event,      DW_SIGNAL_HTML_CHANGED },
+#else
+   { _generic_event,           DW_SIGNAL_HTML_CHANGED },
+#endif
+   { _html_result_event,       DW_SIGNAL_HTML_RESULT }
 };
 
 /* Alignment flags */
@@ -1185,6 +1199,109 @@
    g_object_set_data(G_OBJECT(widget), text, GINT_TO_POINTER(cid));
 }
 
+static void _html_result_event(GObject *object, GAsyncResult *result, gpointer script_data)
+{
+#if USE_WEBKIT2
+    WebKitJavascriptResult *js_result;
+    JSCValue *value;
+    GError *error = NULL;
+    int (*htmlresultfunc)(HWND, int, char *, void *, void *) = NULL;
+    gint handlerdata = GPOINTER_TO_INT(g_object_get_data(object, "_dw_html_result_id"));
+    void *user_data = NULL;
+
+    if(handlerdata)
+    {
+        SignalHandler work;
+        void *params[3] = { GINT_TO_POINTER(handlerdata-1), 0, object };
+
+        work = _get_signal_handler(params);
+
+        if(work.window)
+        {
+            htmlresultfunc = work.func;
+            user_data = work.data;
+        }
+    }
+
+    if(!(js_result = webkit_web_view_run_javascript_finish(WEBKIT_WEB_VIEW(object), result, &error)))
+    {
+        if(htmlresultfunc)
+           htmlresultfunc((HWND)object, DW_ERROR_UNKNOWN, error->message, user_data, script_data);
+        g_error_free (error);
+        return;
+    }
+
+    value = webkit_javascript_result_get_js_value(js_result);
+    if(jsc_value_is_string(value)) 
+    {
+        gchar *str_value = jsc_value_to_string(value);
+        JSCException *exception = jsc_context_get_exception(jsc_value_get_context(value));
+        
+        if(htmlresultfunc)
+        {
+           if(exception)
+               htmlresultfunc((HWND)object, DW_ERROR_UNKNOWN, (char *)jsc_exception_get_message(exception), user_data, script_data);
+           else
+               htmlresultfunc((HWND)object, DW_ERROR_NONE, str_value, user_data, script_data);
+        }
+        g_free (str_value);
+    } 
+    else if(htmlresultfunc)
+        htmlresultfunc((HWND)object, DW_ERROR_UNKNOWN, "Unknown javascript error", user_data, script_data);
+    webkit_javascript_result_unref (js_result);
+#endif
+}
+
+#ifdef USE_WEBKIT
+#ifdef USE_WEBKIT2
+static void _html_changed_event(WebKitWebView  *web_view, WebKitLoadEvent load_event, gpointer data)
+{
+    SignalHandler work = _get_signal_handler(data);
+    char *location = (char *)webkit_web_view_get_uri(web_view);
+    int status = 0;
+    
+    switch (load_event) {
+    case WEBKIT_LOAD_STARTED:
+        status = DW_HTML_CHANGE_STARTED;
+        break;
+    case WEBKIT_LOAD_REDIRECTED:
+        status = DW_HTML_CHANGE_REDIRECT;
+        break;
+    case WEBKIT_LOAD_COMMITTED:
+        status = DW_HTML_CHANGE_LOADING;
+        break;
+    case WEBKIT_LOAD_FINISHED:
+        status = DW_HTML_CHANGE_COMPLETE;
+        break;
+    }
+    if(status && location && work.window && work.func)
+    {
+        int (*htmlchangedfunc)(HWND, int, char *, void *) = work.func;
+        
+        htmlchangedfunc(work.window, status, location, work.data);
+    }
+}
+#else
+static void _html_changed_event(WebKitWebView  *web_view, WebKitWebFrame *frame, gpointer data)
+{
+    SignalHandler work = _get_signal_handler(data);
+    char *location = (char *)webkit_web_view_get_uri(web_view);
+    int status = 0;
+    void **params = data;
+    
+    if(params)
+      status = DW_POINTER_TO_INT(params[1]);
+      
+    if(status && location && work.window && work.func)
+    {
+        int (*htmlchangedfunc)(HWND, int, char *, void *) = work.func;
+        
+        htmlchangedfunc(work.window, status, location, work.data);
+    }
+}
+#endif
+#endif
+
 static gint _set_focus_event(GtkWindow *window, GtkWidget *widget, gpointer data)
 {
    SignalHandler work = _get_signal_handler(data);
@@ -11302,6 +11419,7 @@
 #ifdef USE_WEBKIT2
                WebKitPrintOperation *operation = webkit_print_operation_new(web_view);
                webkit_print_operation_run_dialog(operation, NULL);
+               g_object_unref(operation);
 #else         
                WebKitWebFrame *frame = webkit_web_view_get_focused_frame(web_view);
                webkit_web_frame_print(frame);
@@ -11378,6 +11496,32 @@
 #endif
 }
 
+/*
+ * Executes the javascript contained in "script" in the HTML window.
+ * Parameters:
+ *       handle: Handle to the HTML window.
+ *       script: Javascript code to execute.
+ *       scriptdata: Data passed to the signal handler.
+ * Notes: A DW_SIGNAL_HTML_RESULT event will be raised with scriptdata.
+ * Returns:
+ *       DW_ERROR_NONE (0) on success.
+ */
+int dw_html_javascript_run(HWND handle, char *script, void *scriptdata)
+{
+#ifdef USE_WEBKIT2
+   int _locked_by_me = FALSE;
+   WebKitWebView *web_view;
+   
+   DW_MUTEX_LOCK;
+   if((web_view = _dw_html_web_view(handle)))
+      webkit_web_view_run_javascript (web_view, script, NULL, _html_result_event, scriptdata);
+   DW_MUTEX_UNLOCK;
+   return DW_ERROR_NONE;
+#else
+   return DW_ERROR_UNKNOWN;
+#endif
+}
+
 #if defined(USE_WEBKIT) && !defined(USE_WEBKIT2)
 static void _dw_html_print_cb(GtkWidget *widget, gpointer *data)
 {
@@ -11902,6 +12046,45 @@
       if (GTK_IS_COMBO_BOX(thiswindow))
          thiswindow = gtk_bin_get_child(GTK_BIN(thiswindow));
    }
+#ifdef USE_WEBKIT
+   else if (WEBKIT_IS_WEB_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_HTML_CHANGED) == 0)
+   {
+#ifdef USE_WEBKIT2
+      thisname = "load-changed";
+#else
+      sigid = _set_signal_handler(thiswindow, window, sigfunc, data, thisfunc, discfunc);
+      params[0] = GINT_TO_POINTER(sigid);
+      params[1] = GINT_TO_POINTER(DW_HTML_CHANGE_STARTED);
+      params[2] = (void *)thiswindow;
+      cid = g_signal_connect_data(G_OBJECT(thiswindow), "load-started", G_CALLBACK(thisfunc), params, _dw_signal_disconnect, 0);
+      _set_signal_handler_id(thiswindow, sigid, cid);
+
+      params = calloc(sizeof(void *), 3);
+
+      sigid = _set_signal_handler(thiswindow, window, sigfunc, data, thisfunc, discfunc);
+      params[0] = GINT_TO_POINTER(sigid);
+      params[1] = GINT_TO_POINTER(DW_HTML_CHANGE_LOADING);
+      params[2] = (void *)thiswindow;
+      cid = g_signal_connect_data(G_OBJECT(thiswindow), "load-committed", G_CALLBACK(thisfunc), params, _dw_signal_disconnect, 0);
+      _set_signal_handler_id(thiswindow, sigid, cid);
+
+      params = calloc(sizeof(void *), 3);
+      params[1] = GINT_TO_POINTER(DW_HTML_CHANGE_COMPLETE);
+
+      thisname = "load-finished";
+#endif
+   }
+   else if (WEBKIT_IS_WEB_VIEW(thiswindow) && strcmp(signame, DW_SIGNAL_HTML_RESULT) == 0)
+   {
+      /* We don't actually need a signal handler here... just need to assign the handler ID
+       * Since the handler is created in dw_html_javasript_run()
+       */
+      sigid = _set_signal_handler(thiswindow, window, sigfunc, data, _html_result_event, discfunc);
+      g_object_set_data(G_OBJECT(thiswindow), "_dw_html_result_id", GINT_TO_POINTER(sigid+1));
+      DW_MUTEX_UNLOCK;
+      return;
+   }
+#endif
 #if 0
    else if (strcmp(signame, DW_SIGNAL_LOSE_FOCUS) == 0)
    {