2
votes

I am creating an application where the GUI is presented using HTML and JavaScript and the button actions need to interact with hardware attached via USB. I have all the hardware related functions as a shared library (.so) files.
OS: Ubuntu Server 12.04
IDE: Eclipse Juno
Language: C, JavaScript
Libraries: GTK, Webkit Webview

I am using DOM node traversal to iterate through the controls in the HTML page. I am able to get the buttons using values, but am unable to successfully add events to the button clicks. The HTML page and the corresponding GTK C code are as below.

<html>

<head>
<script type="text/javascript">

    function read()
    {
        alert( 'Read called' );
    }

    function configure()
    {
        alert( 'configure called' );
    }

</script>

<h1> <font color="white"> GTK WebKit </font> </h1>
</head>

<body>
    <label id="labelStep1"> <font color="white" size="4"> Step 1: </font> </label>
    <input type="button" onclick="configure()" value="Configure">

    </br>
    <label id="labelStep2"> <font color="white" size="4"> Step 2: </font> </label>
    <input type="button" onclick="read()" value="Read"> <font color="white" size="6"> </font> </input>

    </br>
    </br>
</body>

</html>

GTK.c:

#include <gtk/gtk.h>
#include <webkit/webkit.h>
#include <webkit/webkitwebview.h>


static void destroyWindow(GtkWidget *pWidget1, GtkWidget *pWidget2);
static gboolean closeWebViewCB(WebKitWebView *pWebView, GtkWidget *pWindow);
static void loadStatusCB(WebKitWebView *pWebView, GParamSpec *pSpec, void *pContext);

 int main (int argc, char *argv[])
 {
    GtkWidget *window;
    GtkWidget *label;

    gtk_init (&argc, &argv);

    /* create the main, top level, window */
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_resize(window, 1024, 768);

    WebKitWebView *pWebView = WEBKIT_WEB_VIEW(webkit_web_view_new());
    GtkWidget *pscrolledWnd = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pscrolledWnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    gtk_window_resize(pscrolledWnd, 1024, 768);

    gtk_container_add(GTK_CONTAINER(pscrolledWnd), GTK_WIDGET(pWebView));
    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(pscrolledWnd));

    webkit_web_view_load_uri(pWebView, "file:///home/developer/Desktop/Dan/workspace/GTK+/Resources/WebViewGTK.html");

    gtk_widget_grab_focus(GTK_WIDGET(pWebView));

    /* give it the title */
    gtk_window_set_title (GTK_WINDOW (window), "GTK WebKit");

    /* Connect the destroy signal of the window to gtk_main_quit
     * When the window is about to be destroyed we get a notification and
     * stop the main GTK+ loop
     */
    g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
    g_signal_connect(pWebView, "close-web-view", G_CALLBACK(closeWebViewCB), window);
    g_signal_connect(pWebView, "notify::load-status", G_CALLBACK(loadStatusCB), window);

    /* Create the "Hello, World" label  */
    label = gtk_label_new ("Hello, World");

    /* and insert it into the main window  */
    gtk_container_add (GTK_CONTAINER (window), label);

    /* make sure that everything, window and label, are visible */
    gtk_widget_show_all (window);

    /* start the main loop, and let it rest there until the application is closed */
    gtk_main ();

    return 0;
 }


 static void destroyWindow(GtkWidget *pWidget1, GtkWidget *pWidget2)
 {
     gtk_main_quit();
 }



 static gboolean closeWebViewCB(WebKitWebView *pWebView, GtkWidget *pWindow)
 {
     gtk_widget_destroy(pWindow);
     return 1;
 }



 static gboolean TestCB(WebKitWebView *pWebView, GtkWidget *pWindow)
 {
     GtkWidget *pMsgBox = gtk_message_dialog_new(pWindow, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_YES_NO, "TestCB Called()!");
     gtk_dialog_run(pMsgBox);
     gtk_widget_destroy(pMsgBox);
     return true;
 }




 static void handleWebPageLoadEvents(WebKitWebView *pWebView, void * pContext)
 {
     int nElemIndex         = 0;
     char *pChElemName      = NULL;
     char chMsgBoxText[255] = { 0 };
     static int nEventAddCallCount = 0;

     GtkWidget *pMsgBox = NULL;//gtk_message_dialog_new(pContext, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, chMsgBoxText /*"handleWebPageLoadEvents Called()!"*/);

     WebKitDOMDocument *pDoc = webkit_web_view_get_dom_document(pWebView);
     WebKitDOMNodeList *pDomNodeList = webkit_dom_document_get_elements_by_tag_name(pDoc, "*");
     gulong elements_Count = webkit_dom_node_list_get_length(pDomNodeList);

     for(nElemIndex = 0; nElemIndex < elements_Count; nElemIndex ++)
     {
         WebKitDOMNode *pElement = webkit_dom_node_list_item(pDomNodeList, nElemIndex);
         if(WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(pElement))
         {
             g_object_get(pElement, "value", & pChElemName, NULL);

             if(NULL != pChElemName)
             {

                 if(g_str_equal("Configure", pChElemName) )
                 {
                     if(webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(pElement), pChElemName, G_CALLBACK(TestCB), false, pContext) )
                         sprintf(chMsgBoxText, "webkit_dom_event_target_add_event_listener  --> %s --> OK", pChElemName);
                     else sprintf(chMsgBoxText, "webkit_dom_event_target_add_event_listener  --> %s --> FAILED", pChElemName);
                 }

                 if(g_str_equal("Read", pChElemName) )
                 {
                     if( webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(pElement), /*pChElemName*/ "Read", G_CALLBACK(TestCB), false, pContext) )
                         sprintf(chMsgBoxText, "webkit_dom_event_target_add_event_listener  --> %s --> OK", pChElemName);
                     else sprintf(chMsgBoxText, "webkit_dom_event_target_add_event_listener  --> %s --> FAILED", pChElemName);
                 }

                 pMsgBox = gtk_message_dialog_new(pContext, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, chMsgBoxText);
                 gtk_dialog_run(pMsgBox);
                 gtk_widget_destroy(pMsgBox);

                 if(pChElemName)
                     g_free(pChElemName);
             }
         }
     }

     g_object_unref(pDomNodeList);
 }




 static void loadStatusCB(WebKitWebView *pWebView, GParamSpec *pSpec, void *pContext)
 {
     char                   Msg[64]     = { 0 };
     static unsigned int    nCounter    = 0;

     WebKitLoadStatus status = webkit_web_view_get_load_status(pWebView);
     //GObject *pObject = G_OBJECT(pWebView);

     g_object_freeze_notify(pContext);

     switch(status)
     {
     case WEBKIT_LOAD_FINISHED:
         sprintf(Msg, "WEBKIT_LOAD_FINISHED~%d", nCounter);
         handleWebPageLoadEvents(pWebView, pContext);
         break;

     case WEBKIT_LOAD_PROVISIONAL:
         sprintf(Msg, "WEBKIT_LOAD_PROVISIONAL~%d", nCounter);
         break;

     case WEBKIT_LOAD_COMMITTED:
         sprintf(Msg, "WEBKIT_LOAD_COMMITTED~%d", nCounter);
         break;

     case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT:
         sprintf(Msg, "WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT~%d", nCounter);
         break;

     case WEBKIT_LOAD_FAILED:
         sprintf(Msg, "WEBKIT_LOAD_FAILED~%d", nCounter);
         break;

     default:
         sprintf(Msg, "default~%d", nCounter);
         break;
     }
 }

