8

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?

Emily
  • 2,577
  • 18
  • 38
  • You may need to explicitly run in the bound thread with `Control.Concurrent.runInBoundThread`. – vivian Jul 27 '14 at 02:44
  • @vivian: could you expand on that? I thought about this, but adding `runInBoundThread` right before or after `forkOS` didn't help, and adding `print =<< isCurrentThreadBound` showed that the thread was already bounded. – Emily Jul 27 '14 at 03:03
  • Does it work as expected outside of GHCi? Probably some event loop is getting stopped and not restarted when you run it twice within a single process. – Boyd Stephen Smith Jr. Jul 28 '14 at 16:10
  • @BoydStephenSmithJr. outside of GHCi it doesn't even show the window the 2nd time, just exits immediately. – Emily Jul 28 '14 at 20:18

1 Answers1

1

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.

Quentin Engles
  • 2,744
  • 1
  • 20
  • 33