diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,21 @@
 Brick changelog
 ---------------
 
+0.47
+----
+
+API changes:
+ * Changed `Brick.Main.customMain` so that it now takes an additional
+   (first) argument: the initial `Vty` handle to use. This lets the
+   caller have more control over the terminal state when, for example,
+   they have previously set up Vty to do other work before calling
+   `customMain`.
+ * Added `Brick.Main.customMainWithVty`. This function is the same as
+   `customMain` except that it also returns the final `Vty` handle that
+   it used internally *without* shutting that Vty handle down. This
+   allows the caller to continue using the terminal without resetting it
+   after `customMainWithVty` finishes executing.
+
 0.46
 ----
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,29 +1,19 @@
 ![](logo/brick-final-clearbg-with-text.svg)
 
-`brick` is a Haskell terminal user interface programming library in the
-style of [gloss](http://hackage.haskell.org/package/gloss). This means
-you write a function that describes how your user interface should look,
-but the library takes care of a lot of the book-keeping that so commonly
-goes into writing such programs.
+`brick` is a Haskell terminal user interface (TUI) programming toolkit.
+To use it, you write a pure function that describes how your user
+interface should look based on your current application state and you
+provide a state transformation function to handle events.
 
 `brick` exposes a declarative API. Unlike most GUI toolkits which
 require you to write a long and tedious sequence of "create a widget,
 now bind an event handler", `brick` just requires you to describe your
-interface using a set of declarative combinators. Then you provide a
-function to transform your application state when input or other kinds
-of events arrive.
+interface using a set of declarative layout combinators.
 
 Under the hood, this library builds upon
 [vty](http://hackage.haskell.org/package/vty), so some knowledge of Vty
 will be helpful in using this library.
 
-Release Announcements / News
-----------------------------
-
-Find out about `brick` releases and other news on Twitter:
-
-https://twitter.com/brick_haskell/
-
 Example
 -------
 
@@ -71,6 +61,17 @@
  * `solitaire`, the card game: https://github.com/ambuc/solitaire
  * `sudoku-tui`, a Sudoku implementation: https://github.com/evanrelf/sudoku-tui
 
+These third-party packages also extend `brick`:
+
+ * [`brick-filetree`](https://github.com/ChrisPenner/brick-filetree) [[Hackage]](http://hackage.haskell.org/package/brick-filetree) - A widget for exploring a directory tree and selecting or flagging files and directories
+
+Release Announcements / News
+----------------------------
+
+Find out about `brick` releases and other news on Twitter:
+
+https://twitter.com/brick_haskell/
+
 Getting Started
 ---------------
 
@@ -113,7 +114,7 @@
  * Type-safe, validated input form API (see the `Brick.Forms` module)
  * A filesystem browser for file and directory selection
  * Borders can be configured to automatically connect!
-
+ 
 Brick-Users Discussion
 ----------------------
 
diff --git a/brick.cabal b/brick.cabal
--- a/brick.cabal
+++ b/brick.cabal
@@ -1,5 +1,5 @@
 name:                brick
-version:             0.46
+version:             0.47
 synopsis:            A declarative terminal user interface library
 description:
   Write terminal applications painlessly with 'brick'! You write an
diff --git a/docs/guide.rst b/docs/guide.rst
--- a/docs/guide.rst
+++ b/docs/guide.rst
@@ -348,8 +348,9 @@
    main :: IO ()
    main = do
        eventChan <- Brick.BChan.newBChan 10
-       finalState <- customMain
-                       (Graphics.Vty.mkVty Graphics.Vty.defaultConfig)
+       let buildVty = Graphics.Vty.mkVty Graphics.Vty.defaultConfig
+       initialVty <- buildVty
+       finalState <- customMain initialVty buildVty
                        (Just eventChan) app initialState
        -- Use finalState and exit
 
diff --git a/docs/samtay-tutorial.md b/docs/samtay-tutorial.md
--- a/docs/samtay-tutorial.md
+++ b/docs/samtay-tutorial.md
@@ -290,7 +290,9 @@
     writeBChan chan Tick
     threadDelay 100000 -- decides how fast your game moves
   g <- initGame
-  void $ customMain (V.mkVty V.defaultConfig) (Just chan) app g
+  let buildVty = V.mkVty V.defaultConfig
+  initialVty <- buildVty
+  void $ customMain initialVty buildVty (Just chan) app g
 ```
 
 We do need to import `Vty.Graphics` since `customMain` allows us
@@ -482,7 +484,9 @@
     writeBChan chan Tick
     int <- atomically $ readTVar tv
     threadDelay int
-  customMain (V.mkVty V.defaultConfig) (Just chan) app (initialGame tv)
+  let buildVty = V.mkVty V.defaultConfig
+  initialVty <- buildVty
+  customMain initialVty buildVty (Just chan) app (initialGame tv)
     >>= printResult
 ```
 
diff --git a/programs/CustomEventDemo.hs b/programs/CustomEventDemo.hs
--- a/programs/CustomEventDemo.hs
+++ b/programs/CustomEventDemo.hs
@@ -82,4 +82,6 @@
         writeBChan chan Counter
         threadDelay 1000000
 
-    void $ customMain (V.mkVty V.defaultConfig) (Just chan) theApp initialState
+    let buildVty = V.mkVty V.defaultConfig
+    initialVty <- buildVty
+    void $ customMain initialVty buildVty (Just chan) theApp initialState
diff --git a/programs/FormDemo.hs b/programs/FormDemo.hs
--- a/programs/FormDemo.hs
+++ b/programs/FormDemo.hs
@@ -145,7 +145,8 @@
         f = setFieldValid False AgeField $
             mkForm initialUserInfo
 
-    f' <- customMain buildVty Nothing app f
+    initialVty <- buildVty
+    f' <- customMain initialVty buildVty Nothing app f
 
     putStrLn "The starting form state was:"
     print initialUserInfo
diff --git a/programs/MouseDemo.hs b/programs/MouseDemo.hs
--- a/programs/MouseDemo.hs
+++ b/programs/MouseDemo.hs
@@ -123,7 +123,8 @@
           V.setMode (V.outputIface v) V.Mouse True
           return v
 
-    void $ M.customMain buildVty Nothing app $ St [] Nothing
+    initialVty <- buildVty
+    void $ M.customMain initialVty buildVty Nothing app $ St [] Nothing
            "Try clicking on various UI elements.\n\
            \Observe that the click coordinates identify the\n\
            \underlying widget coordinates.\n\
diff --git a/src/Brick/Main.hs b/src/Brick/Main.hs
--- a/src/Brick/Main.hs
+++ b/src/Brick/Main.hs
@@ -1,7 +1,9 @@
+{-# LANGUAGE ScopedTypeVariables #-}
 module Brick.Main
   ( App(..)
   , defaultMain
   , customMain
+  , customMainWithVty
   , simpleMain
   , resizeOrQuit
   , simpleApp
@@ -46,7 +48,7 @@
   )
 where
 
-import Control.Exception (finally)
+import qualified Control.Exception as E
 import Lens.Micro ((^.), (&), (.~), (%~), _1, _2)
 import Control.Monad (forever)
 import Control.Monad.Trans.Class (lift)
@@ -127,7 +129,9 @@
             -- ^ The initial application state.
             -> IO s
 defaultMain app st = do
-    customMain (mkVty defaultConfig) Nothing app st
+    let builder = mkVty defaultConfig
+    initialVty <- builder
+    customMain initialVty builder Nothing app st
 
 -- | A simple main entry point which takes a widget and renders it. This
 -- event loop terminates when the user presses any key, but terminal
@@ -170,39 +174,42 @@
 readBrickEvent :: BChan (BrickEvent n e) -> BChan e -> IO (BrickEvent n e)
 readBrickEvent brickChan userChan = either id AppEvent <$> readBChan2 brickChan userChan
 
-runWithNewVty :: (Ord n)
-              => Vty
-              -> BChan (BrickEvent n e)
-              -> Maybe (BChan e)
-              -> App s e n
-              -> RenderState n
-              -> s
-              -> IO (InternalNext n s)
-runWithNewVty buildVty brickChan mUserChan app initialRS initialSt =
-    withVty buildVty $ \vty -> do
-        pid <- forkIO $ supplyVtyEvents vty brickChan
-        let readEvent = case mUserChan of
-              Nothing -> readBChan brickChan
-              Just uc -> readBrickEvent brickChan uc
-            runInner rs st = do
-              (result, newRS) <- runVty vty readEvent app st (resetRenderState rs)
-              case result of
-                  SuspendAndResume act -> do
-                      killThread pid
-                      return $ InternalSuspendAndResume newRS act
-                  Halt s -> do
-                      killThread pid
-                      return $ InternalHalt s
-                  Continue s -> runInner newRS s
-        runInner initialRS initialSt
+runWithVty :: (Ord n)
+           => Vty
+           -> BChan (BrickEvent n e)
+           -> Maybe (BChan e)
+           -> App s e n
+           -> RenderState n
+           -> s
+           -> IO (InternalNext n s)
+runWithVty vty brickChan mUserChan app initialRS initialSt = do
+    pid <- forkIO $ supplyVtyEvents vty brickChan
+    let readEvent = case mUserChan of
+          Nothing -> readBChan brickChan
+          Just uc -> readBrickEvent brickChan uc
+        runInner rs st = do
+          (result, newRS) <- runVty vty readEvent app st (resetRenderState rs)
+          case result of
+              SuspendAndResume act -> do
+                  killThread pid
+                  return $ InternalSuspendAndResume newRS act
+              Halt s -> do
+                  killThread pid
+                  return $ InternalHalt s
+              Continue s -> runInner newRS s
+    runInner initialRS initialSt
 
 -- | The custom event loop entry point to use when the simpler ones
--- don't permit enough control.
+-- don't permit enough control. Returns the final application state
+-- after the application halts.
 customMain :: (Ord n)
-           => IO Vty
-           -- ^ An IO action to build a Vty handle. This is used to
-           -- build a Vty handle whenever the event loop begins or is
-           -- resumed after suspension.
+           => Vty
+           -- ^ The initial Vty handle to use.
+           -> IO Vty
+           -- ^ An IO action to build a Vty handle. This is used
+           -- to build a Vty handle whenever the event loop needs
+           -- to reinitialize the terminal, e.g. on resume after
+           -- suspension.
            -> Maybe (BChan e)
            -- ^ An event channel for sending custom events to the event
            -- loop (you write to this channel, the event loop reads from
@@ -213,20 +220,49 @@
            -> s
            -- ^ The initial application state.
            -> IO s
-customMain buildVty mUserChan app initialAppState = do
-    initialVty <- buildVty
+customMain initialVty buildVty mUserChan app initialAppState = do
+    (s, vty) <- customMainWithVty initialVty buildVty mUserChan app initialAppState
+    shutdown vty
+    return s
+
+-- | Like 'customMain', except the last 'Vty' handle used by the
+-- application is returned without being shut down with 'shutdown'. This
+-- allows the caller to re-use the 'Vty' handle for something else, such
+-- as another Brick application.
+customMainWithVty :: (Ord n)
+                  => Vty
+                  -- ^ The initial Vty handle to use.
+                  -> IO Vty
+                  -- ^ An IO action to build a Vty handle. This is used
+                  -- to build a Vty handle whenever the event loop needs
+                  -- to reinitialize the terminal, e.g. on resume after
+                  -- suspension.
+                  -> Maybe (BChan e)
+                  -- ^ An event channel for sending custom events to the event
+                  -- loop (you write to this channel, the event loop reads from
+                  -- it). Provide 'Nothing' if you don't plan on sending custom
+                  -- events.
+                  -> App s e n
+                  -- ^ The application.
+                  -> s
+                  -- ^ The initial application state.
+                  -> IO (s, Vty)
+customMainWithVty initialVty buildVty mUserChan app initialAppState = do
     let run vty rs st brickChan = do
-            result <- runWithNewVty vty brickChan mUserChan app rs st
+            result <- runWithVty vty brickChan mUserChan app rs st
+                `E.catch` (\(e::E.SomeException) -> shutdown vty >> E.throw e)
             case result of
-                InternalHalt s -> return s
+                InternalHalt s -> return (s, vty)
                 InternalSuspendAndResume newRS action -> do
+                    shutdown vty
                     newAppState <- action
                     newVty <- buildVty
                     run newVty (newRS { renderCache = mempty }) newAppState brickChan
 
-        emptyES = ES [] mempty
+    let emptyES = ES [] mempty
         emptyRS = RS M.empty mempty S.empty mempty mempty
         eventRO = EventRO M.empty initialVty mempty emptyRS
+
     (st, eState) <- runStateT (runReaderT (runEventM (appStartEvent app initialAppState)) eventRO) emptyES
     let initialRS = RS M.empty (esScrollRequests eState) S.empty mempty []
     brickChan <- newBChan 20
@@ -373,10 +409,6 @@
 invalidateCache :: (Ord n) => EventM n ()
 invalidateCache = EventM $ do
     lift $ modify (\s -> s { cacheInvalidateRequests = S.insert InvalidateEntire $ cacheInvalidateRequests s })
-
-withVty :: Vty -> (Vty -> IO a) -> IO a
-withVty vty useVty = do
-    useVty vty `finally` shutdown vty
 
 getRenderState :: EventM n (RenderState n)
 getRenderState = EventM $ asks oldState
diff --git a/src/Brick/Widgets/Core.hs b/src/Brick/Widgets/Core.hs
--- a/src/Brick/Widgets/Core.hs
+++ b/src/Brick/Widgets/Core.hs
@@ -995,13 +995,8 @@
          -> Widget n
 viewport vpname typ p =
     clickable vpname $ Widget Greedy Greedy $ do
-      -- First, update the viewport size.
-      c <- getContext
-      let newVp = VP 0 0 newSize
-          newSize = (c^.availWidthL, c^.availHeightL)
-          doInsert (Just vp) = Just $ vp & vpSize .~ newSize
-          doInsert Nothing = Just newVp
-
+      -- Observe the viewport name so we can detect multiple uses of the
+      -- name.
       let observeName :: (Ord n, Show n) => n -> RenderM n ()
           observeName n = do
               observed <- use observedNamesL
@@ -1017,12 +1012,19 @@
 
       observeName vpname
 
+      -- Update the viewport size.
+      c <- getContext
+      let newVp = VP 0 0 newSize
+          newSize = (c^.availWidthL, c^.availHeightL)
+          doInsert (Just vp) = Just $ vp & vpSize .~ newSize
+          doInsert Nothing = Just newVp
+
       lift $ modify (& viewportMapL %~ (M.alter doInsert vpname))
 
-      -- Then render the sub-rendering with the rendering layout
-      -- constraint released (but raise an exception if we are asked to
-      -- render an infinitely-sized widget in the viewport's scrolling
-      -- dimension)
+      -- Then render the viewport content widget with the rendering
+      -- layout constraint released (but raise an exception if we are
+      -- asked to render an infinitely-sized widget in the viewport's
+      -- scrolling dimension)
       let release = case typ of
             Vertical -> vRelease
             Horizontal -> hRelease