I am very new to GTK, so any help is appreciated.

Regards.

1
I've never used gtk with a webview but I'm guessing you still have to associate a callback function with a button click in html. If you can access the buttons on the webview side from the gtk side then it shouldn't be too hard to attach a callback. - thomas.cloud
If you want to learn how to communicate between webkit/javascript and gtk, you may check out a demo project of mine, gtk-webbrowser, github.com/LiuLang/gtk-webbrowser - LiuLang
@thomas.cloud: Yes, I want to associate a callback with a button click and that's exactly what I am trying to achieve through the code I pasted in my question. According to live.gnome.org/WebKitGtk/ProgrammingGuide/Cookbook I should be able to do that with webkit_dom_event_target_add_event_listener(). I use the same code as reference but I am doing something wrong and am lost. - aeon
@LiuLang: I will certainly check your project. Thanks. Is it possible to have a button click event in JavaScript, loaded in a Webkit WebView control, call a C++ function without any intermediate scripts? - aeon

1 Answers

1
votes

I think you are confusing element name and/or action with HTML event. You should be using click event to get notified about button click. So code should look something like

webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(pElement), "click", G_CALLBACK(TestCB), false, pContext)

There is a example at https://live.gnome.org/WebKitGtk/ProgrammingGuide/Cookbook.

Alternatively if you want to do it using alerts, take a look at script-alert signal of web view. Your callback will be called using the alert message. Python based example of using script-alert signal at https://github.com/nhrdl/notesMD