module Hbro.Hbro (
defaultConfig,
launchHbro
) where
import Hbro.Core
import Hbro.Gui
import Hbro.Keys
import Hbro.Socket
import Hbro.Types
import Hbro.Util
import qualified Config.Dyre as D
import Config.Dyre.Paths
import Control.Concurrent
import Control.Monad.Reader
import qualified Data.Map as M
import Graphics.UI.Gtk.Abstract.Widget
import Graphics.UI.Gtk.General.General hiding(initGUI)
import Graphics.UI.Gtk.WebKit.WebView hiding(webViewGetUri, webViewLoadUri)
import Graphics.UI.Gtk.WebKit.Download
import Network.URI
import System.Console.CmdArgs
import System.Directory
import System.Environment.XDG.BaseDir
import System.FilePath
import System.Glib.Signals
import System.IO
import System.Posix.Process
import System.Posix.Signals
import qualified System.ZMQ as ZMQ
cliOptions :: CliOptions
cliOptions = CliOptions {
mURI = def &= help "URI to open at start-up" &= explicit &= name "u" &= name "uri" &= typ "URI",
mVanilla = def &= help "Do not read custom configuration file." &= explicit &= name "1" &= name "vanilla",
mDenyReconf = def &= help "Deny recompilation even if the configuration file has changed." &= explicit &= name "deny-reconf",
mForceReconf = def &= help "Force recompilation even if the configuration file hasn't changed." &= explicit &= name "force-reconf",
mDyreDebug = def &= help "Force the application to use './cache/' as the cache directory, and ./ as the configuration directory. Useful to debug the program without installation." &= explicit &= name "dyre-debug",
mMasterBinary = def &= explicit &= name "dyre-master-binary"
}
getOptions :: IO CliOptions
getOptions = cmdArgs $ cliOptions
&= verbosityArgs [explicit, name "verbose", name "v"] []
&= versionArg [ignore]
&= help "A minimal KISS-compliant browser."
&= helpArg [explicit, name "help", name "h"]
&= program "hbro"
dyreParameters :: D.Params (Config, CliOptions)
dyreParameters = D.defaultParams {
D.projectName = "hbro",
D.showError = showError,
D.realMain = realMain,
D.ghcOpts = ["-threaded"],
D.statusOut = hPutStrLn stderr
}
showError :: (Config, a) -> String -> (Config, a)
showError (config, x) message = (config { mError = Just message }, x)
defaultConfig :: CommonDirectories -> Config
defaultConfig directories = Config {
mCommonDirectories = directories,
mHomePage = "https://encrypted.google.com/",
mSocketDir = mTemporary directories,
mUIFile = (mConfiguration directories) </> "ui.xml",
mKeyEventHandler = simpleKeyEventHandler,
mKeyEventCallback = \_ -> simpleKeyEventCallback (keysListToMap []),
mWebSettings = [],
mSetup = const (return () :: IO ()),
mCommands = [],
mDownloadHook = \_ _ _ _ -> return (),
mError = Nothing
}
launchHbro :: (CommonDirectories -> Config) -> IO ()
launchHbro configGenerator = do
homeDir <- getHomeDirectory
tmpDir <- getTemporaryDirectory
configDir <- getUserConfigDir "hbro"
dataDir <- getUserDataDir "hbro"
let config = configGenerator (CommonDirectories homeDir tmpDir configDir dataDir)
options <- getOptions
case mVanilla options of
True -> D.wrapMain dyreParameters{ D.configCheck = False } (config, options)
_ -> D.wrapMain dyreParameters (config, options)
realMain :: (Config, CliOptions) -> IO ()
realMain (config, options) = do
maybe (return ()) putStrLn $ mError config
whenLoud $ getPaths dyreParameters >>= \(a,b,c,d,e) -> (putStrLn . unlines) [
"Current binary: " ++ a,
"Custom binary: " ++ b,
"Config file: " ++ c,
"Cache directory: " ++ d,
"Lib directory: " ++ e,
[]]
gui <- initGUI (mUIFile config) (mWebSettings config)
ZMQ.withContext 1 $ realMain' config options gui
realMain' :: Config -> CliOptions -> GUI -> ZMQ.Context -> IO ()
realMain' config options gui@GUI {mWebView = webView, mWindow = window} context = let
environment = Environment options config gui context
setup = mSetup config
socketDir = mSocketDir config
commands = mCommands config
keyEventHandler = mKeyEventHandler config
keyEventCallback = (mKeyEventCallback config) environment
in do
setup environment
void $ on webView downloadRequested $ \download -> do
uri <- (>>= parseURI) `fmap` downloadGetUri download
filename <- downloadGetSuggestedFilename download
size <- downloadGetTotalSize download
case (uri, filename) of
(Just uri', Just filename') -> do
whenNormal $ putStrLn ("Requested download: " ++ show uri')
(mDownloadHook config) environment uri' filename' size
_ -> return ()
return False
rec i <- after webView keyPressEvent $ keyEventHandler keyEventCallback i webView
startURI <- case (mURI options) of
Just uri -> do
fileURI <- doesFileExist uri
case fileURI of
True -> getCurrentDirectory >>= \dir -> return $ Just ("file://" ++ dir </> uri)
_ -> return $ Just uri
_ -> return Nothing
maybe (goHome webView config) (webViewLoadUri webView) (startURI >>= parseURIReference)
pid <- getProcessID
let commandsList = M.fromList $ defaultCommandsList ++ commands
let socketURI = "ipc://" ++ socketDir ++ pathSeparator:"hbro." ++ show pid
void $ forkIO (openRepSocket context socketURI (listenToCommands environment commandsList))
void $ installHandler sigINT (Catch interruptHandler) Nothing
mainGUI
whenLoud $ putStrLn "Closing socket..."
closeSocket context socketURI
whenNormal $ putStrLn "Exiting..."
interruptHandler :: IO ()
interruptHandler = whenLoud (putStrLn "Received SIGINT.") >> mainQuit