Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I safely use WebKitGTK from a forked thread?

I'm trying to make a simple app in Haskell using GTK3 and WebKit. This code creates and shows a window containing a WebView inside, which displays a random number each time a key gets pressed.

import           Control.Monad.Trans (lift)
import           Control.Concurrent (forkOS)
import           System.Random (randomIO)
import           Graphics.UI.Gtk                   -- gtk3
import           Graphics.UI.Gtk.WebKit.WebView    -- webkitgtk3


main = forkOS $ do

  -- Init GTK.
  initGUI

  -- Create a window which would finish the GTK loop
  -- after being closed.
  window <- windowNew
  window `after` objectDestroy $
    mainQuit

  -- Create a WebView inside.
  webView <- webViewNew
  set window [containerChild := webView]

  -- Make the WebView display a random number on key press.
  webView `on` keyReleaseEvent $ lift $ do
    x <- randomIO :: IO Int
    webViewLoadString webView (show x) Nothing Nothing ""
    return True

  -- Run GTK.
  widgetShowAll window
  mainGUI

When I run it in GHCi (7.8.3), it works fine. However, when I run it again without quitting GHCi, the WebView never shows anything – just plain white area. This is upsetting, as I like to tinker with code in GHCi.

Of course, everything works just fine if I don't use forkOS and run the whole thing in the main thread. What's the reason for this limitation (I thought all GTK functions considered the “main” thread to be the one in which initGUI was called), and can it be overcome somehow?

like image 817
Artyom Avatar asked Jul 27 '14 01:07

Artyom


1 Answers

If it works like python(I don't know haskell) you should keep the gtk main loop in the main thread.

In your second thread call g_idle_add with a callback to make changes with gtk, and transport data between your second thread, and gtk. You should start your non-main thread before gtk main so it's not blocked.

I'm sure there is a binding of g_idle_add in haskell. There is also g_timeout_add which works for this too.

This all has something to do with gtk not being thread safe.

like image 59
Quentin Engles Avatar answered Sep 28 '22 20:09

Quentin Engles