diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,28 @@
 # Change Log / Release Notes
 
+## 0.14 (July 30, 2018)
+
+### Bug Fixes
+
+  * The state file that xmonad uses while restarting itself is now
+    removed after it is processed.  This fixes a bug that manifested
+    in several different ways:
+
+    - Names of old workspaces would be resurrected after a restart
+    - Screen sizes would be wrong after changing monitor configuration (#90)
+    - `spawnOnce` stopped working (xmonad/xmonad-contrib#155)
+    - Focus did not follow when moving between workspaces (#87)
+    - etc.
+
+  * Recover old behavior (in 0.12) when `focusFollowsMouse == True`:
+    the focus follows when the mouse enters another workspace
+    but not moving into any window.
+
+  * Compiles with GHC 8.4.1
+
+  * Restored compatability with GHC version prior to 8.0.1 by removing the
+    dependency on directory version 1.2.3.
+
 ## 0.13 (February 10, 2017)
 
 ### Breaking Changes
diff --git a/src/XMonad/Config.hs b/src/XMonad/Config.hs
--- a/src/XMonad/Config.hs
+++ b/src/XMonad/Config.hs
@@ -221,9 +221,9 @@
     , ((modMask .|. shiftMask, xK_q     ), io (exitWith ExitSuccess)) -- %! Quit xmonad
     , ((modMask              , xK_q     ), spawn "if type xmonad; then xmonad --recompile && xmonad --restart; else xmessage xmonad not in \\$PATH: \"$PATH\"; fi") -- %! Restart xmonad
 
-    , ((modMask .|. shiftMask, xK_slash ), spawn ("echo \"" ++ help ++ "\" | xmessage -file -")) -- %! Run xmessage with a summary of the default keybindings (useful for beginners)
+    , ((modMask .|. shiftMask, xK_slash ), helpCommand)
     -- repeat the binding for non-American layout keyboards
-    , ((modMask              , xK_question), spawn ("echo \"" ++ help ++ "\" | xmessage -file -"))
+    , ((modMask              , xK_question), helpCommand)
     ]
     ++
     -- mod-[1..9] %! Switch to workspace N
@@ -237,6 +237,9 @@
     [((m .|. modMask, key), screenWorkspace sc >>= flip whenJust (windows . f))
         | (key, sc) <- zip [xK_w, xK_e, xK_r] [0..]
         , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]
+  where
+    helpCommand :: X ()
+    helpCommand = spawn ("echo " ++ show help ++ " | xmessage -file -")  -- %! Run xmessage with a summary of the default keybindings (useful for beginners)
 
 -- | Mouse bindings: default actions bound to mouse events
 mouseBindings :: XConfig Layout -> M.Map (KeyMask, Button) (Window -> X ())
diff --git a/src/XMonad/Core.hs b/src/XMonad/Core.hs
--- a/src/XMonad/Core.hs
+++ b/src/XMonad/Core.hs
@@ -39,6 +39,7 @@
 import Control.Applicative
 import Control.Monad.State
 import Control.Monad.Reader
+import Data.Semigroup
 import Data.Default
 import System.FilePath
 import System.IO
@@ -56,7 +57,8 @@
 import Data.Typeable
 import Data.List ((\\))
 import Data.Maybe (isJust,fromMaybe)
-import Data.Monoid
+import Data.Monoid hiding ((<>))
+import System.Environment (lookupEnv)
 
 import qualified Data.Map as M
 import qualified Data.Set as S
@@ -71,7 +73,7 @@
     , extensibleState  :: !(M.Map String (Either String StateExtension))
     -- ^ stores custom state information.
     --
-    -- The module "XMonad.Utils.ExtensibleState" in xmonad-contrib
+    -- The module "XMonad.Util.ExtensibleState" in xmonad-contrib
     -- provides additional information and a simple interface for using this.
     }
 
@@ -151,6 +153,9 @@
   pure = return
   (<*>) = ap
 
+instance Semigroup a => Semigroup (X a) where
+    (<>) = liftM2 (<>)
+
 instance (Monoid a) => Monoid (X a) where
     mempty  = return mempty
     mappend = liftM2 mappend
@@ -165,6 +170,9 @@
 runQuery :: Query a -> Window -> X a
 runQuery (Query m) w = runReaderT m w
 
+instance Semigroup a => Semigroup (Query a) where
+    (<>) = liftM2 (<>)
+
 instance Monoid a => Monoid (Query a) where
     mempty  = return mempty
     mappend = liftM2 mappend
@@ -460,7 +468,7 @@
 getXMonadDir =
     findFirstDirWithEnv "XMONAD_CONFIG_DIR"
       [ getAppUserDataDirectory "xmonad"
-      , getXdgDirectory XdgConfig "xmonad"
+      , getXDGDirectory XDGConfig "xmonad"
       ]
 
 -- | Return the path to the xmonad cache directory.  This directory is
@@ -480,7 +488,7 @@
 getXMonadCacheDir =
     findFirstDirWithEnv "XMONAD_CACHE_DIR"
       [ getAppUserDataDirectory "xmonad"
-      , getXdgDirectory XdgCache "xmonad"
+      , getXDGDirectory XDGCache "xmonad"
       ]
 
 -- | Return the path to the xmonad data directory.  This directory is
@@ -500,7 +508,7 @@
 getXMonadDataDir =
     findFirstDirWithEnv "XMONAD_DATA_DIR"
       [ getAppUserDataDirectory "xmonad"
-      , getXdgDirectory XdgData "xmonad"
+      , getXDGDirectory XDGData "xmonad"
       ]
 
 -- | Helper function that will find the first existing directory and
@@ -536,6 +544,27 @@
       Nothing      -> findFirstDirOf paths
       Just envPath -> findFirstDirOf (return envPath:paths)
 
+-- | Helper function to retrieve the various XDG directories.
+-- This has been based on the implementation shipped with GHC version 8.0.1 or
+-- higher. Put here to preserve compatibility with older GHC versions.
+getXDGDirectory :: XDGDirectory -> FilePath -> IO FilePath
+getXDGDirectory xdgDir suffix =
+  normalise . (</> suffix) <$>
+  case xdgDir of
+    XDGData   -> get "XDG_DATA_HOME"   ".local/share"
+    XDGConfig -> get "XDG_CONFIG_HOME" ".config"
+    XDGCache  -> get "XDG_CACHE_HOME"  ".cache"
+  where
+    get name fallback = do
+      env <- lookupEnv name
+      case env of
+        Nothing -> fallback'
+        Just path
+          | isRelative path -> fallback'
+          | otherwise -> return path
+      where
+        fallback' = (</> fallback) <$> getHomeDirectory
+data XDGDirectory = XDGData | XDGConfig | XDGCache
 
 -- | Get the name of the file used to store the xmonad window state.
 stateFileName :: (Functor m, MonadIO m) => m FilePath
diff --git a/src/XMonad/Main.hs b/src/XMonad/Main.hs
--- a/src/XMonad/Main.hs
+++ b/src/XMonad/Main.hs
@@ -368,7 +368,9 @@
         dpy <- asks display
         root <- asks theRoot
         (_, _, w', _, _, _, _, _) <- io $ queryPointer dpy root
-        when (w == w') (focus w)
+        -- when Xlib cannot find a child that contains the pointer,
+        -- it returns None(0)
+        when (w' == 0 || w == w') (focus w)
 
 -- left a window, check if we need to focus root
 handle e@(CrossingEvent {ev_event_type = t})
diff --git a/src/XMonad/Operations.hs b/src/XMonad/Operations.hs
--- a/src/XMonad/Operations.hs
+++ b/src/XMonad/Operations.hs
@@ -465,14 +465,21 @@
     catchIO (writeFile path $ show stateData)
 
 -- | Read the state of a previous xmonad instance from a file and
--- return that state.
+-- return that state.  The state file is removed after reading it.
 readStateFile :: (LayoutClass l Window, Read (l Window)) => XConfig l -> X (Maybe XState)
 readStateFile xmc = do
     path <- stateFileName
-    raw  <- userCode $ io (readFile path)
 
+    -- I'm trying really hard here to make sure we read the entire
+    -- contents of the file before it is removed from the file system.
+    sf' <- userCode . io $ do
+        raw <- withFile path ReadMode readStrict
+        return $! maybeRead reads raw
+
+    io (removeFile path)
+
     return $ do
-      sf <- maybeRead reads =<< raw
+      sf <- join sf'
 
       let winset = W.ensureTags layout (workspaces xmc) $ W.mapLayout (fromMaybe layout . maybeRead lreads) (sfWins sf)
           extState = M.fromList . map (second Left) $ sfExt sf
@@ -490,6 +497,9 @@
     maybeRead reads' s = case reads' s of
                            [(x, "")] -> Just x
                            _         -> Nothing
+
+    readStrict :: Handle -> IO String
+    readStrict h = hGetContents h >>= \s -> length s `seq` return s
 
 -- | Migrate state from a previously running xmonad instance that used
 -- the older @--resume@ technique.
diff --git a/xmonad.cabal b/xmonad.cabal
--- a/xmonad.cabal
+++ b/xmonad.cabal
@@ -1,5 +1,5 @@
 name:               xmonad
-version:            0.13
+version:            0.14
 homepage:           http://xmonad.org
 synopsis:           A tiling window manager
 description:
@@ -32,7 +32,9 @@
                     GHC==7.6.3,
                     GHC==7.8.4,
                     GHC==7.10.3,
-                    GHC==8.0.1
+                    GHC==8.0.2,
+                    GHC==8.2.2,
+                    GHC==8.4.3
 
 data-files:         man/xmonad.hs, man/xmonad.1, man/xmonad.1.html
 
@@ -50,11 +52,6 @@
     default: False
     manual: True
 
-flag profiling
-     description: Enable profiling
-     default: False
-     manual: True
-
 library
     hs-source-dirs:     src
     exposed-modules:    XMonad
@@ -70,7 +67,7 @@
     build-depends: base < 5 && >=3,
                    containers,
                    data-default,
-                   directory >= 1.2.3,
+                   directory,
                    extensible-exceptions,
                    filepath,
                    setlocale,
@@ -78,7 +75,8 @@
                    process,
                    unix,
                    utf8-string >= 0.3 && < 1.1,
-                   X11>=1.8 && < 1.9
+                   X11>=1.8 && < 1.10,
+                   semigroups
 
     if true
         ghc-options:        -funbox-strict-fields -Wall
@@ -88,11 +86,6 @@
     if impl(ghc < 7.0.0)
         extensions: UndecidableInstances
         -- needed for XMonad.Config's instance Default (XConfig a)
-
-
-    if flag(profiling)
-        ghc-prof-options:   -prof -auto-all
-
     if flag(testing)
         buildable: False
 
