2014-07-27 12 views
8

Sto provando a creare una semplice app in Haskell usando GTK3 e WebKit. Questo codice crea e mostra una finestra contenente uno WebView all'interno, che visualizza un numero casuale ogni volta che viene premuto un tasto.Come posso utilizzare WebKitGTK in modo sicuro da un thread a forcella?

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 

Quando lo eseguo in GHCi (7.8.3), funziona correttamente. Tuttavia, quando lo eseguo di nuovo senza uscire da GHCi, lo WebView non mostra mai nulla - solo un'area bianca. Questo è sconvolgente, perché mi piace armeggiare con il codice in GHCi.

Ovviamente, tutto funziona perfettamente se non utilizzo forkOS ed eseguo il tutto nel thread principale. Qual è la ragione di questa limitazione (ho pensato che tutte le funzioni GTK consideravano il thread "principale" quello in cui è stato chiamato lo initGUI) e può essere superato in qualche modo?

+0

Potrebbe essere necessario eseguire esplicitamente il thread associato con 'Control.Concurrent.runInBoundThread'. – vivian

+0

@vivian: potresti ampliarlo? Ho pensato a questo, ma aggiungendo 'runInBoundThread' poco prima o dopo' forkOS' non ha aiutato, e l'aggiunta di 'print = << isCurrentThreadBound' ha dimostrato che il thread era già limitato. – Artyom

+0

Funziona come previsto al di fuori di GHCi? Probabilmente alcuni loop di eventi vengono arrestati e non riavviati quando lo si esegue due volte all'interno di un singolo processo. –

risposta

1

Se funziona come python (non conosco haskell) è necessario conservare lo gtk main loop nello main thread.

Nella seconda chiamata filo g_idle_add con un callback per apportare modifiche con GTK, e transport data between vostra second thread e gtk. È necessario iniziare la filettatura non principale prima del gtk main in modo che non sia bloccata.

Sono sicuro che c'è un binding di g_idle_add in haskell. C'è anche g_timeout_add che funziona anche per questo.

Tutto questo ha qualcosa a che fare con gtk non essendo thread-safe.

Problemi correlati