forked from marko/svitak
add worker thread tracking
add stGen which gets bumped for every worker thread spawned by loadBook every thread captures stGen when it spawns and before actually loading the book in the main thread, and in the worker thread it checks if myGen == stGen this throws away stale requests, meaning if you try and load another book while one is still loading, it will ignore the one still loading and start loading the latest request
This commit is contained in:
parent
f6ec5c20d8
commit
81c2caaf67
3 changed files with 39 additions and 26 deletions
|
|
@ -18,5 +18,6 @@ initialState title path =
|
|||
stIndex = ChapterIndex 0,
|
||||
stZoom = 1.0,
|
||||
stTitle = title,
|
||||
stBookPath = path
|
||||
stBookPath = path,
|
||||
stGen = 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import Control.Monad.Except (ExceptT)
|
|||
import Control.Monad.Reader (ReaderT)
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified Data.Text as T
|
||||
|
||||
-- | Position of a chapter within the linear reading order (the spine).
|
||||
newtype ChapterIndex = ChapterIndex Int
|
||||
deriving (Show, Eq, Ord, Num)
|
||||
|
|
@ -99,7 +98,8 @@ data AppState = AppState
|
|||
stIndex :: ChapterIndex,
|
||||
stZoom :: Double,
|
||||
stTitle :: T.Text,
|
||||
stBookPath :: FilePath
|
||||
stBookPath :: FilePath,
|
||||
stGen :: Int
|
||||
}
|
||||
|
||||
-- | A user request, produced by the keyboard / sidebar and handled centrally.
|
||||
|
|
|
|||
58
app/UI.hs
58
app/UI.hs
|
|
@ -7,14 +7,14 @@
|
|||
module UI (runApp) where
|
||||
|
||||
import Control.Concurrent.Async (async)
|
||||
import Control.Concurrent.STM (TVar, atomically, modifyTVar', newTVarIO, readTVarIO, writeTVar)
|
||||
import Control.Concurrent.STM (TVar, atomically, modifyTVar', newTVarIO, readTVarIO, writeTVar, readTVar)
|
||||
import Control.Monad (unless, void, when)
|
||||
import Data.GI.Base (AttrOp (..), on)
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified Data.Text as T
|
||||
import Data.Word (Word32)
|
||||
import Control.Exception (SomeException, try)
|
||||
import EpubParser (EpubEnv, openEpub)
|
||||
import EpubParser (EpubEnv, openEpub) -- brings the `BookInfo EpubEnv` instance into scope
|
||||
import qualified GI.GLib as GLib
|
||||
import qualified GI.GLib.Constants as GLibConst
|
||||
import qualified GI.Gdk as Gdk
|
||||
|
|
@ -168,27 +168,39 @@ wireEvents ctx = do
|
|||
-- | Load the book's structure off the GTK thread, then populate the sidebar
|
||||
-- and open the first (or last-read) chapter back on the main loop.
|
||||
loadBook :: (BookInfo a) => a -> Ctx -> IO ()
|
||||
loadBook env ctx = void $
|
||||
async $ do
|
||||
result <- loadStructure env
|
||||
case result of
|
||||
Left err -> putStrLn ("Failed to load book: " ++ err)
|
||||
Right (BookStructure refs toc) -> do
|
||||
atomically $ do
|
||||
modifyTVar' (ctxState ctx) $ \s ->
|
||||
s { stRefs = refs,
|
||||
stToc = toc,
|
||||
stCache = M.empty,
|
||||
stIndex = ChapterIndex 0 }
|
||||
writeTVar (ctxRender ctx) (renderChapter env)
|
||||
postGtk $ do
|
||||
Gtk.listBoxRemoveAll (appSidebar (ctxWidgets ctx))
|
||||
populateSidebar (appSidebar (ctxWidgets ctx)) (displayRows refs toc)
|
||||
saved <- loadLastRead
|
||||
let start = case saved of
|
||||
Just (path, idx) | path == bookFilePath env -> idx
|
||||
_ -> ChapterIndex 0
|
||||
handleAction ctx (GoToChapter start "")
|
||||
loadBook env ctx = do
|
||||
myGen <- atomically $ do
|
||||
s <- readTVar (ctxState ctx)
|
||||
let g = stGen s + 1
|
||||
writeTVar (ctxState ctx) (s {stGen = g})
|
||||
pure g
|
||||
void $
|
||||
async $ do
|
||||
result <- loadStructure env
|
||||
case result of
|
||||
Left err -> putStrLn ("Failed to load book: " ++ err)
|
||||
Right (BookStructure refs toc) -> do
|
||||
committed <- atomically $ do
|
||||
s <- readTVar (ctxState ctx)
|
||||
let mine = stGen s == myGen
|
||||
when mine $ do
|
||||
writeTVar (ctxState ctx)
|
||||
(s { stRefs = refs, stToc = toc,
|
||||
stCache = M.empty, stIndex = ChapterIndex 0,
|
||||
stTitle = bookTitle env, stBookPath = bookFilePath env})
|
||||
writeTVar (ctxRender ctx) (renderChapter env)
|
||||
pure mine
|
||||
|
||||
when committed $ postGtk $ do
|
||||
s <- readTVarIO (ctxState ctx)
|
||||
when (stGen s == myGen) $ do
|
||||
Gtk.listBoxRemoveAll (appSidebar (ctxWidgets ctx))
|
||||
populateSidebar (appSidebar (ctxWidgets ctx)) (displayRows refs toc)
|
||||
saved <- loadLastRead
|
||||
let start = case saved of
|
||||
Just (path, idx) | path == bookFilePath env -> idx
|
||||
_ -> ChapterIndex 0
|
||||
handleAction ctx (GoToChapter start "")
|
||||
|
||||
epPicker :: Maybe Gtk.ApplicationWindow -> Ctx -> IO ()
|
||||
epPicker window ctx = do
|
||||
|
|
|
|||
Loading…
Reference in a new issue