2014-07-27 4 views
8

Ich versuche eine einfache App in Haskell mit GTK3 und WebKit zu machen. Dieser Code erstellt und zeigt ein Fenster mit einer WebView Innenseite, die bei jedem Tastendruck eine Zufallszahl anzeigt.Wie kann ich WebKitGTK sicher von einem gegabelten Thread verwenden?

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 

Wenn ich es in GHCi (7.8.3) ausführen, funktioniert es gut. Jedoch, wenn ich es wieder laufen lasse, ohne GHCi zu verlassen, zeigt der WebView nie etwas - einfach nur weißen Bereich. Das ist ärgerlich, da ich gerne mit Code in GHCi bastele.

Natürlich funktioniert alles gut, wenn ich 10 nicht benutze und das Ganze im Hauptthread ablaufen lasse. Was ist der Grund für diese Einschränkung (ich dachte, dass alle GTK-Funktionen der "Haupt" -Thread sind, der derjenige ist, in dem initGUI aufgerufen wurde), und kann es irgendwie überwunden werden?

+0

Möglicherweise müssen Sie explizit im gebundenen Thread mit 'Control.Concurrent.runInBoundThread' ausführen. – vivian

+0

@vivian: Könnten Sie das weiter ausbauen? Ich dachte darüber nach, aber das Hinzufügen von 'runInBoundThread' direkt vor oder nach' forkOS' half nicht, und das Hinzufügen von 'print = << isCurrentThreadBound' zeigte, dass der Thread bereits begrenzt war. – Artyom

+0

Funktioniert es außerhalb von GHCi wie erwartet? Wahrscheinlich wird eine Ereignisschleife gestoppt und nicht erneut gestartet, wenn Sie sie zweimal innerhalb eines einzelnen Prozesses ausführen. –

Antwort

1

Wenn es wie Python funktioniert (ich weiß nicht, Haskell) sollten Sie die gtk main loop in der main thread halten.

In Ihrem zweiten Thread Anruf g_idle_add mit einem Rückruf Änderungen mit gtk zu machen, und transport data between Ihre second thread und gtk. Sie sollten Ihren Nicht-Haupt-Thread vor gtk main starten, damit er nicht blockiert wird.

Ich bin sicher, es gibt eine Bindung von g_idle_add in Haskell. Es gibt auch g_timeout_add, das auch dafür funktioniert.

Das alles hat etwas damit zu tun, dass gtk nicht threadsicher ist.