packages feed

hbro 1.1.2.2 → 1.2.0.0

raw patch · 57 files changed

+5307/−2103 lines, 57 filesdep +classy-preludedep +errorsdep +gtk3dep −directorydep −filepathdep −gtkdep ~hbrodep ~mtl

Dependencies added: classy-prelude, errors, gtk3, hslogger, integer-simple, lifted-async, lifted-base, network-uri, parsec, safe, semigroups, stm, system-fileio, text, time, webkitgtk3

Dependencies removed: directory, filepath, gtk, network, webkit, xdg-basedir

Dependency ranges changed: hbro, mtl

Files

− Hbro.hs
@@ -1,13 +0,0 @@-module Hbro (-    module Hbro.Boot,-    module Hbro.Config,-    module Hbro.Core,-    module Hbro.Error,-    module Hbro.Util,-) where--import Hbro.Boot-import Hbro.Config-import Hbro.Core-import Hbro.Error-import Hbro.Util
− Hbro/Boot.hs
@@ -1,348 +0,0 @@-module Hbro.Boot (hbro) where---- {{{ Imports-import Hbro.Config-import Hbro.Core-import qualified Hbro.Dyre as Dyre-import Hbro.Error-import Hbro.Gui (GUI, GUIReader(..))-import qualified Hbro.Gui as Gui-import Hbro.IPC (IPC(..), IPCReader(..))-import qualified Hbro.IPC as IPC-import qualified Hbro.Keys as Key-import Hbro.Notification-import Hbro.Options (CliOptions, OptionsReader(..))-import qualified Hbro.Options as Options-import Hbro.Util-import qualified Hbro.Webkit.WebSettings as WS-import Hbro.Webkit.WebView---- import Control.Applicative-import Control.Concurrent-import Control.Conditional hiding(when, unless)-import Control.Lens hiding((??))-import Control.Monad-import Control.Monad.Base-import Control.Monad.Error hiding(when)-import Control.Monad.Reader hiding(when)-import Control.Monad.Trans.Control--import Data.Default-import Data.Functor-import Data.List-import qualified Data.Map as M hiding(null)-import Data.Maybe-import Data.Version--import Graphics.UI.Gtk.Abstract.Widget-import Graphics.UI.Gtk.Gdk.EventM-import qualified Graphics.UI.Gtk.General.General as GTK-import qualified Graphics.UI.Gtk.WebKit.Download as W-import Graphics.UI.Gtk.WebKit.WebSettings-import Graphics.UI.Gtk.WebKit.WebNavigationAction-import Graphics.UI.Gtk.WebKit.WebPolicyDecision-import Graphics.UI.Gtk.WebKit.WebView as W--import Paths_hbro--import Prelude hiding(init)--import System.Environment.XDG.BaseDir-import System.Exit-import System.Glib.Signals-import System.Posix.Files-import System.Posix.Signals-import System.ZMQ4 (Rep(..))-import qualified System.ZMQ4 as ZMQ--- }}}----- | Main function to call in the configuration file (cf file @Hbro/Main.hs@).--- First, commandline options are parsed, then configuration is dynamically applied.-hbro :: K () -> IO ()-hbro setup = do-    opts <- Options.get--    when (opts^.Options.help)      $ putStrLn Options.usage >> exitSuccess-    when (opts^.Options.version)   $ putStrLn (showVersion version) >> exitSuccess-    when (opts^.Options.recompile) $ Dyre.recompile >>= maybe exitSuccess (\e -> putStrLn e >> exitFailure)--    Dyre.wrap hbro' opts (setup, opts)---hbro' :: (K (), CliOptions) -> IO ()-hbro' (customSetup, opts) = do-    void $ installHandler sigINT (Catch onInterrupt) Nothing--    when (opts^.Options.verbose) . putStrLn $ "Commandline options: " ++ show opts ++ "\n"--    config <- runReaderT initConfig opts-    gui    <- initGUI opts--    (result, logs) <- withIPC opts $ \ipc -> runK opts config gui ipc $ main customSetup--    either print return result-    unless (opts^.Options.quiet) . unless (null logs) $ putStrLn logs-    unless (opts^.Options.quiet) $ putStrLn "Exiting..."---- {{{ Initialization-initConfig :: (MonadBase IO m, OptionsReader m) => m (Config K)-initConfig = do-    options <- readOptions id-    return . id-          . (options^.Options.quiet   ? set verbosity Quiet   ?? id)-          . (options^.Options.verbose ? set verbosity Verbose ?? id)-          $ def---initGUI :: (MonadBase IO m) => CliOptions -> m (GUI K)-initGUI opts = do-    result <- runErrorT . (`runReaderT` opts) $ do-        file <- getUIFile-        whenM (readOptions Options.verbose) . io . putStrLn $ "Building GUI from file " ++ file ++ "\n"--        io $ void GTK.initGUI-        Gui.buildFrom file-    either (\e -> io (putStrLn e >> exitFailure)) return result---getUIFile :: (MonadBase IO m, OptionsReader m, MonadError String m) => m FilePath-getUIFile = do-    fileFromOption  <- readOptions Options.uIFile-    fileFromConfig  <- io (getUserConfigDir "hbro" >/> "ui.xml")-    fileFromPackage <- io $ getDataFileName "examples/ui.xml"--    maybe-        (throwError "[ERROR] No readable UI file found.")-        return-        =<< io (firstReadableOf . catMaybes $ [fileFromOption, Just fileFromConfig, Just fileFromPackage])-  where-    firstReadableOf []    = return Nothing-    firstReadableOf (x:y) = do-        isThere <- fileExist x-        isReadable <- case isThere of-            False -> return False-            True -> fileAccess x True False False-        isReadable ? return (Just x) ?? firstReadableOf y--withIPC :: (MonadBaseControl IO m) => CliOptions -> (IPC -> m a) -> m a-withIPC options f = restoreM =<< (liftBaseWith $ \runInIO -> do-  ZMQ.withContext $ \c -> do-    ZMQ.withSocket c Rep $ \s -> do-      io . ZMQ.bind s =<< runReaderT Options.getSocketURI options-      runInIO $ f (IPC c s))--- }}}---main :: K () -> K ()-main customSetup = do-    threadSync <- fork socketMain--    Gui.init---- Bind hooks-    bindDownload          =<< Gui.readGUI Gui.webView-    bindKeys-    bindLoadFinished      =<< Gui.readGUI Gui.webView-    bindNavigationRequest =<< Gui.readGUI Gui.webView-    bindNewWebView        =<< Gui.readGUI Gui.webView-    bindNewWindow         =<< Gui.readGUI Gui.webView-    bindResourceOpened    =<< Gui.readGUI Gui.webView-    bindTitleChanged      =<< Gui.readGUI Gui.webView---- Default web settings-    WS.set webSettingsMonospaceFontFamily               "inconsolata"-    WS.set webSettingsEnableDeveloperExtras             True-    WS.set webSettingsEnableHtml5Database               False-    WS.set webSettingsEnableHtml5LocalStorage           False-    WS.set webSettingsEnablePageCache                   True-    WS.set webSettingsEnablePlugins                     False-    WS.set webSettingsEnablePrivateBrowsing             False-    WS.set webSettingsEnableScripts                     False-    WS.set webSettingsEnableSpellChecking               False-    WS.set webSettingsEnableSpatialNavigation           True-    WS.set webSettingsEnableUniversalAccessFromFileUris True-    WS.set webSettingsEnableXssAuditor                  True-    WS.set webSettingsJSCanOpenWindowAuto               False---- Apply custom setup-    customSetup--    config <- readConfig id-    logV $ "Start-up configuration: \n" ++ show config---- Load startpage-    startURI <- Options.getStartURI-    maybe goHome load startURI---- Main loop-    io GTK.mainGUI---- Clean & close-    void . (`IPC.sendCommand` "QUIT") =<< Options.getSocketURI-    io $ takeMVar threadSync----- | IPC thread that listens to commands from external world.-socketMain :: K ()-socketMain = do-    socket <- readIPC IPC.receiver--    whileTrue $ do-        message <- IPC.read socket-        logV $ "Received command: " ++ message--        case words message of-            []                -> IPC.send socket "ERROR Empty command" >> return True-            "QUIT":[]         -> IPC.send socket "OK" >> return False-            command:arguments -> do-                commands' <- IPC.unwrap <$> readConfig commands-                case M.lookup command commands' of-                    Just callback -> (postGUISync' (callback arguments) >>= IPC.send socket) `catchError` (\_ -> IPC.send socket "ERROR")-                    _             -> IPC.send socket "ERROR Unknown command"-                return True-    return ()-  where-    whileTrue f = do-        result <- f-        result ? whileTrue f ?? return ()---onInterrupt :: (MonadBase IO m) => m ()-onInterrupt = io (putStrLn "Received SIGINT." >> GTK.mainQuit)----- {{{ Signals handlers--- Triggered in 2 cases:---  1/ Javascript window.open()---  2/ Context menu "Open in new window"-bindNewWebView :: (MonadBase IO m, ConfigReader m m, MonadBaseControl IO m, MonadError HError m) => WebView -> m ()-bindNewWebView webView = do-    void . liftBaseWith $ \runInIO -> on webView W.createWebView $ \_frame -> do-        webView' <- webViewNew--        void . on webView' W.webViewReady $ return True-        void . on webView' W.navigationPolicyDecisionRequested $ \_ request _ decision -> do-            void . runInIO $ do-                callback <- readConfig onNewWindow-                uri      <- networkRequestGetUri request-                logV $ "New webview <" ++ show uri ++ ">"-                callback uri-            webPolicyDecisionIgnore decision-            return True--        return webView'---bindDownload :: (MonadBase IO m, MonadBaseControl IO m, ConfigReader m m, NotificationReader m, MonadError HError m) =>  WebView -> m ()-bindDownload webView = do-    void . liftBaseWith $ \runInIO -> on webView W.downloadRequested $ \d -> do-        amount <- W.downloadGetTotalSize d--        void . runInIO $ do-            uri      <- downloadGetUri d-            filename <- downloadGetSuggestedFilename d-            callback <- readConfig onDownload--            logV        $ "Requested download <" ++ show uri ++ ">"-            notify 5000 $ "Requested download: " ++ filename ++ " (" ++ show amount ++ ")"--            callback uri filename amount-        return False---bindLoadFinished :: (MonadBase IO m, MonadBaseControl IO m, ConfigReader m m, Error e, Show e, MonadError e m) => WebView -> m ()-bindLoadFinished webView = do-    void . liftBaseWith $ \runInIO -> on webView W.loadFinished $ \_frame-> do-        void . runInIO $ do-            callback <- readConfig onLoadFinished-            logV "Load finished"-            callback `catchError` \e -> (io $ print e) -- >> notify 5000 (show e)-        return ()--bindNavigationRequest :: (MonadBase IO m, MonadBaseControl IO m, ConfigReader m m, MonadError HError m) => WebView -> m ()-bindNavigationRequest webView = do-    liftBaseWith $ \runInIO -> void . on webView W.navigationPolicyDecisionRequested $ \_frame request action decision -> do-        reason <- io $ webNavigationActionGetReason action-        button <- io $ toMouseButton <$> webNavigationActionGetButton action--        case (reason, button) of-            (WebNavigationReasonLinkClicked, Just b) -> void . runInIO $ do-                callback <- readConfig onLinkClicked-                uri      <- networkRequestGetUri request-                logV $ "Link clicked <" ++ show uri ++ ">"-                callback b uri-                io $ webPolicyDecisionIgnore decision-            _ -> {-void . runInIO $ do-                callback <- readConfig onLoadRequested-                uri      <- networkRequestGetUri request-                logV $ "Requested load <" ++ show uri ++ ">"-                callback uri-}-                io $ webPolicyDecisionUse decision-        return True-  where-    toMouseButton 1 = Just LeftButton-    toMouseButton 2 = Just MiddleButton-    toMouseButton 3 = Just RightButton-    toMouseButton _ = Nothing---bindNewWindow :: (MonadBase IO m, MonadBaseControl IO m, ConfigReader m m, MonadError HError m) => WebView -> m ()-bindNewWindow webView = do-    liftBaseWith $ \runInIO -> void . on webView W.newWindowPolicyDecisionRequested $ \_frame request _action decision -> do-        void . runInIO $ do-            callback <- readConfig onNewWindow-            uri      <- networkRequestGetUri request-            logV $ "New window request <" ++ show uri ++ ">"-            callback uri-        webPolicyDecisionIgnore decision-        return True-        --either (\e -> io . putStrLn $ "WARNING: wrong URI given, unable to open new window.") (const $ return ()) result---bindResourceOpened :: (MonadBase IO m, MonadBaseControl IO m, ConfigReader m m, MonadError HError m) => WebView -> m ()-bindResourceOpened webView = do-    liftBaseWith $ \runInIO -> void . on webView W.mimeTypePolicyDecisionRequested $ \_frame request mimetype decision -> do-        void . runInIO $ do-            callback <- readConfig onResourceOpened-            uri <- networkRequestGetUri request-            logV $ "Opening resource [MIME type=" ++ mimetype ++ " | uri=" ++ show uri ++ "]"-            action <- callback uri mimetype-            case action of-                Load -> io $ webPolicyDecisionUse      decision-                _    -> io $ webPolicyDecisionDownload decision-        return True---bindTitleChanged :: (MonadBase IO m, MonadBaseControl IO m, ConfigReader m m, MonadError HError m) => WebView -> m ()-bindTitleChanged webView = do-    liftBaseWith $ \runInIO -> void . on webView W.titleChanged $ \_frame title -> void . runInIO $ do-        logV $ "Title changed to: " ++ title-        callback <- readConfig onTitleChanged-        callback title---bindKeys :: (MonadBaseControl IO m, Key.StatusState m, ConfigReader m m, GUIReader m m, NotificationReader m, Error e, Show e, MonadError e m) => m ()-bindKeys = do-  wv <- readGUI Gui.webView-  liftBaseWith $ \runInIO -> void . on wv keyPressEvent $ do-    modifiers <- eventModifier-    keyVal    <- eventKeyVal--    case (Key.mkStroke modifiers keyVal) of-        Just newStroke -> void . io . runInIO $ do-            oldStrokes  <- Key.readStatus Key.strokes-            theMode     <- Key.readStatus Key.mode-            theBindings <- readConfig keyBindings-            f           <- readConfig onKeyStroke-            let allStrokes = oldStrokes ++ [newStroke]-            f allStrokes-            logV $ "Pressed keys: " ++ (intercalate  " " . map Key.serialize) allStrokes--            case (Key.lookup allStrokes =<< M.lookup theMode theBindings) of-                Just (Key.Leaf callback) -> Key.writeStatus Key.strokes [] >> callback `catchError` \e -> (io $ print e) >> notify 5000 (show e)-                Just (Key.Branch _)      -> Key.writeStatus Key.strokes allStrokes-                _                        -> return ()-            return ()-        _ -> return ()-    return False
− Hbro/Clipboard.hs
@@ -1,27 +0,0 @@--- | Designed to be imported as @qualified@.-module Hbro.Clipboard where---- {{{ Imports-import Hbro.Error-import Hbro.Util--import Control.Monad.Base-import Control.Monad.Error-import Control.Monad.Trans.Control--import Graphics.UI.Gtk.General.Clipboard--- }}}---- | Write given string to primary clipboard-insert :: (MonadBase IO m) => String -> m ()-insert text = io $ clipboardGet selectionPrimary >>= (`clipboardSetText` text)---- | Feed given function with primary cliboard's content-with :: (MonadBaseControl IO m, MonadError HError m) => (String -> m a) -> m ()-with f = do-    clip <- io $ clipboardGet selectionPrimary-    requestText clip f---- | Wrapping around 'clipboardRequestText' to be able to use any monad based on IO as callback-requestText :: (MonadBaseControl IO m, ClipboardClass a, MonadError HError m) => a -> (String -> m b) -> m ()-requestText clip f = liftBaseWith $ \runInIO -> clipboardRequestText clip $ \x -> void . runInIO . maybe (throwError EmptyClipboard) f $ x
− Hbro/Config.hs
@@ -1,108 +0,0 @@-{-# LANGUAGE FlexibleInstances, TemplateHaskell, UndecidableInstances #-}-module Hbro.Config where---- {{{ Imports-import qualified Hbro.Keys as Key-import Hbro.IPC-import Hbro.Util---- import Control.Conditional-import Control.Lens hiding(set)-import Control.Monad.Base-import Control.Monad.Error  hiding(forM_, mapM_)--- import Control.Monad.Writer hiding(forM_, mapM_)---- import Data.Foldable (forM_, mapM_)--- import Data.Functor-import Data.List-import Data.Map (Map)-import qualified Data.Map as M--import Graphics.UI.Gtk.Gdk.EventM--import Network.URI as N hiding(parseURI, parseURIReference)--import Prelude hiding(mapM_)--- }}}---- {{{ Types-data ResourceAction  = Load | Download-data Verbosity       = Quiet | Normal | Verbose deriving(Eq, Show)---- | Custom settings provided by the user-data Config m = Config {-    _homePage         :: URI,                               -- ^ Startup page--- Parameters-    _verbosity        :: Verbosity,                         -- ^ Logs verbosity--- Hooks-    _keyBindings      :: Map Key.Mode (Key.Bindings m),     -- ^ Key bindings-    _onDownload       :: URI -> String -> Int -> m (),      -- ^ Callback triggered when a download is requested-    _onKeyStroke      :: [Key.Stroke] -> m (),              -- ^ Callback triggered when a key is pressed-    _onLinkClicked    :: MouseButton -> URI -> m (),        -- ^ Callback triggered when a link is clicked-    _onLoadRequested  :: URI -> m (),                       -- ^ Callback triggered when a load is requested-    _onLoadFinished   :: m (),                              -- ^ Callback triggered when a load is finished-    _onNewWindow      :: URI -> m (),                       -- ^ Callback triggered when a new window is requested-    _onResourceOpened :: URI -> String -> m ResourceAction, -- ^ Callback triggered when opening a non HTML resource-    _onTitleChanged   :: String -> m (),                    -- ^ Callback triggered when document title is changed-    _commands         :: CommandsMap m                      -- ^ Commands recognized through IPC system-}--makeLenses ''Config--instance Show (Config m) where-    show c = unlines [-        "Home page        = " ++ (show $ c^.homePage),-        "Verbosity        = " ++ (show $ c^.verbosity)]----- | 'MonadReader' for 'Config'-class (Monad m) => ConfigReader n m | m -> n where-    readConfig :: Simple Lens (Config n) a -> m a--instance ConfigReader n ((->) (Config n)) where-    readConfig l = view l----- | 'MonadWriter' for 'Config'-class (Monad m) => ConfigWriter n m | m -> n where-    writeConfig :: Simple Lens (Config n) a -> a -> m ()---- | 'MonadState' for 'Config'-type ConfigState n m = (ConfigReader n m, ConfigWriter n m)--modifyConfig :: (ConfigState n m) => Simple Lens (Config n) a -> (a -> a) -> m ()-modifyConfig l f = writeConfig l . f =<< readConfig l--- }}}---- | Run an action unless verbosity is 'Quiet'-unlessQuiet :: (MonadBase IO m, ConfigReader n m) => m () -> m ()-unlessQuiet f = do-    quiet' <- readConfig verbosity-    case quiet' of-        Quiet -> return ()-        _     -> f---- | Run an action when verbosity is 'Verbose'-whenLoud :: (MonadBase IO m, ConfigReader n m) => m () -> m ()-whenLoud f = do-    verbose' <- readConfig verbosity-    case verbose' of-        Verbose -> f-        _       -> return ()---log, logV :: (MonadBase IO m, ConfigReader n m) => String -> m ()-log  = unlessQuiet . io . putStrLn-logV = whenLoud    . io . putStrLn---- | Bind a keystrokes chain to a callback, in a given mode-bind :: (MonadBase IO m, ConfigState m m) => Key.Mode -> String -> m () -> m ()-bind mode strokes action = case newBindings of-    Just b -> do-        oldValue <- readConfig keyBindings-        let newValue = M.insertWith Key.merge mode b oldValue-        void $ writeConfig keyBindings newValue-        return ()-    _ -> return ()-  where-    newBindings = Key.mkBinding strokes action
− Hbro/Core.hs
@@ -1,340 +0,0 @@-{-# LANGUAGE FlexibleInstances, TypeFamilies #-}-module Hbro.Core where---- {{{ Imports-import qualified Hbro.Clipboard as Clipboard-import Hbro.Config-import Hbro.Error-import Hbro.Gtk.ScrolledWindow (Axis(..), Position(..))-import qualified Hbro.Gtk.ScrolledWindow as SW-import Hbro.Gui as GUI-import qualified Hbro.Keys as Keys-import Hbro.IPC-import Hbro.Network-import Hbro.Notification-import Hbro.Options (CliOptions, OptionsReader)-import qualified Hbro.Options as Options-import Hbro.Prompt (PromptReader)-import qualified Hbro.Prompt as Prompt-import Hbro.Util as H-import qualified Hbro.Webkit.WebView as W--import Control.Applicative-import Control.Conditional hiding(unless)-import Control.Lens hiding((??))-import Control.Monad-import Control.Monad.Base-import Control.Monad.Error  hiding(forM_, mapM_, unless)-import Control.Monad.Reader hiding(forM_, mapM_, unless)-import Control.Monad.Writer hiding(forM_, mapM_, unless)-import Control.Monad.Trans.Control--import Data.Default--- import Data.Foldable--- import Data.Functor-import Data.IORef-import Data.Maybe-import qualified Data.Map as M--import Graphics.UI.Gtk.Gdk.EventM-import Graphics.UI.Gtk.General.General-import Graphics.UI.Gtk.WebKit.WebDataSource-import Graphics.UI.Gtk.WebKit.WebFrame as W-import Graphics.UI.Gtk.WebKit.WebInspector-import Graphics.UI.Gtk.WebKit.WebView as W-import Graphics.UI.Gtk.Windows.Window--import Network.URI (URI, uriScheme)-import qualified Network.URI as N--import Prelude hiding(concat, mapM_)--import qualified System.Glib.Attributes as G--- }}}---- {{{ Types---newtype (Monad m) => KT m a = KT { unKT :: ErrorT HError (WriterT String (ReaderT CliOptions (ReaderT (IORef (Config (KT m))) (ReaderT (GUI (KT m)) (ReaderT IPC m))))) a}---    deriving (Applicative, Functor, Monad, MonadWriter String)---type K = KT IO-newtype K a = K { unKT :: ErrorT HError (WriterT String (ReaderT CliOptions (ReaderT (IORef (Config K)) (ReaderT (GUI K) (ReaderT IPC (ReaderT (IORef Keys.Status) IO)))))) a}-    deriving (Applicative, Functor, Monad, MonadBase IO, MonadError HError, MonadWriter String)--instance MonadBaseControl IO K where-    newtype StM K a  = StK { unStK :: StM (ErrorT HError (WriterT String (ReaderT CliOptions (ReaderT (IORef (Config K)) (ReaderT (GUI K) (ReaderT IPC (ReaderT (IORef Keys.Status) IO))))))) a }-    liftBaseWith f   = K . liftBaseWith $ \runInBase -> f $ liftM StK . runInBase . unKT-    restoreM         = K . restoreM . unStK--instance ConfigReader K K where-    readConfig l = K $ (lift . lift . lift) ask >>= io . readIORef >>= return . view l--instance ConfigWriter K K where-    writeConfig l v = K $ (lift . lift . lift) ask >>= io . (`modifyIORef` set l v)--instance GUIReader K K where-    readGUI l = K $ (lift . lift . lift . lift) ask >>= return . view l--instance IPCReader K where-    readIPC l = K $ (lift . lift . lift . lift . lift) ask >>= return . view l--instance NotificationReader K where-    readNotification l = K $ (lift . lift . lift . lift) ask >>= return . view (notificationBar.l)--instance OptionsReader K where-    readOptions l = K $ (lift . lift) ask >>= return . view l--instance PromptReader K K where-    readPrompt l = K $ (lift . lift . lift . lift) ask >>= return . view (promptBar.l)--instance Keys.StatusReader K where-    readStatus l = K $ (lift . lift . lift . lift . lift . lift) ask >>= io . readIORef >>= return . view l--instance Keys.StatusWriter K where-    writeStatus l v = K $ (lift . lift . lift . lift . lift . lift) ask >>= io . (`modifyIORef` set l v)--runK :: CliOptions -> Config K -> GUI K -> IPC -> K a -> IO ((Either HError a), String)-runK options config gui ipc k = do-    config'    <- newIORef config-    keysStatus <- newIORef def-    (`runReaderT` keysStatus) . (`runReaderT` ipc) . (`runReaderT` gui) . (`runReaderT` config'). (`runReaderT` options) . runWriterT . runErrorT $ unKT k---data CaseSensitivity = CaseSensitive | CaseInsensitive-data Direction       = Forward       | Backward-data Wrap            = Wrap          | NoWrap-data ZoomDirection   = In            | Out--- }}}----- {{{ Default configuration-instance Default (Config K) where-    def = Config {-        _homePage         = fromJust . N.parseURI $ "https://duckduckgo.com/",-        _verbosity        = Normal,-        _keyBindings      = defaultKeyBindings,-        _commands         = def,-        _onDownload       = defaultDownload,-        _onKeyStroke      = const $ return (),-        _onLinkClicked    = defaultLinkClicked,-        _onLoadFinished   = return (),-        _onLoadRequested  = \uri -> load uri,-        _onNewWindow      = \uri -> spawn "hbro" [show uri],-        _onResourceOpened = defaultResourceOpened,-        _onTitleChanged   = \title -> readGUI mainWindow >>= io . (`G.set` [ windowTitle G.:= ("hbro | " ++ title)])} -- return ()}---- | List of default supported requests.-instance Default (CommandsMap K) where-    def = CommandsMap . M.fromList $ [-    -- Get information-        ("GET_URI",           \_arguments -> show <$> getURI),-        ("GET_TITLE",         \_arguments -> show <$> getTitle),-        ("GET_FAVICON_URI",   \_arguments -> show <$> getFaviconURI),-        ("GET_LOAD_PROGRESS", \_arguments -> show <$> getLoadProgress),-    -- Trigger actions-        ("LOAD_URI",          \arguments -> case arguments of-            uri:_ -> parseURIReference uri >>= load >> return "OK"-            _     -> return "ERROR Argument needed."),-        ("STOP_LOADING",      \_arguments -> stopLoading >> return "OK"),-        ("RELOAD",            \_arguments -> reload      >> return "OK"),-        ("GO_BACK",           \_arguments -> goBack      >> return "OK"),-        ("GO_FORWARD",        \_arguments -> goForward   >> return "OK"),-        ("ZOOM_IN",           \_arguments -> zoomIn      >> return "OK"),-        ("ZOOM_OUT",          \_arguments -> zoomOut     >> return "OK")]---defaultDownload :: URI -> String -> Int -> K ()-defaultDownload _ _ _ = return ()--defaultLinkClicked :: (MonadBase IO m, MonadWriter String m, GUIReader n m) => MouseButton -> URI -> m ()-defaultLinkClicked MiddleButton uri = spawn "hbro" [show uri]-defaultLinkClicked _            uri = load uri---defaultKeyBindings :: M.Map Keys.Mode (Keys.Bindings K)-defaultKeyBindings = M.singleton Keys.Normal $ Keys.toBindings [-    -- Browse-        ("M-<Left>",      goBack),-        ("M-<Right>",     goForward),-        ("C-<Escape>",    stopLoading),-        ("<F5>",          reload),-        ("C-r",           reload),-        ("C-<F5>",        reloadBypassCache),-        ("M-r",           reloadBypassCache),-        ("C-^",           scroll Horizontal (Absolute 0)),-        ("C-$",           scroll Horizontal (Absolute 100)),-        ("C-<Home>",      scroll Vertical   (Absolute 0)),-        ("C-<End>",       scroll Vertical   (Absolute 100)),-        ("M-<Home>",      goHome),-    -- Copy/paste-        ("C-c",           getURI   >>= Clipboard.insert . show >> notify 5000 "URI copied to clipboard"),-        ("M-c",           getTitle >>= Clipboard.insert >> notify 5000 "Page title copied to clipboard"),-        ("C-v",           Clipboard.with $ parseURIReference >=> load),-        ("M-v",           Clipboard.with $ \uri -> spawn "hbro" [uri]),-    -- Display-        ("C-+",           zoomIn),-        ("C--",           zoomOut),-        -- ("<F11>",         with (_window . _UI) windowFullscreen),-        -- ("<Escape>",      with (_window . _UI) windowUnfullscreen),-        ("C-b",           toggleVisibility =<< readGUI statusBar),-        ("C-u",           toggleSourceMode),-    -- Prompt-        ("C-o",           Prompt.readURI "Open URI" "" load),-        ("M-o",           getURI >>= \uri -> Prompt.readURI "Open URI " (show uri) load),-    -- Search-        ("/",             Prompt.iread "Search " "" $ searchText_ CaseInsensitive Forward Wrap),-        ("C-f",           Prompt.iread "Search " "" $ searchText_ CaseInsensitive Forward Wrap),-        ("?",             Prompt.iread "Search " "" $ searchText_ CaseInsensitive Backward Wrap),-        ("C-n",           void . searchText CaseInsensitive Forward  Wrap =<< Prompt.getEntryValue),-        ("C-N",           void . searchText CaseInsensitive Backward Wrap =<< Prompt.getEntryValue),-    -- Misc-        ("<Escape>",      Prompt.hide),-        ("C-i",           inspect),-        ("C-p",           printPage),-        ("C-t",           spawn "hbro" []),-        ("C-w",           quit)]---- /!\ NetworkRequest's Haskell binding is missing the function "webkit_network_request_get_message", which makes it rather useless...--- | Display content if webview can show the given MIME type, otherwise download it.-defaultResourceOpened :: (MonadBase IO m, GUIReader n m) => URI -> String -> m ResourceAction-defaultResourceOpened _uri mimetype = do-    canShow <- io . (`webViewCanShowMimeType` mimetype) =<< readGUI webView-    return (canShow ? Load ?? Download)--- }}}---- {{{ Util-isCaseSensitive :: CaseSensitivity -> Bool-isCaseSensitive CaseSensitive = True-isCaseSensitive _             = False--isForward :: Direction -> Bool-isForward Forward = True-isForward _       = False--isWrapped :: Wrap -> Bool-isWrapped Wrap = True-isWrapped _    = False---{-getState :: (MonadBase IO m, MonadError HError m, Typeable a) => String -> a -> m a-getState key defaultValue = do-    customMap <- gets _custom-    let result = fromDynamic =<< M.lookup key customMap-    case result of-        Just value -> return value-        _          -> do-            modify $ \s -> s { _custom = M.insert key (toDyn defaultValue) customMap }-            return defaultValue-}--- }}}---- {{{ Getters-getFaviconURI :: (MonadBase IO m, GUIReader n m, MonadError HError m) => m URI-getFaviconURI = W.getIconUri =<< readGUI webView--getLoadProgress :: (MonadBase IO m, GUIReader n m) => m Double-getLoadProgress = io . W.webViewGetProgress =<< readGUI webView--getURI :: (MonadBase IO m, GUIReader n m, MonadError HError m) => m URI-getURI = W.getUri =<< readGUI webView--getTitle :: (MonadBase IO m, GUIReader n m, MonadError HError m) => m String-getTitle = W.getTitle =<< readGUI webView--- }}}----- {{{ Browsing-goHome :: (MonadBase IO m, GUIReader n m, ConfigReader n' m, MonadWriter String m) => m ()-goHome = load =<< readConfig homePage--load :: (MonadBase IO m, GUIReader n m, MonadWriter String m) => URI -> m ()-load uri = do-    tell $ "Loading URI: " ++ (show uri')-    io . (`W.webViewLoadUri` uri') =<< readGUI webView-  where-    uri' = case uriScheme uri of-             [] -> "http://" ++ show uri-             _  -> show uri--reload, reloadBypassCache :: (MonadBase IO m, GUIReader n m, MonadError HError m) => m ()-reload            = io . W.webViewReload =<< readGUI webView-reloadBypassCache = io . W.webViewReloadBypassCache =<< readGUI webView--stopLoading :: (MonadBase IO m, GUIReader n m, MonadWriter String m) => m ()-stopLoading = do-    io . W.webViewStopLoading =<< readGUI webView-    tell $ "Stopped loading"--goBack, goForward :: (MonadBase IO m, GUIReader n m, MonadError HError m) => m ()-goBack = do-    readGUI webView >>= io . W.webViewCanGoBack >>= (`unless` throwError CannotGoBack)-    io . W.webViewGoBack =<< readGUI webView-goForward = do-    readGUI webView >>= io . W.webViewCanGoForward >>= (`unless` throwError CannotGoForward)-    readGUI webView >>= io . W.webViewGoForward--- }}}---- {{{ Display--- | Toggle source display.--- Current implementation forces a refresh of current web page, which may be undesired.-toggleSourceMode :: (MonadBase IO m, GUIReader n m, MonadError HError m) => m ()-toggleSourceMode = do-    v <- readGUI webView-    io . W.webViewSetViewSourceMode v =<< (io $ not <$> W.webViewGetViewSourceMode v)-    reload--zoomIn, zoomOut :: (MonadBase IO m, GUIReader n m) => m ()-zoomIn  = io . W.webViewZoomIn  =<< readGUI webView-zoomOut = io . W.webViewZoomOut =<< readGUI webView--scroll :: (MonadBase IO m, GUIReader n m) => Axis -> Position -> m ()-scroll axis percentage = SW.scroll axis percentage =<< readGUI scrollWindow----- | Show web inspector for current webpage.-inspect :: (MonadBase IO m, GUIReader n m) => m ()-inspect = do-    inspector <- io . W.webViewGetInspector =<< readGUI webView-    io $ webInspectorInspectCoordinates inspector 0 0--- }}}---- {{{-searchText :: (MonadBase IO m, GUIReader n m) => CaseSensitivity -> Direction -> Wrap -> String -> m Bool-searchText s d w text = do-    v <- readGUI webView-    io $ W.webViewSearchText v text (isCaseSensitive s) (isForward d) (isWrapped w)--searchText_ :: (MonadBase IO m, GUIReader n m) => CaseSensitivity -> Direction -> Wrap -> String -> m ()-searchText_ s d w text = searchText s d w text >> return ()--printPage :: (MonadBase IO m, GUIReader n m) => m ()-printPage = io . W.webFramePrint =<< io . W.webViewGetMainFrame =<< readGUI webView--download :: (MonadBase IO m, ConfigReader m m) => URI -> m ()-download uri = do-    callback <- readConfig onDownload-    callback uri (show uri) 0--- }}}--quit :: (MonadBase IO m) => m ()-quit = io mainQuit----- {{{ Misc--- | Execute a javascript file on current webpage.-executeJSFile :: (MonadBase IO m, MonadReader r m, MonadWriter String m) => FilePath -> WebView -> m ()-executeJSFile filePath webView' = do-    tell $ "Executing Javascript file: " ++ filePath-    script <- io $ readFile filePath-    let script' = unwords . map (++ "\n") . lines $ script--    io $ webViewExecuteScript webView' script'--- }}}---- | Save current web page to a file,--- along with all its resources in a separated directory.--- Doesn't work for now, because web_resource_get_data's binding is missing...-_savePage :: String -> WebView -> IO ()-_savePage _path webView' = do-    frame        <- webViewGetMainFrame webView'-    dataSource   <- webFrameGetDataSource frame-    _mainResource <- webDataSourceGetMainResource dataSource-    _subResources <- webDataSourceGetSubresources dataSource-    return ()
− Hbro/Dyre.hs
@@ -1,61 +0,0 @@--- | Dynamic reconfiguration. Designed to be imported as @qualified@.-module Hbro.Dyre (-    wrap,-    recompile-) where---- {{{ Imports-import Hbro.Options hiding(recompile)-import Hbro.Util--import Config.Dyre-import Config.Dyre.Compile-import Config.Dyre.Paths--import Control.Lens-import Control.Monad.Base-import Control.Monad.Reader--import System.IO--- }}}---nullMain :: a -> IO ()-nullMain = const $ return ()---- Print various paths used for dynamic reconfiguration-printPaths :: MonadBase IO m => m ()-printPaths = io $ do-    (a, b, c, d, e) <- getPaths $ parameters nullMain False-    putStrLn $ unlines [-        "Current binary:  " ++ a,-        "Custom binary:   " ++ b,-        "Config file:     " ++ c,-        "Cache directory: " ++ d,-        "Lib directory:   " ++ e]---- Dynamic reconfiguration settings-parameters :: (a -> IO ()) -> Bool -> Params (Either String a)-parameters main verbose' = defaultParams {-    projectName             = "hbro",-    showError               = const Left,-    realMain                = main',-    ghcOpts                 = ["-threaded"],-    statusOut               = hPutStrLn stderr,-    includeCurrentDirectory = False}-  where-    main' (Left e)  = putStrLn e-    main' (Right x) = do-      when verbose' printPaths-      main x--wrap :: (a -> IO ()) -> CliOptions -> a -> IO ()-wrap main opts args = do-    wrapMain ((parameters main (opts^.verbose)) { configCheck = not $ opts^.vanilla }) $ Right args----- | Launch a recompilation of the configuration file-recompile :: IO (Maybe String)-recompile = do-    customCompile  $ parameters nullMain False-    getErrorString $ parameters nullMain False
− Hbro/Error.hs
@@ -1,45 +0,0 @@-module Hbro.Error where---- {{{ Imports-import Control.Monad.Error--import Data.Maybe--import Graphics.UI.Gtk.WebKit.Download-import Graphics.UI.Gtk.WebKit.NetworkRequest--import System.IO.Error--- }}}--data HError =-    CannotGoBack-  | CannotGoForward-  | EmptyCallback-  | EmptyClipboard-  | EmptyDownloadURI Download-  | EmptyRequestURI NetworkRequest-  | EmptySuggestedFileName Download-  | InvalidIconURI-  | InvalidPageTitle-  | InvalidPageURI-  | InvalidURI String-  | IOE IOError-  | OtherError String--instance Error HError where-    strMsg = OtherError--instance Show HError where-    show CannotGoBack               = "Unable to go back: already at oldest page."-    show CannotGoForward            = "Unable to go forward: already at newest page."-    show (IOE e)                    = "IO error: " ++ ioeGetLocation e ++ ": " ++ fromMaybe "" (ioeGetFileName e) ++ " " ++ ioeGetErrorString e-    show InvalidIconURI             = "No favicon URI."-    show InvalidPageTitle           = "No page title."-    show InvalidPageURI             = "Invalid page URI."-    show (InvalidURI s)             = show s-    show (EmptyDownloadURI _)       = "Invalid download URI."-    show (EmptyClipboard)           = "Empty clipboard."-    show (EmptySuggestedFileName _) = "No suggested name for this download."-    show (EmptyRequestURI _)        = "Invalid request URI."-    show EmptyCallback              = "No callback defined."-    show (OtherError s)             = show s
− Hbro/Gtk/ScrolledWindow.hs
@@ -1,34 +0,0 @@-module Hbro.Gtk.ScrolledWindow where---- {{{ Imports-import Hbro.Util--import Control.Monad.Base--import Graphics.UI.Gtk.Misc.Adjustment-import Graphics.UI.Gtk.Scrolling.ScrolledWindow--- }}}--data Axis     = Horizontal | Vertical-data Position = Absolute Double | Relative Double---getAdjustment :: (MonadBase IO m) => Axis -> ScrolledWindow -> m Adjustment-getAdjustment Horizontal = io . scrolledWindowGetHAdjustment-getAdjustment Vertical   = io . scrolledWindowGetVAdjustment----- | General scrolling command.-scroll :: (MonadBase IO m) => Axis -> Position -> ScrolledWindow -> m ()-scroll axis percentage scrollWindow = io $ do-     adj     <- io . getAdjustment axis $ scrollWindow-     page    <- io $ adjustmentGetPageSize adj-     current <- io $ adjustmentGetValue adj-     lower   <- io $ adjustmentGetLower adj-     upper   <- io $ adjustmentGetUpper adj--     let shift (Absolute x) = lower   + x/100 * (upper - page - lower)-         shift (Relative x) = current + x/100 * page-         limit x            = (x `max` lower) `min` (upper - page)--     io $ adjustmentSetValue adj $ limit (shift percentage)
− Hbro/Gui.hs
@@ -1,249 +0,0 @@-{-# LANGUAGE FlexibleInstances, TemplateHaskell #-}-module Hbro.Gui (-    Buildable(..),-    StatusBar(..),-    GUI(),-    GUIReader(..),-    mainWindow,-    inspectorWindow,-    scrollWindow,-    webView,-    promptBar,-    statusBar,-    notificationBar,-    builder,-    getObject,-    toggleVisibility,-    buildFrom,-    init)-where---- {{{ Imports-import Hbro.Notification-import Hbro.Prompt (PromptBar(..), PromptReader(..))-import qualified Hbro.Prompt as Prompt-import Hbro.Util-import qualified Hbro.Webkit.WebView as WebView--import Control.Applicative-import Control.Conditional hiding(when)-import Control.Lens hiding((??), view)-import Control.Monad hiding(forM_, mapM_)-import Control.Monad.Base-import Control.Monad.Error  hiding(forM_, mapM_)-import Control.Monad.Trans.Control---- import Data.Foldable--- import Data.Functor-import Data.IORef--import Graphics.Rendering.Pango.Enums-import Graphics.UI.Gtk.Abstract.Container-import Graphics.UI.Gtk.Abstract.Box-import Graphics.UI.Gtk.Abstract.Object-import Graphics.UI.Gtk.Abstract.Widget-import Graphics.UI.Gtk.Builder-import Graphics.UI.Gtk.Display.Label-import Graphics.UI.Gtk.Entry.Entry-import Graphics.UI.Gtk.Gdk.EventM-import Graphics.UI.Gtk.General.General as GTK-import Graphics.UI.Gtk.Layout.HBox-import Graphics.UI.Gtk.Layout.VBox-import Graphics.UI.Gtk.Scrolling.ScrolledWindow-import Graphics.UI.Gtk.WebKit.WebInspector-import Graphics.UI.Gtk.WebKit.WebView hiding(webViewLoadUri)-import Graphics.UI.Gtk.Windows.Window--import Prelude hiding(init, mapM_)--import System.Glib.Attributes hiding(get, set)-import qualified System.Glib.Attributes as G (get, set)-import System.Glib.Signals-import System.Glib.Types--- }}}---- {{{ Types-newtype StatusBar = StatusBar HBox--instance GObjectClass StatusBar where-    toGObject (StatusBar h) = toGObject h-    unsafeCastGObject g     = StatusBar $ unsafeCastGObject g-instance ObjectClass StatusBar-instance WidgetClass StatusBar---data GUI m = GUI {-    _mainWindow         :: Window,-    _inspectorWindow    :: Window,-    _scrollWindow       :: ScrolledWindow,  -- ^ 'ScrolledWindow' containing the webview-    _webView            :: WebView,-    _promptBar          :: PromptBar m,-    _statusBar          :: StatusBar,-    _notificationBar    :: NotificationBar,-    _builder            :: Builder          -- ^ Builder object created from XML file-}--makeLenses ''GUI---- | 'MonadReader' for 'GUI'-class (Monad m) => GUIReader n m | m -> n where-    readGUI :: Simple Lens (GUI n) a -> m a---- | UI elements that can be built from a @GtkBuilder@ object (that is: an XML file)-class Buildable a where-    build :: (MonadBase IO m) => Builder -> m a--instance (Monad m) => Buildable (PromptBar m) where-    build b = io $ do-        l  <- builderGetObject b castToLabel "promptDescription"-        e  <- builderGetObject b castToEntry "promptEntry"-        b' <- builderGetObject b castToHBox  "promptBox"-        oC <- newIORef . const $ return ()-        oV <- newIORef . const $ return ()--        return $ PromptBar b' l e oC oV--instance Buildable (WebView, ScrolledWindow) where-    build b = io $ do-        window  <- builderGetObject b castToScrolledWindow "webViewParent"-        wv      <- webViewNew-        containerAdd window wv--        return (wv, window)--instance Buildable (Window, VBox) where-    build b = io $ do-        w  <- builderGetObject b castToWindow "mainWindow"-        b' <- builderGetObject b castToVBox "windowBox"-        return (w, b')--instance Buildable StatusBar where-    build b = io $ StatusBar <$> builderGetObject b castToHBox "statusBox"--instance Buildable NotificationBar where-    build b = io $ NotificationBar <$> builderGetObject b castToLabel "notificationLabel" <*> newIORef Nothing--instance (Monad m) => Buildable (GUI m) where-    build b = do-        (webView', sWindow') <- build b-        (window', wBox')     <- build b-        promptBar'           <- build b-        statusBar'           <- build b-        notificationBar'     <- build b-        inspectorWindow'     <- initWebInspector webView' wBox'--        return $ GUI window' inspectorWindow' sWindow' webView' promptBar' statusBar' notificationBar' b--- }}}----- {{{ Util--- | Return the casted 'GObject' corresponding to the given name (set in the builder's XML file)-getObject :: (MonadBase IO m, GUIReader n m, GObjectClass a) => (GObject -> a) -> String -> m a-getObject cast name = do-    b <- readGUI builder-    io $ builderGetObject b cast name---- | Toggle a widget's visibility (provided for convenience).-toggleVisibility :: (MonadBase IO m, WidgetClass a) => a -> m ()-toggleVisibility widget = io $ do-    visibility <- G.get widget widgetVisible-    visibility ? widgetHide widget ?? widgetShow widget--- }}}----- {{{ Initialization-buildFrom :: (Monad n, MonadBase IO m) => FilePath -> m (GUI n)-buildFrom uiFile = do-    b <- io builderNew-    io $ builderAddFromFile b uiFile-    build b---init :: (MonadBase IO m, MonadBaseControl IO m, GUIReader m m, NotificationReader m, PromptReader m m, Error e, Show e, MonadError e m) => m ()-init = do-    w  <- readGUI webView-    mw <- readGUI mainWindow-    initWindow       mw-    initScrollWindow =<< readGUI scrollWindow-    Prompt.init      =<< readGUI promptBar-    WebView.init     w--    io . windowSetDefault mw $ Just w---- Validate/cancel prompt-    e <- readGUI $ promptBar.(Prompt.entry)-    io . void $ on e keyPressEvent (f w)---- Show window-    io . widgetShowAll =<< readGUI mainWindow-    Prompt.hide--    return ()-  where-    f w = do-        key <- eventKeyName-        when (key == "Return" || key == "Escape") $ io $ do-            --runInIO clean-            widgetGrabFocus w-            return ()-        return False---initScrollWindow :: (MonadBase IO m) => ScrolledWindow -> m ()-initScrollWindow window = io $ scrolledWindowSetPolicy window PolicyNever PolicyNever---initWindow :: (MonadBase IO m) => Window -> m ()-initWindow window = io $ do-    windowSetDefaultSize window 1024 768-    widgetModifyBg window StateNormal (Color 0 0 10000)-    void $ onDestroy window GTK.mainQuit---initWebInspector :: (MonadBase IO m) => WebView -> VBox -> m (Window)-initWebInspector webView' windowBox = do-    inspector <- io $ webViewGetInspector webView'-    window'   <- io windowNew-    io $ G.set window' [ windowTitle := "hbro | Web inspector" ]--    io . void . on inspector inspectWebView $ \_ -> do-        view <- webViewNew-        containerAdd window' view-        return view--    io . void . on inspector showWindow $ do-        widgetShowAll window'-        return True---- TODO: when does this signal happen ?!-    --_ <- on inspector finished $ return ()---- Attach inspector to browser's main window-    _ <- io $ on inspector attachWindow $ do-        webview <- webInspectorGetWebView inspector-        case webview of-            Just view -> do-                widgetHide window'-                containerRemove window' view-                widgetSetSizeRequest view (-1) 250-                boxPackEnd windowBox view PackNatural 0-                widgetShow view-                return True-            _ -> return False---- Detach inspector in a distinct window-    _ <- io $ on inspector detachWindow $ do-        webview <- webInspectorGetWebView inspector-        _ <- case webview of-            Just view -> do-                containerRemove windowBox view-                containerAdd window' view-                widgetShowAll window'-                return True-            _ -> return False--        widgetShowAll window'-        return True--    return window'--- }}}
− Hbro/IPC.hs
@@ -1,64 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--- | Designed to be imported as @qualified@.-module Hbro.IPC where---- {{{ Imports--- import Hbro.Error-import Hbro.Util--import Control.Lens hiding(Context)-import Control.Monad.Base--- import Control.Monad.Error hiding(mapM_)--- import Control.Monad.Writer--import Data.ByteString.Char8 (pack, unpack)---import Data.Foldable-import Data.Functor-import Data.Map (Map)---- import Graphics.UI.Gtk.General.General--import Prelude hiding(log, mapM_, read)---- import System.Posix.Types--- import System.Process-import System.ZMQ4 hiding(close, context, init, message, receive, send, socket)-import qualified System.ZMQ4 as ZMQ (receive, send)--- }}}---- {{{ Types-data IPC = IPC {-    _context  :: Context,-    _receiver :: Socket Rep}---- | 'MonadReader' for 'IPC'-class IPCReader m where-    readIPC :: Simple Lens IPC a -> m a--makeLenses ''IPC--newtype CommandsMap m = CommandsMap { unwrap :: Map String ([String] -> m String) }--- }}}---- | Send message through given socket-send :: (MonadBase IO m, Sender a) => Socket a -> String -> m ()-send socket payload = io $ ZMQ.send socket [] (pack payload)---- | Wait for a message to be received from given socket-read :: (MonadBase IO m, Receiver a) => Socket a -> m String-read socket = io $ unpack <$> ZMQ.receive socket---- | Send a single command to the given socket (which must be 'Rep'), and return the answer-sendCommand :: (MonadBase IO m, IPCReader m) => String -> String -> m String-sendCommand socketURI command = do-    theContext <- readIPC context-    io $ withSocket theContext Req $ \socket -> do-      connect socket socketURI-      send socket command-      read socket---- | Same as 'sendCommand', but for all running instances of the browser.-{-sendCommandToAll :: (MonadBase IO m, ConfigReader m m, IPCReader m) => String -> m [String]-sendCommandToAll command = do-    dir  <- readConfig socketDir-    getAllProcessIDs >>= mapM ((`sendCommand` command) . (`socketPath` dir))-}
− Hbro/Keys.hs
@@ -1,194 +0,0 @@-{-# LANGUAGE FlexibleInstances, TemplateHaskell, TupleSections #-}--- | Key bindings model.--- Designed to be imported as @qualified@.-module Hbro.Keys (-    Tree(..),-    Stroke,-    Bindings,-    Mode(..),-    Status(..),-    mode,-    strokes,-    StatusReader(..),-    StatusWriter(..),-    StatusState,-    mkStroke,-    merge,-    lookup,-    deserialize,-    prefixMod,-    serialize,-    toString,-    mkBinding,-    toBindings)-where---- {{{ Imports--- import Hbro.Util--import Control.Lens-import Control.Monad hiding(forM_)--- import Control.Monad.Error hiding(forM_)--- import Control.Monad.IO.Class--- import Control.Monad.Reader hiding(forM_)--- import Control.Monad.Trans.Control--import Data.Default--- import Data.Foldable-import Data.Functor--- import Data.Monoid-import Data.Map (Map)-import qualified Data.Map as M-import Data.Maybe-import Data.Set (Set)-import qualified Data.Set as S hiding(foldl)--import Graphics.UI.Gtk.Abstract.Widget-import Graphics.UI.Gtk.Gdk.EventM-import Graphics.UI.Gtk.Gdk.Keys--- import Graphics.UI.Gtk.General.Enums--import Prelude hiding(lookup, mapM_)--- }}}----- {{{ Types--- | A tree implementation that labels edges-data Tree edge leaf = Empty | Leaf leaf | Branch (Map edge (Tree edge leaf)) deriving(Show)---- | A single keystroke, i.e. a set of modifiers and a single key (its string description)-type Stroke = (Set Modifier, String)---- | List of keys bound to actions-type Bindings m = Tree Stroke (m ())---data Mode = Normal | Insert deriving(Eq, Ord)---- | Global state-data Status = Status {-    _mode     :: Mode,     -- ^ Current mode-    _strokes  :: [Stroke]  -- ^ Previous keystrokes-    }--instance Default Status where-    def = Status Normal []--makeLenses ''Status---- | 'MonadReader' for 'Status'-class StatusReader m where-    readStatus :: Simple Lens Status a -> m a---- | 'MonadWriter' for 'Status'-class StatusWriter m where-    writeStatus :: Simple Lens Status a -> a -> m ()---- | 'MonadState' for 'Status'-type (StatusState m) = (StatusReader m, StatusWriter m)--{-instance Monoid KeyMap where-    mempty = KeyBindings M.empty-    mappend (KeyBindings a) (KeyBindings b) = KeyBindings (mappend a b)-}--instance Ord Modifier where-    compare x y = compare (show x) (show y)--- }}}---mkStroke :: [Modifier] -> KeyVal -> Maybe Stroke-mkStroke m k = Just . (S.fromList m,) =<< toString k-----toTree :: Ord a => [([a], b)] -> Tree a b---toTree = foldl merge Empty . map toBranch--toBranch :: Ord a => ([a], b) -> Tree a b-toBranch ([], a)    = Leaf a-toBranch ((h:t), a) = Branch (M.fromList [(h, toBranch (t, a))])---- | In case of conflicts, the rightmost operand is preferred-merge :: Ord a => Tree a b -> Tree a b -> Tree a b-merge Empty      x          = x-merge x          Empty      = x-merge (Leaf _)   (Leaf b)   = Leaf b-merge (Leaf _)   (Branch b) = Branch b-merge (Branch _) (Leaf b)   = Leaf b-merge (Branch a) (Branch b) = Branch $ M.unionWith merge a b---lookup :: Ord a => [a] -> Tree a b -> Maybe (Tree a b)-lookup _     Empty      = Nothing-lookup []    (Leaf x)   = Just (Leaf x)-lookup []    x          = Just x-lookup _     (Leaf _)   = Nothing-lookup (h:t) (Branch m) = M.lookup h m >>= lookup t----- | Convert a KeyVal to a String.--- For printable characters, the corresponding String is returned, except for the space character for which "<Space>" is returned.--- For non-printable characters, the corresponding keyName wrapped into "< >" is returned.--- For modifiers, Nothing is returned.-toString :: KeyVal -> Maybe String-toString keyVal = case keyToChar keyVal of-    Just ' '    -> Just "<Space>"-    Just char   -> Just [char]-    _           -> case keyName keyVal of-        "Caps_Lock"         -> Nothing-        "Shift_L"           -> Nothing-        "Shift_R"           -> Nothing-        "Control_L"         -> Nothing-        "Control_R"         -> Nothing-        "Alt_L"             -> Nothing-        "Alt_R"             -> Nothing-        "Super_L"           -> Nothing-        "Super_R"           -> Nothing-        "Menu"              -> Nothing-        "ISO_Level3_Shift"  -> Nothing-        "dead_circumflex"   -> Just "^"-        "dead_diaeresis"    -> Just "¨"-        x                   -> Just ('<':x ++ ">")---serialize :: Stroke -> String-serialize (m, k) = S.foldr (++) "" (S.map serializeMod m) ++ k---serializeMod :: Modifier -> String-serializeMod Control = "C-"--- serializeMod Shift   = "S-"-serializeMod Alt     = "M-"-serializeMod _       = ""---- | Parse a 'String' representation of a keystrokes chain-deserialize :: String -> Maybe [Stroke]-deserialize ""          = Just []-deserialize (' ':t)     = deserialize t-deserialize ('C':'-':t) = prefixMod Control =<< deserialize t-deserialize ('M':'-':t) = prefixMod Alt     =<< deserialize t--- deserialize ('S':'-':t) = prefixMod Shift   =<< deserialize t-deserialize (k:' ':t)   = prepend k <$> deserialize t-deserialize (k:t)       = prefixVal k =<< deserialize t---prefixMod :: Modifier -> [Stroke] -> Maybe [Stroke]-prefixMod modifier ((m, keys):t) = Just ((S.insert modifier m, keys):t)-prefixMod _        _             = Nothing---prefixVal :: Char -> [Stroke] -> Maybe [Stroke]-prefixVal k [] = Just [(S.empty, [k])]-prefixVal k ((modifiers, keys):t)-    | S.null modifiers = Just ((modifiers, k:keys):t)-    | otherwise        = Nothing---prepend :: Char -> [Stroke] -> [Stroke]-prepend k x = (S.empty, [k]):x---mkBinding :: String -> m () -> Maybe (Bindings m)-mkBinding keys action = toBranch . (, action) <$> deserialize keys--toBindings :: [(String, m ())] -> Bindings m-toBindings = foldl merge Empty . catMaybes . map (\(a, b) -> mkBinding a b)
− Hbro/Main.hs
@@ -1,9 +0,0 @@-module Main where---- {{{ Imports-import Hbro--- }}}---- Default main function provided as example-main :: IO ()-main = hbro $ return ()
− Hbro/Network.hs
@@ -1,18 +0,0 @@--- | Functions from 'Network.URI' rewritten with 'MonadError' instead of 'Maybe'.-module Hbro.Network where---- {{{ Imports-import Hbro.Error--import Control.Monad.Error--import Network.URI as N--- }}}---parseURIReference :: (MonadError HError m) => String -> m URI-parseURIReference uri = maybe (throwError $ InvalidURI uri) return $ N.parseURIReference uri---parseURI :: (MonadError HError m) => String -> m URI-parseURI uri = maybe (throwError $ InvalidURI uri) return $ N.parseURI uri
− Hbro/Notification.hs
@@ -1,53 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}-module Hbro.Notification where---- {{{ Imports-import Hbro.Util--import Control.Lens-import Control.Monad.Base-import Control.Monad.Error hiding(forM_, mapM_)--import Data.Foldable-import Data.IORef--import Graphics.Rendering.Pango.Enums-import Graphics.UI.Gtk.Display.Label-import Graphics.UI.Gtk.General.General--import Prelude hiding(mapM_)--- }}}---- {{{ Types-data NotificationBar = NotificationBar {-    _label :: Label,-    _timer :: IORef (Maybe HandlerId)}--makeLenses ''NotificationBar---- | 'MonadReader' for 'NotificationBar'-class NotificationReader m where-    readNotification :: Simple Lens NotificationBar a -> m a---- | 'MonadWriter' for 'NotificationBar'-class (Monad m) => NotificationWriter m where-    writeNotification :: Simple Lens NotificationBar a -> a -> m a---- | 'MonadState' for 'NotificationBar'-type NotificationState m = (NotificationReader m, NotificationWriter m)--- }}}---notify :: (Functor m, MonadBase IO m, NotificationReader m, Error e, MonadError e m) => Int -> String -> m ()-notify duration text = do-    label'  <- readNotification label-    handler <- readNotification timer--    io $ do-        labelSetAttributes label' [AttrForeground {paStart = 0, paEnd = -1, paColor = Color 32767 32767 32767}]-        labelSetMarkup label' text-        mapM_ timeoutRemove =<< readIORef handler--    newID <- io $ timeoutAdd (labelSetMarkup label' "" >> return False) duration-    io . void $ writeIORef handler (Just newID)-    return ()
− Hbro/Options.hs
@@ -1,156 +0,0 @@-{-# LANGUAGE FlexibleInstances, TemplateHaskell #-}--- | Commandline options tools. Designed to be imported as @qualified@.-module Hbro.Options (-    CliOptions(),-    OptionsReader(..),-    startURI,-    socketPath,-    help,-    quiet,-    uIFile,-    verbose,-    version,-    vanilla,-    recompile,-    denyReconf,-    forceReconf,-    dyreDebug,-    usage,-    get,-    getStartURI,-    getSocketURI)-where---- {{{ Imports-import Hbro.Util--import Control.Conditional-import Control.Lens as L  hiding((??))-import Control.Monad.Base-import Control.Monad.Reader--import Data.Default-import Data.Functor-import Data.List-import Data.Maybe--import Network.URI as N--import Prelude hiding(log)--import System.Console.GetOpt-import System.Directory-import System.Environment-import System.FilePath-import System.Posix.Process--- }}}---- {{{ Types--- | Available commandline options (cf @hbro -h@).-data CliOptions = CliOptions {-    _startURI      :: Maybe String,-    _socketPath    :: Maybe FilePath,-    _UIFile        :: Maybe FilePath,-    _help          :: Bool,-    _quiet         :: Bool,-    _verbose       :: Bool,-    _version       :: Bool,-    _vanilla       :: Bool,-    _recompile     :: Bool,-    _denyReconf    :: Bool,-    _forceReconf   :: Bool,-    _dyreDebug     :: Bool}-    deriving(Eq)--makeLenses ''CliOptions--instance Show CliOptions where-    show opts = intercalate " " $ catMaybes [-        return . ("URI=" ++)     =<< view startURI opts,-        return . ("SOCKET=" ++)  =<< view socketPath opts,-        return . ("UI_FILE=" ++) =<< view uIFile opts,-        view help        opts ? Just "HELP" ?? Nothing,-        view quiet       opts ? Just "QUIET" ?? Nothing,-        view verbose     opts ? Just "VERBOSE" ?? Nothing,-        view version     opts ? Just "VERSION" ?? Nothing,-        view vanilla     opts ? Just "VANILLA" ?? Nothing,-        view recompile   opts ? Just "RECOMPILE" ?? Nothing,-        view denyReconf  opts ? Just "DENY_RECONFIGURATION" ?? Nothing,-        view forceReconf opts ? Just "FORCE_RECONFIGURATION" ?? Nothing,-        view dyreDebug   opts ? Just "DYRE_DEBUG" ?? Nothing]--instance Default CliOptions where-    def = CliOptions {-        _startURI     = Nothing,-        _socketPath   = Nothing,-        _UIFile       = Nothing,-        _help         = False,-        _quiet        = False,-        _verbose      = False,-        _version      = False,-        _vanilla      = False,-        _recompile    = False,-        _denyReconf   = False,-        _forceReconf  = False,-        _dyreDebug    = False}---- | 'MonadReader' for 'CliOptions'-class OptionsReader m where-    readOptions :: Simple Lens CliOptions a -> m a--instance (Monad m) => OptionsReader (ReaderT CliOptions m) where-    readOptions l = return . view l =<< ask--instance OptionsReader ((->) CliOptions) where-    readOptions l = view l--- }}}---description :: [OptDescr (CliOptions -> CliOptions)]-description = [-    Option ['h']     ["help"]               (NoArg (set help True))                         "Print this help",-    Option ['q']     ["quiet"]              (NoArg (set quiet True))                        "Do not print any log",-    Option ['v']     ["verbose"]            (NoArg (set verbose True))                      "Print detailed logs",-    Option ['V']     ["version"]            (NoArg (set version True))                      "Print version",-    Option ['1']     ["vanilla"]            (NoArg (set vanilla True))                      "Do not read custom configuration file",-    Option ['r']     ["recompile"]          (NoArg (set recompile True))                    "Only recompile configuration",-    Option ['s']     ["socket"]             (ReqArg (\v -> set socketPath (Just v)) "PATH") "Where to open IPC socket",-    Option ['u']     ["ui"]                 (ReqArg (\v -> set uIFile (Just v)) "PATH")     "Path to UI descriptor (XML file)",-    Option []        ["force-reconf"]       (NoArg id)                                      "Recompile configuration before starting the program",-    Option []        ["deny-reconf"]        (NoArg id)                                      "Do not recompile configuration even if it has changed",-    Option []        ["dyre-debug"]         (NoArg id)                                      "Use './cache/' as the cache directory and ./ as the configuration directory. Useful to debug the program"]---- | Usage text (cf @hbro -h@)-usage :: String-usage = usageInfo "Usage: hbro [OPTIONS] [URI]" description---- | Get and parse commandline options-get :: (MonadBase IO m) => m CliOptions-get = io $ do-    options <- getOpt' Permute description <$> getArgs-    case options of-        (opts, input, _, []) -> return $ set startURI ((null $ concat input) ? Nothing ?? Just (concat input)) (foldl (flip id) def opts)-        (_, _, _, _)         -> return def---- | Get URI passed in commandline, check whether it is a file path or an internet URI--- and return the corresponding normalized URI (that is: prefixed with "file://" or "http://")-getStartURI :: (MonadBase IO m, OptionsReader m) => m (Maybe URI)-getStartURI = do-    theURI <- readOptions startURI-    case theURI of-      Just uri -> do-          fileURI <- io $ doesFileExist uri-          case fileURI of-              True -> io getCurrentDirectory >>= return . N.parseURIReference . ("file://" ++) . (</> uri)-              _    -> return $ N.parseURIReference uri-      _ -> return Nothing----- | Return socket URI used by this instance-getSocketURI :: (MonadBase IO m, OptionsReader m) => m String-getSocketURI = maybe getDefaultSocketURI (return . ("ipc://" ++)) =<< readOptions socketPath-  where-    getDefaultSocketURI = do-      dir <- io getTemporaryDirectory-      pid <- io getProcessID-      return $ "ipc://" ++ dir </> "hbro." ++ show pid
− Hbro/Prompt.hs
@@ -1,175 +0,0 @@-{-# LANGUAGE FlexibleInstances, TemplateHaskell #-}--- | Designed to be imported as @qualified@.-module Hbro.Prompt(-    PromptBar(..),-    onChanged,-    onValidated,-    entry,-    description,-    box,-    PromptReader(..),-    init,-    open,-    hide,-    clean,-    read,-    incrementalRead,-    iread,-    readURI,-    getEntryValue)-where---- {{{ Imports-import Hbro.Error--- import Hbro.Gui-import Hbro.Network-import Hbro.Notification-import Hbro.Util--import Control.Conditional hiding(when)-import Control.Lens hiding((??))-import Control.Monad hiding(forM_, mapM_)-import Control.Monad.Base-import Control.Monad.Error hiding(forM_, mapM_, when)-import Control.Monad.Writer-import Control.Monad.Trans.Control---- import Data.Foldable--- import Data.Functor-import Data.IORef--import Graphics.Rendering.Pango.Enums-import Graphics.UI.Gtk.Abstract.Widget--- import Graphics.UI.Gtk.Builder-import Graphics.UI.Gtk.Display.Label-import Graphics.UI.Gtk.Entry.Editable-import Graphics.UI.Gtk.Entry.Entry-import Graphics.UI.Gtk.Gdk.EventM-import Graphics.UI.Gtk.Layout.HBox--import Network.URI hiding(parseURIReference)--import Prelude hiding(init, mapM_, read)--import System.Glib.Signals--- }}}---- {{{ Types-data PromptBar m = PromptBar {-    _box           :: HBox,-    _description   :: Label,-    _entry         :: Entry,-    _onChanged     :: IORef (String -> m ()),-    _onValidated   :: IORef (String -> m ())}--makeLenses ''PromptBar--class (Monad m, Monad n) => PromptReader n m | m -> n where-    readPrompt :: Simple Lens (PromptBar n) a -> m a--- }}}---- Validate/cancel prompt-onEntryValidated :: (MonadBase IO m, MonadBaseControl IO m, NotificationReader m, Error e, Show e, MonadError e m, EntryClass t) => t -> (String -> m ()) -> m (ConnectId t)-onEntryValidated entry' f = liftBaseWith $ \runInIO -> on entry' keyPressEvent $ do-    key <- eventKeyName-    io $ when (key == "Return") $ do-        void . runInIO $ (io (entryGetText entry') >>= f) `catchError` \e -> io (print e) >> notify 5000 (show e)-    return False---- Incremental behavior-onEntryChanged :: (MonadBaseControl IO m, NotificationReader m, Error e, Show e, MonadError e m, EditableClass t, EntryClass t) => t -> (String -> m ()) -> m (ConnectId t)-onEntryChanged entry' f = liftBaseWith $ \runInIO -> on entry' editableChanged $ do-    void . runInIO $ (io (entryGetText entry') >>= f) `catchError` \e -> io (print e) >> notify 5000 (show e)---init :: (MonadBase IO m, MonadBaseControl IO m, NotificationReader m, Error e, Show e, MonadError e m) => PromptBar m -> m ()-init promptBar = do-    io $ labelSetAttributes l [allItalic, allBold]-    io $ labelSetAttributes l [AttrForeground {paStart = 0, paEnd = -1, paColor = Color 32767 32767 32767}]--    io $ widgetModifyBase entry' StateNormal $ Color 0 0 0-    io $ widgetModifyText entry' StateNormal $ Color 32767 32767 32767--    void . onEntryChanged   entry' $ \v -> io (readIORef onChanged')   >>= \f -> f v-    void . onEntryValidated entry' $ \v -> io (readIORef onValidated') >>= \f -> f v-  where-    l            = _description promptBar-    entry'       = _entry promptBar-    onChanged'   = _onChanged promptBar-    onValidated' = _onValidated promptBar---open :: (Functor m, MonadBase IO m, PromptReader n m, MonadWriter String m) => String -> String -> m ()-open newDescription defaultText = do-    tell "Opening prompt."-    e <- readPrompt entry-    io . (`labelSetText` newDescription) =<< readPrompt description-    io $ entrySetText e defaultText-    io . widgetShow =<< readPrompt box-    io $ widgetGrabFocus e-    io $ editableSetPosition e (-1)--hide :: (MonadBase IO m, PromptReader n m) => m ()-hide = io . widgetHide =<< readPrompt box---- | Close prompt, clean its content and callbacks-clean :: (MonadBase IO m, PromptReader n m) => m ()-clean = do-     e <- readPrompt entry-     io $ (`widgetRestoreText` StateNormal) e-     io . widgetModifyText e StateNormal $ Color 32767 32767 32767-     hide--     readPrompt onChanged   >>= io . (`writeIORef` return (return ()))-     readPrompt onValidated >>= io . (`writeIORef` return (return ()))-     return ()---- | Open prompt bar with given description and default value,--- and register a callback to trigger at validation.-read :: (MonadBaseControl IO m, PromptReader m m, Error e, MonadError e m, MonadWriter String m)-     => String        -- ^ Prompt description-     -> String        -- ^ Initial value-     -> (String -> m ())    -- ^ Function to trigger when validating prompt value-     -> m ()-read = read' False---- | Same as 'read', but callback is triggered for each change in prompt's entry.-incrementalRead :: (MonadBase IO m, MonadBaseControl IO m, PromptReader m m, Error e, MonadError e m, MonadWriter String m) => String -> String -> (String -> m ())  -> m ()-incrementalRead = read' True---- | Alias for 'incrementalRead'.-iread :: (MonadBaseControl IO m, PromptReader m m, Error e, MonadError e m, MonadWriter String m) => String -> String -> (String -> m ())  -> m ()-iread = incrementalRead--read' :: (MonadBaseControl IO m, PromptReader m m, Error e, MonadError e m, MonadWriter String m) => Bool -> String -> String -> (String -> m ()) -> m ()-read' incremental description' startValue f = do-    clean-    open description' startValue--    when incremental $ readPrompt onChanged >>= io . (`writeIORef` f)-    readPrompt onValidated >>= io . (`writeIORef` (f >=> const clean))-    return ()----- | Same as 'read' for URI values-readURI :: (MonadBase IO m, PromptReader m m, MonadError HError m, MonadWriter String m) => String -> String -> (URI -> m ()) -> m ()-readURI description' startValue callback = do-    clean-    open description' startValue-    checkURI startValue--    readPrompt onChanged   >>= io . (`writeIORef` checkURI)-    readPrompt onValidated >>= io . (`writeIORef` (parseURIReference >=> callback >=> const clean))-    return ()-  where-    checkURI v = do-        e <- readPrompt entry-        io $ widgetModifyText e StateNormal color-      where-        color = (isURIReference v) ? green ?? red-        green = Color     0 65535 0-        red   = Color 65535     0 0---getEntryValue :: (MonadBase IO m, PromptReader n m) => m String-getEntryValue = io . entryGetText =<< readPrompt entry
− Hbro/Util.hs
@@ -1,76 +0,0 @@-module Hbro.Util where---- {{{ Imports-import Control.Concurrent-import Control.Exception-import Control.Monad hiding(mapM_)-import Control.Monad.Base--- import Control.Monad.Error hiding(mapM_)--- import Control.Monad.Reader hiding(mapM_)-import Control.Monad.Trans.Control---- import Data.Foldable-import Data.Functor-import Data.List--import Graphics.Rendering.Pango.Enums-import Graphics.UI.Gtk.General.General---- import qualified Network.URI as N--import Prelude hiding(log, mapM_)--import System.FilePath-import qualified System.Info as Sys--- import System.IO-import System.Posix.Process-import System.Posix.Types-import System.Process--- }}}---- {{{ Aliases/shortcuts--- | Alias for 'liftIO'-io :: MonadBase IO m => IO a -> m a-io = liftBase---- | Like 'forkIO' using 'MVar' as thread control-fork :: (MonadBaseControl IO m) => m () -> m (MVar ())-fork f = do-    mvar <- io newEmptyMVar-    liftBaseWith $ \runInIO -> void . forkIO $ finally (void $ runInIO f) (putMVar mvar ())-    return mvar---- | Like '(</>)' with first argument in IO to build platform-dependent paths.-(>/>) :: (MonadBase IO m) => IO FilePath -> FilePath -> m FilePath-(>/>) a b = io $ (</> b) <$> a--- }}}---- {{{ Process management--- | Run external command and won't kill when parent process exit.-spawn :: MonadBase IO m => String -> [String] -> m ()-spawn command options = io . void $ createProcess (proc command options) { std_in = CreatePipe,  std_out = CreatePipe, std_err = CreatePipe, close_fds = True }---- | Return the list of process IDs corresponding to all running instances of the browser.-getAllProcessIDs :: MonadBase IO m => m [ProcessID]-getAllProcessIDs = do-    (_, pids, _)  <- io $ readProcessWithExitCode "pidof" ["hbro"] []-    (_, pids', _) <- io $ readProcessWithExitCode "pidof" ["hbro-" ++ Sys.os ++ "-" ++ Sys.arch] []-    myPid         <- io $ getProcessID--    return $ delete myPid . map (read :: String -> ProcessID) . nub . words $ pids ++ " " ++ pids'--- }}}---{-errorHandler :: (MonadBase IO m, MonadReader r m, HasOptions r) => FilePath -> IOError -> m ()-errorHandler file e = do-  when (isAlreadyInUseError e) $ unlessQuiet . io . putStrLn $ "ERROR: file <" ++ file ++ "> is already opened and cannot be reopened."-  when (isDoesNotExistError e) $ unlessQuiet . io . putStrLn $ "ERROR: file <" ++ file ++ "> doesn't exist."-  when (isPermissionError   e) $ unlessQuiet . io . putStrLn $ "ERROR: user doesn't have permission to open file <" ++ file ++ ">."-}---- Common pango attributes-allItalic, allBold :: PangoAttribute-allItalic = AttrStyle  {paStart = 0, paEnd = -1, paStyle  = StyleItalic}-allBold   = AttrWeight {paStart = 0, paEnd = -1, paWeight = WeightBold}--postGUISync' :: (MonadBaseControl IO m) => m a -> m a-postGUISync' f = control $ \runInIO -> postGUISync (runInIO f)
− Hbro/Webkit/WebSettings.hs
@@ -1,37 +0,0 @@--- | Designed to be imported as @qualified@.-module Hbro.Webkit.WebSettings where---- {{{ Imports-import Hbro.Gui-import Hbro.Util--import Control.Monad-import Control.Monad.Base--import Graphics.UI.Gtk.WebKit.WebSettings-import Graphics.UI.Gtk.WebKit.WebView--import System.Glib.Attributes as G--- }}}---set :: (MonadBase IO m, GUIReader n m) => Attr WebSettings a -> a -> m ()-set element newValue = modify_ element $ const newValue--modify :: (MonadBase IO m, GUIReader n m) => Attr WebSettings a -> (a -> a) -> m a-modify element modifier = do-    w <- readGUI webView-    settings <- io $ webViewGetWebSettings w-    oldValue <- io $ get settings element-    io $ G.set settings [element := modifier oldValue]-    io $ webViewSetWebSettings w settings-    return oldValue--modify_ :: (MonadBase IO m, GUIReader n m) => Attr WebSettings a -> (a -> a) -> m ()-modify_ e m = void $ modify e m--toggle :: (MonadBase IO m, GUIReader n m) => Attr WebSettings Bool -> m Bool-toggle = (`modify` not)--toggle_ :: (MonadBase IO m, GUIReader n m) => Attr WebSettings Bool -> m ()-toggle_ = (`modify_` not)
− Hbro/Webkit/WebView.hs
@@ -1,57 +0,0 @@--- | Rewrite many 'Graphics.UI.Gtk.WebKit.WebView' functions in a monadic way.--- Designed to be imported as @qualified@.-module Hbro.Webkit.WebView where---- {{{ Imports-import Hbro.Error-import Hbro.Network-import Hbro.Util--import Control.Monad.Base-import Control.Monad.Error  hiding(forM_, mapM_)--- import Control.Monad.Reader hiding(forM_, mapM_)---- import Data.Foldable (forM_, mapM_)--- import Data.Functor--import Graphics.UI.Gtk.Abstract.Widget-import qualified Graphics.UI.Gtk.General.General as GTK-import qualified Graphics.UI.Gtk.WebKit.Download as W-import Graphics.UI.Gtk.WebKit.NetworkRequest (NetworkRequest)-import qualified Graphics.UI.Gtk.WebKit.NetworkRequest as W-import Graphics.UI.Gtk.WebKit.WebView (WebView)-import qualified Graphics.UI.Gtk.WebKit.WebView as W--import Network.URI as N hiding(parseURI, parseURIReference)--import Prelude hiding(mapM_)--import System.Glib.Attributes-import System.Glib.Signals--- }}}---init :: (MonadBase IO m) => WebView -> m ()-init webView = io $ do-    set webView [ widgetCanDefault := True ]-    void . on webView W.closeWebView $ GTK.mainQuit >> return False---- {{{ Monad-agnostic version of various WebKit functions-getUri :: (MonadBase IO m, MonadError HError m) => WebView -> m URI-getUri = maybe (throwError InvalidPageURI) parseURI <=< io . W.webViewGetUri--getTitle :: (MonadBase IO m, MonadError HError m) => WebView -> m String-getTitle = maybe (throwError InvalidPageTitle) return <=< io . W.webViewGetTitle--getIconUri :: (MonadBase IO m, MonadError HError m) => WebView -> m URI-getIconUri = maybe (throwError InvalidIconURI) parseURI <=< io . W.webViewGetUri--networkRequestGetUri :: NetworkRequest -> forall m. (MonadBase IO m, MonadError HError m) => m URI-networkRequestGetUri r = parseURIReference =<< maybe (throwError $ EmptyRequestURI r) return =<< io (W.networkRequestGetUri r)--downloadGetUri :: (MonadBase IO m, MonadError HError m) => W.Download -> m URI-downloadGetUri d = parseURI =<< maybe (throwError $ EmptyDownloadURI d) return =<< io (W.downloadGetUri d)--downloadGetSuggestedFilename :: (MonadBase IO m, MonadError HError m) => W.Download -> m String-downloadGetSuggestedFilename d = maybe (throwError $ EmptySuggestedFileName d) return =<< io (W.downloadGetSuggestedFilename d)--- }}}
README.rst view
@@ -2,10 +2,9 @@ hbro ==== --**In a nutshell**: *hbro* is a minimal, KISS compliant browser for linux written, configured and extensible in Haskell.+**In a nutshell**: *hbro* is a minimal, KISS compliant web browser for linux; it is written, configured and extensible in Haskell. -Informations about versions, dependencies, source repositories and contacts can be found in hackage_.+Information about versions, dependencies, source repositories and contacts can be found in hackage_.   Design principles@@ -16,13 +15,13 @@   A web browser retrieves, renders and traverses web pages, period.  `Keep It Simple, Stupid`_-  The program should be written with simplicity in mind, and without obsession for performance, features or release frequency. It should not take time to start-up, consume much RAM or crash. Its code should be easy to understand (well, as long as you speak Haskell...) to encourage users to hack it. Simplicity provides lightness, scalability, stability and maintainability.+  The program should be written with simplicity in mind, and without obsession for performance, features or release frequency. It should boot instantly, consume little memory and offer an uncluttered graphical interface. The code should be easy to grasp (well, as long as you speak Haskell...) to encourage users to hack it. Simplicity provides lightness, scalability, stability and maintainability.  Extensible-  Configuration system should allow users to implement extra features. External programs should be able to query/order *hbro*.+  Configuration system should allow users to implement extra features. External programs should be able to query/command the web browser.  Good defaults-  A default configuration, suitable for users that cannot afford or don't want to spend (waste ?) their time in tweaks, should be provided.+  The default behavior should be suitable for users that cannot afford or don't want to spend (waste ?) their time in tweaks.  Keyboard driven   Keyboard control should be made as much convenient, with as little mouse intervention, as possible.@@ -35,10 +34,13 @@   Modern, purely-functional language that makes it possible to work with a short, elegant and robust code.  Layout engine : WebKit_-  Webkit seems to be the only engine being open-source, (kind of) standards-compliant and providing a Haskell binding. It's not much of a choice, fortunately it's not that bad.+  Has to be open-source, be (kind of) standards-compliant, and provide a Haskell binding. WebKit is pretty much the only choice left. +HTTP client : WebKit_+  Ideally, the HTTP client should be delegated to a distinct library (typically http-conduit_), but WebKit clearly wasn't designed to be used as a *mere* layout engine. So for now, it still handles all network connections.+ UI toolkit : `GTK+`_-  Given the above programming language and layout engine, there's no much choice left for the UI toolkit.+  Given the programming language and layout engine, there's no much choice left for the UI toolkit.  Interprocess interface : ZeroMQ_   Socket-like interface that implements various convenient communication schemes like request-reply and publish-subscribe.@@ -50,6 +52,12 @@ Suggestions about better alternatives for any of these points (except the programming language) are welcome.  +Installation+------------++At the moment, *hbro* depends on the *integer-simple* package, which means you won't be able to build it using a standard GHC that uses the *integer-gmp* package. This distinction is `documented here`_, and the reason for this constraint is `explained there`_.++ Configuration ------------- @@ -59,13 +67,13 @@ GUI layout ---------- -The graphical layout is described in an XML file that is parsed by GtkBuilder_ to build up the whole GUI. This file is looked for in several places with the following order of priority:+The graphical layout is described in an XML file that is parsed by GtkBuilder_. This file is looked for in several places with the following order of priority:  - the value from commandline option ``-u``;-- the file ``~/.config/hbro.ui.xml``;+- the file ``~/.config/hbro/ui.xml``; - the file ``examples/ui.xml`` bundled with the package. -You must at least define the following widgets with the adequate ``id`` attribute:+At least the following widgets must be defined, with the adequate ``id`` attributes, for the browser to start:  +-----------------------+-----------------------+ | Type                  | ``id``                |@@ -91,9 +99,10 @@ Known bugs and limitations -------------------------- -Unfortunately, many problems/limitations are inherited from the *Haskell* binding for *webkit*/*gtk*. Until fixed in upstream, nothing can be done on *hbro* to work around them. Here's a summary of them:+Many problems/limitations are inherited from the *Haskell* bindings webkitgtk3_ and gtk3_. Until fixed in upstream, nothing can be done on *hbro* to work around them. Here's a summary of them: -- segfaults when loading some webpages or enabling javascript/flash;+- **segmentation faults when loading some webpages while javascript/flash is enabled**;+- vertical scrollbar cannot be hidden; - no proxy configuration; - no cookies management; - javascript's ``window.open`` requests open in the same window instead of spawning a new one;@@ -119,3 +128,8 @@ .. _Dyre: https://github.com/willdonnelly/dyre .. _hbro-contrib: http://hackage.haskell.org/package/hbro-contrib .. _GtkBuilder: https://developer.gnome.org/gtk3/stable/GtkBuilder.html+.. _http-conduit: https://hackage.haskell.org/package/http-conduit+.. _webkitgtk3: http://hackage.haskell.org/package/webkitgtk3+.. _gtk3: http://hackage.haskell.org/package/gtk3+.. _documented here: https://ghc.haskell.org/trac/ghc/wiki/Commentary/Libraries/Integer+.. _explained there: http://sourceforge.net/p/gtk2hs/mailman/gtk2hs-users/thread/20140515065151.GA8342%40mystik/
examples/ui.xml view
@@ -1,5 +1,8 @@ <interface>     <object class="GtkWindow" id="mainWindow">+        <property name="default-height">768</property>+        <property name="default-width">1024</property>+         <child><object class="GtkVBox" id="windowBox">             <property name="homogeneous">False</property>             <property name="spacing">0</property>
+ executable/Main.hs view
@@ -0,0 +1,7 @@+module Main where++import Hbro++-- Default main function provided as example+main :: IO ()+main = hbro doNothing
hbro.cabal view
@@ -1,8 +1,8 @@ Name:                hbro-Version:             1.1.2.2-Synopsis:            Minimal KISS compliant browser--- Description:-Homepage:            http://projects.haskell.org/hbro/+Version:             1.2.0.0+Synopsis:            Minimal KISS-compliant browser+Description:         Cf README+Homepage:            https://bitbucket.org/k0ral/hbro Category:            Browser,Web  License:             OtherLicense@@ -17,6 +17,9 @@ Data-files:          examples/ui.xml  Source-repository head+    Type:     git+    Location: https://github.com/k0ral/hbro.git+Source-repository head     Type:     hg     Location: https://bitbucket.org/k0ral/hbro Source-repository head@@ -27,25 +30,39 @@     Build-depends:         base == 4.*,         bytestring,+        classy-prelude,         cond,         containers,         data-default,-        directory,         dyre >= 0.8.8,-        filepath,+        errors,         glib,-        gtk >= 0.12.3,+        gtk3 >= 0.13,+        hslogger,+        -- http-conduit,+        -- http-conduit-browser,+        -- http-types,+        integer-simple,         lens,+        lifted-async,+        lifted-base,+        mtl >= 2.2.1,         monad-control,-        mtl,-        network,+        network-uri,         pango,+        parsec,         process,+        safe,+        semigroups,+        stm,+        system-fileio,+        text,+        -- text-icu,+        time,         transformers,         transformers-base,         unix,-        webkit,-        xdg-basedir,+        webkitgtk3 >= 0.13,         zeromq4-haskell     Exposed-modules:         Hbro,@@ -54,27 +71,55 @@         Hbro.Config,         Hbro.Core,         Hbro.Error,+        Hbro.Gdk.KeyVal,         Hbro.Gui,+        Hbro.Gui.Buildable,+        Hbro.Gui.NotificationBar,+        Hbro.Gui.PromptBar,+        Hbro.Gui.PromptBar.Hooks,+        Hbro.Gui.PromptBar.Signals,+        Hbro.Gui.StatusBar,+        Hbro.Hooks,         Hbro.IPC,+        Hbro.IPC.Hooks,+        Hbro.K,         Hbro.Keys,-        Hbro.Network,-        Hbro.Notification,+        Hbro.Keys.Model,+        Hbro.Keys.Monadic,+        Hbro.Keys.Signals,+        Hbro.Logger,         Hbro.Options,-        Hbro.Prompt,-        Hbro.Util,-        Hbro.Gtk.ScrolledWindow,-        Hbro.Webkit.WebSettings,-        Hbro.Webkit.WebView+        Hbro.Prelude,+        Hbro.Signals,+        Hbro.Webkit.WebSettings+        Hbro.WebView.Hooks,+        Hbro.WebView.Signals,+        Network.URI.Monadic+    Other-modules:+        Graphics.UI.Gtk.WebKit.Lifted,+        Graphics.UI.Gtk.WebKit.Lifted.WebView,+        -- Hbro.CFunctions,+        Hbro.Dyre,+        Hbro.IPC.Signals,+        Paths_hbro     Extensions:         ConstraintKinds,+        DeriveDataTypeable,         FlexibleContexts,+        FlexibleInstances,         FunctionalDependencies,         GeneralizedNewtypeDeriving,         MultiParamTypeClasses,+        NoImplicitPrelude,+        OverloadedStrings,         RankNTypes--    Other-modules: Hbro.Dyre, Paths_hbro-    Ghc-options: -Wall+    -- Build-tools: hsc2hs+    -- C-sources: cbits/cbits.c+    -- Include-dirs: include+    -- Includes: include/cbits.h+    -- Install-includes: include/cbits.h+    Hs-Source-Dirs: library+    Ghc-options: -Wall -fno-warn-unused-do-bind -threaded  Flag threaded     Description: Build with -threaded@@ -82,12 +127,10 @@  Executable hbro     Build-depends:-        hbro >= 1.1.1.0,-        base == 4.*,-        glib,-        gtk+        hbro >= 1.2.0.0,+        base == 4.*     Main-is: Main.hs-    Hs-Source-Dirs: Hbro+    Hs-Source-Dirs: executable     Ghc-options: -Wall     if flag(threaded)         Ghc-options: -threaded
+ library/Graphics/UI/Gtk/WebKit/Lifted.hs view
@@ -0,0 +1,36 @@+-- | Some lifted functions from 'Graphics.UI.Gtk.WebKit'.+-- Designed to be imported as @qualified@.+module Graphics.UI.Gtk.WebKit.Lifted (+-- * 'NetworkRequest'+    networkRequestGetUri,+-- * 'Download'+    downloadGetUri,+-- * 'NetworkRequest'+    downloadGetSuggestedFilename,+) where++-- {{{ Imports+import Hbro.Error+import Hbro.Prelude++-- import Graphics.UI.Gtk.General.General as GTK+import qualified Graphics.UI.Gtk.WebKit.Download as W+import Graphics.UI.Gtk.WebKit.NetworkRequest (NetworkRequest)+import qualified Graphics.UI.Gtk.WebKit.NetworkRequest as W++import Network.URI.Monadic+-- }}}++-- | Error message+unavailableFileName, unavailableURI :: Text+unavailableFileName = "No file name available"+unavailableURI = "No URI available"++networkRequestGetUri :: (MonadIO m, MonadError Text m) => NetworkRequest -> m URI+networkRequestGetUri r = parseURIReference =<< io (W.networkRequestGetUri r) <!> unavailableURI++downloadGetUri :: (MonadIO m, MonadError Text m) => W.Download -> m URI+downloadGetUri d = parseURI =<< io (W.downloadGetUri d) <!> unavailableURI++downloadGetSuggestedFilename :: (MonadIO m, MonadError Text m) => W.Download -> m Text+downloadGetSuggestedFilename d = io (W.downloadGetSuggestedFilename d) <!> unavailableFileName
+ library/Graphics/UI/Gtk/WebKit/Lifted/WebView.hs view
@@ -0,0 +1,47 @@+-- | Some lifted functions from 'Graphics.UI.Gtk.WebKit.WebView'.+-- Designed to be imported as @qualified@.+module Graphics.UI.Gtk.WebKit.Lifted.WebView+    ( webViewGetUri+    , webViewGetIconUri+    , webViewTryGetFaviconPixbuf+    , webViewGetTitle+    , loadHtmlString+    , loadString+    , module Export+    ) where++-- {{{ Imports+import Hbro.Error+import Hbro.Prelude++import Graphics.UI.Gtk.Gdk.Pixbuf+import Graphics.UI.Gtk.WebKit.WebView as Export hiding(webViewGetUri, webViewGetIconUri, webViewGetTitle, webViewTryGetFaviconPixbuf)+import qualified Graphics.UI.Gtk.WebKit.WebView as W++import Network.URI.Monadic+-- }}}++-- | Error message+unavailableFavicon, unavailableURI, titleUnavailable :: Text+unavailableFavicon = "No available favicon."+unavailableURI = "No available URI."+titleUnavailable = "No available title."+++webViewGetUri :: (BaseIO m, MonadError Text m) => WebView -> m URI+webViewGetUri = gSync . W.webViewGetUri >=> maybe (throwError unavailableURI) return >=> parseURI++webViewGetIconUri :: (BaseIO m, MonadError Text m) => WebView -> m URI+webViewGetIconUri = gSync . W.webViewGetIconUri >=> maybe (throwError unavailableURI) return >=> parseURI++webViewTryGetFaviconPixbuf :: (BaseIO m, MonadError Text m) => WebView -> Int -> Int -> m Pixbuf+webViewTryGetFaviconPixbuf webView width height = gSync (W.webViewTryGetFaviconPixbuf webView width height) >>= maybe (throwError unavailableFavicon) return++webViewGetTitle :: (BaseIO m, MonadError Text m) => WebView -> m Text+webViewGetTitle = gSync . W.webViewGetTitle >=> maybe (throwError titleUnavailable) return++loadHtmlString :: (BaseIO m) => Text -> URI -> WebView -> m ()+loadHtmlString html uri webView = gAsync $ W.webViewLoadHtmlString webView html (tshow uri)++loadString :: (BaseIO m) => Text -> URI -> WebView -> m ()+loadString html uri webView = gAsync $ W.webViewLoadString webView html Nothing (tshow uri)
+ library/Hbro.hs view
@@ -0,0 +1,28 @@+module Hbro ( module X) where++import Hbro.Boot as X+-- import Hbro.Clipboard+-- import Hbro.Config+import Hbro.Core as X+import Hbro.Error as X+import Hbro.Gdk.KeyVal as X+-- import Hbro.Gui+import Hbro.Gui.Buildable as X+-- import Hbro.Gui.NotificationBar+-- import Hbro.Gui.PromptBar+-- import Hbro.Gui.StatusBar+-- import Hbro.Hooks+import Hbro.IPC as X+-- import Hbro.IPC.Hooks+import Hbro.K as X+-- import Hbro.Keys+-- import Hbro.Keys.Model+import Hbro.Keys.Monadic as X+-- import Hbro.Keys.Signals+-- import Hbro.Options+-- import Hbro.Signals+-- import Hbro.Signals.PromptBar+import Hbro.Prelude as X+-- import Hbro.Webkit.WebSettings+-- import Hbro.WebView.Hooks+-- import Hbro.WebView.Signals
+ library/Hbro/Boot.hs view
@@ -0,0 +1,90 @@+module Hbro.Boot (hbro) where++-- {{{ Imports+import Hbro.Config as Config+import Hbro.Core as Core+import Hbro.Dyre as Dyre+import Hbro.Error+import Hbro.Gui as Gui+import Hbro.Hooks as Hooks+import Hbro.IPC as IPC (routine)+import Hbro.K as K+import Hbro.Options as Options+import Hbro.Signals as Signals+import Hbro.Logger+import Hbro.Prelude+import Hbro.Webkit.WebSettings as Settings++import Control.Concurrent.Async.Lifted+import Control.Lens hiding((??))+import Control.Monad.Reader hiding(guard, mapM_, msum, when)++import Filesystem++import Graphics.UI.Gtk.General.General as Gtk++import Paths_hbro++import System.Posix.Signals+import System.ZMQ4.Monadic (runZMQ)+-- }}}++-- | Main function to call in the configuration file (cf file @Hbro/Main.hs@).+hbro :: K () -> IO ()+hbro setup = void . runMaybeT $ do+    options <- parseOptions++    Dyre.wrap (options^.dyreModeL)+              (\x -> withAsyncBound guiThread (mainThread x))+              (setup, options)++-- | Gtk main loop thread.+guiThread :: IO ()+guiThread = do+    async $ do+        installHandler sigINT  (Catch onInterrupt) Nothing+        installHandler sigTERM (Catch onInterrupt) Nothing+    initGUI >> mainGUI+    debugM "hbro.main" "GUI thread correctly exited."+  where onInterrupt  = logInterrupt >> gAsync mainQuit+        logInterrupt = infoM "hbro.main" "Received interrupt signal."+++mainThread :: (ControlIO m) => (K (), CliOptions) -> Async (StM IO ()) -> m ()+mainThread (customSetup, options) uiThread = logErrors_ $ do+    -- Signals+    signals <- Signals.initialize+    hooks   <- Hooks.initialize++    -- GUI+    uiFiles <- getUIFiles options+    gui     <- asum $ map Gui.initialize uiFiles+    attachGuiSignals gui signals++    -- K monad+    globalStatus <- K.init gui hooks signals++    -- IPC+    socketURI <- getSocketURI options++    io . (`runReaderT` globalStatus) . runExceptT $ do+        resetKeyBindings+        Settings.resetAll+        lift customSetup++        debugM "hbro.boot" . ("Start-up configuration: \n" ++) . describe =<< Config.get id++        logErrors_ $ maybe goHome load (options^.startURIL)++    io . withAsyncList (Hooks.routines globalStatus signals hooks) $ \_ -> do+      withAsync (runZMQ $ IPC.routine socketURI (signals^._ipcSignals)) $ \_ ->+        wait uiThread++    debugM "hbro.main" "All threads correctly exited."++-- | Return the list of available UI files (from configuration and package)+getUIFiles :: (BaseIO m) => CliOptions -> m [FilePath]+getUIFiles options = do+    fileFromConfig  <- getAppConfigDirectory "hbro" >/> "ui.xml"+    fileFromPackage <- fpFromText . pack <$> (io $ getDataFileName "examples/ui.xml")+    return $ catMaybes [options^.uiFileL, Just fileFromConfig, Just fileFromPackage]
+ library/Hbro/Clipboard.hs view
@@ -0,0 +1,35 @@+-- | Designed to be imported as @qualified@.+module Hbro.Clipboard where++-- {{{ Imports+import Hbro.Error+import Hbro.Logger+import Hbro.Prelude++import Graphics.UI.Gtk.General.Clipboard+import Graphics.UI.Gtk.General.Selection+-- }}}++-- | Write given 'Text' to the selection-primary clipboard+write :: (BaseIO m) => Text -> m ()+write = write' selectionPrimary++-- | Write given text to the given clipboard+write' :: (BaseIO m) => SelectionTag -> Text -> m ()+write' tag text = do+    debugM "hbro.clipboard" $ "Writing to clipboard: " ++ text+    gSync (clipboardGet tag) >>= gAsync . (`clipboardSetText` text)++-- | Read clipboard's content. Both 'selectionPrimary' and 'selectionClipboard' are inspected (in this order).+read :: (BaseIO m) => ExceptT Text m Text+read = read' selectionPrimary <|> read' selectionClipboard++-- | Return the content from the given clipboard.+read' :: (BaseIO m, MonadError Text m) => SelectionTag -> m Text+read' tag = do+    clipboard <- gSync $ clipboardGet tag+    result    <- newEmptyMVar++    gAsync . clipboardRequestText clipboard $ putMVar result++    takeMVar result <!> ("Empty clipboard [" ++ tshow tag ++ "]")
+ library/Hbro/Config.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE TemplateHaskell, UndecidableInstances #-}+-- | General configuration parameters.+-- The recommended way to import this module is:+-- @+-- import Hbro.Config hiding(get, set)+-- import qualified Hbro.Config as Config+-- @+module Hbro.Config (+-- * Types+      Config+    , homePageL+    , HasConfig(..)+-- * Getter/setter+    , get+    , set+) where++-- {{{ Imports+import Hbro.Prelude++import Control.Lens hiding(set)+import qualified Control.Lens as L (set)+import Control.Monad.Reader++import Network.URI (URI)+import qualified Network.URI as N+-- }}}++-- | Custom settings provided by the user+data Config = Config+    { _homePage :: URI+    }++makeLensesWith ?? ''Config $ lensRules+    & lensField .~ (\name -> Just (tailSafe name ++ "L"))+++instance Describable Config where+    describe c = "Home page = " ++ (tshow $ c^.homePageL)++instance Default Config where+    def = Config+        { _homePage = fromJust . N.parseURI $ "https://duckduckgo.com/"+        }++class HasConfig t where _config :: Lens' t (TVar Config)++instance HasConfig (TVar Config) where _config = id++get :: (MonadReader r m, BaseIO m, HasConfig r) => Lens' Config a -> m a+get l = return . view l =<< atomically . readTVar =<< askL _config++set :: (MonadReader r m, BaseIO m, HasConfig r) => Lens' Config a -> a -> m ()+set l v = atomically . (`modifyTVar` L.set l v) =<< askL _config
+ library/Hbro/Core.hs view
@@ -0,0 +1,179 @@+{-# LANGUAGE TemplateHaskell, TypeFamilies #-}+module Hbro.Core (+-- * Types+      CaseSensitivity(..)+    , Direction(..)+    , Wrap(..)+    , ZoomDirection(..)+-- * Getters+    , getCurrentURI+    , getFaviconURI+    , getFavicon+    , getLoadProgress+    , getPageTitle+-- * Browsing+    , goHome+    , load+    , reload+    , reloadBypassCache+    , stopLoading+    , goBack+    , goForward+-- * Other+    , printPage+    , searchText+    , searchText_+    , quit+    , executeJSFile+    ) where++-- {{{ Imports+import Graphics.UI.Gtk.WebKit.Lifted.WebView++import Hbro.Config as Config+import Hbro.Error+import Hbro.Gui as Gui+import Hbro.Logger hiding(initialize)+import Hbro.Prelude as H++import Control.Monad.Reader hiding(guard, unless)++import Graphics.UI.Gtk.Gdk.Pixbuf (Pixbuf)+import Graphics.UI.Gtk.General.General+import Graphics.UI.Gtk.WebKit.WebDataSource+import Graphics.UI.Gtk.WebKit.WebFrame++import Network.URI.Monadic+-- }}}++-- {{{ Types+data CaseSensitivity = CaseSensitive | CaseInsensitive++instance ToBool CaseSensitivity where+    toBool CaseSensitive   = True+    toBool CaseInsensitive = False++data Direction = Forward | Backward++instance ToBool Direction where+    toBool Forward  = True+    toBool Backward = False++data Wrap = Wrap | NoWrap++instance ToBool Wrap where+    toBool Wrap   = True+    toBool NoWrap = False++data ZoomDirection = In | Out+-- }}}++-- {{{ Getters+getCurrentURI :: (BaseIO m, MonadReader t m, HasGUI t, MonadError Text m) => m URI+getCurrentURI = webViewGetUri =<< Gui.get webViewL++getFaviconURI :: (BaseIO m, MonadReader t m, HasGUI t, MonadError Text m) => m URI+getFaviconURI = webViewGetIconUri =<< Gui.get webViewL++getFavicon :: (BaseIO m, MonadReader t m, HasGUI t, MonadError Text m) => Int -> Int -> m Pixbuf+getFavicon w h = (\v -> webViewTryGetFaviconPixbuf v w h) =<< Gui.get webViewL++getLoadProgress :: (BaseIO m, MonadReader t m, HasGUI t) => m Double+getLoadProgress = gSync . webViewGetProgress =<< Gui.get webViewL++getPageTitle :: (BaseIO m, MonadReader t m, HasGUI t, MonadError Text m) => m Text+getPageTitle = webViewGetTitle =<< Gui.get webViewL+-- }}}++-- {{{ Browsing+goHome :: (BaseIO m, MonadReader t m, HasGUI t, HasConfig t, MonadError Text m) => m ()+goHome = load =<< Config.get homePageL++load :: (BaseIO m, MonadReader t m, HasGUI t, MonadError Text m) => URI -> m ()+load uri = do+    debugM "hbro.core" $ "Loading URI: " ++ tshow uri+    -- void . logErrors $ do+    --     currentURI <- getURI+    --     guard (currentURI /= uri')+    --     Browser.advance currentURI++    -- load' uri'+    webview <- Gui.get webViewL+    gSync . webViewLoadUri webview $ show uri'++  where+    uri' = case uriScheme uri of+             [] -> uri { uriScheme = "http://" }+             _  -> uri+    -- baseOf uri = uri {+        -- uriPath = (++ "/") . join "/" . Prelude.init . split "/" $ uriPath uri+    -- }+++-- load' :: (MonadBaseControl IO m, MonadReader t m, HasGUI t, HasHTTPClient t, MonadError Text m) => URI -> m ()+-- load' uri = do+--     page <- Client.retrieve uri+--     -- render page =<< Client.getURI+--     render page uri+++reload, goBack, goForward :: (BaseIO m, MonadReader t m, HasGUI t, MonadError Text m) => m ()+-- reload    = load  =<< Client.getURI+-- goBack    = load' =<< Browser.stepBackward =<< getURI+-- goForward = load' =<< Browser.stepForward =<< getURI+reload    = gAsync . webViewReload    =<< Gui.get webViewL+goBack    = gAsync . webViewGoBack    =<< Gui.get webViewL+goForward = gAsync . webViewGoForward =<< Gui.get webViewL++reloadBypassCache, stopLoading :: (BaseIO m, MonadReader t m, HasGUI t) => m ()+reloadBypassCache = Gui.get webViewL >>= gAsync . webViewReloadBypassCache >> logDebug "Reloading without cache."+stopLoading = Gui.get webViewL >>= gAsync . webViewStopLoading >> logDebug "Stopped loading"+-- }}}+++-- {{{+searchText :: (BaseIO m, MonadReader t m, HasGUI t) => CaseSensitivity -> Direction -> Wrap -> Text -> m Bool+searchText s d w text = do+    logDebug $ "Searching text: " ++ text+    v <- Gui.get webViewL+    gSync $ webViewSearchText v text (toBool s) (toBool d) (toBool w)++searchText_ :: (BaseIO m, MonadReader t m, HasGUI t) => CaseSensitivity -> Direction -> Wrap -> Text -> m ()+searchText_ s d w text = void $ searchText s d w text++printPage :: (BaseIO m, MonadReader t m, HasGUI t) => m ()+printPage = gAsync . webFramePrint =<< gSync . webViewGetMainFrame =<< Gui.get webViewL+-- }}}++-- | Terminate the program.+quit :: (BaseIO m) => m ()+quit = gAsync mainQuit+++-- {{{ Misc+-- | Execute a javascript file on current webpage.+executeJSFile :: (BaseIO m, MonadReader r m) => FilePath -> WebView -> m ()+executeJSFile filePath webView' = do+    debugM "hbro.core" $ "Executing Javascript file: " ++ fpToText filePath+    script <- readFile filePath+    let script' = asText . unwords . map (++ "\n") . lines $ script++    gAsync $ webViewExecuteScript webView' script'+-- }}}++-- | Save current web page to a file,+-- along with all its resources in a separated directory.+-- Doesn't work for now, because web_resource_get_data's binding is missing...+_savePage :: Text -> WebView -> IO ()+_savePage _path webView' = do+    frame         <- webViewGetMainFrame webView'+    dataSource    <- webFrameGetDataSource frame+    _mainResource <- webDataSourceGetMainResource dataSource+    _subResources <- webDataSourceGetSubresources dataSource+    return ()+++-- {{{ Util+logDebug :: (BaseIO m) => Text -> m ()+logDebug = debugM "hbro.core"+-- }}}
+ library/Hbro/Dyre.hs view
@@ -0,0 +1,65 @@+-- | Dynamic reconfiguration. Designed to be imported as @qualified@.+module Hbro.Dyre+    ( Mode(..)+    , wrap+    , recompile+    ) where++-- {{{ Imports+import Hbro.Logger+import Hbro.Prelude++import Config.Dyre+import Config.Dyre.Compile+import Config.Dyre.Paths+-- }}}++-- | How dynamic reconfiguration process should behave.+data Mode = Normal | Vanilla | ForceReconfiguration | IgnoreReconfiguration+    deriving(Eq, Show)++-- | Default mode is 'Normal', that is: use custom configuration file and recompile if change detected.+instance Default Mode where def = Normal++-- | Describe various paths used for dynamic reconfiguration+describePaths :: BaseIO m => m Text+describePaths = io $ do+    (a, b, c, d, e) <- getPaths baseParameters+    return . unlines $ map pack+        [ "Current binary:  " ++ a+        , "Custom binary:   " ++ b+        , "Config file:     " ++ c+        , "Cache directory: " ++ d+        , "Lib directory:   " ++ e+        ]++-- Dynamic reconfiguration settings+parameters :: Mode -> (a -> IO b) -> Params (Either Text a)+parameters mode main = baseParameters+    { configCheck = mode /= Vanilla+    , realMain    = main'+    }+  where+    main' (Left e)  = errorM "hbro.dyre" e+    main' (Right x) = do+      debugM "hbro.dyre" . ("Dynamic reconfiguration paths:\n" ++) =<< describePaths+      void $ main x++baseParameters :: Params (Either Text a)+baseParameters = defaultParams+    { projectName             = "hbro"+    , showError               = const (Left . pack)+    , ghcOpts                 = ["-threaded"]+    , statusOut               = hPutStrLn stderr+    , includeCurrentDirectory = False+    }++wrap :: (BaseIO m) => Mode -> (a -> IO b) -> a -> m ()+wrap mode main args = io . wrapMain (parameters mode main) $ Right args+++-- | Launch a recompilation of the configuration file+recompile :: (BaseIO m) => m (Maybe Text)+recompile = io $ do+    customCompile baseParameters+    map pack <$> getErrorString baseParameters
+ library/Hbro/Error.hs view
@@ -0,0 +1,29 @@+module Hbro.Error ( module X, module Hbro.Error) where++-- {{{ Imports+import Hbro.Logger+import Hbro.Prelude++import Control.Error.Util as X (note, hush)+import Control.Monad.Except as X (MonadError(..), ExceptT, runExceptT, withExceptT)+import Control.Monad.Trans.Maybe as X+-- }}}++-- | Convert a 'Maybe' value into a 'MonadError' monad.+failWith :: (MonadError e m) => Maybe a -> e -> m a+failWith x e = either throwError return $ note e x++-- | Monadic and infix version of 'failWith'+(<!>) :: (MonadError e m) => m (Maybe a) -> e -> m a+(<!>) f e = f >>= (`failWith` e)++-- | Like 'runExceptT', except that the error is automatically logged, then discarded.+logErrors :: (BaseIO m) => ExceptT Text m a -> m (Maybe a)+logErrors = runExceptT >=> either (\e -> errorM "hbro.error" e >> return Nothing) (return . Just)++logErrors' :: (BaseIO m) => ExceptT e m a -> m (Maybe a)+logErrors' = return . either (const Nothing) Just <=< runExceptT++-- | Like 'logErrors', but discards the result.+logErrors_ :: (BaseIO m) => ExceptT Text m a -> m ()+logErrors_ = void . logErrors
+ library/Hbro/Gdk/KeyVal.hsc view
@@ -0,0 +1,2229 @@+{-# LANGUAGE CPP, ForeignFunctionInterface, TupleSections #-}+-- | Binding for GDK key constants defined in @gdk/gdkkeysyms.h@+module Hbro.Gdk.KeyVal where++-- {{{ Imports+import Hbro.Prelude++import Data.Char++import qualified Graphics.UI.Gtk.Gdk.Keys as Gtk++import Text.Parsec hiding((<|>))+import Text.Parsec.Text++#include <gdk/gdkkeysyms.h>+-- }}}++newtype KeyVal = KeyVal { unKeyValue :: Word32 }+    deriving (Eq, Ord)++-- | Single characters are returned as is. For other keys, the corresponding keyName wrapped into @\<\>@ is returned.+instance Describable KeyVal where+    describe (KeyVal key) = name <| (length name < 2) |> ("<" ++ name ++ ">")+      where name = Gtk.keyName key++keyVal, shortKeyVal, longKeyVal :: Parser KeyVal+keyVal = spaces *> (shortKeyVal <|> longKeyVal)+shortKeyVal = KeyVal . fromIntegral . ord <$> noneOf "<>"+longKeyVal = KeyVal . Gtk.keyFromName . pack <$> between (char '<') (char '>') (many1 anyChar)+++#{enum KeyVal, KeyVal,+    _VoidSymbol                  = GDK_KEY_VoidSymbol,+    _BackSpace                   = GDK_KEY_BackSpace,+    _Tab                         = GDK_KEY_Tab,+    _Linefeed                    = GDK_KEY_Linefeed,+    _Clear                       = GDK_KEY_Clear,+    _Return                      = GDK_KEY_Return,+    _Pause                       = GDK_KEY_Pause,+    _Scroll_Lock                 = GDK_KEY_Scroll_Lock,+    _Sys_Req                     = GDK_KEY_Sys_Req,+    _Escape                      = GDK_KEY_Escape,+    _Delete                      = GDK_KEY_Delete,+    _Multi_key                   = GDK_KEY_Multi_key,+    _Codeinput                   = GDK_KEY_Codeinput,+    _SingleCandidate             = GDK_KEY_SingleCandidate,+    _MultipleCandidate           = GDK_KEY_MultipleCandidate,+    _PreviousCandidate           = GDK_KEY_PreviousCandidate,+    _Kanji                       = GDK_KEY_Kanji,+    _Muhenkan                    = GDK_KEY_Muhenkan,+    _Henkan_Mode                 = GDK_KEY_Henkan_Mode,+    _Henkan                      = GDK_KEY_Henkan,+    _Romaji                      = GDK_KEY_Romaji,+    _Hiragana                    = GDK_KEY_Hiragana,+    _Katakana                    = GDK_KEY_Katakana,+    _Hiragana_Katakana           = GDK_KEY_Hiragana_Katakana,+    _Zenkaku                     = GDK_KEY_Zenkaku,+    _Hankaku                     = GDK_KEY_Hankaku,+    _Zenkaku_Hankaku             = GDK_KEY_Zenkaku_Hankaku,+    _Touroku                     = GDK_KEY_Touroku,+    _Massyo                      = GDK_KEY_Massyo,+    _Kana_Lock                   = GDK_KEY_Kana_Lock,+    _Kana_Shift                  = GDK_KEY_Kana_Shift,+    _Eisu_Shift                  = GDK_KEY_Eisu_Shift,+    _Eisu_toggle                 = GDK_KEY_Eisu_toggle,+    _Kanji_Bangou                = GDK_KEY_Kanji_Bangou,+    _Zen_Koho                    = GDK_KEY_Zen_Koho,+    _Mae_Koho                    = GDK_KEY_Mae_Koho,+    _Home                        = GDK_KEY_Home,+    _Left                        = GDK_KEY_Left,+    _Up                          = GDK_KEY_Up,+    _Right                       = GDK_KEY_Right,+    _Down                        = GDK_KEY_Down,+    _Prior                       = GDK_KEY_Prior,+    _Page_Up                     = GDK_KEY_Page_Up,+    _Next                        = GDK_KEY_Next,+    _Page_Down                   = GDK_KEY_Page_Down,+    _End                         = GDK_KEY_End,+    _Begin                       = GDK_KEY_Begin,+    _Select                      = GDK_KEY_Select,+    _Print                       = GDK_KEY_Print,+    _Execute                     = GDK_KEY_Execute,+    _Insert                      = GDK_KEY_Insert,+    _Undo                        = GDK_KEY_Undo,+    _Redo                        = GDK_KEY_Redo,+    _Menu                        = GDK_KEY_Menu,+    _Find                        = GDK_KEY_Find,+    _Cancel                      = GDK_KEY_Cancel,+    _Help                        = GDK_KEY_Help,+    _Break                       = GDK_KEY_Break,+    _Mode_switch                 = GDK_KEY_Mode_switch,+    _script_switch               = GDK_KEY_script_switch,+    _Num_Lock                    = GDK_KEY_Num_Lock,+    _KP_Space                    = GDK_KEY_KP_Space,+    _KP_Tab                      = GDK_KEY_KP_Tab,+    _KP_Enter                    = GDK_KEY_KP_Enter,+    _KP_F1                       = GDK_KEY_KP_F1,+    _KP_F2                       = GDK_KEY_KP_F2,+    _KP_F3                       = GDK_KEY_KP_F3,+    _KP_F4                       = GDK_KEY_KP_F4,+    _KP_Home                     = GDK_KEY_KP_Home,+    _KP_Left                     = GDK_KEY_KP_Left,+    _KP_Up                       = GDK_KEY_KP_Up,+    _KP_Right                    = GDK_KEY_KP_Right,+    _KP_Down                     = GDK_KEY_KP_Down,+    _KP_Prior                    = GDK_KEY_KP_Prior,+    _KP_Page_Up                  = GDK_KEY_KP_Page_Up,+    _KP_Next                     = GDK_KEY_KP_Next,+    _KP_Page_Down                = GDK_KEY_KP_Page_Down,+    _KP_End                      = GDK_KEY_KP_End,+    _KP_Begin                    = GDK_KEY_KP_Begin,+    _KP_Insert                   = GDK_KEY_KP_Insert,+    _KP_Delete                   = GDK_KEY_KP_Delete,+    _KP_Equal                    = GDK_KEY_KP_Equal,+    _KP_Multiply                 = GDK_KEY_KP_Multiply,+    _KP_Add                      = GDK_KEY_KP_Add,+    _KP_Separator                = GDK_KEY_KP_Separator,+    _KP_Subtract                 = GDK_KEY_KP_Subtract,+    _KP_Decimal                  = GDK_KEY_KP_Decimal,+    _KP_Divide                   = GDK_KEY_KP_Divide,+    _KP_0                        = GDK_KEY_KP_0,+    _KP_1                        = GDK_KEY_KP_1,+    _KP_2                        = GDK_KEY_KP_2,+    _KP_3                        = GDK_KEY_KP_3,+    _KP_4                        = GDK_KEY_KP_4,+    _KP_5                        = GDK_KEY_KP_5,+    _KP_6                        = GDK_KEY_KP_6,+    _KP_7                        = GDK_KEY_KP_7,+    _KP_8                        = GDK_KEY_KP_8,+    _KP_9                        = GDK_KEY_KP_9,+    _F1                          = GDK_KEY_F1,+    _F2                          = GDK_KEY_F2,+    _F3                          = GDK_KEY_F3,+    _F4                          = GDK_KEY_F4,+    _F5                          = GDK_KEY_F5,+    _F6                          = GDK_KEY_F6,+    _F7                          = GDK_KEY_F7,+    _F8                          = GDK_KEY_F8,+    _F9                          = GDK_KEY_F9,+    _F10                         = GDK_KEY_F10,+    _F11                         = GDK_KEY_F11,+    _L1                          = GDK_KEY_L1,+    _F12                         = GDK_KEY_F12,+    _L2                          = GDK_KEY_L2,+    _F13                         = GDK_KEY_F13,+    _L3                          = GDK_KEY_L3,+    _F14                         = GDK_KEY_F14,+    _L4                          = GDK_KEY_L4,+    _F15                         = GDK_KEY_F15,+    _L5                          = GDK_KEY_L5,+    _F16                         = GDK_KEY_F16,+    _L6                          = GDK_KEY_L6,+    _F17                         = GDK_KEY_F17,+    _L7                          = GDK_KEY_L7,+    _F18                         = GDK_KEY_F18,+    _L8                          = GDK_KEY_L8,+    _F19                         = GDK_KEY_F19,+    _L9                          = GDK_KEY_L9,+    _F20                         = GDK_KEY_F20,+    _L10                         = GDK_KEY_L10,+    _F21                         = GDK_KEY_F21,+    _R1                          = GDK_KEY_R1,+    _F22                         = GDK_KEY_F22,+    _R2                          = GDK_KEY_R2,+    _F23                         = GDK_KEY_F23,+    _R3                          = GDK_KEY_R3,+    _F24                         = GDK_KEY_F24,+    _R4                          = GDK_KEY_R4,+    _F25                         = GDK_KEY_F25,+    _R5                          = GDK_KEY_R5,+    _F26                         = GDK_KEY_F26,+    _R6                          = GDK_KEY_R6,+    _F27                         = GDK_KEY_F27,+    _R7                          = GDK_KEY_R7,+    _F28                         = GDK_KEY_F28,+    _R8                          = GDK_KEY_R8,+    _F29                         = GDK_KEY_F29,+    _R9                          = GDK_KEY_R9,+    _F30                         = GDK_KEY_F30,+    _R10                         = GDK_KEY_R10,+    _F31                         = GDK_KEY_F31,+    _R11                         = GDK_KEY_R11,+    _F32                         = GDK_KEY_F32,+    _R12                         = GDK_KEY_R12,+    _F33                         = GDK_KEY_F33,+    _R13                         = GDK_KEY_R13,+    _F34                         = GDK_KEY_F34,+    _R14                         = GDK_KEY_R14,+    _F35                         = GDK_KEY_F35,+    _R15                         = GDK_KEY_R15,+    _Shift_L                     = GDK_KEY_Shift_L,+    _Shift_R                     = GDK_KEY_Shift_R,+    _Control_L                   = GDK_KEY_Control_L,+    _Control_R                   = GDK_KEY_Control_R,+    _Caps_Lock                   = GDK_KEY_Caps_Lock,+    _Shift_Lock                  = GDK_KEY_Shift_Lock,+    _Meta_L                      = GDK_KEY_Meta_L,+    _Meta_R                      = GDK_KEY_Meta_R,+    _Alt_L                       = GDK_KEY_Alt_L,+    _Alt_R                       = GDK_KEY_Alt_R,+    _Super_L                     = GDK_KEY_Super_L,+    _Super_R                     = GDK_KEY_Super_R,+    _Hyper_L                     = GDK_KEY_Hyper_L,+    _Hyper_R                     = GDK_KEY_Hyper_R,+    _ISO_Lock                    = GDK_KEY_ISO_Lock,+    _ISO_Level2_Latch            = GDK_KEY_ISO_Level2_Latch,+    _ISO_Level3_Shift            = GDK_KEY_ISO_Level3_Shift,+    _ISO_Level3_Latch            = GDK_KEY_ISO_Level3_Latch,+    _ISO_Level3_Lock             = GDK_KEY_ISO_Level3_Lock,+    _ISO_Level5_Shift            = GDK_KEY_ISO_Level5_Shift,+    _ISO_Level5_Latch            = GDK_KEY_ISO_Level5_Latch,+    _ISO_Level5_Lock             = GDK_KEY_ISO_Level5_Lock,+    _ISO_Group_Shift             = GDK_KEY_ISO_Group_Shift,+    _ISO_Group_Latch             = GDK_KEY_ISO_Group_Latch,+    _ISO_Group_Lock              = GDK_KEY_ISO_Group_Lock,+    _ISO_Next_Group              = GDK_KEY_ISO_Next_Group,+    _ISO_Next_Group_Lock         = GDK_KEY_ISO_Next_Group_Lock,+    _ISO_Prev_Group              = GDK_KEY_ISO_Prev_Group,+    _ISO_Prev_Group_Lock         = GDK_KEY_ISO_Prev_Group_Lock,+    _ISO_First_Group             = GDK_KEY_ISO_First_Group,+    _ISO_First_Group_Lock        = GDK_KEY_ISO_First_Group_Lock,+    _ISO_Last_Group              = GDK_KEY_ISO_Last_Group,+    _ISO_Last_Group_Lock         = GDK_KEY_ISO_Last_Group_Lock,+    _ISO_Left_Tab                = GDK_KEY_ISO_Left_Tab,+    _ISO_Move_Line_Up            = GDK_KEY_ISO_Move_Line_Up,+    _ISO_Move_Line_Down          = GDK_KEY_ISO_Move_Line_Down,+    _ISO_Partial_Line_Up         = GDK_KEY_ISO_Partial_Line_Up,+    _ISO_Partial_Line_Down       = GDK_KEY_ISO_Partial_Line_Down,+    _ISO_Partial_Space_Left      = GDK_KEY_ISO_Partial_Space_Left,+    _ISO_Partial_Space_Right     = GDK_KEY_ISO_Partial_Space_Right,+    _ISO_Set_Margin_Left         = GDK_KEY_ISO_Set_Margin_Left,+    _ISO_Set_Margin_Right        = GDK_KEY_ISO_Set_Margin_Right,+    _ISO_Release_Margin_Left     = GDK_KEY_ISO_Release_Margin_Left,+    _ISO_Release_Margin_Right    = GDK_KEY_ISO_Release_Margin_Right,+    _ISO_Release_Both_Margins    = GDK_KEY_ISO_Release_Both_Margins,+    _ISO_Fast_Cursor_Left        = GDK_KEY_ISO_Fast_Cursor_Left,+    _ISO_Fast_Cursor_Right       = GDK_KEY_ISO_Fast_Cursor_Right,+    _ISO_Fast_Cursor_Up          = GDK_KEY_ISO_Fast_Cursor_Up,+    _ISO_Fast_Cursor_Down        = GDK_KEY_ISO_Fast_Cursor_Down,+    _ISO_Continuous_Underline    = GDK_KEY_ISO_Continuous_Underline,+    _ISO_Discontinuous_Underline = GDK_KEY_ISO_Discontinuous_Underline,+    _ISO_Emphasize               = GDK_KEY_ISO_Emphasize,+    _ISO_Center_Object           = GDK_KEY_ISO_Center_Object,+    _ISO_Enter                   = GDK_KEY_ISO_Enter,+    _dead_grave                  = GDK_KEY_dead_grave,+    _dead_acute                  = GDK_KEY_dead_acute,+    _dead_circumflex             = GDK_KEY_dead_circumflex,+    _dead_tilde                  = GDK_KEY_dead_tilde,+    _dead_perispomeni            = GDK_KEY_dead_perispomeni,+    _dead_macron                 = GDK_KEY_dead_macron,+    _dead_breve                  = GDK_KEY_dead_breve,+    _dead_abovedot               = GDK_KEY_dead_abovedot,+    _dead_diaeresis              = GDK_KEY_dead_diaeresis,+    _dead_abovering              = GDK_KEY_dead_abovering,+    _dead_doubleacute            = GDK_KEY_dead_doubleacute,+    _dead_caron                  = GDK_KEY_dead_caron,+    _dead_cedilla                = GDK_KEY_dead_cedilla,+    _dead_ogonek                 = GDK_KEY_dead_ogonek,+    _dead_iota                   = GDK_KEY_dead_iota,+    _dead_voiced_sound           = GDK_KEY_dead_voiced_sound,+    _dead_semivoiced_sound       = GDK_KEY_dead_semivoiced_sound,+    _dead_belowdot               = GDK_KEY_dead_belowdot,+    _dead_hook                   = GDK_KEY_dead_hook,+    _dead_horn                   = GDK_KEY_dead_horn,+    _dead_stroke                 = GDK_KEY_dead_stroke,+    _dead_abovecomma             = GDK_KEY_dead_abovecomma,+    _dead_psili                  = GDK_KEY_dead_psili,+    _dead_abovereversedcomma     = GDK_KEY_dead_abovereversedcomma,+    _dead_dasia                  = GDK_KEY_dead_dasia,+    _dead_doublegrave            = GDK_KEY_dead_doublegrave,+    _dead_belowring              = GDK_KEY_dead_belowring,+    _dead_belowmacron            = GDK_KEY_dead_belowmacron,+    _dead_belowcircumflex        = GDK_KEY_dead_belowcircumflex,+    _dead_belowtilde             = GDK_KEY_dead_belowtilde,+    _dead_belowbreve             = GDK_KEY_dead_belowbreve,+    _dead_belowdiaeresis         = GDK_KEY_dead_belowdiaeresis,+    _dead_invertedbreve          = GDK_KEY_dead_invertedbreve,+    _dead_belowcomma             = GDK_KEY_dead_belowcomma,+    _dead_currency               = GDK_KEY_dead_currency,+    _dead_a                      = GDK_KEY_dead_a,+    _dead_A                      = GDK_KEY_dead_A,+    _dead_e                      = GDK_KEY_dead_e,+    _dead_E                      = GDK_KEY_dead_E,+    _dead_i                      = GDK_KEY_dead_i,+    _dead_I                      = GDK_KEY_dead_I,+    _dead_o                      = GDK_KEY_dead_o,+    _dead_O                      = GDK_KEY_dead_O,+    _dead_u                      = GDK_KEY_dead_u,+    _dead_U                      = GDK_KEY_dead_U,+    _dead_small_schwa            = GDK_KEY_dead_small_schwa,+    _dead_capital_schwa          = GDK_KEY_dead_capital_schwa,+    _First_Virtual_Screen        = GDK_KEY_First_Virtual_Screen,+    _Prev_Virtual_Screen         = GDK_KEY_Prev_Virtual_Screen,+    _Next_Virtual_Screen         = GDK_KEY_Next_Virtual_Screen,+    _Last_Virtual_Screen         = GDK_KEY_Last_Virtual_Screen,+    _Terminate_Server            = GDK_KEY_Terminate_Server,+    _AccessX_Enable              = GDK_KEY_AccessX_Enable,+    _AccessX_Feedback_Enable     = GDK_KEY_AccessX_Feedback_Enable,+    _RepeatKeys_Enable           = GDK_KEY_RepeatKeys_Enable,+    _SlowKeys_Enable             = GDK_KEY_SlowKeys_Enable,+    _BounceKeys_Enable           = GDK_KEY_BounceKeys_Enable,+    _StickyKeys_Enable           = GDK_KEY_StickyKeys_Enable,+    _MouseKeys_Enable            = GDK_KEY_MouseKeys_Enable,+    _MouseKeys_Accel_Enable      = GDK_KEY_MouseKeys_Accel_Enable,+    _Overlay1_Enable             = GDK_KEY_Overlay1_Enable,+    _Overlay2_Enable             = GDK_KEY_Overlay2_Enable,+    _AudibleBell_Enable          = GDK_KEY_AudibleBell_Enable,+    _Pointer_Left                = GDK_KEY_Pointer_Left,+    _Pointer_Right               = GDK_KEY_Pointer_Right,+    _Pointer_Up                  = GDK_KEY_Pointer_Up,+    _Pointer_Down                = GDK_KEY_Pointer_Down,+    _Pointer_UpLeft              = GDK_KEY_Pointer_UpLeft,+    _Pointer_UpRight             = GDK_KEY_Pointer_UpRight,+    _Pointer_DownLeft            = GDK_KEY_Pointer_DownLeft,+    _Pointer_DownRight           = GDK_KEY_Pointer_DownRight,+    _Pointer_Button_Dflt         = GDK_KEY_Pointer_Button_Dflt,+    _Pointer_Button1             = GDK_KEY_Pointer_Button1,+    _Pointer_Button2             = GDK_KEY_Pointer_Button2,+    _Pointer_Button3             = GDK_KEY_Pointer_Button3,+    _Pointer_Button4             = GDK_KEY_Pointer_Button4,+    _Pointer_Button5             = GDK_KEY_Pointer_Button5,+    _Pointer_DblClick_Dflt       = GDK_KEY_Pointer_DblClick_Dflt,+    _Pointer_DblClick1           = GDK_KEY_Pointer_DblClick1,+    _Pointer_DblClick2           = GDK_KEY_Pointer_DblClick2,+    _Pointer_DblClick3           = GDK_KEY_Pointer_DblClick3,+    _Pointer_DblClick4           = GDK_KEY_Pointer_DblClick4,+    _Pointer_DblClick5           = GDK_KEY_Pointer_DblClick5,+    _Pointer_Drag_Dflt           = GDK_KEY_Pointer_Drag_Dflt,+    _Pointer_Drag1               = GDK_KEY_Pointer_Drag1,+    _Pointer_Drag2               = GDK_KEY_Pointer_Drag2,+    _Pointer_Drag3               = GDK_KEY_Pointer_Drag3,+    _Pointer_Drag4               = GDK_KEY_Pointer_Drag4,+    _Pointer_Drag5               = GDK_KEY_Pointer_Drag5,+    _Pointer_EnableKeys          = GDK_KEY_Pointer_EnableKeys,+    _Pointer_Accelerate          = GDK_KEY_Pointer_Accelerate,+    _Pointer_DfltBtnNext         = GDK_KEY_Pointer_DfltBtnNext,+    _Pointer_DfltBtnPrev         = GDK_KEY_Pointer_DfltBtnPrev,+    _3270_Duplicate              = GDK_KEY_3270_Duplicate,+    _3270_FieldMark              = GDK_KEY_3270_FieldMark,+    _3270_Right2                 = GDK_KEY_3270_Right2,+    _3270_Left2                  = GDK_KEY_3270_Left2,+    _3270_BackTab                = GDK_KEY_3270_BackTab,+    _3270_EraseEOF               = GDK_KEY_3270_EraseEOF,+    _3270_EraseInput             = GDK_KEY_3270_EraseInput,+    _3270_Reset                  = GDK_KEY_3270_Reset,+    _3270_Quit                   = GDK_KEY_3270_Quit,+    _3270_PA1                    = GDK_KEY_3270_PA1,+    _3270_PA2                    = GDK_KEY_3270_PA2,+    _3270_PA3                    = GDK_KEY_3270_PA3,+    _3270_Test                   = GDK_KEY_3270_Test,+    _3270_Attn                   = GDK_KEY_3270_Attn,+    _3270_CursorBlink            = GDK_KEY_3270_CursorBlink,+    _3270_AltCursor              = GDK_KEY_3270_AltCursor,+    _3270_KeyClick               = GDK_KEY_3270_KeyClick,+    _3270_Jump                   = GDK_KEY_3270_Jump,+    _3270_Ident                  = GDK_KEY_3270_Ident,+    _3270_Rule                   = GDK_KEY_3270_Rule,+    _3270_Copy                   = GDK_KEY_3270_Copy,+    _3270_Play                   = GDK_KEY_3270_Play,+    _3270_Setup                  = GDK_KEY_3270_Setup,+    _3270_Record                 = GDK_KEY_3270_Record,+    _3270_ChangeScreen           = GDK_KEY_3270_ChangeScreen,+    _3270_DeleteWord             = GDK_KEY_3270_DeleteWord,+    _3270_ExSelect               = GDK_KEY_3270_ExSelect,+    _3270_CursorSelect           = GDK_KEY_3270_CursorSelect,+    _3270_PrintScreen            = GDK_KEY_3270_PrintScreen,+    _3270_Enter                  = GDK_KEY_3270_Enter,+    _space                       = GDK_KEY_space,+    _exclam                      = GDK_KEY_exclam,+    _quotedbl                    = GDK_KEY_quotedbl,+    _numbersign                  = GDK_KEY_numbersign,+    _dollar                      = GDK_KEY_dollar,+    _percent                     = GDK_KEY_percent,+    _ampersand                   = GDK_KEY_ampersand,+    _apostrophe                  = GDK_KEY_apostrophe,+    _quoteright                  = GDK_KEY_quoteright,+    _parenleft                   = GDK_KEY_parenleft,+    _parenright                  = GDK_KEY_parenright,+    _asterisk                    = GDK_KEY_asterisk,+    _plus                        = GDK_KEY_plus,+    _comma                       = GDK_KEY_comma,+    _minus                       = GDK_KEY_minus,+    _period                      = GDK_KEY_period,+    _slash                       = GDK_KEY_slash,+    _0                           = GDK_KEY_0,+    _1                           = GDK_KEY_1,+    _2                           = GDK_KEY_2,+    _3                           = GDK_KEY_3,+    _4                           = GDK_KEY_4,+    _5                           = GDK_KEY_5,+    _6                           = GDK_KEY_6,+    _7                           = GDK_KEY_7,+    _8                           = GDK_KEY_8,+    _9                           = GDK_KEY_9,+    _colon                       = GDK_KEY_colon,+    _semicolon                   = GDK_KEY_semicolon,+    _less                        = GDK_KEY_less,+    _equal                       = GDK_KEY_equal,+    _greater                     = GDK_KEY_greater,+    _question                    = GDK_KEY_question,+    _at                          = GDK_KEY_at,+    _A                           = GDK_KEY_A,+    _B                           = GDK_KEY_B,+    _C                           = GDK_KEY_C,+    _D                           = GDK_KEY_D,+    _E                           = GDK_KEY_E,+    _F                           = GDK_KEY_F,+    _G                           = GDK_KEY_G,+    _H                           = GDK_KEY_H,+    _I                           = GDK_KEY_I,+    _J                           = GDK_KEY_J,+    _K                           = GDK_KEY_K,+    _L                           = GDK_KEY_L,+    _M                           = GDK_KEY_M,+    _N                           = GDK_KEY_N,+    _O                           = GDK_KEY_O,+    _P                           = GDK_KEY_P,+    _Q                           = GDK_KEY_Q,+    _R                           = GDK_KEY_R,+    _S                           = GDK_KEY_S,+    _T                           = GDK_KEY_T,+    _U                           = GDK_KEY_U,+    _V                           = GDK_KEY_V,+    _W                           = GDK_KEY_W,+    _X                           = GDK_KEY_X,+    _Y                           = GDK_KEY_Y,+    _Z                           = GDK_KEY_Z,+    _bracketleft                 = GDK_KEY_bracketleft,+    _backslash                   = GDK_KEY_backslash,+    _bracketright                = GDK_KEY_bracketright,+    _asciicircum                 = GDK_KEY_asciicircum,+    _underscore                  = GDK_KEY_underscore,+    _grave                       = GDK_KEY_grave,+    _quoteleft                   = GDK_KEY_quoteleft,+    _a                           = GDK_KEY_a,+    _b                           = GDK_KEY_b,+    _c                           = GDK_KEY_c,+    _d                           = GDK_KEY_d,+    _e                           = GDK_KEY_e,+    _f                           = GDK_KEY_f,+    _g                           = GDK_KEY_g,+    _h                           = GDK_KEY_h,+    _i                           = GDK_KEY_i,+    _j                           = GDK_KEY_j,+    _k                           = GDK_KEY_k,+    _l                           = GDK_KEY_l,+    _m                           = GDK_KEY_m,+    _n                           = GDK_KEY_n,+    _o                           = GDK_KEY_o,+    _p                           = GDK_KEY_p,+    _q                           = GDK_KEY_q,+    _r                           = GDK_KEY_r,+    _s                           = GDK_KEY_s,+    _t                           = GDK_KEY_t,+    _u                           = GDK_KEY_u,+    _v                           = GDK_KEY_v,+    _w                           = GDK_KEY_w,+    _x                           = GDK_KEY_x,+    _y                           = GDK_KEY_y,+    _z                           = GDK_KEY_z,+    _braceleft                   = GDK_KEY_braceleft,+    _bar                         = GDK_KEY_bar,+    _braceright                  = GDK_KEY_braceright,+    _asciitilde                  = GDK_KEY_asciitilde,+    _nobreakspace                = GDK_KEY_nobreakspace,+    _exclamdown                  = GDK_KEY_exclamdown,+    _cent                        = GDK_KEY_cent,+    _sterling                    = GDK_KEY_sterling,+    _currency                    = GDK_KEY_currency,+    _yen                         = GDK_KEY_yen,+    _brokenbar                   = GDK_KEY_brokenbar,+    _section                     = GDK_KEY_section,+    _diaeresis                   = GDK_KEY_diaeresis,+    _copyright                   = GDK_KEY_copyright,+    _ordfeminine                 = GDK_KEY_ordfeminine,+    _guillemotleft               = GDK_KEY_guillemotleft,+    _notsign                     = GDK_KEY_notsign,+    _hyphen                      = GDK_KEY_hyphen,+    _registered                  = GDK_KEY_registered,+    _macron                      = GDK_KEY_macron,+    _degree                      = GDK_KEY_degree,+    _plusminus                   = GDK_KEY_plusminus,+    _twosuperior                 = GDK_KEY_twosuperior,+    _threesuperior               = GDK_KEY_threesuperior,+    _acute                       = GDK_KEY_acute,+    _mu                          = GDK_KEY_mu,+    _paragraph                   = GDK_KEY_paragraph,+    _periodcentered              = GDK_KEY_periodcentered,+    _cedilla                     = GDK_KEY_cedilla,+    _onesuperior                 = GDK_KEY_onesuperior,+    _masculine                   = GDK_KEY_masculine,+    _guillemotright              = GDK_KEY_guillemotright,+    _onequarter                  = GDK_KEY_onequarter,+    _onehalf                     = GDK_KEY_onehalf,+    _threequarters               = GDK_KEY_threequarters,+    _questiondown                = GDK_KEY_questiondown,+    _Agrave                      = GDK_KEY_Agrave,+    _Aacute                      = GDK_KEY_Aacute,+    _Acircumflex                 = GDK_KEY_Acircumflex,+    _Atilde                      = GDK_KEY_Atilde,+    _Adiaeresis                  = GDK_KEY_Adiaeresis,+    _Aring                       = GDK_KEY_Aring,+    _AE                          = GDK_KEY_AE,+    _Ccedilla                    = GDK_KEY_Ccedilla,+    _Egrave                      = GDK_KEY_Egrave,+    _Eacute                      = GDK_KEY_Eacute,+    _Ecircumflex                 = GDK_KEY_Ecircumflex,+    _Ediaeresis                  = GDK_KEY_Ediaeresis,+    _Igrave                      = GDK_KEY_Igrave,+    _Iacute                      = GDK_KEY_Iacute,+    _Icircumflex                 = GDK_KEY_Icircumflex,+    _Idiaeresis                  = GDK_KEY_Idiaeresis,+    _ETH                         = GDK_KEY_ETH,+    _Eth                         = GDK_KEY_Eth,+    _Ntilde                      = GDK_KEY_Ntilde,+    _Ograve                      = GDK_KEY_Ograve,+    _Oacute                      = GDK_KEY_Oacute,+    _Ocircumflex                 = GDK_KEY_Ocircumflex,+    _Otilde                      = GDK_KEY_Otilde,+    _Odiaeresis                  = GDK_KEY_Odiaeresis,+    _multiply                    = GDK_KEY_multiply,+    _Oslash                      = GDK_KEY_Oslash,+    _Ooblique                    = GDK_KEY_Ooblique,+    _Ugrave                      = GDK_KEY_Ugrave,+    _Uacute                      = GDK_KEY_Uacute,+    _Ucircumflex                 = GDK_KEY_Ucircumflex,+    _Udiaeresis                  = GDK_KEY_Udiaeresis,+    _Yacute                      = GDK_KEY_Yacute,+    _THORN                       = GDK_KEY_THORN,+    _Thorn                       = GDK_KEY_Thorn,+    _ssharp                      = GDK_KEY_ssharp,+    _agrave                      = GDK_KEY_agrave,+    _aacute                      = GDK_KEY_aacute,+    _acircumflex                 = GDK_KEY_acircumflex,+    _atilde                      = GDK_KEY_atilde,+    _adiaeresis                  = GDK_KEY_adiaeresis,+    _aring                       = GDK_KEY_aring,+    _ae                          = GDK_KEY_ae,+    _ccedilla                    = GDK_KEY_ccedilla,+    _egrave                      = GDK_KEY_egrave,+    _eacute                      = GDK_KEY_eacute,+    _ecircumflex                 = GDK_KEY_ecircumflex,+    _ediaeresis                  = GDK_KEY_ediaeresis,+    _igrave                      = GDK_KEY_igrave,+    _iacute                      = GDK_KEY_iacute,+    _icircumflex                 = GDK_KEY_icircumflex,+    _idiaeresis                  = GDK_KEY_idiaeresis,+    _eth                         = GDK_KEY_eth,+    _ntilde                      = GDK_KEY_ntilde,+    _ograve                      = GDK_KEY_ograve,+    _oacute                      = GDK_KEY_oacute,+    _ocircumflex                 = GDK_KEY_ocircumflex,+    _otilde                      = GDK_KEY_otilde,+    _odiaeresis                  = GDK_KEY_odiaeresis,+    _division                    = GDK_KEY_division,+    _oslash                      = GDK_KEY_oslash,+    _ooblique                    = GDK_KEY_ooblique,+    _ugrave                      = GDK_KEY_ugrave,+    _uacute                      = GDK_KEY_uacute,+    _ucircumflex                 = GDK_KEY_ucircumflex,+    _udiaeresis                  = GDK_KEY_udiaeresis,+    _yacute                      = GDK_KEY_yacute,+    _thorn                       = GDK_KEY_thorn,+    _ydiaeresis                  = GDK_KEY_ydiaeresis,+    _Aogonek                     = GDK_KEY_Aogonek,+    _breve                       = GDK_KEY_breve,+    _Lstroke                     = GDK_KEY_Lstroke,+    _Lcaron                      = GDK_KEY_Lcaron,+    _Sacute                      = GDK_KEY_Sacute,+    _Scaron                      = GDK_KEY_Scaron,+    _Scedilla                    = GDK_KEY_Scedilla,+    _Tcaron                      = GDK_KEY_Tcaron,+    _Zacute                      = GDK_KEY_Zacute,+    _Zcaron                      = GDK_KEY_Zcaron,+    _Zabovedot                   = GDK_KEY_Zabovedot,+    _aogonek                     = GDK_KEY_aogonek,+    _ogonek                      = GDK_KEY_ogonek,+    _lstroke                     = GDK_KEY_lstroke,+    _lcaron                      = GDK_KEY_lcaron,+    _sacute                      = GDK_KEY_sacute,+    _caron                       = GDK_KEY_caron,+    _scaron                      = GDK_KEY_scaron,+    _scedilla                    = GDK_KEY_scedilla,+    _tcaron                      = GDK_KEY_tcaron,+    _zacute                      = GDK_KEY_zacute,+    _doubleacute                 = GDK_KEY_doubleacute,+    _zcaron                      = GDK_KEY_zcaron,+    _zabovedot                   = GDK_KEY_zabovedot,+    _Racute                      = GDK_KEY_Racute,+    _Abreve                      = GDK_KEY_Abreve,+    _Lacute                      = GDK_KEY_Lacute,+    _Cacute                      = GDK_KEY_Cacute,+    _Ccaron                      = GDK_KEY_Ccaron,+    _Eogonek                     = GDK_KEY_Eogonek,+    _Ecaron                      = GDK_KEY_Ecaron,+    _Dcaron                      = GDK_KEY_Dcaron,+    _Dstroke                     = GDK_KEY_Dstroke,+    _Nacute                      = GDK_KEY_Nacute,+    _Ncaron                      = GDK_KEY_Ncaron,+    _Odoubleacute                = GDK_KEY_Odoubleacute,+    _Rcaron                      = GDK_KEY_Rcaron,+    _Uring                       = GDK_KEY_Uring,+    _Udoubleacute                = GDK_KEY_Udoubleacute,+    _Tcedilla                    = GDK_KEY_Tcedilla,+    _racute                      = GDK_KEY_racute,+    _abreve                      = GDK_KEY_abreve,+    _lacute                      = GDK_KEY_lacute,+    _cacute                      = GDK_KEY_cacute,+    _ccaron                      = GDK_KEY_ccaron,+    _eogonek                     = GDK_KEY_eogonek,+    _ecaron                      = GDK_KEY_ecaron,+    _dcaron                      = GDK_KEY_dcaron,+    _dstroke                     = GDK_KEY_dstroke,+    _nacute                      = GDK_KEY_nacute,+    _ncaron                      = GDK_KEY_ncaron,+    _odoubleacute                = GDK_KEY_odoubleacute,+    _rcaron                      = GDK_KEY_rcaron,+    _uring                       = GDK_KEY_uring,+    _udoubleacute                = GDK_KEY_udoubleacute,+    _tcedilla                    = GDK_KEY_tcedilla,+    _abovedot                    = GDK_KEY_abovedot,+    _Hstroke                     = GDK_KEY_Hstroke,+    _Hcircumflex                 = GDK_KEY_Hcircumflex,+    _Iabovedot                   = GDK_KEY_Iabovedot,+    _Gbreve                      = GDK_KEY_Gbreve,+    _Jcircumflex                 = GDK_KEY_Jcircumflex,+    _hstroke                     = GDK_KEY_hstroke,+    _hcircumflex                 = GDK_KEY_hcircumflex,+    _idotless                    = GDK_KEY_idotless,+    _gbreve                      = GDK_KEY_gbreve,+    _jcircumflex                 = GDK_KEY_jcircumflex,+    _Cabovedot                   = GDK_KEY_Cabovedot,+    _Ccircumflex                 = GDK_KEY_Ccircumflex,+    _Gabovedot                   = GDK_KEY_Gabovedot,+    _Gcircumflex                 = GDK_KEY_Gcircumflex,+    _Ubreve                      = GDK_KEY_Ubreve,+    _Scircumflex                 = GDK_KEY_Scircumflex,+    _cabovedot                   = GDK_KEY_cabovedot,+    _ccircumflex                 = GDK_KEY_ccircumflex,+    _gabovedot                   = GDK_KEY_gabovedot,+    _gcircumflex                 = GDK_KEY_gcircumflex,+    _ubreve                      = GDK_KEY_ubreve,+    _scircumflex                 = GDK_KEY_scircumflex,+    _kra                         = GDK_KEY_kra,+    _kappa                       = GDK_KEY_kappa,+    _Rcedilla                    = GDK_KEY_Rcedilla,+    _Itilde                      = GDK_KEY_Itilde,+    _Lcedilla                    = GDK_KEY_Lcedilla,+    _Emacron                     = GDK_KEY_Emacron,+    _Gcedilla                    = GDK_KEY_Gcedilla,+    _Tslash                      = GDK_KEY_Tslash,+    _rcedilla                    = GDK_KEY_rcedilla,+    _itilde                      = GDK_KEY_itilde,+    _lcedilla                    = GDK_KEY_lcedilla,+    _emacron                     = GDK_KEY_emacron,+    _gcedilla                    = GDK_KEY_gcedilla,+    _tslash                      = GDK_KEY_tslash,+    _ENG                         = GDK_KEY_ENG,+    _eng                         = GDK_KEY_eng,+    _Amacron                     = GDK_KEY_Amacron,+    _Iogonek                     = GDK_KEY_Iogonek,+    _Eabovedot                   = GDK_KEY_Eabovedot,+    _Imacron                     = GDK_KEY_Imacron,+    _Ncedilla                    = GDK_KEY_Ncedilla,+    _Omacron                     = GDK_KEY_Omacron,+    _Kcedilla                    = GDK_KEY_Kcedilla,+    _Uogonek                     = GDK_KEY_Uogonek,+    _Utilde                      = GDK_KEY_Utilde,+    _Umacron                     = GDK_KEY_Umacron,+    _amacron                     = GDK_KEY_amacron,+    _iogonek                     = GDK_KEY_iogonek,+    _eabovedot                   = GDK_KEY_eabovedot,+    _imacron                     = GDK_KEY_imacron,+    _ncedilla                    = GDK_KEY_ncedilla,+    _omacron                     = GDK_KEY_omacron,+    _kcedilla                    = GDK_KEY_kcedilla,+    _uogonek                     = GDK_KEY_uogonek,+    _utilde                      = GDK_KEY_utilde,+    _umacron                     = GDK_KEY_umacron,+    _Wcircumflex                 = GDK_KEY_Wcircumflex,+    _wcircumflex                 = GDK_KEY_wcircumflex,+    _Ycircumflex                 = GDK_KEY_Ycircumflex,+    _ycircumflex                 = GDK_KEY_ycircumflex,+    _Babovedot                   = GDK_KEY_Babovedot,+    _babovedot                   = GDK_KEY_babovedot,+    _Dabovedot                   = GDK_KEY_Dabovedot,+    _dabovedot                   = GDK_KEY_dabovedot,+    _Fabovedot                   = GDK_KEY_Fabovedot,+    _fabovedot                   = GDK_KEY_fabovedot,+    _Mabovedot                   = GDK_KEY_Mabovedot,+    _mabovedot                   = GDK_KEY_mabovedot,+    _Pabovedot                   = GDK_KEY_Pabovedot,+    _pabovedot                   = GDK_KEY_pabovedot,+    _Sabovedot                   = GDK_KEY_Sabovedot,+    _sabovedot                   = GDK_KEY_sabovedot,+    _Tabovedot                   = GDK_KEY_Tabovedot,+    _tabovedot                   = GDK_KEY_tabovedot,+    _Wgrave                      = GDK_KEY_Wgrave,+    _wgrave                      = GDK_KEY_wgrave,+    _Wacute                      = GDK_KEY_Wacute,+    _wacute                      = GDK_KEY_wacute,+    _Wdiaeresis                  = GDK_KEY_Wdiaeresis,+    _wdiaeresis                  = GDK_KEY_wdiaeresis,+    _Ygrave                      = GDK_KEY_Ygrave,+    _ygrave                      = GDK_KEY_ygrave,+    _OE                          = GDK_KEY_OE,+    _oe                          = GDK_KEY_oe,+    _Ydiaeresis                  = GDK_KEY_Ydiaeresis,+    _overline                    = GDK_KEY_overline,+    _kana_fullstop               = GDK_KEY_kana_fullstop,+    _kana_openingbracket         = GDK_KEY_kana_openingbracket,+    _kana_closingbracket         = GDK_KEY_kana_closingbracket,+    _kana_comma                  = GDK_KEY_kana_comma,+    _kana_conjunctive            = GDK_KEY_kana_conjunctive,+    _kana_middledot              = GDK_KEY_kana_middledot,+    _kana_WO                     = GDK_KEY_kana_WO,+    _kana_a                      = GDK_KEY_kana_a,+    _kana_i                      = GDK_KEY_kana_i,+    _kana_u                      = GDK_KEY_kana_u,+    _kana_e                      = GDK_KEY_kana_e,+    _kana_o                      = GDK_KEY_kana_o,+    _kana_ya                     = GDK_KEY_kana_ya,+    _kana_yu                     = GDK_KEY_kana_yu,+    _kana_yo                     = GDK_KEY_kana_yo,+    _kana_tsu                    = GDK_KEY_kana_tsu,+    _kana_tu                     = GDK_KEY_kana_tu,+    _prolongedsound              = GDK_KEY_prolongedsound,+    _kana_A                      = GDK_KEY_kana_A,+    _kana_I                      = GDK_KEY_kana_I,+    _kana_U                      = GDK_KEY_kana_U,+    _kana_E                      = GDK_KEY_kana_E,+    _kana_O                      = GDK_KEY_kana_O,+    _kana_KA                     = GDK_KEY_kana_KA,+    _kana_KI                     = GDK_KEY_kana_KI,+    _kana_KU                     = GDK_KEY_kana_KU,+    _kana_KE                     = GDK_KEY_kana_KE,+    _kana_KO                     = GDK_KEY_kana_KO,+    _kana_SA                     = GDK_KEY_kana_SA,+    _kana_SHI                    = GDK_KEY_kana_SHI,+    _kana_SU                     = GDK_KEY_kana_SU,+    _kana_SE                     = GDK_KEY_kana_SE,+    _kana_SO                     = GDK_KEY_kana_SO,+    _kana_TA                     = GDK_KEY_kana_TA,+    _kana_CHI                    = GDK_KEY_kana_CHI,+    _kana_TI                     = GDK_KEY_kana_TI,+    _kana_TSU                    = GDK_KEY_kana_TSU,+    _kana_TU                     = GDK_KEY_kana_TU,+    _kana_TE                     = GDK_KEY_kana_TE,+    _kana_TO                     = GDK_KEY_kana_TO,+    _kana_NA                     = GDK_KEY_kana_NA,+    _kana_NI                     = GDK_KEY_kana_NI,+    _kana_NU                     = GDK_KEY_kana_NU,+    _kana_NE                     = GDK_KEY_kana_NE,+    _kana_NO                     = GDK_KEY_kana_NO,+    _kana_HA                     = GDK_KEY_kana_HA,+    _kana_HI                     = GDK_KEY_kana_HI,+    _kana_FU                     = GDK_KEY_kana_FU,+    _kana_HU                     = GDK_KEY_kana_HU,+    _kana_HE                     = GDK_KEY_kana_HE,+    _kana_HO                     = GDK_KEY_kana_HO,+    _kana_MA                     = GDK_KEY_kana_MA,+    _kana_MI                     = GDK_KEY_kana_MI,+    _kana_MU                     = GDK_KEY_kana_MU,+    _kana_ME                     = GDK_KEY_kana_ME,+    _kana_MO                     = GDK_KEY_kana_MO,+    _kana_YA                     = GDK_KEY_kana_YA,+    _kana_YU                     = GDK_KEY_kana_YU,+    _kana_YO                     = GDK_KEY_kana_YO,+    _kana_RA                     = GDK_KEY_kana_RA,+    _kana_RI                     = GDK_KEY_kana_RI,+    _kana_RU                     = GDK_KEY_kana_RU,+    _kana_RE                     = GDK_KEY_kana_RE,+    _kana_RO                     = GDK_KEY_kana_RO,+    _kana_WA                     = GDK_KEY_kana_WA,+    _kana_N                      = GDK_KEY_kana_N,+    _voicedsound                 = GDK_KEY_voicedsound,+    _semivoicedsound             = GDK_KEY_semivoicedsound,+    _kana_switch                 = GDK_KEY_kana_switch,+    _Farsi_0                     = GDK_KEY_Farsi_0,+    _Farsi_1                     = GDK_KEY_Farsi_1,+    _Farsi_2                     = GDK_KEY_Farsi_2,+    _Farsi_3                     = GDK_KEY_Farsi_3,+    _Farsi_4                     = GDK_KEY_Farsi_4,+    _Farsi_5                     = GDK_KEY_Farsi_5,+    _Farsi_6                     = GDK_KEY_Farsi_6,+    _Farsi_7                     = GDK_KEY_Farsi_7,+    _Farsi_8                     = GDK_KEY_Farsi_8,+    _Farsi_9                     = GDK_KEY_Farsi_9,+    _Arabic_percent              = GDK_KEY_Arabic_percent,+    _Arabic_superscript_alef     = GDK_KEY_Arabic_superscript_alef,+    _Arabic_tteh                 = GDK_KEY_Arabic_tteh,+    _Arabic_peh                  = GDK_KEY_Arabic_peh,+    _Arabic_tcheh                = GDK_KEY_Arabic_tcheh,+    _Arabic_ddal                 = GDK_KEY_Arabic_ddal,+    _Arabic_rreh                 = GDK_KEY_Arabic_rreh,+    _Arabic_comma                = GDK_KEY_Arabic_comma,+    _Arabic_fullstop             = GDK_KEY_Arabic_fullstop,+    _Arabic_0                    = GDK_KEY_Arabic_0,+    _Arabic_1                    = GDK_KEY_Arabic_1,+    _Arabic_2                    = GDK_KEY_Arabic_2,+    _Arabic_3                    = GDK_KEY_Arabic_3,+    _Arabic_4                    = GDK_KEY_Arabic_4,+    _Arabic_5                    = GDK_KEY_Arabic_5,+    _Arabic_6                    = GDK_KEY_Arabic_6,+    _Arabic_7                    = GDK_KEY_Arabic_7,+    _Arabic_8                    = GDK_KEY_Arabic_8,+    _Arabic_9                    = GDK_KEY_Arabic_9,+    _Arabic_semicolon            = GDK_KEY_Arabic_semicolon,+    _Arabic_question_mark        = GDK_KEY_Arabic_question_mark,+    _Arabic_hamza                = GDK_KEY_Arabic_hamza,+    _Arabic_maddaonalef          = GDK_KEY_Arabic_maddaonalef,+    _Arabic_hamzaonalef          = GDK_KEY_Arabic_hamzaonalef,+    _Arabic_hamzaonwaw           = GDK_KEY_Arabic_hamzaonwaw,+    _Arabic_hamzaunderalef       = GDK_KEY_Arabic_hamzaunderalef,+    _Arabic_hamzaonyeh           = GDK_KEY_Arabic_hamzaonyeh,+    _Arabic_alef                 = GDK_KEY_Arabic_alef,+    _Arabic_beh                  = GDK_KEY_Arabic_beh,+    _Arabic_tehmarbuta           = GDK_KEY_Arabic_tehmarbuta,+    _Arabic_teh                  = GDK_KEY_Arabic_teh,+    _Arabic_theh                 = GDK_KEY_Arabic_theh,+    _Arabic_jeem                 = GDK_KEY_Arabic_jeem,+    _Arabic_hah                  = GDK_KEY_Arabic_hah,+    _Arabic_khah                 = GDK_KEY_Arabic_khah,+    _Arabic_dal                  = GDK_KEY_Arabic_dal,+    _Arabic_thal                 = GDK_KEY_Arabic_thal,+    _Arabic_ra                   = GDK_KEY_Arabic_ra,+    _Arabic_zain                 = GDK_KEY_Arabic_zain,+    _Arabic_seen                 = GDK_KEY_Arabic_seen,+    _Arabic_sheen                = GDK_KEY_Arabic_sheen,+    _Arabic_sad                  = GDK_KEY_Arabic_sad,+    _Arabic_dad                  = GDK_KEY_Arabic_dad,+    _Arabic_tah                  = GDK_KEY_Arabic_tah,+    _Arabic_zah                  = GDK_KEY_Arabic_zah,+    _Arabic_ain                  = GDK_KEY_Arabic_ain,+    _Arabic_ghain                = GDK_KEY_Arabic_ghain,+    _Arabic_tatweel              = GDK_KEY_Arabic_tatweel,+    _Arabic_feh                  = GDK_KEY_Arabic_feh,+    _Arabic_qaf                  = GDK_KEY_Arabic_qaf,+    _Arabic_kaf                  = GDK_KEY_Arabic_kaf,+    _Arabic_lam                  = GDK_KEY_Arabic_lam,+    _Arabic_meem                 = GDK_KEY_Arabic_meem,+    _Arabic_noon                 = GDK_KEY_Arabic_noon,+    _Arabic_ha                   = GDK_KEY_Arabic_ha,+    _Arabic_heh                  = GDK_KEY_Arabic_heh,+    _Arabic_waw                  = GDK_KEY_Arabic_waw,+    _Arabic_alefmaksura          = GDK_KEY_Arabic_alefmaksura,+    _Arabic_yeh                  = GDK_KEY_Arabic_yeh,+    _Arabic_fathatan             = GDK_KEY_Arabic_fathatan,+    _Arabic_dammatan             = GDK_KEY_Arabic_dammatan,+    _Arabic_kasratan             = GDK_KEY_Arabic_kasratan,+    _Arabic_fatha                = GDK_KEY_Arabic_fatha,+    _Arabic_damma                = GDK_KEY_Arabic_damma,+    _Arabic_kasra                = GDK_KEY_Arabic_kasra,+    _Arabic_shadda               = GDK_KEY_Arabic_shadda,+    _Arabic_sukun                = GDK_KEY_Arabic_sukun,+    _Arabic_madda_above          = GDK_KEY_Arabic_madda_above,+    _Arabic_hamza_above          = GDK_KEY_Arabic_hamza_above,+    _Arabic_hamza_below          = GDK_KEY_Arabic_hamza_below,+    _Arabic_jeh                  = GDK_KEY_Arabic_jeh,+    _Arabic_veh                  = GDK_KEY_Arabic_veh,+    _Arabic_keheh                = GDK_KEY_Arabic_keheh,+    _Arabic_gaf                  = GDK_KEY_Arabic_gaf,+    _Arabic_noon_ghunna          = GDK_KEY_Arabic_noon_ghunna,+    _Arabic_heh_doachashmee      = GDK_KEY_Arabic_heh_doachashmee,+    _Farsi_yeh                   = GDK_KEY_Farsi_yeh,+    _Arabic_farsi_yeh            = GDK_KEY_Arabic_farsi_yeh,+    _Arabic_yeh_baree            = GDK_KEY_Arabic_yeh_baree,+    _Arabic_heh_goal             = GDK_KEY_Arabic_heh_goal,+    _Arabic_switch               = GDK_KEY_Arabic_switch,+    _Cyrillic_GHE_bar            = GDK_KEY_Cyrillic_GHE_bar,+    _Cyrillic_ghe_bar            = GDK_KEY_Cyrillic_ghe_bar,+    _Cyrillic_ZHE_descender      = GDK_KEY_Cyrillic_ZHE_descender,+    _Cyrillic_zhe_descender      = GDK_KEY_Cyrillic_zhe_descender,+    _Cyrillic_KA_descender       = GDK_KEY_Cyrillic_KA_descender,+    _Cyrillic_ka_descender       = GDK_KEY_Cyrillic_ka_descender,+    _Cyrillic_KA_vertstroke      = GDK_KEY_Cyrillic_KA_vertstroke,+    _Cyrillic_ka_vertstroke      = GDK_KEY_Cyrillic_ka_vertstroke,+    _Cyrillic_EN_descender       = GDK_KEY_Cyrillic_EN_descender,+    _Cyrillic_en_descender       = GDK_KEY_Cyrillic_en_descender,+    _Cyrillic_U_straight         = GDK_KEY_Cyrillic_U_straight,+    _Cyrillic_u_straight         = GDK_KEY_Cyrillic_u_straight,+    _Cyrillic_U_straight_bar     = GDK_KEY_Cyrillic_U_straight_bar,+    _Cyrillic_u_straight_bar     = GDK_KEY_Cyrillic_u_straight_bar,+    _Cyrillic_HA_descender       = GDK_KEY_Cyrillic_HA_descender,+    _Cyrillic_ha_descender       = GDK_KEY_Cyrillic_ha_descender,+    _Cyrillic_CHE_descender      = GDK_KEY_Cyrillic_CHE_descender,+    _Cyrillic_che_descender      = GDK_KEY_Cyrillic_che_descender,+    _Cyrillic_CHE_vertstroke     = GDK_KEY_Cyrillic_CHE_vertstroke,+    _Cyrillic_che_vertstroke     = GDK_KEY_Cyrillic_che_vertstroke,+    _Cyrillic_SHHA               = GDK_KEY_Cyrillic_SHHA,+    _Cyrillic_shha               = GDK_KEY_Cyrillic_shha,+    _Cyrillic_SCHWA              = GDK_KEY_Cyrillic_SCHWA,+    _Cyrillic_schwa              = GDK_KEY_Cyrillic_schwa,+    _Cyrillic_I_macron           = GDK_KEY_Cyrillic_I_macron,+    _Cyrillic_i_macron           = GDK_KEY_Cyrillic_i_macron,+    _Cyrillic_O_bar              = GDK_KEY_Cyrillic_O_bar,+    _Cyrillic_o_bar              = GDK_KEY_Cyrillic_o_bar,+    _Cyrillic_U_macron           = GDK_KEY_Cyrillic_U_macron,+    _Cyrillic_u_macron           = GDK_KEY_Cyrillic_u_macron,+    _Serbian_dje                 = GDK_KEY_Serbian_dje,+    _Macedonia_gje               = GDK_KEY_Macedonia_gje,+    _Cyrillic_io                 = GDK_KEY_Cyrillic_io,+    _Ukrainian_ie                = GDK_KEY_Ukrainian_ie,+    _Ukranian_je                 = GDK_KEY_Ukranian_je,+    _Macedonia_dse               = GDK_KEY_Macedonia_dse,+    _Ukrainian_i                 = GDK_KEY_Ukrainian_i,+    _Ukranian_i                  = GDK_KEY_Ukranian_i,+    _Ukrainian_yi                = GDK_KEY_Ukrainian_yi,+    _Ukranian_yi                 = GDK_KEY_Ukranian_yi,+    _Cyrillic_je                 = GDK_KEY_Cyrillic_je,+    _Serbian_je                  = GDK_KEY_Serbian_je,+    _Cyrillic_lje                = GDK_KEY_Cyrillic_lje,+    _Serbian_lje                 = GDK_KEY_Serbian_lje,+    _Cyrillic_nje                = GDK_KEY_Cyrillic_nje,+    _Serbian_nje                 = GDK_KEY_Serbian_nje,+    _Serbian_tshe                = GDK_KEY_Serbian_tshe,+    _Macedonia_kje               = GDK_KEY_Macedonia_kje,+    _Ukrainian_ghe_with_upturn   = GDK_KEY_Ukrainian_ghe_with_upturn,+    _Byelorussian_shortu         = GDK_KEY_Byelorussian_shortu,+    _Cyrillic_dzhe               = GDK_KEY_Cyrillic_dzhe,+    _Serbian_dze                 = GDK_KEY_Serbian_dze,+    _numerosign                  = GDK_KEY_numerosign,+    _Serbian_DJE                 = GDK_KEY_Serbian_DJE,+    _Macedonia_GJE               = GDK_KEY_Macedonia_GJE,+    _Cyrillic_IO                 = GDK_KEY_Cyrillic_IO,+    _Ukrainian_IE                = GDK_KEY_Ukrainian_IE,+    _Ukranian_JE                 = GDK_KEY_Ukranian_JE,+    _Macedonia_DSE               = GDK_KEY_Macedonia_DSE,+    _Ukrainian_I                 = GDK_KEY_Ukrainian_I,+    _Ukranian_I                  = GDK_KEY_Ukranian_I,+    _Ukrainian_YI                = GDK_KEY_Ukrainian_YI,+    _Ukranian_YI                 = GDK_KEY_Ukranian_YI,+    _Cyrillic_JE                 = GDK_KEY_Cyrillic_JE,+    _Serbian_JE                  = GDK_KEY_Serbian_JE,+    _Cyrillic_LJE                = GDK_KEY_Cyrillic_LJE,+    _Serbian_LJE                 = GDK_KEY_Serbian_LJE,+    _Cyrillic_NJE                = GDK_KEY_Cyrillic_NJE,+    _Serbian_NJE                 = GDK_KEY_Serbian_NJE,+    _Serbian_TSHE                = GDK_KEY_Serbian_TSHE,+    _Macedonia_KJE               = GDK_KEY_Macedonia_KJE,+    _Ukrainian_GHE_WITH_UPTURN   = GDK_KEY_Ukrainian_GHE_WITH_UPTURN,+    _Byelorussian_SHORTU         = GDK_KEY_Byelorussian_SHORTU,+    _Cyrillic_DZHE               = GDK_KEY_Cyrillic_DZHE,+    _Serbian_DZE                 = GDK_KEY_Serbian_DZE,+    _Cyrillic_yu                 = GDK_KEY_Cyrillic_yu,+    _Cyrillic_a                  = GDK_KEY_Cyrillic_a,+    _Cyrillic_be                 = GDK_KEY_Cyrillic_be,+    _Cyrillic_tse                = GDK_KEY_Cyrillic_tse,+    _Cyrillic_de                 = GDK_KEY_Cyrillic_de,+    _Cyrillic_ie                 = GDK_KEY_Cyrillic_ie,+    _Cyrillic_ef                 = GDK_KEY_Cyrillic_ef,+    _Cyrillic_ghe                = GDK_KEY_Cyrillic_ghe,+    _Cyrillic_ha                 = GDK_KEY_Cyrillic_ha,+    _Cyrillic_i                  = GDK_KEY_Cyrillic_i,+    _Cyrillic_shorti             = GDK_KEY_Cyrillic_shorti,+    _Cyrillic_ka                 = GDK_KEY_Cyrillic_ka,+    _Cyrillic_el                 = GDK_KEY_Cyrillic_el,+    _Cyrillic_em                 = GDK_KEY_Cyrillic_em,+    _Cyrillic_en                 = GDK_KEY_Cyrillic_en,+    _Cyrillic_o                  = GDK_KEY_Cyrillic_o,+    _Cyrillic_pe                 = GDK_KEY_Cyrillic_pe,+    _Cyrillic_ya                 = GDK_KEY_Cyrillic_ya,+    _Cyrillic_er                 = GDK_KEY_Cyrillic_er,+    _Cyrillic_es                 = GDK_KEY_Cyrillic_es,+    _Cyrillic_te                 = GDK_KEY_Cyrillic_te,+    _Cyrillic_u                  = GDK_KEY_Cyrillic_u,+    _Cyrillic_zhe                = GDK_KEY_Cyrillic_zhe,+    _Cyrillic_ve                 = GDK_KEY_Cyrillic_ve,+    _Cyrillic_softsign           = GDK_KEY_Cyrillic_softsign,+    _Cyrillic_yeru               = GDK_KEY_Cyrillic_yeru,+    _Cyrillic_ze                 = GDK_KEY_Cyrillic_ze,+    _Cyrillic_sha                = GDK_KEY_Cyrillic_sha,+    _Cyrillic_e                  = GDK_KEY_Cyrillic_e,+    _Cyrillic_shcha              = GDK_KEY_Cyrillic_shcha,+    _Cyrillic_che                = GDK_KEY_Cyrillic_che,+    _Cyrillic_hardsign           = GDK_KEY_Cyrillic_hardsign,+    _Cyrillic_YU                 = GDK_KEY_Cyrillic_YU,+    _Cyrillic_A                  = GDK_KEY_Cyrillic_A,+    _Cyrillic_BE                 = GDK_KEY_Cyrillic_BE,+    _Cyrillic_TSE                = GDK_KEY_Cyrillic_TSE,+    _Cyrillic_DE                 = GDK_KEY_Cyrillic_DE,+    _Cyrillic_IE                 = GDK_KEY_Cyrillic_IE,+    _Cyrillic_EF                 = GDK_KEY_Cyrillic_EF,+    _Cyrillic_GHE                = GDK_KEY_Cyrillic_GHE,+    _Cyrillic_HA                 = GDK_KEY_Cyrillic_HA,+    _Cyrillic_I                  = GDK_KEY_Cyrillic_I,+    _Cyrillic_SHORTI             = GDK_KEY_Cyrillic_SHORTI,+    _Cyrillic_KA                 = GDK_KEY_Cyrillic_KA,+    _Cyrillic_EL                 = GDK_KEY_Cyrillic_EL,+    _Cyrillic_EM                 = GDK_KEY_Cyrillic_EM,+    _Cyrillic_EN                 = GDK_KEY_Cyrillic_EN,+    _Cyrillic_O                  = GDK_KEY_Cyrillic_O,+    _Cyrillic_PE                 = GDK_KEY_Cyrillic_PE,+    _Cyrillic_YA                 = GDK_KEY_Cyrillic_YA,+    _Cyrillic_ER                 = GDK_KEY_Cyrillic_ER,+    _Cyrillic_ES                 = GDK_KEY_Cyrillic_ES,+    _Cyrillic_TE                 = GDK_KEY_Cyrillic_TE,+    _Cyrillic_U                  = GDK_KEY_Cyrillic_U,+    _Cyrillic_ZHE                = GDK_KEY_Cyrillic_ZHE,+    _Cyrillic_VE                 = GDK_KEY_Cyrillic_VE,+    _Cyrillic_SOFTSIGN           = GDK_KEY_Cyrillic_SOFTSIGN,+    _Cyrillic_YERU               = GDK_KEY_Cyrillic_YERU,+    _Cyrillic_ZE                 = GDK_KEY_Cyrillic_ZE,+    _Cyrillic_SHA                = GDK_KEY_Cyrillic_SHA,+    _Cyrillic_E                  = GDK_KEY_Cyrillic_E,+    _Cyrillic_SHCHA              = GDK_KEY_Cyrillic_SHCHA,+    _Cyrillic_CHE                = GDK_KEY_Cyrillic_CHE,+    _Cyrillic_HARDSIGN           = GDK_KEY_Cyrillic_HARDSIGN,+    _Greek_ALPHAaccent           = GDK_KEY_Greek_ALPHAaccent,+    _Greek_EPSILONaccent         = GDK_KEY_Greek_EPSILONaccent,+    _Greek_ETAaccent             = GDK_KEY_Greek_ETAaccent,+    _Greek_IOTAaccent            = GDK_KEY_Greek_IOTAaccent,+    _Greek_IOTAdieresis          = GDK_KEY_Greek_IOTAdieresis,+    _Greek_IOTAdiaeresis         = GDK_KEY_Greek_IOTAdiaeresis,+    _Greek_OMICRONaccent         = GDK_KEY_Greek_OMICRONaccent,+    _Greek_UPSILONaccent         = GDK_KEY_Greek_UPSILONaccent,+    _Greek_UPSILONdieresis       = GDK_KEY_Greek_UPSILONdieresis,+    _Greek_OMEGAaccent           = GDK_KEY_Greek_OMEGAaccent,+    _Greek_accentdieresis        = GDK_KEY_Greek_accentdieresis,+    _Greek_horizbar              = GDK_KEY_Greek_horizbar,+    _Greek_alphaaccent           = GDK_KEY_Greek_alphaaccent,+    _Greek_epsilonaccent         = GDK_KEY_Greek_epsilonaccent,+    _Greek_etaaccent             = GDK_KEY_Greek_etaaccent,+    _Greek_iotaaccent            = GDK_KEY_Greek_iotaaccent,+    _Greek_iotadieresis          = GDK_KEY_Greek_iotadieresis,+    _Greek_iotaaccentdieresis    = GDK_KEY_Greek_iotaaccentdieresis,+    _Greek_omicronaccent         = GDK_KEY_Greek_omicronaccent,+    _Greek_upsilonaccent         = GDK_KEY_Greek_upsilonaccent,+    _Greek_upsilondieresis       = GDK_KEY_Greek_upsilondieresis,+    _Greek_upsilonaccentdieresis = GDK_KEY_Greek_upsilonaccentdieresis,+    _Greek_omegaaccent           = GDK_KEY_Greek_omegaaccent,+    _Greek_ALPHA                 = GDK_KEY_Greek_ALPHA,+    _Greek_BETA                  = GDK_KEY_Greek_BETA,+    _Greek_GAMMA                 = GDK_KEY_Greek_GAMMA,+    _Greek_DELTA                 = GDK_KEY_Greek_DELTA,+    _Greek_EPSILON               = GDK_KEY_Greek_EPSILON,+    _Greek_ZETA                  = GDK_KEY_Greek_ZETA,+    _Greek_ETA                   = GDK_KEY_Greek_ETA,+    _Greek_THETA                 = GDK_KEY_Greek_THETA,+    _Greek_IOTA                  = GDK_KEY_Greek_IOTA,+    _Greek_KAPPA                 = GDK_KEY_Greek_KAPPA,+    _Greek_LAMDA                 = GDK_KEY_Greek_LAMDA,+    _Greek_LAMBDA                = GDK_KEY_Greek_LAMBDA,+    _Greek_MU                    = GDK_KEY_Greek_MU,+    _Greek_NU                    = GDK_KEY_Greek_NU,+    _Greek_XI                    = GDK_KEY_Greek_XI,+    _Greek_OMICRON               = GDK_KEY_Greek_OMICRON,+    _Greek_PI                    = GDK_KEY_Greek_PI,+    _Greek_RHO                   = GDK_KEY_Greek_RHO,+    _Greek_SIGMA                 = GDK_KEY_Greek_SIGMA,+    _Greek_TAU                   = GDK_KEY_Greek_TAU,+    _Greek_UPSILON               = GDK_KEY_Greek_UPSILON,+    _Greek_PHI                   = GDK_KEY_Greek_PHI,+    _Greek_CHI                   = GDK_KEY_Greek_CHI,+    _Greek_PSI                   = GDK_KEY_Greek_PSI,+    _Greek_OMEGA                 = GDK_KEY_Greek_OMEGA,+    _Greek_alpha                 = GDK_KEY_Greek_alpha,+    _Greek_beta                  = GDK_KEY_Greek_beta,+    _Greek_gamma                 = GDK_KEY_Greek_gamma,+    _Greek_delta                 = GDK_KEY_Greek_delta,+    _Greek_epsilon               = GDK_KEY_Greek_epsilon,+    _Greek_zeta                  = GDK_KEY_Greek_zeta,+    _Greek_eta                   = GDK_KEY_Greek_eta,+    _Greek_theta                 = GDK_KEY_Greek_theta,+    _Greek_iota                  = GDK_KEY_Greek_iota,+    _Greek_kappa                 = GDK_KEY_Greek_kappa,+    _Greek_lamda                 = GDK_KEY_Greek_lamda,+    _Greek_lambda                = GDK_KEY_Greek_lambda,+    _Greek_mu                    = GDK_KEY_Greek_mu,+    _Greek_nu                    = GDK_KEY_Greek_nu,+    _Greek_xi                    = GDK_KEY_Greek_xi,+    _Greek_omicron               = GDK_KEY_Greek_omicron,+    _Greek_pi                    = GDK_KEY_Greek_pi,+    _Greek_rho                   = GDK_KEY_Greek_rho,+    _Greek_sigma                 = GDK_KEY_Greek_sigma,+    _Greek_finalsmallsigma       = GDK_KEY_Greek_finalsmallsigma,+    _Greek_tau                   = GDK_KEY_Greek_tau,+    _Greek_upsilon               = GDK_KEY_Greek_upsilon,+    _Greek_phi                   = GDK_KEY_Greek_phi,+    _Greek_chi                   = GDK_KEY_Greek_chi,+    _Greek_psi                   = GDK_KEY_Greek_psi,+    _Greek_omega                 = GDK_KEY_Greek_omega,+    _Greek_switch                = GDK_KEY_Greek_switch,+    _leftradical                 = GDK_KEY_leftradical,+    _topleftradical              = GDK_KEY_topleftradical,+    _horizconnector              = GDK_KEY_horizconnector,+    _topintegral                 = GDK_KEY_topintegral,+    _botintegral                 = GDK_KEY_botintegral,+    _vertconnector               = GDK_KEY_vertconnector,+    _topleftsqbracket            = GDK_KEY_topleftsqbracket,+    _botleftsqbracket            = GDK_KEY_botleftsqbracket,+    _toprightsqbracket           = GDK_KEY_toprightsqbracket,+    _botrightsqbracket           = GDK_KEY_botrightsqbracket,+    _topleftparens               = GDK_KEY_topleftparens,+    _botleftparens               = GDK_KEY_botleftparens,+    _toprightparens              = GDK_KEY_toprightparens,+    _botrightparens              = GDK_KEY_botrightparens,+    _leftmiddlecurlybrace        = GDK_KEY_leftmiddlecurlybrace,+    _rightmiddlecurlybrace       = GDK_KEY_rightmiddlecurlybrace,+    _topleftsummation            = GDK_KEY_topleftsummation,+    _botleftsummation            = GDK_KEY_botleftsummation,+    _topvertsummationconnector   = GDK_KEY_topvertsummationconnector,+    _botvertsummationconnector   = GDK_KEY_botvertsummationconnector,+    _toprightsummation           = GDK_KEY_toprightsummation,+    _botrightsummation           = GDK_KEY_botrightsummation,+    _rightmiddlesummation        = GDK_KEY_rightmiddlesummation,+    _lessthanequal               = GDK_KEY_lessthanequal,+    _notequal                    = GDK_KEY_notequal,+    _greaterthanequal            = GDK_KEY_greaterthanequal,+    _integral                    = GDK_KEY_integral,+    _therefore                   = GDK_KEY_therefore,+    _variation                   = GDK_KEY_variation,+    _infinity                    = GDK_KEY_infinity,+    _nabla                       = GDK_KEY_nabla,+    _approximate                 = GDK_KEY_approximate,+    _similarequal                = GDK_KEY_similarequal,+    _ifonlyif                    = GDK_KEY_ifonlyif,+    _implies                     = GDK_KEY_implies,+    _identical                   = GDK_KEY_identical,+    _radical                     = GDK_KEY_radical,+    _includedin                  = GDK_KEY_includedin,+    _includes                    = GDK_KEY_includes,+    _intersection                = GDK_KEY_intersection,+    _union                       = GDK_KEY_union,+    _logicaland                  = GDK_KEY_logicaland,+    _logicalor                   = GDK_KEY_logicalor,+    _partialderivative           = GDK_KEY_partialderivative,+    _function                    = GDK_KEY_function,+    _leftarrow                   = GDK_KEY_leftarrow,+    _uparrow                     = GDK_KEY_uparrow,+    _rightarrow                  = GDK_KEY_rightarrow,+    _downarrow                   = GDK_KEY_downarrow,+    _blank                       = GDK_KEY_blank,+    _soliddiamond                = GDK_KEY_soliddiamond,+    _checkerboard                = GDK_KEY_checkerboard,+    _ht                          = GDK_KEY_ht,+    _ff                          = GDK_KEY_ff,+    _cr                          = GDK_KEY_cr,+    _lf                          = GDK_KEY_lf,+    _nl                          = GDK_KEY_nl,+    _vt                          = GDK_KEY_vt,+    _lowrightcorner              = GDK_KEY_lowrightcorner,+    _uprightcorner               = GDK_KEY_uprightcorner,+    _upleftcorner                = GDK_KEY_upleftcorner,+    _lowleftcorner               = GDK_KEY_lowleftcorner,+    _crossinglines               = GDK_KEY_crossinglines,+    _horizlinescan1              = GDK_KEY_horizlinescan1,+    _horizlinescan3              = GDK_KEY_horizlinescan3,+    _horizlinescan5              = GDK_KEY_horizlinescan5,+    _horizlinescan7              = GDK_KEY_horizlinescan7,+    _horizlinescan9              = GDK_KEY_horizlinescan9,+    _leftt                       = GDK_KEY_leftt,+    _rightt                      = GDK_KEY_rightt,+    _bott                        = GDK_KEY_bott,+    _topt                        = GDK_KEY_topt,+    _vertbar                     = GDK_KEY_vertbar,+    _emspace                     = GDK_KEY_emspace,+    _enspace                     = GDK_KEY_enspace,+    _em3space                    = GDK_KEY_em3space,+    _em4space                    = GDK_KEY_em4space,+    _digitspace                  = GDK_KEY_digitspace,+    _punctspace                  = GDK_KEY_punctspace,+    _thinspace                   = GDK_KEY_thinspace,+    _hairspace                   = GDK_KEY_hairspace,+    _emdash                      = GDK_KEY_emdash,+    _endash                      = GDK_KEY_endash,+    _signifblank                 = GDK_KEY_signifblank,+    _ellipsis                    = GDK_KEY_ellipsis,+    _doubbaselinedot             = GDK_KEY_doubbaselinedot,+    _onethird                    = GDK_KEY_onethird,+    _twothirds                   = GDK_KEY_twothirds,+    _onefifth                    = GDK_KEY_onefifth,+    _twofifths                   = GDK_KEY_twofifths,+    _threefifths                 = GDK_KEY_threefifths,+    _fourfifths                  = GDK_KEY_fourfifths,+    _onesixth                    = GDK_KEY_onesixth,+    _fivesixths                  = GDK_KEY_fivesixths,+    _careof                      = GDK_KEY_careof,+    _figdash                     = GDK_KEY_figdash,+    _leftanglebracket            = GDK_KEY_leftanglebracket,+    _decimalpoint                = GDK_KEY_decimalpoint,+    _rightanglebracket           = GDK_KEY_rightanglebracket,+    _marker                      = GDK_KEY_marker,+    _oneeighth                   = GDK_KEY_oneeighth,+    _threeeighths                = GDK_KEY_threeeighths,+    _fiveeighths                 = GDK_KEY_fiveeighths,+    _seveneighths                = GDK_KEY_seveneighths,+    _trademark                   = GDK_KEY_trademark,+    _signaturemark               = GDK_KEY_signaturemark,+    _trademarkincircle           = GDK_KEY_trademarkincircle,+    _leftopentriangle            = GDK_KEY_leftopentriangle,+    _rightopentriangle           = GDK_KEY_rightopentriangle,+    _emopencircle                = GDK_KEY_emopencircle,+    _emopenrectangle             = GDK_KEY_emopenrectangle,+    _leftsinglequotemark         = GDK_KEY_leftsinglequotemark,+    _rightsinglequotemark        = GDK_KEY_rightsinglequotemark,+    _leftdoublequotemark         = GDK_KEY_leftdoublequotemark,+    _rightdoublequotemark        = GDK_KEY_rightdoublequotemark,+    _prescription                = GDK_KEY_prescription,+    _minutes                     = GDK_KEY_minutes,+    _seconds                     = GDK_KEY_seconds,+    _latincross                  = GDK_KEY_latincross,+    _hexagram                    = GDK_KEY_hexagram,+    _filledrectbullet            = GDK_KEY_filledrectbullet,+    _filledlefttribullet         = GDK_KEY_filledlefttribullet,+    _filledrighttribullet        = GDK_KEY_filledrighttribullet,+    _emfilledcircle              = GDK_KEY_emfilledcircle,+    _emfilledrect                = GDK_KEY_emfilledrect,+    _enopencircbullet            = GDK_KEY_enopencircbullet,+    _enopensquarebullet          = GDK_KEY_enopensquarebullet,+    _openrectbullet              = GDK_KEY_openrectbullet,+    _opentribulletup             = GDK_KEY_opentribulletup,+    _opentribulletdown           = GDK_KEY_opentribulletdown,+    _openstar                    = GDK_KEY_openstar,+    _enfilledcircbullet          = GDK_KEY_enfilledcircbullet,+    _enfilledsqbullet            = GDK_KEY_enfilledsqbullet,+    _filledtribulletup           = GDK_KEY_filledtribulletup,+    _filledtribulletdown         = GDK_KEY_filledtribulletdown,+    _leftpointer                 = GDK_KEY_leftpointer,+    _rightpointer                = GDK_KEY_rightpointer,+    _club                        = GDK_KEY_club,+    _diamond                     = GDK_KEY_diamond,+    _heart                       = GDK_KEY_heart,+    _maltesecross                = GDK_KEY_maltesecross,+    _dagger                      = GDK_KEY_dagger,+    _doubledagger                = GDK_KEY_doubledagger,+    _checkmark                   = GDK_KEY_checkmark,+    _ballotcross                 = GDK_KEY_ballotcross,+    _musicalsharp                = GDK_KEY_musicalsharp,+    _musicalflat                 = GDK_KEY_musicalflat,+    _malesymbol                  = GDK_KEY_malesymbol,+    _femalesymbol                = GDK_KEY_femalesymbol,+    _telephone                   = GDK_KEY_telephone,+    _telephonerecorder           = GDK_KEY_telephonerecorder,+    _phonographcopyright         = GDK_KEY_phonographcopyright,+    _caret                       = GDK_KEY_caret,+    _singlelowquotemark          = GDK_KEY_singlelowquotemark,+    _doublelowquotemark          = GDK_KEY_doublelowquotemark,+    _cursor                      = GDK_KEY_cursor,+    _leftcaret                   = GDK_KEY_leftcaret,+    _rightcaret                  = GDK_KEY_rightcaret,+    _downcaret                   = GDK_KEY_downcaret,+    _upcaret                     = GDK_KEY_upcaret,+    _overbar                     = GDK_KEY_overbar,+    _downtack                    = GDK_KEY_downtack,+    _upshoe                      = GDK_KEY_upshoe,+    _downstile                   = GDK_KEY_downstile,+    _underbar                    = GDK_KEY_underbar,+    _jot                         = GDK_KEY_jot,+    _quad                        = GDK_KEY_quad,+    _uptack                      = GDK_KEY_uptack,+    _circle                      = GDK_KEY_circle,+    _upstile                     = GDK_KEY_upstile,+    _downshoe                    = GDK_KEY_downshoe,+    _rightshoe                   = GDK_KEY_rightshoe,+    _leftshoe                    = GDK_KEY_leftshoe,+    _lefttack                    = GDK_KEY_lefttack,+    _righttack                   = GDK_KEY_righttack,+    _hebrew_doublelowline        = GDK_KEY_hebrew_doublelowline,+    _hebrew_aleph                = GDK_KEY_hebrew_aleph,+    _hebrew_bet                  = GDK_KEY_hebrew_bet,+    _hebrew_beth                 = GDK_KEY_hebrew_beth,+    _hebrew_gimel                = GDK_KEY_hebrew_gimel,+    _hebrew_gimmel               = GDK_KEY_hebrew_gimmel,+    _hebrew_dalet                = GDK_KEY_hebrew_dalet,+    _hebrew_daleth               = GDK_KEY_hebrew_daleth,+    _hebrew_he                   = GDK_KEY_hebrew_he,+    _hebrew_waw                  = GDK_KEY_hebrew_waw,+    _hebrew_zain                 = GDK_KEY_hebrew_zain,+    _hebrew_zayin                = GDK_KEY_hebrew_zayin,+    _hebrew_chet                 = GDK_KEY_hebrew_chet,+    _hebrew_het                  = GDK_KEY_hebrew_het,+    _hebrew_tet                  = GDK_KEY_hebrew_tet,+    _hebrew_teth                 = GDK_KEY_hebrew_teth,+    _hebrew_yod                  = GDK_KEY_hebrew_yod,+    _hebrew_finalkaph            = GDK_KEY_hebrew_finalkaph,+    _hebrew_kaph                 = GDK_KEY_hebrew_kaph,+    _hebrew_lamed                = GDK_KEY_hebrew_lamed,+    _hebrew_finalmem             = GDK_KEY_hebrew_finalmem,+    _hebrew_mem                  = GDK_KEY_hebrew_mem,+    _hebrew_finalnun             = GDK_KEY_hebrew_finalnun,+    _hebrew_nun                  = GDK_KEY_hebrew_nun,+    _hebrew_samech               = GDK_KEY_hebrew_samech,+    _hebrew_samekh               = GDK_KEY_hebrew_samekh,+    _hebrew_ayin                 = GDK_KEY_hebrew_ayin,+    _hebrew_finalpe              = GDK_KEY_hebrew_finalpe,+    _hebrew_pe                   = GDK_KEY_hebrew_pe,+    _hebrew_finalzade            = GDK_KEY_hebrew_finalzade,+    _hebrew_finalzadi            = GDK_KEY_hebrew_finalzadi,+    _hebrew_zade                 = GDK_KEY_hebrew_zade,+    _hebrew_zadi                 = GDK_KEY_hebrew_zadi,+    _hebrew_qoph                 = GDK_KEY_hebrew_qoph,+    _hebrew_kuf                  = GDK_KEY_hebrew_kuf,+    _hebrew_resh                 = GDK_KEY_hebrew_resh,+    _hebrew_shin                 = GDK_KEY_hebrew_shin,+    _hebrew_taw                  = GDK_KEY_hebrew_taw,+    _hebrew_taf                  = GDK_KEY_hebrew_taf,+    _Hebrew_switch               = GDK_KEY_Hebrew_switch,+    _Thai_kokai                  = GDK_KEY_Thai_kokai,+    _Thai_khokhai                = GDK_KEY_Thai_khokhai,+    _Thai_khokhuat               = GDK_KEY_Thai_khokhuat,+    _Thai_khokhwai               = GDK_KEY_Thai_khokhwai,+    _Thai_khokhon                = GDK_KEY_Thai_khokhon,+    _Thai_khorakhang             = GDK_KEY_Thai_khorakhang,+    _Thai_ngongu                 = GDK_KEY_Thai_ngongu,+    _Thai_chochan                = GDK_KEY_Thai_chochan,+    _Thai_choching               = GDK_KEY_Thai_choching,+    _Thai_chochang               = GDK_KEY_Thai_chochang,+    _Thai_soso                   = GDK_KEY_Thai_soso,+    _Thai_chochoe                = GDK_KEY_Thai_chochoe,+    _Thai_yoying                 = GDK_KEY_Thai_yoying,+    _Thai_dochada                = GDK_KEY_Thai_dochada,+    _Thai_topatak                = GDK_KEY_Thai_topatak,+    _Thai_thothan                = GDK_KEY_Thai_thothan,+    _Thai_thonangmontho          = GDK_KEY_Thai_thonangmontho,+    _Thai_thophuthao             = GDK_KEY_Thai_thophuthao,+    _Thai_nonen                  = GDK_KEY_Thai_nonen,+    _Thai_dodek                  = GDK_KEY_Thai_dodek,+    _Thai_totao                  = GDK_KEY_Thai_totao,+    _Thai_thothung               = GDK_KEY_Thai_thothung,+    _Thai_thothahan              = GDK_KEY_Thai_thothahan,+    _Thai_thothong               = GDK_KEY_Thai_thothong,+    _Thai_nonu                   = GDK_KEY_Thai_nonu,+    _Thai_bobaimai               = GDK_KEY_Thai_bobaimai,+    _Thai_popla                  = GDK_KEY_Thai_popla,+    _Thai_phophung               = GDK_KEY_Thai_phophung,+    _Thai_fofa                   = GDK_KEY_Thai_fofa,+    _Thai_phophan                = GDK_KEY_Thai_phophan,+    _Thai_fofan                  = GDK_KEY_Thai_fofan,+    _Thai_phosamphao             = GDK_KEY_Thai_phosamphao,+    _Thai_moma                   = GDK_KEY_Thai_moma,+    _Thai_yoyak                  = GDK_KEY_Thai_yoyak,+    _Thai_rorua                  = GDK_KEY_Thai_rorua,+    _Thai_ru                     = GDK_KEY_Thai_ru,+    _Thai_loling                 = GDK_KEY_Thai_loling,+    _Thai_lu                     = GDK_KEY_Thai_lu,+    _Thai_wowaen                 = GDK_KEY_Thai_wowaen,+    _Thai_sosala                 = GDK_KEY_Thai_sosala,+    _Thai_sorusi                 = GDK_KEY_Thai_sorusi,+    _Thai_sosua                  = GDK_KEY_Thai_sosua,+    _Thai_hohip                  = GDK_KEY_Thai_hohip,+    _Thai_lochula                = GDK_KEY_Thai_lochula,+    _Thai_oang                   = GDK_KEY_Thai_oang,+    _Thai_honokhuk               = GDK_KEY_Thai_honokhuk,+    _Thai_paiyannoi              = GDK_KEY_Thai_paiyannoi,+    _Thai_saraa                  = GDK_KEY_Thai_saraa,+    _Thai_maihanakat             = GDK_KEY_Thai_maihanakat,+    _Thai_saraaa                 = GDK_KEY_Thai_saraaa,+    _Thai_saraam                 = GDK_KEY_Thai_saraam,+    _Thai_sarai                  = GDK_KEY_Thai_sarai,+    _Thai_saraii                 = GDK_KEY_Thai_saraii,+    _Thai_saraue                 = GDK_KEY_Thai_saraue,+    _Thai_sarauee                = GDK_KEY_Thai_sarauee,+    _Thai_sarau                  = GDK_KEY_Thai_sarau,+    _Thai_sarauu                 = GDK_KEY_Thai_sarauu,+    _Thai_phinthu                = GDK_KEY_Thai_phinthu,+    _Thai_maihanakat_maitho      = GDK_KEY_Thai_maihanakat_maitho,+    _Thai_baht                   = GDK_KEY_Thai_baht,+    _Thai_sarae                  = GDK_KEY_Thai_sarae,+    _Thai_saraae                 = GDK_KEY_Thai_saraae,+    _Thai_sarao                  = GDK_KEY_Thai_sarao,+    _Thai_saraaimaimuan          = GDK_KEY_Thai_saraaimaimuan,+    _Thai_saraaimaimalai         = GDK_KEY_Thai_saraaimaimalai,+    _Thai_lakkhangyao            = GDK_KEY_Thai_lakkhangyao,+    _Thai_maiyamok               = GDK_KEY_Thai_maiyamok,+    _Thai_maitaikhu              = GDK_KEY_Thai_maitaikhu,+    _Thai_maiek                  = GDK_KEY_Thai_maiek,+    _Thai_maitho                 = GDK_KEY_Thai_maitho,+    _Thai_maitri                 = GDK_KEY_Thai_maitri,+    _Thai_maichattawa            = GDK_KEY_Thai_maichattawa,+    _Thai_thanthakhat            = GDK_KEY_Thai_thanthakhat,+    _Thai_nikhahit               = GDK_KEY_Thai_nikhahit,+    _Thai_leksun                 = GDK_KEY_Thai_leksun,+    _Thai_leknung                = GDK_KEY_Thai_leknung,+    _Thai_leksong                = GDK_KEY_Thai_leksong,+    _Thai_leksam                 = GDK_KEY_Thai_leksam,+    _Thai_leksi                  = GDK_KEY_Thai_leksi,+    _Thai_lekha                  = GDK_KEY_Thai_lekha,+    _Thai_lekhok                 = GDK_KEY_Thai_lekhok,+    _Thai_lekchet                = GDK_KEY_Thai_lekchet,+    _Thai_lekpaet                = GDK_KEY_Thai_lekpaet,+    _Thai_lekkao                 = GDK_KEY_Thai_lekkao,+    _Hangul                      = GDK_KEY_Hangul,+    _Hangul_Start                = GDK_KEY_Hangul_Start,+    _Hangul_End                  = GDK_KEY_Hangul_End,+    _Hangul_Hanja                = GDK_KEY_Hangul_Hanja,+    _Hangul_Jamo                 = GDK_KEY_Hangul_Jamo,+    _Hangul_Romaja               = GDK_KEY_Hangul_Romaja,+    _Hangul_Codeinput            = GDK_KEY_Hangul_Codeinput,+    _Hangul_Jeonja               = GDK_KEY_Hangul_Jeonja,+    _Hangul_Banja                = GDK_KEY_Hangul_Banja,+    _Hangul_PreHanja             = GDK_KEY_Hangul_PreHanja,+    _Hangul_PostHanja            = GDK_KEY_Hangul_PostHanja,+    _Hangul_SingleCandidate      = GDK_KEY_Hangul_SingleCandidate,+    _Hangul_MultipleCandidate    = GDK_KEY_Hangul_MultipleCandidate,+    _Hangul_PreviousCandidate    = GDK_KEY_Hangul_PreviousCandidate,+    _Hangul_Special              = GDK_KEY_Hangul_Special,+    _Hangul_switch               = GDK_KEY_Hangul_switch,+    _Hangul_Kiyeog               = GDK_KEY_Hangul_Kiyeog,+    _Hangul_SsangKiyeog          = GDK_KEY_Hangul_SsangKiyeog,+    _Hangul_KiyeogSios           = GDK_KEY_Hangul_KiyeogSios,+    _Hangul_Nieun                = GDK_KEY_Hangul_Nieun,+    _Hangul_NieunJieuj           = GDK_KEY_Hangul_NieunJieuj,+    _Hangul_NieunHieuh           = GDK_KEY_Hangul_NieunHieuh,+    _Hangul_Dikeud               = GDK_KEY_Hangul_Dikeud,+    _Hangul_SsangDikeud          = GDK_KEY_Hangul_SsangDikeud,+    _Hangul_Rieul                = GDK_KEY_Hangul_Rieul,+    _Hangul_RieulKiyeog          = GDK_KEY_Hangul_RieulKiyeog,+    _Hangul_RieulMieum           = GDK_KEY_Hangul_RieulMieum,+    _Hangul_RieulPieub           = GDK_KEY_Hangul_RieulPieub,+    _Hangul_RieulSios            = GDK_KEY_Hangul_RieulSios,+    _Hangul_RieulTieut           = GDK_KEY_Hangul_RieulTieut,+    _Hangul_RieulPhieuf          = GDK_KEY_Hangul_RieulPhieuf,+    _Hangul_RieulHieuh           = GDK_KEY_Hangul_RieulHieuh,+    _Hangul_Mieum                = GDK_KEY_Hangul_Mieum,+    _Hangul_Pieub                = GDK_KEY_Hangul_Pieub,+    _Hangul_SsangPieub           = GDK_KEY_Hangul_SsangPieub,+    _Hangul_PieubSios            = GDK_KEY_Hangul_PieubSios,+    _Hangul_Sios                 = GDK_KEY_Hangul_Sios,+    _Hangul_SsangSios            = GDK_KEY_Hangul_SsangSios,+    _Hangul_Ieung                = GDK_KEY_Hangul_Ieung,+    _Hangul_Jieuj                = GDK_KEY_Hangul_Jieuj,+    _Hangul_SsangJieuj           = GDK_KEY_Hangul_SsangJieuj,+    _Hangul_Cieuc                = GDK_KEY_Hangul_Cieuc,+    _Hangul_Khieuq               = GDK_KEY_Hangul_Khieuq,+    _Hangul_Tieut                = GDK_KEY_Hangul_Tieut,+    _Hangul_Phieuf               = GDK_KEY_Hangul_Phieuf,+    _Hangul_Hieuh                = GDK_KEY_Hangul_Hieuh,+    _Hangul_A                    = GDK_KEY_Hangul_A,+    _Hangul_AE                   = GDK_KEY_Hangul_AE,+    _Hangul_YA                   = GDK_KEY_Hangul_YA,+    _Hangul_YAE                  = GDK_KEY_Hangul_YAE,+    _Hangul_EO                   = GDK_KEY_Hangul_EO,+    _Hangul_E                    = GDK_KEY_Hangul_E,+    _Hangul_YEO                  = GDK_KEY_Hangul_YEO,+    _Hangul_YE                   = GDK_KEY_Hangul_YE,+    _Hangul_O                    = GDK_KEY_Hangul_O,+    _Hangul_WA                   = GDK_KEY_Hangul_WA,+    _Hangul_WAE                  = GDK_KEY_Hangul_WAE,+    _Hangul_OE                   = GDK_KEY_Hangul_OE,+    _Hangul_YO                   = GDK_KEY_Hangul_YO,+    _Hangul_U                    = GDK_KEY_Hangul_U,+    _Hangul_WEO                  = GDK_KEY_Hangul_WEO,+    _Hangul_WE                   = GDK_KEY_Hangul_WE,+    _Hangul_WI                   = GDK_KEY_Hangul_WI,+    _Hangul_YU                   = GDK_KEY_Hangul_YU,+    _Hangul_EU                   = GDK_KEY_Hangul_EU,+    _Hangul_YI                   = GDK_KEY_Hangul_YI,+    _Hangul_I                    = GDK_KEY_Hangul_I,+    _Hangul_J_Kiyeog             = GDK_KEY_Hangul_J_Kiyeog,+    _Hangul_J_SsangKiyeog        = GDK_KEY_Hangul_J_SsangKiyeog,+    _Hangul_J_KiyeogSios         = GDK_KEY_Hangul_J_KiyeogSios,+    _Hangul_J_Nieun              = GDK_KEY_Hangul_J_Nieun,+    _Hangul_J_NieunJieuj         = GDK_KEY_Hangul_J_NieunJieuj,+    _Hangul_J_NieunHieuh         = GDK_KEY_Hangul_J_NieunHieuh,+    _Hangul_J_Dikeud             = GDK_KEY_Hangul_J_Dikeud,+    _Hangul_J_Rieul              = GDK_KEY_Hangul_J_Rieul,+    _Hangul_J_RieulKiyeog        = GDK_KEY_Hangul_J_RieulKiyeog,+    _Hangul_J_RieulMieum         = GDK_KEY_Hangul_J_RieulMieum,+    _Hangul_J_RieulPieub         = GDK_KEY_Hangul_J_RieulPieub,+    _Hangul_J_RieulSios          = GDK_KEY_Hangul_J_RieulSios,+    _Hangul_J_RieulTieut         = GDK_KEY_Hangul_J_RieulTieut,+    _Hangul_J_RieulPhieuf        = GDK_KEY_Hangul_J_RieulPhieuf,+    _Hangul_J_RieulHieuh         = GDK_KEY_Hangul_J_RieulHieuh,+    _Hangul_J_Mieum              = GDK_KEY_Hangul_J_Mieum,+    _Hangul_J_Pieub              = GDK_KEY_Hangul_J_Pieub,+    _Hangul_J_PieubSios          = GDK_KEY_Hangul_J_PieubSios,+    _Hangul_J_Sios               = GDK_KEY_Hangul_J_Sios,+    _Hangul_J_SsangSios          = GDK_KEY_Hangul_J_SsangSios,+    _Hangul_J_Ieung              = GDK_KEY_Hangul_J_Ieung,+    _Hangul_J_Jieuj              = GDK_KEY_Hangul_J_Jieuj,+    _Hangul_J_Cieuc              = GDK_KEY_Hangul_J_Cieuc,+    _Hangul_J_Khieuq             = GDK_KEY_Hangul_J_Khieuq,+    _Hangul_J_Tieut              = GDK_KEY_Hangul_J_Tieut,+    _Hangul_J_Phieuf             = GDK_KEY_Hangul_J_Phieuf,+    _Hangul_J_Hieuh              = GDK_KEY_Hangul_J_Hieuh,+    _Hangul_RieulYeorinHieuh     = GDK_KEY_Hangul_RieulYeorinHieuh,+    _Hangul_SunkyeongeumMieum    = GDK_KEY_Hangul_SunkyeongeumMieum,+    _Hangul_SunkyeongeumPieub    = GDK_KEY_Hangul_SunkyeongeumPieub,+    _Hangul_PanSios              = GDK_KEY_Hangul_PanSios,+    _Hangul_KkogjiDalrinIeung    = GDK_KEY_Hangul_KkogjiDalrinIeung,+    _Hangul_SunkyeongeumPhieuf   = GDK_KEY_Hangul_SunkyeongeumPhieuf,+    _Hangul_YeorinHieuh          = GDK_KEY_Hangul_YeorinHieuh,+    _Hangul_AraeA                = GDK_KEY_Hangul_AraeA,+    _Hangul_AraeAE               = GDK_KEY_Hangul_AraeAE,+    _Hangul_J_PanSios            = GDK_KEY_Hangul_J_PanSios,+    _Hangul_J_KkogjiDalrinIeung  = GDK_KEY_Hangul_J_KkogjiDalrinIeung,+    _Hangul_J_YeorinHieuh        = GDK_KEY_Hangul_J_YeorinHieuh,+    _Korean_Won                  = GDK_KEY_Korean_Won,+    _Armenian_ligature_ew        = GDK_KEY_Armenian_ligature_ew,+    _Armenian_full_stop          = GDK_KEY_Armenian_full_stop,+    _Armenian_verjaket           = GDK_KEY_Armenian_verjaket,+    _Armenian_separation_mark    = GDK_KEY_Armenian_separation_mark,+    _Armenian_but                = GDK_KEY_Armenian_but,+    _Armenian_hyphen             = GDK_KEY_Armenian_hyphen,+    _Armenian_yentamna           = GDK_KEY_Armenian_yentamna,+    _Armenian_exclam             = GDK_KEY_Armenian_exclam,+    _Armenian_amanak             = GDK_KEY_Armenian_amanak,+    _Armenian_accent             = GDK_KEY_Armenian_accent,+    _Armenian_shesht             = GDK_KEY_Armenian_shesht,+    _Armenian_question           = GDK_KEY_Armenian_question,+    _Armenian_paruyk             = GDK_KEY_Armenian_paruyk,+    _Armenian_AYB                = GDK_KEY_Armenian_AYB,+    _Armenian_ayb                = GDK_KEY_Armenian_ayb,+    _Armenian_BEN                = GDK_KEY_Armenian_BEN,+    _Armenian_ben                = GDK_KEY_Armenian_ben,+    _Armenian_GIM                = GDK_KEY_Armenian_GIM,+    _Armenian_gim                = GDK_KEY_Armenian_gim,+    _Armenian_DA                 = GDK_KEY_Armenian_DA,+    _Armenian_da                 = GDK_KEY_Armenian_da,+    _Armenian_YECH               = GDK_KEY_Armenian_YECH,+    _Armenian_yech               = GDK_KEY_Armenian_yech,+    _Armenian_ZA                 = GDK_KEY_Armenian_ZA,+    _Armenian_za                 = GDK_KEY_Armenian_za,+    _Armenian_E                  = GDK_KEY_Armenian_E,+    _Armenian_e                  = GDK_KEY_Armenian_e,+    _Armenian_AT                 = GDK_KEY_Armenian_AT,+    _Armenian_at                 = GDK_KEY_Armenian_at,+    _Armenian_TO                 = GDK_KEY_Armenian_TO,+    _Armenian_to                 = GDK_KEY_Armenian_to,+    _Armenian_ZHE                = GDK_KEY_Armenian_ZHE,+    _Armenian_zhe                = GDK_KEY_Armenian_zhe,+    _Armenian_INI                = GDK_KEY_Armenian_INI,+    _Armenian_ini                = GDK_KEY_Armenian_ini,+    _Armenian_LYUN               = GDK_KEY_Armenian_LYUN,+    _Armenian_lyun               = GDK_KEY_Armenian_lyun,+    _Armenian_KHE                = GDK_KEY_Armenian_KHE,+    _Armenian_khe                = GDK_KEY_Armenian_khe,+    _Armenian_TSA                = GDK_KEY_Armenian_TSA,+    _Armenian_tsa                = GDK_KEY_Armenian_tsa,+    _Armenian_KEN                = GDK_KEY_Armenian_KEN,+    _Armenian_ken                = GDK_KEY_Armenian_ken,+    _Armenian_HO                 = GDK_KEY_Armenian_HO,+    _Armenian_ho                 = GDK_KEY_Armenian_ho,+    _Armenian_DZA                = GDK_KEY_Armenian_DZA,+    _Armenian_dza                = GDK_KEY_Armenian_dza,+    _Armenian_GHAT               = GDK_KEY_Armenian_GHAT,+    _Armenian_ghat               = GDK_KEY_Armenian_ghat,+    _Armenian_TCHE               = GDK_KEY_Armenian_TCHE,+    _Armenian_tche               = GDK_KEY_Armenian_tche,+    _Armenian_MEN                = GDK_KEY_Armenian_MEN,+    _Armenian_men                = GDK_KEY_Armenian_men,+    _Armenian_HI                 = GDK_KEY_Armenian_HI,+    _Armenian_hi                 = GDK_KEY_Armenian_hi,+    _Armenian_NU                 = GDK_KEY_Armenian_NU,+    _Armenian_nu                 = GDK_KEY_Armenian_nu,+    _Armenian_SHA                = GDK_KEY_Armenian_SHA,+    _Armenian_sha                = GDK_KEY_Armenian_sha,+    _Armenian_VO                 = GDK_KEY_Armenian_VO,+    _Armenian_vo                 = GDK_KEY_Armenian_vo,+    _Armenian_CHA                = GDK_KEY_Armenian_CHA,+    _Armenian_cha                = GDK_KEY_Armenian_cha,+    _Armenian_PE                 = GDK_KEY_Armenian_PE,+    _Armenian_pe                 = GDK_KEY_Armenian_pe,+    _Armenian_JE                 = GDK_KEY_Armenian_JE,+    _Armenian_je                 = GDK_KEY_Armenian_je,+    _Armenian_RA                 = GDK_KEY_Armenian_RA,+    _Armenian_ra                 = GDK_KEY_Armenian_ra,+    _Armenian_SE                 = GDK_KEY_Armenian_SE,+    _Armenian_se                 = GDK_KEY_Armenian_se,+    _Armenian_VEV                = GDK_KEY_Armenian_VEV,+    _Armenian_vev                = GDK_KEY_Armenian_vev,+    _Armenian_TYUN               = GDK_KEY_Armenian_TYUN,+    _Armenian_tyun               = GDK_KEY_Armenian_tyun,+    _Armenian_RE                 = GDK_KEY_Armenian_RE,+    _Armenian_re                 = GDK_KEY_Armenian_re,+    _Armenian_TSO                = GDK_KEY_Armenian_TSO,+    _Armenian_tso                = GDK_KEY_Armenian_tso,+    _Armenian_VYUN               = GDK_KEY_Armenian_VYUN,+    _Armenian_vyun               = GDK_KEY_Armenian_vyun,+    _Armenian_PYUR               = GDK_KEY_Armenian_PYUR,+    _Armenian_pyur               = GDK_KEY_Armenian_pyur,+    _Armenian_KE                 = GDK_KEY_Armenian_KE,+    _Armenian_ke                 = GDK_KEY_Armenian_ke,+    _Armenian_O                  = GDK_KEY_Armenian_O,+    _Armenian_o                  = GDK_KEY_Armenian_o,+    _Armenian_FE                 = GDK_KEY_Armenian_FE,+    _Armenian_fe                 = GDK_KEY_Armenian_fe,+    _Armenian_apostrophe         = GDK_KEY_Armenian_apostrophe,+    _Georgian_an                 = GDK_KEY_Georgian_an,+    _Georgian_ban                = GDK_KEY_Georgian_ban,+    _Georgian_gan                = GDK_KEY_Georgian_gan,+    _Georgian_don                = GDK_KEY_Georgian_don,+    _Georgian_en                 = GDK_KEY_Georgian_en,+    _Georgian_vin                = GDK_KEY_Georgian_vin,+    _Georgian_zen                = GDK_KEY_Georgian_zen,+    _Georgian_tan                = GDK_KEY_Georgian_tan,+    _Georgian_in                 = GDK_KEY_Georgian_in,+    _Georgian_kan                = GDK_KEY_Georgian_kan,+    _Georgian_las                = GDK_KEY_Georgian_las,+    _Georgian_man                = GDK_KEY_Georgian_man,+    _Georgian_nar                = GDK_KEY_Georgian_nar,+    _Georgian_on                 = GDK_KEY_Georgian_on,+    _Georgian_par                = GDK_KEY_Georgian_par,+    _Georgian_zhar               = GDK_KEY_Georgian_zhar,+    _Georgian_rae                = GDK_KEY_Georgian_rae,+    _Georgian_san                = GDK_KEY_Georgian_san,+    _Georgian_tar                = GDK_KEY_Georgian_tar,+    _Georgian_un                 = GDK_KEY_Georgian_un,+    _Georgian_phar               = GDK_KEY_Georgian_phar,+    _Georgian_khar               = GDK_KEY_Georgian_khar,+    _Georgian_ghan               = GDK_KEY_Georgian_ghan,+    _Georgian_qar                = GDK_KEY_Georgian_qar,+    _Georgian_shin               = GDK_KEY_Georgian_shin,+    _Georgian_chin               = GDK_KEY_Georgian_chin,+    _Georgian_can                = GDK_KEY_Georgian_can,+    _Georgian_jil                = GDK_KEY_Georgian_jil,+    _Georgian_cil                = GDK_KEY_Georgian_cil,+    _Georgian_char               = GDK_KEY_Georgian_char,+    _Georgian_xan                = GDK_KEY_Georgian_xan,+    _Georgian_jhan               = GDK_KEY_Georgian_jhan,+    _Georgian_hae                = GDK_KEY_Georgian_hae,+    _Georgian_he                 = GDK_KEY_Georgian_he,+    _Georgian_hie                = GDK_KEY_Georgian_hie,+    _Georgian_we                 = GDK_KEY_Georgian_we,+    _Georgian_har                = GDK_KEY_Georgian_har,+    _Georgian_hoe                = GDK_KEY_Georgian_hoe,+    _Georgian_fi                 = GDK_KEY_Georgian_fi,+    _Xabovedot                   = GDK_KEY_Xabovedot,+    _Ibreve                      = GDK_KEY_Ibreve,+    _Zstroke                     = GDK_KEY_Zstroke,+    _Gcaron                      = GDK_KEY_Gcaron,+    _Ocaron                      = GDK_KEY_Ocaron,+    _Obarred                     = GDK_KEY_Obarred,+    _xabovedot                   = GDK_KEY_xabovedot,+    _ibreve                      = GDK_KEY_ibreve,+    _zstroke                     = GDK_KEY_zstroke,+    _gcaron                      = GDK_KEY_gcaron,+    _ocaron                      = GDK_KEY_ocaron,+    _obarred                     = GDK_KEY_obarred,+    _SCHWA                       = GDK_KEY_SCHWA,+    _schwa                       = GDK_KEY_schwa,+    _Lbelowdot                   = GDK_KEY_Lbelowdot,+    _lbelowdot                   = GDK_KEY_lbelowdot,+    _Abelowdot                   = GDK_KEY_Abelowdot,+    _abelowdot                   = GDK_KEY_abelowdot,+    _Ahook                       = GDK_KEY_Ahook,+    _ahook                       = GDK_KEY_ahook,+    _Acircumflexacute            = GDK_KEY_Acircumflexacute,+    _acircumflexacute            = GDK_KEY_acircumflexacute,+    _Acircumflexgrave            = GDK_KEY_Acircumflexgrave,+    _acircumflexgrave            = GDK_KEY_acircumflexgrave,+    _Acircumflexhook             = GDK_KEY_Acircumflexhook,+    _acircumflexhook             = GDK_KEY_acircumflexhook,+    _Acircumflextilde            = GDK_KEY_Acircumflextilde,+    _acircumflextilde            = GDK_KEY_acircumflextilde,+    _Acircumflexbelowdot         = GDK_KEY_Acircumflexbelowdot,+    _acircumflexbelowdot         = GDK_KEY_acircumflexbelowdot,+    _Abreveacute                 = GDK_KEY_Abreveacute,+    _abreveacute                 = GDK_KEY_abreveacute,+    _Abrevegrave                 = GDK_KEY_Abrevegrave,+    _abrevegrave                 = GDK_KEY_abrevegrave,+    _Abrevehook                  = GDK_KEY_Abrevehook,+    _abrevehook                  = GDK_KEY_abrevehook,+    _Abrevetilde                 = GDK_KEY_Abrevetilde,+    _abrevetilde                 = GDK_KEY_abrevetilde,+    _Abrevebelowdot              = GDK_KEY_Abrevebelowdot,+    _abrevebelowdot              = GDK_KEY_abrevebelowdot,+    _Ebelowdot                   = GDK_KEY_Ebelowdot,+    _ebelowdot                   = GDK_KEY_ebelowdot,+    _Ehook                       = GDK_KEY_Ehook,+    _ehook                       = GDK_KEY_ehook,+    _Etilde                      = GDK_KEY_Etilde,+    _etilde                      = GDK_KEY_etilde,+    _Ecircumflexacute            = GDK_KEY_Ecircumflexacute,+    _ecircumflexacute            = GDK_KEY_ecircumflexacute,+    _Ecircumflexgrave            = GDK_KEY_Ecircumflexgrave,+    _ecircumflexgrave            = GDK_KEY_ecircumflexgrave,+    _Ecircumflexhook             = GDK_KEY_Ecircumflexhook,+    _ecircumflexhook             = GDK_KEY_ecircumflexhook,+    _Ecircumflextilde            = GDK_KEY_Ecircumflextilde,+    _ecircumflextilde            = GDK_KEY_ecircumflextilde,+    _Ecircumflexbelowdot         = GDK_KEY_Ecircumflexbelowdot,+    _ecircumflexbelowdot         = GDK_KEY_ecircumflexbelowdot,+    _Ihook                       = GDK_KEY_Ihook,+    _ihook                       = GDK_KEY_ihook,+    _Ibelowdot                   = GDK_KEY_Ibelowdot,+    _ibelowdot                   = GDK_KEY_ibelowdot,+    _Obelowdot                   = GDK_KEY_Obelowdot,+    _obelowdot                   = GDK_KEY_obelowdot,+    _Ohook                       = GDK_KEY_Ohook,+    _ohook                       = GDK_KEY_ohook,+    _Ocircumflexacute            = GDK_KEY_Ocircumflexacute,+    _ocircumflexacute            = GDK_KEY_ocircumflexacute,+    _Ocircumflexgrave            = GDK_KEY_Ocircumflexgrave,+    _ocircumflexgrave            = GDK_KEY_ocircumflexgrave,+    _Ocircumflexhook             = GDK_KEY_Ocircumflexhook,+    _ocircumflexhook             = GDK_KEY_ocircumflexhook,+    _Ocircumflextilde            = GDK_KEY_Ocircumflextilde,+    _ocircumflextilde            = GDK_KEY_ocircumflextilde,+    _Ocircumflexbelowdot         = GDK_KEY_Ocircumflexbelowdot,+    _ocircumflexbelowdot         = GDK_KEY_ocircumflexbelowdot,+    _Ohornacute                  = GDK_KEY_Ohornacute,+    _ohornacute                  = GDK_KEY_ohornacute,+    _Ohorngrave                  = GDK_KEY_Ohorngrave,+    _ohorngrave                  = GDK_KEY_ohorngrave,+    _Ohornhook                   = GDK_KEY_Ohornhook,+    _ohornhook                   = GDK_KEY_ohornhook,+    _Ohorntilde                  = GDK_KEY_Ohorntilde,+    _ohorntilde                  = GDK_KEY_ohorntilde,+    _Ohornbelowdot               = GDK_KEY_Ohornbelowdot,+    _ohornbelowdot               = GDK_KEY_ohornbelowdot,+    _Ubelowdot                   = GDK_KEY_Ubelowdot,+    _ubelowdot                   = GDK_KEY_ubelowdot,+    _Uhook                       = GDK_KEY_Uhook,+    _uhook                       = GDK_KEY_uhook,+    _Uhornacute                  = GDK_KEY_Uhornacute,+    _uhornacute                  = GDK_KEY_uhornacute,+    _Uhorngrave                  = GDK_KEY_Uhorngrave,+    _uhorngrave                  = GDK_KEY_uhorngrave,+    _Uhornhook                   = GDK_KEY_Uhornhook,+    _uhornhook                   = GDK_KEY_uhornhook,+    _Uhorntilde                  = GDK_KEY_Uhorntilde,+    _uhorntilde                  = GDK_KEY_uhorntilde,+    _Uhornbelowdot               = GDK_KEY_Uhornbelowdot,+    _uhornbelowdot               = GDK_KEY_uhornbelowdot,+    _Ybelowdot                   = GDK_KEY_Ybelowdot,+    _ybelowdot                   = GDK_KEY_ybelowdot,+    _Yhook                       = GDK_KEY_Yhook,+    _yhook                       = GDK_KEY_yhook,+    _Ytilde                      = GDK_KEY_Ytilde,+    _ytilde                      = GDK_KEY_ytilde,+    _Ohorn                       = GDK_KEY_Ohorn,+    _ohorn                       = GDK_KEY_ohorn,+    _Uhorn                       = GDK_KEY_Uhorn,+    _uhorn                       = GDK_KEY_uhorn,+    _EcuSign                     = GDK_KEY_EcuSign,+    _ColonSign                   = GDK_KEY_ColonSign,+    _CruzeiroSign                = GDK_KEY_CruzeiroSign,+    _FFrancSign                  = GDK_KEY_FFrancSign,+    _LiraSign                    = GDK_KEY_LiraSign,+    _MillSign                    = GDK_KEY_MillSign,+    _NairaSign                   = GDK_KEY_NairaSign,+    _PesetaSign                  = GDK_KEY_PesetaSign,+    _RupeeSign                   = GDK_KEY_RupeeSign,+    _WonSign                     = GDK_KEY_WonSign,+    _NewSheqelSign               = GDK_KEY_NewSheqelSign,+    _DongSign                    = GDK_KEY_DongSign,+    _EuroSign                    = GDK_KEY_EuroSign,+    _zerosuperior                = GDK_KEY_zerosuperior,+    _foursuperior                = GDK_KEY_foursuperior,+    _fivesuperior                = GDK_KEY_fivesuperior,+    _sixsuperior                 = GDK_KEY_sixsuperior,+    _sevensuperior               = GDK_KEY_sevensuperior,+    _eightsuperior               = GDK_KEY_eightsuperior,+    _ninesuperior                = GDK_KEY_ninesuperior,+    _zerosubscript               = GDK_KEY_zerosubscript,+    _onesubscript                = GDK_KEY_onesubscript,+    _twosubscript                = GDK_KEY_twosubscript,+    _threesubscript              = GDK_KEY_threesubscript,+    _foursubscript               = GDK_KEY_foursubscript,+    _fivesubscript               = GDK_KEY_fivesubscript,+    _sixsubscript                = GDK_KEY_sixsubscript,+    _sevensubscript              = GDK_KEY_sevensubscript,+    _eightsubscript              = GDK_KEY_eightsubscript,+    _ninesubscript               = GDK_KEY_ninesubscript,+    _partdifferential            = GDK_KEY_partdifferential,+    _emptyset                    = GDK_KEY_emptyset,+    _elementof                   = GDK_KEY_elementof,+    _notelementof                = GDK_KEY_notelementof,+    _containsas                  = GDK_KEY_containsas,+    _squareroot                  = GDK_KEY_squareroot,+    _cuberoot                    = GDK_KEY_cuberoot,+    _fourthroot                  = GDK_KEY_fourthroot,+    _dintegral                   = GDK_KEY_dintegral,+    _tintegral                   = GDK_KEY_tintegral,+    _because                     = GDK_KEY_because,+    _approxeq                    = GDK_KEY_approxeq,+    _notapproxeq                 = GDK_KEY_notapproxeq,+    _notidentical                = GDK_KEY_notidentical,+    _stricteq                    = GDK_KEY_stricteq,+    _braille_dot_1               = GDK_KEY_braille_dot_1,+    _braille_dot_2               = GDK_KEY_braille_dot_2,+    _braille_dot_3               = GDK_KEY_braille_dot_3,+    _braille_dot_4               = GDK_KEY_braille_dot_4,+    _braille_dot_5               = GDK_KEY_braille_dot_5,+    _braille_dot_6               = GDK_KEY_braille_dot_6,+    _braille_dot_7               = GDK_KEY_braille_dot_7,+    _braille_dot_8               = GDK_KEY_braille_dot_8,+    _braille_dot_9               = GDK_KEY_braille_dot_9,+    _braille_dot_10              = GDK_KEY_braille_dot_10,+    _braille_blank               = GDK_KEY_braille_blank,+    _braille_dots_1              = GDK_KEY_braille_dots_1,+    _braille_dots_2              = GDK_KEY_braille_dots_2,+    _braille_dots_12             = GDK_KEY_braille_dots_12,+    _braille_dots_3              = GDK_KEY_braille_dots_3,+    _braille_dots_13             = GDK_KEY_braille_dots_13,+    _braille_dots_23             = GDK_KEY_braille_dots_23,+    _braille_dots_123            = GDK_KEY_braille_dots_123,+    _braille_dots_4              = GDK_KEY_braille_dots_4,+    _braille_dots_14             = GDK_KEY_braille_dots_14,+    _braille_dots_24             = GDK_KEY_braille_dots_24,+    _braille_dots_124            = GDK_KEY_braille_dots_124,+    _braille_dots_34             = GDK_KEY_braille_dots_34,+    _braille_dots_134            = GDK_KEY_braille_dots_134,+    _braille_dots_234            = GDK_KEY_braille_dots_234,+    _braille_dots_1234           = GDK_KEY_braille_dots_1234,+    _braille_dots_5              = GDK_KEY_braille_dots_5,+    _braille_dots_15             = GDK_KEY_braille_dots_15,+    _braille_dots_25             = GDK_KEY_braille_dots_25,+    _braille_dots_125            = GDK_KEY_braille_dots_125,+    _braille_dots_35             = GDK_KEY_braille_dots_35,+    _braille_dots_135            = GDK_KEY_braille_dots_135,+    _braille_dots_235            = GDK_KEY_braille_dots_235,+    _braille_dots_1235           = GDK_KEY_braille_dots_1235,+    _braille_dots_45             = GDK_KEY_braille_dots_45,+    _braille_dots_145            = GDK_KEY_braille_dots_145,+    _braille_dots_245            = GDK_KEY_braille_dots_245,+    _braille_dots_1245           = GDK_KEY_braille_dots_1245,+    _braille_dots_345            = GDK_KEY_braille_dots_345,+    _braille_dots_1345           = GDK_KEY_braille_dots_1345,+    _braille_dots_2345           = GDK_KEY_braille_dots_2345,+    _braille_dots_12345          = GDK_KEY_braille_dots_12345,+    _braille_dots_6              = GDK_KEY_braille_dots_6,+    _braille_dots_16             = GDK_KEY_braille_dots_16,+    _braille_dots_26             = GDK_KEY_braille_dots_26,+    _braille_dots_126            = GDK_KEY_braille_dots_126,+    _braille_dots_36             = GDK_KEY_braille_dots_36,+    _braille_dots_136            = GDK_KEY_braille_dots_136,+    _braille_dots_236            = GDK_KEY_braille_dots_236,+    _braille_dots_1236           = GDK_KEY_braille_dots_1236,+    _braille_dots_46             = GDK_KEY_braille_dots_46,+    _braille_dots_146            = GDK_KEY_braille_dots_146,+    _braille_dots_246            = GDK_KEY_braille_dots_246,+    _braille_dots_1246           = GDK_KEY_braille_dots_1246,+    _braille_dots_346            = GDK_KEY_braille_dots_346,+    _braille_dots_1346           = GDK_KEY_braille_dots_1346,+    _braille_dots_2346           = GDK_KEY_braille_dots_2346,+    _braille_dots_12346          = GDK_KEY_braille_dots_12346,+    _braille_dots_56             = GDK_KEY_braille_dots_56,+    _braille_dots_156            = GDK_KEY_braille_dots_156,+    _braille_dots_256            = GDK_KEY_braille_dots_256,+    _braille_dots_1256           = GDK_KEY_braille_dots_1256,+    _braille_dots_356            = GDK_KEY_braille_dots_356,+    _braille_dots_1356           = GDK_KEY_braille_dots_1356,+    _braille_dots_2356           = GDK_KEY_braille_dots_2356,+    _braille_dots_12356          = GDK_KEY_braille_dots_12356,+    _braille_dots_456            = GDK_KEY_braille_dots_456,+    _braille_dots_1456           = GDK_KEY_braille_dots_1456,+    _braille_dots_2456           = GDK_KEY_braille_dots_2456,+    _braille_dots_12456          = GDK_KEY_braille_dots_12456,+    _braille_dots_3456           = GDK_KEY_braille_dots_3456,+    _braille_dots_13456          = GDK_KEY_braille_dots_13456,+    _braille_dots_23456          = GDK_KEY_braille_dots_23456,+    _braille_dots_123456         = GDK_KEY_braille_dots_123456,+    _braille_dots_7              = GDK_KEY_braille_dots_7,+    _braille_dots_17             = GDK_KEY_braille_dots_17,+    _braille_dots_27             = GDK_KEY_braille_dots_27,+    _braille_dots_127            = GDK_KEY_braille_dots_127,+    _braille_dots_37             = GDK_KEY_braille_dots_37,+    _braille_dots_137            = GDK_KEY_braille_dots_137,+    _braille_dots_237            = GDK_KEY_braille_dots_237,+    _braille_dots_1237           = GDK_KEY_braille_dots_1237,+    _braille_dots_47             = GDK_KEY_braille_dots_47,+    _braille_dots_147            = GDK_KEY_braille_dots_147,+    _braille_dots_247            = GDK_KEY_braille_dots_247,+    _braille_dots_1247           = GDK_KEY_braille_dots_1247,+    _braille_dots_347            = GDK_KEY_braille_dots_347,+    _braille_dots_1347           = GDK_KEY_braille_dots_1347,+    _braille_dots_2347           = GDK_KEY_braille_dots_2347,+    _braille_dots_12347          = GDK_KEY_braille_dots_12347,+    _braille_dots_57             = GDK_KEY_braille_dots_57,+    _braille_dots_157            = GDK_KEY_braille_dots_157,+    _braille_dots_257            = GDK_KEY_braille_dots_257,+    _braille_dots_1257           = GDK_KEY_braille_dots_1257,+    _braille_dots_357            = GDK_KEY_braille_dots_357,+    _braille_dots_1357           = GDK_KEY_braille_dots_1357,+    _braille_dots_2357           = GDK_KEY_braille_dots_2357,+    _braille_dots_12357          = GDK_KEY_braille_dots_12357,+    _braille_dots_457            = GDK_KEY_braille_dots_457,+    _braille_dots_1457           = GDK_KEY_braille_dots_1457,+    _braille_dots_2457           = GDK_KEY_braille_dots_2457,+    _braille_dots_12457          = GDK_KEY_braille_dots_12457,+    _braille_dots_3457           = GDK_KEY_braille_dots_3457,+    _braille_dots_13457          = GDK_KEY_braille_dots_13457,+    _braille_dots_23457          = GDK_KEY_braille_dots_23457,+    _braille_dots_123457         = GDK_KEY_braille_dots_123457,+    _braille_dots_67             = GDK_KEY_braille_dots_67,+    _braille_dots_167            = GDK_KEY_braille_dots_167,+    _braille_dots_267            = GDK_KEY_braille_dots_267,+    _braille_dots_1267           = GDK_KEY_braille_dots_1267,+    _braille_dots_367            = GDK_KEY_braille_dots_367,+    _braille_dots_1367           = GDK_KEY_braille_dots_1367,+    _braille_dots_2367           = GDK_KEY_braille_dots_2367,+    _braille_dots_12367          = GDK_KEY_braille_dots_12367,+    _braille_dots_467            = GDK_KEY_braille_dots_467,+    _braille_dots_1467           = GDK_KEY_braille_dots_1467,+    _braille_dots_2467           = GDK_KEY_braille_dots_2467,+    _braille_dots_12467          = GDK_KEY_braille_dots_12467,+    _braille_dots_3467           = GDK_KEY_braille_dots_3467,+    _braille_dots_13467          = GDK_KEY_braille_dots_13467,+    _braille_dots_23467          = GDK_KEY_braille_dots_23467,+    _braille_dots_123467         = GDK_KEY_braille_dots_123467,+    _braille_dots_567            = GDK_KEY_braille_dots_567,+    _braille_dots_1567           = GDK_KEY_braille_dots_1567,+    _braille_dots_2567           = GDK_KEY_braille_dots_2567,+    _braille_dots_12567          = GDK_KEY_braille_dots_12567,+    _braille_dots_3567           = GDK_KEY_braille_dots_3567,+    _braille_dots_13567          = GDK_KEY_braille_dots_13567,+    _braille_dots_23567          = GDK_KEY_braille_dots_23567,+    _braille_dots_123567         = GDK_KEY_braille_dots_123567,+    _braille_dots_4567           = GDK_KEY_braille_dots_4567,+    _braille_dots_14567          = GDK_KEY_braille_dots_14567,+    _braille_dots_24567          = GDK_KEY_braille_dots_24567,+    _braille_dots_124567         = GDK_KEY_braille_dots_124567,+    _braille_dots_34567          = GDK_KEY_braille_dots_34567,+    _braille_dots_134567         = GDK_KEY_braille_dots_134567,+    _braille_dots_234567         = GDK_KEY_braille_dots_234567,+    _braille_dots_1234567        = GDK_KEY_braille_dots_1234567,+    _braille_dots_8              = GDK_KEY_braille_dots_8,+    _braille_dots_18             = GDK_KEY_braille_dots_18,+    _braille_dots_28             = GDK_KEY_braille_dots_28,+    _braille_dots_128            = GDK_KEY_braille_dots_128,+    _braille_dots_38             = GDK_KEY_braille_dots_38,+    _braille_dots_138            = GDK_KEY_braille_dots_138,+    _braille_dots_238            = GDK_KEY_braille_dots_238,+    _braille_dots_1238           = GDK_KEY_braille_dots_1238,+    _braille_dots_48             = GDK_KEY_braille_dots_48,+    _braille_dots_148            = GDK_KEY_braille_dots_148,+    _braille_dots_248            = GDK_KEY_braille_dots_248,+    _braille_dots_1248           = GDK_KEY_braille_dots_1248,+    _braille_dots_348            = GDK_KEY_braille_dots_348,+    _braille_dots_1348           = GDK_KEY_braille_dots_1348,+    _braille_dots_2348           = GDK_KEY_braille_dots_2348,+    _braille_dots_12348          = GDK_KEY_braille_dots_12348,+    _braille_dots_58             = GDK_KEY_braille_dots_58,+    _braille_dots_158            = GDK_KEY_braille_dots_158,+    _braille_dots_258            = GDK_KEY_braille_dots_258,+    _braille_dots_1258           = GDK_KEY_braille_dots_1258,+    _braille_dots_358            = GDK_KEY_braille_dots_358,+    _braille_dots_1358           = GDK_KEY_braille_dots_1358,+    _braille_dots_2358           = GDK_KEY_braille_dots_2358,+    _braille_dots_12358          = GDK_KEY_braille_dots_12358,+    _braille_dots_458            = GDK_KEY_braille_dots_458,+    _braille_dots_1458           = GDK_KEY_braille_dots_1458,+    _braille_dots_2458           = GDK_KEY_braille_dots_2458,+    _braille_dots_12458          = GDK_KEY_braille_dots_12458,+    _braille_dots_3458           = GDK_KEY_braille_dots_3458,+    _braille_dots_13458          = GDK_KEY_braille_dots_13458,+    _braille_dots_23458          = GDK_KEY_braille_dots_23458,+    _braille_dots_123458         = GDK_KEY_braille_dots_123458,+    _braille_dots_68             = GDK_KEY_braille_dots_68,+    _braille_dots_168            = GDK_KEY_braille_dots_168,+    _braille_dots_268            = GDK_KEY_braille_dots_268,+    _braille_dots_1268           = GDK_KEY_braille_dots_1268,+    _braille_dots_368            = GDK_KEY_braille_dots_368,+    _braille_dots_1368           = GDK_KEY_braille_dots_1368,+    _braille_dots_2368           = GDK_KEY_braille_dots_2368,+    _braille_dots_12368          = GDK_KEY_braille_dots_12368,+    _braille_dots_468            = GDK_KEY_braille_dots_468,+    _braille_dots_1468           = GDK_KEY_braille_dots_1468,+    _braille_dots_2468           = GDK_KEY_braille_dots_2468,+    _braille_dots_12468          = GDK_KEY_braille_dots_12468,+    _braille_dots_3468           = GDK_KEY_braille_dots_3468,+    _braille_dots_13468          = GDK_KEY_braille_dots_13468,+    _braille_dots_23468          = GDK_KEY_braille_dots_23468,+    _braille_dots_123468         = GDK_KEY_braille_dots_123468,+    _braille_dots_568            = GDK_KEY_braille_dots_568,+    _braille_dots_1568           = GDK_KEY_braille_dots_1568,+    _braille_dots_2568           = GDK_KEY_braille_dots_2568,+    _braille_dots_12568          = GDK_KEY_braille_dots_12568,+    _braille_dots_3568           = GDK_KEY_braille_dots_3568,+    _braille_dots_13568          = GDK_KEY_braille_dots_13568,+    _braille_dots_23568          = GDK_KEY_braille_dots_23568,+    _braille_dots_123568         = GDK_KEY_braille_dots_123568,+    _braille_dots_4568           = GDK_KEY_braille_dots_4568,+    _braille_dots_14568          = GDK_KEY_braille_dots_14568,+    _braille_dots_24568          = GDK_KEY_braille_dots_24568,+    _braille_dots_124568         = GDK_KEY_braille_dots_124568,+    _braille_dots_34568          = GDK_KEY_braille_dots_34568,+    _braille_dots_134568         = GDK_KEY_braille_dots_134568,+    _braille_dots_234568         = GDK_KEY_braille_dots_234568,+    _braille_dots_1234568        = GDK_KEY_braille_dots_1234568,+    _braille_dots_78             = GDK_KEY_braille_dots_78,+    _braille_dots_178            = GDK_KEY_braille_dots_178,+    _braille_dots_278            = GDK_KEY_braille_dots_278,+    _braille_dots_1278           = GDK_KEY_braille_dots_1278,+    _braille_dots_378            = GDK_KEY_braille_dots_378,+    _braille_dots_1378           = GDK_KEY_braille_dots_1378,+    _braille_dots_2378           = GDK_KEY_braille_dots_2378,+    _braille_dots_12378          = GDK_KEY_braille_dots_12378,+    _braille_dots_478            = GDK_KEY_braille_dots_478,+    _braille_dots_1478           = GDK_KEY_braille_dots_1478,+    _braille_dots_2478           = GDK_KEY_braille_dots_2478,+    _braille_dots_12478          = GDK_KEY_braille_dots_12478,+    _braille_dots_3478           = GDK_KEY_braille_dots_3478,+    _braille_dots_13478          = GDK_KEY_braille_dots_13478,+    _braille_dots_23478          = GDK_KEY_braille_dots_23478,+    _braille_dots_123478         = GDK_KEY_braille_dots_123478,+    _braille_dots_578            = GDK_KEY_braille_dots_578,+    _braille_dots_1578           = GDK_KEY_braille_dots_1578,+    _braille_dots_2578           = GDK_KEY_braille_dots_2578,+    _braille_dots_12578          = GDK_KEY_braille_dots_12578,+    _braille_dots_3578           = GDK_KEY_braille_dots_3578,+    _braille_dots_13578          = GDK_KEY_braille_dots_13578,+    _braille_dots_23578          = GDK_KEY_braille_dots_23578,+    _braille_dots_123578         = GDK_KEY_braille_dots_123578,+    _braille_dots_4578           = GDK_KEY_braille_dots_4578,+    _braille_dots_14578          = GDK_KEY_braille_dots_14578,+    _braille_dots_24578          = GDK_KEY_braille_dots_24578,+    _braille_dots_124578         = GDK_KEY_braille_dots_124578,+    _braille_dots_34578          = GDK_KEY_braille_dots_34578,+    _braille_dots_134578         = GDK_KEY_braille_dots_134578,+    _braille_dots_234578         = GDK_KEY_braille_dots_234578,+    _braille_dots_1234578        = GDK_KEY_braille_dots_1234578,+    _braille_dots_678            = GDK_KEY_braille_dots_678,+    _braille_dots_1678           = GDK_KEY_braille_dots_1678,+    _braille_dots_2678           = GDK_KEY_braille_dots_2678,+    _braille_dots_12678          = GDK_KEY_braille_dots_12678,+    _braille_dots_3678           = GDK_KEY_braille_dots_3678,+    _braille_dots_13678          = GDK_KEY_braille_dots_13678,+    _braille_dots_23678          = GDK_KEY_braille_dots_23678,+    _braille_dots_123678         = GDK_KEY_braille_dots_123678,+    _braille_dots_4678           = GDK_KEY_braille_dots_4678,+    _braille_dots_14678          = GDK_KEY_braille_dots_14678,+    _braille_dots_24678          = GDK_KEY_braille_dots_24678,+    _braille_dots_124678         = GDK_KEY_braille_dots_124678,+    _braille_dots_34678          = GDK_KEY_braille_dots_34678,+    _braille_dots_134678         = GDK_KEY_braille_dots_134678,+    _braille_dots_234678         = GDK_KEY_braille_dots_234678,+    _braille_dots_1234678        = GDK_KEY_braille_dots_1234678,+    _braille_dots_5678           = GDK_KEY_braille_dots_5678,+    _braille_dots_15678          = GDK_KEY_braille_dots_15678,+    _braille_dots_25678          = GDK_KEY_braille_dots_25678,+    _braille_dots_125678         = GDK_KEY_braille_dots_125678,+    _braille_dots_35678          = GDK_KEY_braille_dots_35678,+    _braille_dots_135678         = GDK_KEY_braille_dots_135678,+    _braille_dots_235678         = GDK_KEY_braille_dots_235678,+    _braille_dots_1235678        = GDK_KEY_braille_dots_1235678,+    _braille_dots_45678          = GDK_KEY_braille_dots_45678,+    _braille_dots_145678         = GDK_KEY_braille_dots_145678,+    _braille_dots_245678         = GDK_KEY_braille_dots_245678,+    _braille_dots_1245678        = GDK_KEY_braille_dots_1245678,+    _braille_dots_345678         = GDK_KEY_braille_dots_345678,+    _braille_dots_1345678        = GDK_KEY_braille_dots_1345678,+    _braille_dots_2345678        = GDK_KEY_braille_dots_2345678,+    _braille_dots_12345678       = GDK_KEY_braille_dots_12345678,+    _ModeLock                    = GDK_KEY_ModeLock,+    _MonBrightnessUp             = GDK_KEY_MonBrightnessUp,+    _MonBrightnessDown           = GDK_KEY_MonBrightnessDown,+    _KbdLightOnOff               = GDK_KEY_KbdLightOnOff,+    _KbdBrightnessUp             = GDK_KEY_KbdBrightnessUp,+    _KbdBrightnessDown           = GDK_KEY_KbdBrightnessDown,+    _Standby                     = GDK_KEY_Standby,+    _AudioLowerVolume            = GDK_KEY_AudioLowerVolume,+    _AudioMute                   = GDK_KEY_AudioMute,+    _AudioRaiseVolume            = GDK_KEY_AudioRaiseVolume,+    _AudioPlay                   = GDK_KEY_AudioPlay,+    _AudioStop                   = GDK_KEY_AudioStop,+    _AudioPrev                   = GDK_KEY_AudioPrev,+    _AudioNext                   = GDK_KEY_AudioNext,+    _HomePage                    = GDK_KEY_HomePage,+    _Mail                        = GDK_KEY_Mail,+    _Start                       = GDK_KEY_Start,+    _Search                      = GDK_KEY_Search,+    _AudioRecord                 = GDK_KEY_AudioRecord,+    _Calculator                  = GDK_KEY_Calculator,+    _Memo                        = GDK_KEY_Memo,+    _ToDoList                    = GDK_KEY_ToDoList,+    _Calendar                    = GDK_KEY_Calendar,+    _PowerDown                   = GDK_KEY_PowerDown,+    _ContrastAdjust              = GDK_KEY_ContrastAdjust,+    _RockerUp                    = GDK_KEY_RockerUp,+    _RockerDown                  = GDK_KEY_RockerDown,+    _RockerEnter                 = GDK_KEY_RockerEnter,+    _Back                        = GDK_KEY_Back,+    _Forward                     = GDK_KEY_Forward,+    _Stop                        = GDK_KEY_Stop,+    _Refresh                     = GDK_KEY_Refresh,+    _PowerOff                    = GDK_KEY_PowerOff,+    _WakeUp                      = GDK_KEY_WakeUp,+    _Eject                       = GDK_KEY_Eject,+    _ScreenSaver                 = GDK_KEY_ScreenSaver,+    _WWW                         = GDK_KEY_WWW,+    _Sleep                       = GDK_KEY_Sleep,+    _Favorites                   = GDK_KEY_Favorites,+    _AudioPause                  = GDK_KEY_AudioPause,+    _AudioMedia                  = GDK_KEY_AudioMedia,+    _MyComputer                  = GDK_KEY_MyComputer,+    _VendorHome                  = GDK_KEY_VendorHome,+    _LightBulb                   = GDK_KEY_LightBulb,+    _Shop                        = GDK_KEY_Shop,+    _History                     = GDK_KEY_History,+    _OpenURL                     = GDK_KEY_OpenURL,+    _AddFavorite                 = GDK_KEY_AddFavorite,+    _HotLinks                    = GDK_KEY_HotLinks,+    _BrightnessAdjust            = GDK_KEY_BrightnessAdjust,+    _Finance                     = GDK_KEY_Finance,+    _Community                   = GDK_KEY_Community,+    _AudioRewind                 = GDK_KEY_AudioRewind,+    _BackForward                 = GDK_KEY_BackForward,+    _Launch0                     = GDK_KEY_Launch0,+    _Launch1                     = GDK_KEY_Launch1,+    _Launch2                     = GDK_KEY_Launch2,+    _Launch3                     = GDK_KEY_Launch3,+    _Launch4                     = GDK_KEY_Launch4,+    _Launch5                     = GDK_KEY_Launch5,+    _Launch6                     = GDK_KEY_Launch6,+    _Launch7                     = GDK_KEY_Launch7,+    _Launch8                     = GDK_KEY_Launch8,+    _Launch9                     = GDK_KEY_Launch9,+    _LaunchA                     = GDK_KEY_LaunchA,+    _LaunchB                     = GDK_KEY_LaunchB,+    _LaunchC                     = GDK_KEY_LaunchC,+    _LaunchD                     = GDK_KEY_LaunchD,+    _LaunchE                     = GDK_KEY_LaunchE,+    _LaunchF                     = GDK_KEY_LaunchF,+    _ApplicationLeft             = GDK_KEY_ApplicationLeft,+    _ApplicationRight            = GDK_KEY_ApplicationRight,+    _Book                        = GDK_KEY_Book,+    _CD                          = GDK_KEY_CD,+    _WindowClear                 = GDK_KEY_WindowClear,+    _Close                       = GDK_KEY_Close,+    _Copy                        = GDK_KEY_Copy,+    _Cut                         = GDK_KEY_Cut,+    _Display                     = GDK_KEY_Display,+    _DOS                         = GDK_KEY_DOS,+    _Documents                   = GDK_KEY_Documents,+    _Excel                       = GDK_KEY_Excel,+    _Explorer                    = GDK_KEY_Explorer,+    _Game                        = GDK_KEY_Game,+    _Go                          = GDK_KEY_Go,+    _iTouch                      = GDK_KEY_iTouch,+    _LogOff                      = GDK_KEY_LogOff,+    _Market                      = GDK_KEY_Market,+    _Meeting                     = GDK_KEY_Meeting,+    _MenuKB                      = GDK_KEY_MenuKB,+    _MenuPB                      = GDK_KEY_MenuPB,+    _MySites                     = GDK_KEY_MySites,+    _New                         = GDK_KEY_New,+    _News                        = GDK_KEY_News,+    _OfficeHome                  = GDK_KEY_OfficeHome,+    _Open                        = GDK_KEY_Open,+    _Option                      = GDK_KEY_Option,+    _Paste                       = GDK_KEY_Paste,+    _Phone                       = GDK_KEY_Phone,+    _Reply                       = GDK_KEY_Reply,+    _Reload                      = GDK_KEY_Reload,+    _RotateWindows               = GDK_KEY_RotateWindows,+    _RotationPB                  = GDK_KEY_RotationPB,+    _RotationKB                  = GDK_KEY_RotationKB,+    _Save                        = GDK_KEY_Save,+    _ScrollUp                    = GDK_KEY_ScrollUp,+    _ScrollDown                  = GDK_KEY_ScrollDown,+    _ScrollClick                 = GDK_KEY_ScrollClick,+    _Send                        = GDK_KEY_Send,+    _Spell                       = GDK_KEY_Spell,+    _SplitScreen                 = GDK_KEY_SplitScreen,+    _Support                     = GDK_KEY_Support,+    _TaskPane                    = GDK_KEY_TaskPane,+    _Terminal                    = GDK_KEY_Terminal,+    _Tools                       = GDK_KEY_Tools,+    _Travel                      = GDK_KEY_Travel,+    _UserPB                      = GDK_KEY_UserPB,+    _User1KB                     = GDK_KEY_User1KB,+    _User2KB                     = GDK_KEY_User2KB,+    _Video                       = GDK_KEY_Video,+    _WheelButton                 = GDK_KEY_WheelButton,+    _Word                        = GDK_KEY_Word,+    _Xfer                        = GDK_KEY_Xfer,+    _ZoomIn                      = GDK_KEY_ZoomIn,+    _ZoomOut                     = GDK_KEY_ZoomOut,+    _Away                        = GDK_KEY_Away,+    _Messenger                   = GDK_KEY_Messenger,+    _WebCam                      = GDK_KEY_WebCam,+    _MailForward                 = GDK_KEY_MailForward,+    _Pictures                    = GDK_KEY_Pictures,+    _Music                       = GDK_KEY_Music,+    _Battery                     = GDK_KEY_Battery,+    _Bluetooth                   = GDK_KEY_Bluetooth,+    _WLAN                        = GDK_KEY_WLAN,+    _UWB                         = GDK_KEY_UWB,+    _AudioForward                = GDK_KEY_AudioForward,+    _AudioRepeat                 = GDK_KEY_AudioRepeat,+    _AudioRandomPlay             = GDK_KEY_AudioRandomPlay,+    _Subtitle                    = GDK_KEY_Subtitle,+    _AudioCycleTrack             = GDK_KEY_AudioCycleTrack,+    _CycleAngle                  = GDK_KEY_CycleAngle,+    _FrameBack                   = GDK_KEY_FrameBack,+    _FrameForward                = GDK_KEY_FrameForward,+    _Time                        = GDK_KEY_Time,+    _SelectButton                = GDK_KEY_SelectButton,+    _View                        = GDK_KEY_View,+    _TopMenu                     = GDK_KEY_TopMenu,+    _Red                         = GDK_KEY_Red,+    _Green                       = GDK_KEY_Green,+    _Yellow                      = GDK_KEY_Yellow,+    _Blue                        = GDK_KEY_Blue,+    _Suspend                     = GDK_KEY_Suspend,+    _Hibernate                   = GDK_KEY_Hibernate,+    _TouchpadToggle              = GDK_KEY_TouchpadToggle,+    _Switch_VT_1                 = GDK_KEY_Switch_VT_1,+    _Switch_VT_2                 = GDK_KEY_Switch_VT_2,+    _Switch_VT_3                 = GDK_KEY_Switch_VT_3,+    _Switch_VT_4                 = GDK_KEY_Switch_VT_4,+    _Switch_VT_5                 = GDK_KEY_Switch_VT_5,+    _Switch_VT_6                 = GDK_KEY_Switch_VT_6,+    _Switch_VT_7                 = GDK_KEY_Switch_VT_7,+    _Switch_VT_8                 = GDK_KEY_Switch_VT_8,+    _Switch_VT_9                 = GDK_KEY_Switch_VT_9,+    _Switch_VT_10                = GDK_KEY_Switch_VT_10,+    _Switch_VT_11                = GDK_KEY_Switch_VT_11,+    _Switch_VT_12                = GDK_KEY_Switch_VT_12,+    _Ungrab                      = GDK_KEY_Ungrab,+    _ClearGrab                   = GDK_KEY_ClearGrab,+    _Next_VMode                  = GDK_KEY_Next_VMode,+    _Prev_VMode                  = GDK_KEY_Prev_VMode+    }++-- | Modal keys are: caps lock+isModalKey :: KeyVal -> Bool+isModalKey k+    | k == _Caps_Lock = True+    | otherwise       = False++-- | Modifiers are: shift, control, alt, super, menu+isModifier :: KeyVal -> Bool+isModifier k+    | k == _Shift_L          = True+    | k == _Shift_R          = True+    | k == _Control_L        = True+    | k == _Control_R        = True+    | k == _Alt_L            = True+    | k == _Alt_R            = True+    | k == _Super_L          = True+    | k == _Super_R          = True+    | k == _Menu             = True+    | k == _ISO_Level3_Shift = True+    | otherwise              = False
+ library/Hbro/Gui.hs view
@@ -0,0 +1,275 @@+{-# LANGUAGE TemplateHaskell, ViewPatterns #-}+module Hbro.Gui (+-- * Types+      GUI+    , HasGUI(..)+-- * Basic+    , get+    , initialize+-- * Getter+    , canRender+    , isSourceMode+    , getDOM+-- * Actions+    , toggle+    , render+    , scroll+    , scrollH+    , scrollV+    , setSourceMode+    , toggleSourceMode+    , zoomIn+    , zoomOut+-- * Misc+    , Axis(..)+    , Position(..)+    , getObject+) where++-- {{{ Imports+import Graphics.UI.Gtk.WebKit.Lifted.WebView++import Hbro.Error as Hbro+import Hbro.Gui.Buildable+import Hbro.Gui.NotificationBar (HasNotificationBar(..))+import qualified Hbro.Gui.NotificationBar as NotifBar+import Hbro.Gui.PromptBar (PromptBar, HasPromptBar(..))+import qualified Hbro.Gui.PromptBar as Prompt+import Hbro.Gui.PromptBar.Signals as Prompt+import Hbro.Gui.StatusBar+import Hbro.Logger hiding(initialize)+import Hbro.Prelude hiding(on)++import Control.Lens.Getter+import Control.Lens.Lens+import Control.Lens.Setter+import Control.Lens.TH+import Control.Monad.Reader hiding(join, mapM_, when)++import Data.Text (splitOn)++import Graphics.Rendering.Pango.Enums+import Graphics.UI.Gtk.Abstract.Container+import Graphics.UI.Gtk.Abstract.Widget+import qualified Graphics.UI.Gtk.Builder as Gtk+import Graphics.UI.Gtk.General.General as GTK+import Graphics.UI.Gtk.Misc.Adjustment+import Graphics.UI.Gtk.Scrolling.ScrolledWindow+import Graphics.UI.Gtk.WebKit.DOM.Document+import Graphics.UI.Gtk.Windows.Window++import Network.URI as N++import System.Glib.Attributes hiding(get, set)+import qualified System.Glib.Attributes as G (get, set)+-- import System.Glib.GError+import System.Glib.Signals+import System.Glib.Types+-- }}}++-- {{{ Types+data Axis     = Horizontal | Vertical deriving(Show)+data Position = Absolute Double | Relative Double deriving(Show)++data GUI = GUI+    { _mainWindow      :: Window+    , _scrollWindow    :: ScrolledWindow  -- ^ 'ScrolledWindow' containing the webview+    , _webView         :: WebView+    , _promptBar       :: PromptBar+    , _statusBar       :: StatusBar+    , _notificationBar :: NotifBar.NotificationBar+    , _builder         :: Gtk.Builder          -- ^ Builder object created from XML file+    }++makeLensesWith ?? ''GUI $ classyRules+    & lensField .~ (\name -> Just (tail name ++ "L"))+    & lensClass .~ (\name -> Just ("Has" ++ name, "_" ++ toLower name))++-- | A 'GUI' can be built from an XML file.+instance Buildable GUI where+    buildWith b = do+        sWindow <- gSync $ Gtk.builderGetObject b castToScrolledWindow (asText "webViewParent")+        webView <- gSync webViewNew++        gAsync $ containerAdd sWindow webView++        GUI <$> gSync (Gtk.builderGetObject b castToWindow (asText "mainWindow"))+            <*> pure sWindow+            <*> pure webView+            <*> buildWith b+            <*> buildWith b+            <*> buildWith b+            <*> pure b++instance HasNotificationBar GUI where _notificationbar = notificationBarL+instance HasPromptBar GUI       where _promptbar       = promptBarL+-- }}}++get :: (MonadReader r m, BaseIO m, HasGUI r) => Lens' GUI a -> m a+get l = askL (_gui.l)+++-- {{{ Initialization+initialize :: (BaseIO m, MonadError Text m, MonadPlus m) => FilePath -> m GUI+initialize file = do+    gui <- buildFrom file++    let webView = gui^.webViewL++    initializeWindow    $ gui^.mainWindowL+    initializeWebView   webView+    Prompt.initialize   $ gui^.promptBarL+    NotifBar.initialize $ gui^.notificationBarL++    gAsync . widgetShowAll $ gui^.mainWindowL+    runReaderT Prompt.hide (gui^.promptBarL)++    gAsync $ windowSetDefault (gui^.mainWindowL) (Just $ gui^.webViewL)++    let closePrompt = widgetHide (gui^.promptBarL.boxL) >> widgetGrabFocus webView >> return ()+    onEntryCancelled (gui^.promptBarL.entryL) $ const closePrompt+    onEntryActivated (gui^.promptBarL.entryL) $ const closePrompt++    -- io $ scrolledWindowSetPolicy (gui^.scrollWindowL) PolicyNever PolicyNever+    -- io $ G.set (gui^.scrollWindowL) [ scrolledWindowHscrollbarPolicy := PolicyNever, scrolledWindowVscrollbarPolicy := PolicyNever]++    return gui++buildFrom :: (BaseIO m, MonadError Text m, Buildable t) => FilePath -> m t+buildFrom (fpToText -> uiFile) = do+    infoM "hbro.gui" $ "Building UI from: " ++ uiFile++    builder <- gSync Gtk.builderNew++    {-result <- -}+    gSync $ Gtk.builderAddFromFile builder (unpack uiFile)+    -- leftM throwError result++    buildWith builder++-- TODO: catch IOException+-- builderAddFromFile ::+-- builderAddFromFile builder file = catchGErrorJustDomain (Right <$> Gtk.builderAddFromFile builder file) handler+--   where+--     handler :: Gtk.BuilderError -> Text -> IO (Either Text a)+--     handler e message = return . Left $ "Error while building GUI from [" ++ file ++ "]: " ++ message++initializeWindow :: (BaseIO m) => Window -> m ()+initializeWindow window = gAsync $ do+    widgetModifyBg window StateNormal (Color 0 0 5000)+    void . on window deleteEvent $ gAsync GTK.mainQuit >> return False++initializeWebView :: (BaseIO m) => WebView -> m ()+initializeWebView webView = gAsync $ do+    G.set webView [ widgetCanDefault := True ]+    -- webViewSetMaintainsBackForwardList webView False+    on webView closeWebView $ gAsync GTK.mainQuit >> return False+    void . on webView consoleMessage $ \a b n c -> do+        putStrLn "console message"+        mapM_ putStrLn [a, b, tshow n, c]+        return True+    -- void . on webView resourceRequestStarting $ \frame resource request response -> do+    --     uri <- webResourceGetUri resource+    --     putStrLn $ "resource request starting: " ++ uri+    --     -- print =<< webResourceGetData resource+    --     putStrLn =<< (maybe (return "No request") (return . ("Request URI: " ++) . show <=< W.networkRequestGetUri) request)+    --     putStrLn =<< (maybe (return "No response") (return . ("Response URI: " ++) . show <=< networkResponseGetUri) response)++    --     -- case (endswith ".css" uri || uri `endswith` ".png" || uri `endswith` ".ico") of+    --        -- True -> (putStrLn "OK")+    --     (maybe (return ()) (`networkRequestSetUri` "about:blank") request)+-- }}}++-- {{{ Actions+-- | Toggle a widget's visibility+toggle :: (BaseIO m, WidgetClass a) => a -> m ()+toggle widget = do+    visibility <- gSync $ G.get widget widgetVisible+    gAsync $ (widgetHide <| visibility |> widgetShow) widget++canRender :: (BaseIO m, MonadReader t m, HasGUI t) => Text -> m Bool+canRender mimetype = gSync . (`webViewCanShowMimeType` mimetype) =<< get webViewL+++render :: (MonadReader t m, HasGUI t, BaseIO m) => Text -> URI -> m ()+render page uri = do+    debugM "hbro.gui" $ "Rendering <" ++ tshow uri ++ ">"+    -- loadString page uri =<< get' webViewL++    -- debugM "hbro.gui" $ "Base URI: " ++ show (baseOf uri)++    loadString page (baseOf uri) =<< get webViewL+  where+    baseOf uri' = uri' {+        uriPath = unpack . (`snoc` '/') . intercalate "/" . initSafe . splitOn "/" . pack $ uriPath uri'+    }++-- | Shortcut to 'scroll' horizontally or vertically.+scrollH, scrollV :: (BaseIO m, MonadReader t m, HasGUI t) => Position -> m ()+scrollH = scroll Horizontal+scrollV = scroll Vertical++-- | Scroll WebView.+scroll :: (BaseIO m, MonadReader t m, HasGUI t) => Axis -> Position -> m ()+scroll axis percentage = scroll' axis percentage =<< get scrollWindowL++-- General scrolling command+scroll' :: (BaseIO m) => Axis -> Position -> ScrolledWindow -> m ()+scroll' axis percentage scrollWindow = do+     logDebug $ "Set scroll " ++ tshow axis ++ " = " ++ tshow percentage++     adj     <- gSync . getAdjustment axis $ scrollWindow+     page    <- gSync $ adjustmentGetPageSize adj+     current <- gSync $ adjustmentGetValue adj+     lower   <- gSync $ adjustmentGetLower adj+     upper   <- gSync $ adjustmentGetUpper adj++     let shift (Absolute x) = lower   + x/100 * (upper - page - lower)+         shift (Relative x) = current + x/100 * page+         limit x            = (x `max` lower) `min` (upper - page)++     gAsync . adjustmentSetValue adj $ limit (shift percentage)+++getAdjustment :: (BaseIO m) => Axis -> ScrolledWindow -> m Adjustment+getAdjustment Horizontal = gSync . scrolledWindowGetHAdjustment+getAdjustment Vertical   = gSync . scrolledWindowGetVAdjustment+++-- TODO: see if the lens system can be leveraged to get/set this property+-- sourceMode :: Lens++isSourceMode :: (BaseIO m, MonadReader t m, HasGUI t) => m Bool+isSourceMode = gSync . webViewGetViewSourceMode =<< get webViewL++setSourceMode :: (BaseIO m, MonadReader t m, HasGUI t) => Bool -> m ()+setSourceMode value = get webViewL >>= gAsync . (`webViewSetViewSourceMode` value) >> logDebug ("Set source mode = " ++ tshow value)++-- | Toggle source display. This needs to be done *before* loading an URI.+toggleSourceMode :: (BaseIO m, MonadReader t m, HasGUI t) => m ()+toggleSourceMode = setSourceMode . not =<< isSourceMode+++zoomIn, zoomOut :: (BaseIO m, MonadReader t m, HasGUI t) => m ()+zoomIn  = get webViewL >>= gAsync . webViewZoomIn >> logDebug "Zooming in."+zoomOut = get webViewL >>= gAsync . webViewZoomOut >> logDebug "Zooming out."++getDOM :: (BaseIO m, MonadReader t m, HasGUI t) => m (Maybe Document)+getDOM = gSync . webViewGetDomDocument =<< get webViewL++-- | Return the casted 'GObject' corresponding to the given name (set in the builder's XML file)+getObject :: (BaseIO m, MonadReader t m, HasGUI t, GObjectClass a)+          => (GObject -> a)   -- ^ @castTo@ function+          -> Text           -- ^ Widget name+          -> m a+getObject cast name = do+    b <- get builderL+    gSync $ Gtk.builderGetObject b cast name+-- }}}+++-- {{{ Util+logDebug{-, logInfo-} :: (BaseIO m) => Text -> m ()+logDebug = debugM "hbro.gui"+-- logInfo  = infoM  "hbro.gui"+-- }}}
+ library/Hbro/Gui/Buildable.hs view
@@ -0,0 +1,10 @@+module Hbro.Gui.Buildable where++-- {{{ Imports+import Hbro.Prelude++import Graphics.UI.Gtk.Builder+-- }}}++-- | UI elements that can be built from a @GtkBuilder@ object (that is: an XML file)+class Buildable a where buildWith :: (BaseIO m) => Builder -> m a
+ library/Hbro/Gui/NotificationBar.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE TemplateHaskell #-}+module Hbro.Gui.NotificationBar (+-- * Type+      NotificationBar+    , HasNotificationBar(..)+    , initialize+) where++-- {{{ Imports+-- import Hbro.Error+import Hbro.Gui.Buildable+import Hbro.Logger hiding(initialize)+import Hbro.Prelude++import Control.Lens+import Control.Monad.Reader++import Graphics.Rendering.Pango.Enums+import Graphics.UI.Gtk.Abstract.Widget+import Graphics.UI.Gtk.Builder+import Graphics.UI.Gtk.Display.Label++import System.Glib.Types+import System.Log.Formatter+import System.Log.Handler.Simple+import System.Log.Logger (addHandler, rootLoggerName, updateGlobalLogger)+-- }}}++-- TODO: color notifications depending on their level+-- TODO: make it possible to expand the notification bar to display the last N log lines+-- TODO: make it possible to change the log level++-- {{{ Types+newtype NotificationBar = NotificationBar { _label :: Label }++makeLensesWith ?? ''NotificationBar $ classyRules+    & lensField .~ (\name -> Just (tailSafe name ++ "L"))+    & lensClass .~ (\name -> Just ("Has" ++ name, "_" ++ toLower name))++-- | A 'NotificationBar' can be built from an XML file.+instance Buildable NotificationBar where+    buildWith b = NotificationBar <$> gSync (builderGetObject b castToLabel $ asText "notificationLabel")++instance GObjectClass NotificationBar where+    toGObject (NotificationBar l) = toGObject l+    unsafeCastGObject = NotificationBar . unsafeCastGObject++-- | A 'NotificationBar' can be manipulated as a 'Widget'.+instance WidgetClass NotificationBar+-- }}}++get' :: (MonadReader r m, BaseIO m, HasNotificationBar r) => Lens' NotificationBar a -> m a+get' l = askL $ _notificationbar.l++-- modify' :: (MonadReader r m, BaseIO m, HasNotificationBar r) => (Status -> Status) -> m ()+-- modify' f = io . atomically . (`modifyTVar` f) =<< asks (view _notificationBar)++initialize :: (BaseIO m) => NotificationBar -> m ()+initialize notifBar = io . updateGlobalLogger rootLoggerName $ addHandler (logHandler notifBar)+++logHandler :: NotificationBar -> GenericHandler NotificationBar+logHandler notifBar = GenericHandler+    { priority  = INFO+    , formatter = simpleLogFormatter "$msg"+    , privData  = notifBar+    , writeFunc = \n t -> runReaderT (write t) n+    , closeFunc = \_ -> return ()+    }++write :: (BaseIO m, MonadReader r m, HasNotificationBar r) => String -> m ()+write text = do+    label  <- get' labelL++    gAsync $ do+        labelSetAttributes label [AttrForeground {paStart = 0, paEnd = -1, paColor = gray}]+        labelSetMarkup label text
+ library/Hbro/Gui/PromptBar.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, TemplateHaskell #-}+-- | Designed to be imported as @qualified@.+module Hbro.Gui.PromptBar (+-- * Types+      PromptBar+    -- description+    , HasPromptBar(..)+    , labelName+    , entryName+    , boxName+-- * Functions+    , initialize+    , open+    , unhide+    , hide+    , Hbro.Gui.PromptBar.clean+-- * Prompts+    , prompt+    , prompt'+    , promptURI+    , getEntryValue+) where++-- {{{ Imports+import Hbro.Error+import Hbro.Gui.Buildable+import Hbro.Gui.PromptBar.Signals+import Hbro.Gui.PromptBar.Hooks hiding(clean, set)+import qualified Hbro.Gui.PromptBar.Hooks as Hooks+import Hbro.Logger hiding(initialize)+import Hbro.Prelude++import Control.Lens.Getter+import Control.Lens.Setter+import Control.Lens.Lens+import Control.Lens.TH+import Control.Monad.Reader hiding(when)++import Graphics.Rendering.Pango.Enums+import Graphics.UI.Gtk.Abstract.Widget+import Graphics.UI.Gtk.Builder+import Graphics.UI.Gtk.Display.Label+import Graphics.UI.Gtk.Entry.Editable+import Graphics.UI.Gtk.Entry.Entry+import Graphics.UI.Gtk.Layout.HBox++import Network.URI.Monadic+-- }}}++-- {{{ Types+-- | No exported constructor, please use 'buildWith'+data PromptBar = PromptBar+    { _box         :: HBox+    , _description :: Label+    , _entry       :: Entry+    }++makeLensesWith ?? ''PromptBar $ classyRules+    & lensField .~ (\name -> Just (tail name ++ "L"))+    & lensClass .~ (\name -> Just ("Has" ++ name, "_" ++ toLower name))++-- | A 'PromptBar' can be built from an XML file.+instance Buildable PromptBar where+    buildWith b = PromptBar <$> gSync (builderGetObject b castToHBox boxName)+                            <*> gSync (builderGetObject b castToLabel labelName)+                            <*> gSync (builderGetObject b castToEntry entryName)++-- | Widget name used in the XML file that describes the UI+labelName, entryName, boxName :: Text+labelName = "promptDescription"+entryName = "promptEntry"+boxName   = "promptBox"++-- | Error message+promptInterrupted :: Text+promptInterrupted = "Prompt interrupted."+-- }}}++initialize :: (BaseIO m) => PromptBar -> m ()+initialize aPromptBar = gAsync $ do+    description `labelSetAttributes` [allItalic, allBold]+    description `labelSetAttributes` [AttrForeground {paStart = 0, paEnd = -1, paColor = gray}]+    widgetModifyBase entry StateNormal black+    widgetModifyText entry StateNormal gray+  where+    description = aPromptBar^.descriptionL+    entry       = aPromptBar^.entryL+++-- | Pops-up the prompt bar, filling it with given arguments.+open :: (BaseIO m, MonadReader t m, HasPromptBar t)+     => Text   -- ^ Description+     -> Text   -- ^ Pre-fill value+     -> m ()+open a b = do+    debugM "hbro.promptbar" "Opening prompt."+    void . open' a b =<< askL _promptbar++open' :: (BaseIO m) => Text -> Text -> PromptBar -> m PromptBar+open' newDescription defaultText =+    withM_ descriptionL (gAsync . (`labelSetText` newDescription))+        >=> withM_ entryL (gAsync . (`entrySetText` defaultText))+        >=> withM_ boxL (gAsync . widgetShow)+        >=> withM_ entryL (gAsync . widgetGrabFocus)+        >=> withM_ entryL (gAsync . (`editableSetPosition` (-1)))++unhide, hide :: (BaseIO m, MonadReader t m, HasPromptBar t) => m ()+unhide = gAsync . widgetShow =<< askL (_promptbar.boxL)+hide   = gAsync . widgetHide =<< askL (_promptbar.boxL)++-- | Close prompt, that is: clean its content, signals and callbacks+clean :: (BaseIO m, MonadReader t m, HasPromptBar t, HasPromptHooks n t) => m ()+clean = do+    gAsync . (`widgetRestoreText` StateNormal)           =<< askL (_promptbar.entryL)+    gAsync . (\e -> widgetModifyText e StateNormal gray) =<< askL (_promptbar.entryL)++    hide+    Hooks.clean+++-- {{{ Prompts+-- | Same as 'prompt\'' without the value-changed callback+prompt :: (BaseIO m, MonadError Text m, MonadReader t m, HasPromptBar t, HasPromptHooks n t, BaseIO n)+     => Text                       -- ^ Prompt description+     -> Text                       -- ^ Initial value+     -> m Text+prompt a b = prompt' a b (const $ return ())+++-- | Open prompt bar with given description and default value,+-- register a callback to trigger when value is changed, and another one when value is validated.+prompt' :: (BaseIO m, MonadError Text m, MonadReader t m, HasPromptBar t, HasPromptHooks n t, BaseIO n)+        => Text             -- ^ Prompt description+        -> Text             -- ^ Pre-fill value+        -> (Text -> n ())   -- ^ Callback triggered each time prompt value changes+        -> m Text+prompt' description startValue f = do+    clean+    open description startValue+    result <- newEmptyMVar++    Hooks.set onChangedL $ \(Changed x) -> f x+    Hooks.set onCancelledL $ \_ -> putMVar result Nothing+    Hooks.set onValidatedL $ \(Activated x) -> putMVar result (Just x)+    takeMVar result <!> promptInterrupted+++-- | Same as 'prompt\'' for URI values+promptURI :: (BaseIO m, BaseIO n, MonadError Text m, MonadError Text n, MonadReader t m, MonadReader t n, HasPromptBar t, HasPromptHooks n t)+          => Text -> Text -> m URI+promptURI description startValue = do+    clean+    open description startValue+    checkURI (Changed startValue)++    result <- newEmptyMVar++    Hooks.set onChangedL checkURI+    Hooks.set onCancelledL $ \_ -> putMVar result Nothing+    Hooks.set onValidatedL $ \(Activated uri) -> putMVar result (Just uri)++    parseURIReference =<< takeMVar result <!> promptInterrupted+++checkURI :: (BaseIO m, MonadReader t m, HasPromptBar t) => Changed -> m ()+checkURI (Changed v) = do+    debugM "hbro.prompt" $ "Is URI ? " ++ tshow (isURIReference $ unpack v)+    (gAsync . \e -> widgetModifyText e StateNormal (green <| isURIReference (unpack v) |> red)) =<< askL (_promptbar.entryL)+++getEntryValue :: (BaseIO m, MonadReader t m, HasPromptBar t) => m Text+getEntryValue = gSync . entryGetText =<< askL (_promptbar.entryL)
+ library/Hbro/Gui/PromptBar/Hooks.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE TemplateHaskell #-}+module Hbro.Gui.PromptBar.Hooks+    ( PromptHooks+    , onCancelledL+    , onChangedL+    , onValidatedL+    , initHooks+    , HasPromptHooks(..)+    , clean+    , set+    ) where++-- {{{ Imports+-- import Hbro.Error+import Hbro.Gui.PromptBar.Signals+import Hbro.Prelude++import Control.Lens.Lens+import Control.Lens.Getter+import Control.Lens.Setter hiding(set)+import Control.Lens.TH+import Control.Monad.Reader hiding(when)+-- }}}++-- | No exported constructor, please use 'initHooks'+data PromptHooks m = PromptHooks+    { _onCancelled :: TMVar (Cancelled -> m ())+    , _onChanged   :: TMVar (Changed   -> m ())+    , _onValidated :: TMVar (Activated -> m ())+    }++makeLensesWith ?? ''PromptHooks $ lensRules+    & lensField .~ (\name -> Just (tail name ++ "L"))++class HasPromptHooks n a | a -> n where _promptHooks :: Lens' a (PromptHooks n)+instance HasPromptHooks n (PromptHooks n) where _promptHooks = id++initHooks :: (BaseIO m) => m (PromptHooks n)+initHooks = io (PromptHooks <$> newEmptyTMVarIO <*> newEmptyTMVarIO <*> newEmptyTMVarIO)++clean :: (BaseIO m, MonadReader t m, HasPromptHooks n t) => m ()+clean = do+    hooks <- askL _promptHooks+    void . atomically $ do+        tryTakeTMVar $ hooks^.onCancelledL+        tryTakeTMVar $ hooks^.onChangedL+        tryTakeTMVar $ hooks^.onValidatedL+++set :: (BaseIO m, MonadReader t m, HasPromptHooks n t) => Lens' (PromptHooks n) (TMVar (x -> n ())) -> (x -> n ()) -> m ()+set l f = do+    hook' <- askL $ _promptHooks.l+    atomically $ writeTMVar hook' f
+ library/Hbro/Gui/PromptBar/Signals.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE TemplateHaskell #-}+module Hbro.Gui.PromptBar.Signals (+-- * Utils+    onEntryCancelled,+    onEntryChanged,+    onEntryActivated,+-- * Signals+    Cancelled(..),+    Changed(..),+    Activated(..),+    Signals,+    cancelledL,+    changedL,+    validatedL,+    initSignals,+    attach,+) where++-- {{{ Imports+-- import Hbro.Error+import Hbro.Gdk.KeyVal+import Hbro.Logger+import Hbro.Prelude hiding(on)++import Control.Lens++import Graphics.UI.Gtk.Abstract.Widget+import Graphics.UI.Gtk.Entry.Editable+import Graphics.UI.Gtk.Entry.Entry+import Graphics.UI.Gtk.Gdk.EventM as Gdk++import System.Glib.Signals+-- }}}+++-- {{{ Utils+onEntryCancelled :: (BaseIO m, EntryClass t) => t -> (Cancelled -> IO ()) -> m (ConnectId t)+onEntryCancelled theEntry f = gSync . on theEntry keyPressEvent $ do+    key <- KeyVal <$> eventKeyVal+    io . when (key == _Escape) $ do+        value <- entryGetText theEntry+        debugM "hbro.prompt" $ "Prompt cancelled with value: " ++ value+        f (Cancelled value)+    return False++onEntryChanged :: (BaseIO m, EditableClass t, EntryClass t) => t -> (Changed -> IO ()) -> m (ConnectId t)+onEntryChanged theEntry f = gSync . on theEntry editableChanged $ do+    value <- entryGetText theEntry+    debugM "hbro.prompt" $ "Prompt value changed to: " ++ value+    f (Changed value)+++onEntryActivated :: (BaseIO m, EntryClass t) => t -> (Activated -> IO ()) -> m (ConnectId t)+onEntryActivated theEntry f = gSync . on theEntry entryActivated $ do+    value <- entryGetText theEntry+    debugM "hbro.prompt" $ "Prompt activated with value: " ++ value+    f (Activated value)+-- }}}++-- {{{ Types+data Cancelled = Cancelled Text+instance Describable Cancelled where describe _ = "PromptCancelled"++data Changed   = Changed Text+instance Describable Changed where describe _ = "PromptChanged"++data Activated = Activated Text+instance Describable Activated where describe _ = "PromptActivated"++data Signals = Signals+    { _cancelled   :: TMVar Cancelled+    , _changed     :: TMVar Changed+    , _validated   :: TMVar Activated+    }++makeLensesWith ?? ''Signals $ lensRules+    & lensField .~ (\name -> Just (tail name ++ "L"))+-- }}}++initSignals :: (BaseIO m) => m Signals+initSignals = io (Signals <$> newEmptyTMVarIO <*> newEmptyTMVarIO <*> newEmptyTMVarIO)+++attach :: (BaseIO m, EditableClass t, EntryClass t) => t -> Signals -> m ()+attach entry signals = void $ sequence+    [ onEntryCancelled entry $ void . atomically . tryPutTMVar (signals^.cancelledL)+    , onEntryChanged   entry $ void . atomically . tryPutTMVar (signals^.changedL)+    , onEntryActivated entry $ void . atomically . tryPutTMVar (signals^.validatedL)+    ]
+ library/Hbro/Gui/StatusBar.hs view
@@ -0,0 +1,30 @@+module Hbro.Gui.StatusBar where++-- {{{ Imports+import Hbro.Gui.Buildable+import Hbro.Prelude++import Graphics.UI.Gtk.Abstract.Widget+import Graphics.UI.Gtk.Builder+import Graphics.UI.Gtk.Layout.HBox++import System.Glib.Types+-- }}}++-- | Status bar is just a horizontal layout that can host widgets.+newtype StatusBar = StatusBar HBox++-- | A 'StatusBar' can be built from an XML file.+instance Buildable StatusBar where+    buildWith b = StatusBar <$> gSync (builderGetObject b castToHBox statusBarName)++instance GObjectClass StatusBar where+    toGObject (StatusBar h) = toGObject h+    unsafeCastGObject g     = StatusBar $ unsafeCastGObject g++-- instance ObjectClass StatusBar+instance WidgetClass StatusBar++-- | Name used in XML file to build status bar.+statusBarName :: String+statusBarName = "statusBox"
+ library/Hbro/Hooks.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE TemplateHaskell #-}+module Hbro.Hooks+    ( ResourceAction(..)+    , LinkClickedHook(..)+    , LoadRequestedHook(..)+    , NewWindowHook(..)+    , ResourceOpenedHook(..)+    , TitleChangedHook(..)+    , Hooks+    , keyHooksL+    , promptHooksL+    , webViewHooksL+    , initialize+    , routines+) where++-- {{{ Imports+import Hbro.Error+import qualified Hbro.Keys as Keys+import qualified Hbro.Keys.Signals as Keys+import qualified Hbro.IPC.Hooks as IPC+import Hbro.Signals hiding(initialize)+import Hbro.Gui.PromptBar.Signals hiding(Signals)+import Hbro.Gui.PromptBar.Hooks+import qualified Hbro.Gui.PromptBar.Hooks as Prompt+import Hbro.Logger hiding(initialize)+import Hbro.Prelude+import Hbro.WebView.Hooks hiding(Hooks)+import qualified Hbro.WebView.Hooks as WebView (Hooks, initHooks)+import Hbro.WebView.Signals hiding(Signals)++import Control.Lens.Getter+import Control.Lens.Lens+import Control.Lens.Setter+import Control.Lens.TH+import Control.Monad.Reader+-- }}}+++-- {{{ Hooks+data Hooks m = Hooks+    { _webViewHooks     :: WebView.Hooks m+    , _keyHooks         :: Keys.Hooks m+    , _ipcHooks         :: TVar (IPC.Hooks m)+    , _promptHooks      :: PromptHooks m+    }++makeLensesWith ?? ''Hooks $ lensRules+    & lensField .~ (\name -> Just (tail name ++ "L"))++initialize :: (Functor n, BaseIO m, Default (Keys.Status n), Default (LinkClickedHook n),+              Default (LoadRequestedHook n), Default (NewWindowHook n),+              Default (ResourceOpenedHook n), Default (TitleChangedHook n),+              Default (IPC.Hooks n))+          => m (Hooks n)+initialize = io (Hooks <$> WebView.initHooks+                      <*> Keys.initializeHooks+                      <*> newTVarIO def+                      <*> Prompt.initHooks)++routines :: (ControlIO m) => a -> Signals -> Hooks (ExceptT Text (ReaderT a m)) -> [m ()]+routines globalContext signals hooks =+-- WebView+    [ dequeueRoutine globalContext      (signals^._webViewSignals.downloadL)       $ hooks^.webViewHooksL.onDownloadL+    , dequeueRoutine globalContext      (signals^._webViewSignals.linkHoveredL)    $ hooks^.webViewHooksL.onLinkHoveredL+    , dequeueRoutine globalContext      (signals^._webViewSignals.linkClickedL)    $ hooks^.webViewHooksL.onLinkClickedL+    , dequeueRoutine globalContext      (signals^._webViewSignals.loadFinishedL)   $ hooks^.webViewHooksL.onLoadFinishedL+    , dequeueRoutine globalContext      (signals^._webViewSignals.loadRequestedL)  $ hooks^.webViewHooksL.onLoadRequestedL+    , dequeueRoutine globalContext      (signals^._webViewSignals.loadStartedL)    $ hooks^.webViewHooksL.onLoadStartedL+    , dequeueRoutine globalContext      (signals^._webViewSignals.newWindowL)      $ hooks^.webViewHooksL.onNewWindowL+    , dequeueRoutine globalContext      (signals^._webViewSignals.resourceOpenedL) $ hooks^.webViewHooksL.onResourceOpenedL+    , dequeueRoutine globalContext      (signals^._webViewSignals.titleChangedL)   $ hooks^.webViewHooksL.onTitleChangedL+-- Keys+    , Keys.dequeue globalContext  (signals^._webViewSignals.keyPressedL) $ hooks^.keyHooksL+-- IPC+    , IPC.dequeue globalContext   (signals^._ipcSignals) $ hooks^.ipcHooksL+-- Prompt+    , dequeueRoutine globalContext      (signals^._promptSignals.cancelledL) $ hooks^.promptHooksL.onCancelledL+    , dequeueRoutine globalContext      (signals^._promptSignals.changedL)   $ hooks^.promptHooksL.onChangedL+    , dequeueRoutine globalContext      (signals^._promptSignals.validatedL) $ hooks^.promptHooksL.onValidatedL+    ]+  -- where dequeueRoutine globalContext = dequeueRoutine globalContext+++dequeueRoutine :: (ControlIO m, Describable s)+               => a -> TMVar s -> TMVar (s -> ExceptT Text (ReaderT a m) ()) -> m ()+dequeueRoutine globalContext signal hook = forever $ do+    arguments <- atomically $ takeTMVar signal+    debugM "hbro.hooks" $ "Signal acknowledged [" ++ describe arguments ++ "]."++    (`runReaderT` globalContext) . logErrors' $ do+        f <- (atomically $ tryReadTMVar hook) <!> ("Undefined hook: " ++ describe arguments)+        handleIO (throwError . tshow) $ f arguments+-- }}}
+ library/Hbro/IPC.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE TemplateHaskell, TupleSections #-}+-- | Designed to be imported as @qualified@.+module Hbro.IPC+    ( routine+    , sendMessage+    ) where++-- {{{ Imports+import Hbro.IPC.Signals+import Hbro.Logger+import Hbro.Prelude++import Control.Lens hiding(Action, Context)++import System.ZMQ4.Monadic (ZMQ, Rep(..), Req(..), runZMQ)+import qualified System.ZMQ4.Monadic as ZMQ+-- }}}++-- | Designed to be run in a distinct thread+routine :: Text -> Signals -> ZMQ z ()+routine uri signals = do+    socket <- ZMQ.socket Rep+    io . infoM "hbro.ipc" $ "Opening IPC socket at: " ++ uri+    ZMQ.bind socket (unpack uri)++    forever $ do+      message <- receive socket+      io . debugM "hbro.ipc" $ "Received command: " ++ message++      case words message of+          []                -> send socket "ERROR Empty command"+          command:arguments -> do+              atomically $ putTMVar nextCommand (Command command, arguments)+              response' <- atomically $ takeTMVar response+              io . debugM "hbro.ipc" $ "Sending response: " ++ tshow response'+              send socket $ either ("ERROR " ++) id response'+    where+      nextCommand = signals^.nextCommandL+      response    = signals^.responseL++-- {{{ Utils+-- | Send message to given socket+send :: (ZMQ.Sender a) => ZMQ.Socket z a -> Text -> ZMQ z ()+send socket payload = ZMQ.send socket [] (encodeUtf8 payload)++-- | Send a single command to the given socket (which must be 'Rep'), and return the answer+sendMessage :: (BaseIO m)+            => Text   -- ^ Target socket URI+            -> Text   -- ^ Message+            -> m Text+sendMessage socketURI message = runZMQ $ do+    socket <- ZMQ.socket Req+    ZMQ.bind socket (unpack socketURI)+    io . debugM "hbro.ipc" $ "Sending message to IPC socket at: " ++ socketURI+    send socket message+    receive socket++-- | Wait for a message to be received from given socket+receive :: (ZMQ.Receiver a) => ZMQ.Socket z a -> ZMQ z Text+receive socket = decodeUtf8 <$> ZMQ.receive socket++-- | Same as 'sendMessage', but for all running instances of the browser.+-- sendMessageToAll :: (MonadBase IO m, MonadReader t m, HasConfig t) => String -> m [String]+-- sendMessageToAll message = do+--     dir  <- readConfig socketDir+--     getAllProcessIDs >>= mapM ((`sendMessage` message) . (`socketPath` dir))+-- }}}
+ library/Hbro/IPC/Hooks.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE TemplateHaskell #-}+module Hbro.IPC.Hooks where++-- {{{ Imports+import Hbro.Error+import Hbro.IPC.Signals+import Hbro.Prelude++import Control.Lens hiding(Action)+import Control.Monad.Reader++import Data.Map as M+-- }}}++-- {{{ Types+type Action m   = [Argument] -> (m Response)       -- ^ Actions may depend on arguments+newtype Hooks m = Hooks (Map Command (Action m))   -- ^ Map commands to actions+-- }}}++-- | Bind a new command to an action+bind :: Command -> Action m -> Hooks m -> Hooks m+bind command f (Hooks hooks) = Hooks $ M.insert command f hooks++-- |+dequeue :: (BaseIO m) => a -> Signals -> TVar (Hooks (ExceptT Text (ReaderT a m))) -> m ()+dequeue globalContext signals bindings = forever $ do+    (Command c, arguments) <- atomically . takeTMVar $ nextCommand+    (Hooks theBindings)    <- atomically $ readTVar bindings++    -- result <- (`runReaderT` globalContext) . handleAll (return . Left . show) $ do+    result <- (`runReaderT` globalContext) . runExceptT $ do+        f <- return (M.lookup (Command c) theBindings) <!> ("Unknown command: " ++ c)+        f arguments+    atomically . putTMVar response $ join result+  where+    nextCommand = signals^.nextCommandL+    response    = signals^.responseL
+ library/Hbro/IPC/Signals.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE TemplateHaskell, TupleSections #-}+-- | Designed to be imported as @qualified@.+module Hbro.IPC.Signals+    ( Argument+    , Response+    , Command(..)+-- * Signals+    , Signals+    , nextCommandL+    , responseL+    , initSignals+) where++-- {{{ Imports+import Hbro.Prelude++import Control.Lens hiding(Action, Context)+-- }}}+++-- {{{ Types+-- | Commands are mere 'Text's+newtype Command = Command Text deriving(Eq, Ord)++-- | Arguments are 'Text's too+type Argument = Text++-- | Responses may be OK or KO+type Response = Either Text Text+-- type Queue    = [(Command, [Argument])]++data Signals = Signals+    { _nextCommand :: TMVar (Command, [Argument])+    , _response    :: TMVar Response+    }++makeLensesWith ?? ''Signals $ lensRules+    & lensField .~ (\name -> Just (tailSafe name ++ "L"))+-- }}}++initSignals :: (BaseIO m) => m Signals+initSignals = io (Signals <$> newEmptyTMVarIO <*> newEmptyTMVarIO)
+ library/Hbro/K.hs view
@@ -0,0 +1,165 @@+{-# LANGUAGE TemplateHaskell, TypeFamilies #-}+module Hbro.K (+    KData,+    K,+    init,+    getHooks,+    resetKeyBindings,+) where++-- {{{+import Hbro.Clipboard as Clipboard+import Hbro.Config as Config+import Hbro.Core+import Hbro.Error+import Hbro.Gdk.KeyVal+import Hbro.Gui as Gui+import Hbro.Gui.NotificationBar+import Hbro.Gui.PromptBar as Prompt+-- import Hbro.IPC as IPC (Command(..))+import Hbro.IPC.Hooks as IPC+import Hbro.IPC.Signals as IPC+import Hbro.Keys as Keys+import Hbro.Keys.Model ((.|))+import Hbro.Keys.Monadic as Keys+import Hbro.Hooks as Hooks+import Hbro.Signals as Signals+import Hbro.Gui.PromptBar.Hooks+import Hbro.Prelude+import Hbro.WebView.Hooks as WebView+import Hbro.WebView.Signals as WebView++-- import Control.Lens.Getter+import Control.Lens.Lens+import Control.Lens.Setter+import Control.Lens.TH+import Control.Monad.Reader++import Data.Map as M hiding(foldl, map)++import Graphics.UI.Gtk.Gdk.EventM as Gdk+import Graphics.UI.Gtk.Windows.Window+import Graphics.UI.Gtk.WebKit.WebView++import Network.URI.Monadic++import qualified System.Glib.Attributes as G+-- }}}++data KData = KData+    { _config      :: TVar Config+    , _gui         :: GUI+    , _hooks       :: Hooks.Hooks KE+    , _signals     :: Signals.Signals+    }++type K  = ReaderT KData IO+type KE = ExceptT Text K++makeLensesWith ?? ''KData $ lensRules+    & lensField .~ (\name -> Just (tailSafe name ++ "L"))+++instance HasConfig KData           where _config          = configL+instance HasGUI KData              where _gui             = guiL+instance Keys.HasHooks KE KData    where _hooks           = hooksL.keyHooksL+instance HasPromptHooks KE KData   where _promptHooks     = hooksL.promptHooksL+instance WebView.HasHooks KE KData where _hooks           = hooksL.webViewHooksL+instance HasNotificationBar KData  where _notificationbar = guiL.notificationBarL+instance HasPromptBar KData        where _promptbar       = guiL.promptBarL+++init :: (BaseIO m) => GUI -> Hooks.Hooks KE -> Signals.Signals -> m KData+init ui hooks signals = io (KData <$> newTVarIO def <*> pure ui <*> pure hooks <*> pure signals)++getHooks :: (MonadReader KData m) => m (Hooks.Hooks KE)+getHooks = askL hooksL++-- {{{ Default configuration+-- instance Default (Signals.DownloadHook KE) where+    -- def = Signals.DownloadHook . const . const . const $ return ()++instance Default (Hooks.LinkClickedHook KE) where+    def = Hooks.LinkClickedHook f+            where f (LinkClicked uri Gdk.MiddleButton) = spawn "hbro" ["-u", show uri]+                  f (LinkClicked uri _               ) = load uri++instance Default (Hooks.LoadRequestedHook KE) where+    def = Hooks.LoadRequestedHook $ \(LoadRequested uri) -> load uri++instance Default (Hooks.NewWindowHook KE) where+    def = Hooks.NewWindowHook $ \(NewWindow uri) -> spawn "hbro" ["-u", show uri]++-- /!\ NetworkRequest's Haskell binding is missing the function "webkit_network_request_get_message", which makes it rather useless...+-- | Display content if webview can show the given MIME type, otherwise download it.+instance Default (Hooks.ResourceOpenedHook KE) where+    def = Hooks.ResourceOpenedHook $ \(ResourceOpened _uri mimetype) -> do+        return Hooks.Load <<| canRender mimetype |>> return Hooks.Download'++instance Default (Hooks.TitleChangedHook KE) where+    def = Hooks.TitleChangedHook (\(TitleChanged title) -> gAsync . (`G.set` [ windowTitle G.:= ("hbro | " ++ title)]) =<< Gui.get mainWindowL)+++-- | List of default supported requests.+instance Default (IPC.Hooks KE) where+    def = IPC.Hooks . M.fromList . map (first IPC.Command) $ [+    -- Get information+        ("GET_URI",             \_arguments -> Right . tshow <$> getCurrentURI),+        ("GET_TITLE",           \_arguments -> Right <$> getPageTitle),+        ("GET_FAVICON_URI",     \_arguments -> Right . tshow <$> getFaviconURI),+        ("GET_LOAD_PROGRESS",   \_arguments -> Right . tshow <$> getLoadProgress),+    -- Trigger actions+        ("LOAD_URI",            \arguments -> case arguments of+            uri:_ -> parseURIReference uri >>= load >> (return $ Right "OK")+            _     -> return . Left $ "Argument needed."),+        ("STOP_LOADING",        \_arguments -> stopLoading       >> (return $ Right "OK")),+        ("RELOAD",              \_arguments -> reload            >> (return $ Right "OK")),+        ("RELOAD_BYPASS_CACHE", \_arguments -> reloadBypassCache >> (return $ Right "OK")),+        ("GO_BACK",             \_arguments -> goBack            >> (return $ Right "OK")),+        ("GO_FORWARD",          \_arguments -> goForward         >> (return $ Right "OK")),+        ("ZOOM_IN",             \_arguments -> zoomIn            >> (return $ Right "OK")),+        ("ZOOM_OUT",            \_arguments -> zoomOut           >> (return $ Right "OK"))]+++resetKeyBindings :: (BaseIO m, MonadReader t m, Keys.HasHooks (ExceptT Text K) t) => m ()+resetKeyBindings = do+-- Browse+    Keys.bind (_Alt     .| _Left)   $ goBack+    Keys.bind (_Alt     .| _Right)  $ goForward+    Keys.bind (_Control .| _Escape) $ stopLoading+    Keys.bind _F5                   $ reload+    Keys.bind (_Control .| _r)      $ reload+    Keys.bind (_Control .| _F5)     $ reloadBypassCache+    Keys.bind (_Alt     .| _r)      $ reloadBypassCache+    Keys.bind (_Control .| _dead_circumflex) $ scrollH (Absolute 0)+    Keys.bind (_Control .| _dollar) $ scrollH (Absolute 100)+    Keys.bind (_Control .| _Home)   $ scrollV (Absolute 0)+    Keys.bind (_Control .| _End)    $ scrollV (Absolute 100)+    Keys.bind (_Alt     .| _Home)   $ goHome+-- Copy/paste+    Keys.bind (_Control .| _c)      $ getCurrentURI >>= Clipboard.write . tshow+    Keys.bind (_Alt     .| _c)      $ getPageTitle >>= Clipboard.write+    Keys.bind (_Control .| _v)      $ Clipboard.read >>= parseURIReference >>= load+    Keys.bind (_Alt     .| _v)      $ Clipboard.read >>= spawn "hbro" . ("-u":) . (:[]) . unpack+-- Display+    Keys.bind (_Control .| _plus)   $ zoomIn+    Keys.bind (_Control .| _minus)  $ zoomOut+    Keys.bind (_Control .| _b)      $ Gui.toggle =<< Gui.get statusBarL+    Keys.bind (_Alt     .| _b)      $ Gui.toggle =<< Gui.get notificationBarL+    Keys.bind (_Control .| _u)      $ toggleSourceMode >> reload+-- Prompt+    Keys.bind (_Control .| _o)      $ promptURI "Open URI" "" >>= load+    Keys.bind (_Alt     .| _o)      $ getCurrentURI >>= \uri -> promptURI "Open URI " (tshow uri) >>= load+-- Search+    Keys.bind _slash                $ void $ prompt' "Search " "" $ searchText_ CaseInsensitive Forward Wrap+    Keys.bind (_Control .| _f)      $ prompt "Search " "" >>= searchText_ CaseInsensitive Forward Wrap+    Keys.bind _question             $ void $ prompt' "Search " "" $ searchText_ CaseInsensitive Backward Wrap+    Keys.bind (_Control .| _n)      $ searchText_ CaseInsensitive Forward  Wrap =<< Prompt.getEntryValue+    Keys.bind (_Control .| _p)      $ searchText_ CaseInsensitive Backward Wrap =<< Prompt.getEntryValue+    Keys.bind (_Control .| _h)      $ gAsync . webViewUnMarkTextMatches =<< Gui.get webViewL+-- Misc+    -- Keys.bind (_Control .| _i)      $ openInspector+    Keys.bind (_Alt     .| _Print)  printPage+    Keys.bind (_Control .| _t)      $ spawn "hbro" []+    Keys.bind (_Control .| _w)      quit+-- }}}
+ library/Hbro/Keys.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE TemplateHaskell, TupleSections, ViewPatterns #-}+-- | Key bindings model.+-- Designed to be imported as @qualified@.+module Hbro.Keys (+-- * Modifiers+      Modifier(..)+    , _Alt+    , _Control+    , _Shift+    , modifier+-- * Mode+    , Mode(..)+-- * Bindings implementation+    , KeyStroke+    , keyStroke+    , Bindings+    , Status+    , Hooks+    , statusL+    , onKeyPressedL+-- * Interface+    , HasHooks(..)+    , initializeHooks+    , Hbro.Keys.set+    ) where++-- {{{ Imports+import Hbro.Gdk.KeyVal+import Hbro.Keys.Model ((.|), modifiersL, keyL)+import qualified Hbro.Keys.Model as Model+import Hbro.Prelude++import Control.Lens.Getter+import Control.Lens.Lens+import Control.Lens.Setter+import Control.Lens.TH+import Control.Monad.Reader hiding(forM_, guard, mapM_)++import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.Set as Set++import qualified Graphics.UI.Gtk.Gdk.EventM as Gdk++import Text.Parsec+import Text.Parsec.Text+-- }}}++-- {{{ Modifiers+newtype Modifier = Modifier Gdk.Modifier deriving(Eq)++instance Describable Modifier where+    describe (Modifier Gdk.Control) = "C-"+    describe (Modifier Gdk.Shift)   = "S-"+    describe (Modifier Gdk.Alt)     = "M-"+    describe (Modifier _)           = ""++instance Ord Modifier where compare = comparing describe++instance ToSet Modifier Modifier where toSet = Set.singleton++_Alt, _Control, _Shift :: Modifier+_Alt     = Modifier Gdk.Alt+_Control = Modifier Gdk.Control+_Shift   = Modifier Gdk.Shift++modifier :: Parser Modifier+modifier = spaces *> choice [ string "C-" >> return _Control+                            , string "M-" >> return _Alt+                            -- , string "S-" >> return _Shift+                            ]+-- }}}++-- {{{ Key mode (à la vi)+data Mode = Normal | Insert deriving(Eq, Ord)++instance Default Mode where def = Normal+-- }}}++-- {{{ Bindings implementation+type KeyStroke  = Model.KeyStroke Modifier KeyVal++instance Describable KeyStroke where+   describe s = foldr (++) "" (map describe . Set.toList $ s^.modifiersL) ++ describe (s^.keyL)++instance ToNonEmpty KeyStroke KeyStroke where+    toNonEmpty x = x :| []++instance ToNonEmpty KeyStroke KeyVal where+    toNonEmpty x = ((Set.empty .| x) :| [])++keyStroke :: Parser KeyStroke+keyStroke = do+    spaces+    m <- maybe Set.empty Set.singleton <$> optionMaybe modifier+    k <- keyVal+    return $ Model.KeyStroke m k++-- type Binding m  = Model.Binding  Hbro.Keys.Stroke (m ())+type Bindings m = Model.Bindings KeyStroke (m ())+type Status m   = Model.Status KeyStroke Mode (m ())+data Hooks m    = Hooks+    { _status       :: TVar (Status m)+    , _onKeyPressed :: TMVar ([KeyStroke] -> m ())+    }++makeLensesWith ?? ''Hooks $ lensRules+    & lensField .~ (\name -> Just (tail name ++ "L"))++class HasHooks m t | t -> m where _hooks :: Lens' t (Hooks m)++instance HasHooks m (Hooks m) where _hooks = id++initializeHooks :: IO (Hooks m)+initializeHooks = Hooks <$> newTVarIO def <*> newEmptyTMVarIO++set :: (BaseIO m, MonadReader r m, HasHooks n r) => Lens' (Hooks n) (TMVar a) -> a -> m ()+set l v = atomically . (`writeTMVar` v) =<< askL (_hooks.l)+-- }}}+++{-instance Monoid KeyMap where+    mempty = KeyBindings M.empty+    mappend (KeyBindings a) (KeyBindings b) = KeyBindings (mappend a b)-}
+ library/Hbro/Keys/Model.hs view
@@ -0,0 +1,170 @@+{-# LANGUAGE TemplateHaskell, TupleSections #-}+-- | Key bindings model.+-- Designed to be imported as @qualified@.+module Hbro.Keys.Model (+-- * Key strokes model+    KeyStroke(..),+    modifiersL,+    keyL,+    (.|),+-- * Bindings model+    Binding,+    Bindings,+    Tree(..),+    ModalBindings,+    (-->),+    insert,+    merge,+    Hbro.Keys.Model.lookup,+-- * State machine+    Status(Status),+    modeL,+    keyStrokesL,+    bindingsL,+    bind,+    bind',+    setMode,+    press,+    getBoundFunction,+    resetStrokes,+) where++-- {{{ Imports+import Hbro.Prelude hiding(lookup)++import Control.Lens ()+import Control.Lens.Getter+import Control.Lens.Lens+import Control.Lens.Setter+import Control.Lens.TH++import Data.List.NonEmpty (NonEmpty(..), nonEmpty)+import qualified Data.List.NonEmpty as NE (fromList, toList)+import qualified Data.Map as M++import qualified Prelude (lookup)+-- }}}++-- {{{ Key strokes model+-- | A single keystroke is a (possibly empty) set of (unorderered and unique) modifiers, and a single key.+data KeyStroke modifier key = KeyStroke+    { _modifiers :: Set modifier+    , _key       :: key+    } deriving (Eq, Ord)++makeLensesWith ?? ''KeyStroke $ lensRules+    & lensField .~ (\name -> Just (tailSafe name ++ "L"))++(.|) :: (ToSet modifier m) => m -> key -> KeyStroke modifier key+(.|) m k = KeyStroke (toSet m) k+-- }}}++-- {{{ Binding model+-- | A binding is simply a (non-empty) list of strokes bound to an action+type Binding keystroke action = (NonEmpty keystroke, action)++-- | A non-empty tree implementation that labels edges and leaves+type BranchedTree b l = [(b, Tree b l)]+data Tree b l         = Leaf l | Branch (NonEmpty (b, Tree b l))++-- | Bindings are stored together in a tree structure+type Bindings keystroke action = BranchedTree keystroke action++-- | Modal bindings (à la vi)+type ModalBindings mode keystroke action = Map mode (Bindings keystroke action)+++(-->) :: (ToNonEmpty keystroke s) => s -> action -> Binding keystroke action+(-->) s a = (toNonEmpty s, a)+++-- | Make a branch out of a single binding+toBranch :: Ord a => (NonEmpty a, b) -> BranchedTree a b+toBranch  ((h:|[]),   a) = [ (h, Leaf a) ]+toBranch  ((h:|h':t), a) = [ (h, Branch $ toBranch' ((h':|t), a)) ]++toBranch' :: (NonEmpty b, l) -> NonEmpty (b, Tree b l)+toBranch' ((h:|[]),   a) = (h, Leaf a) :| []+toBranch' ((h:|h':t), a) = (h, Branch $ toBranch' ((h':|t), a)) :| []++-- | Merge 2 trees. In case of conflicts, prefer the rightmost operand.+merge :: Ord a => BranchedTree a b -> BranchedTree a b -> BranchedTree a b+merge [] []         = []+merge []  b         = b+merge a  []         = a+merge (h:t) (h':t') = NE.toList $ merge' (h:|t) (h':|t')++merge' :: (Ord k, Ord a)+       => NonEmpty (k, Tree a b) -> NonEmpty (k, Tree a b) -> NonEmpty (k, Tree a b)+merge' a b = NE.fromList . M.assocs $ M.unionWith merge'' (M.fromList $ NE.toList a) (M.fromList $ NE.toList b)++merge'' :: Ord a => Tree a b -> Tree a b -> Tree a b+merge'' (Leaf _)   (Leaf b)   = Leaf b+merge'' (Leaf _)   (Branch b) = Branch b+merge'' (Branch _) (Leaf b)   = Leaf b+merge'' (Branch a) (Branch b) = Branch $ merge' a b++-- | Is there a leaf at the end of the given path ?+lookup :: Ord a => NonEmpty a -> BranchedTree a b -> Maybe b+lookup a b = case walk a b of+    Just (Leaf x) -> Just x+    _             -> Nothing++-- | Return the subtree rooted at the end of the given path+walk :: Ord a => NonEmpty a -> BranchedTree a b -> Maybe (Tree a b)+walk _       []  = Nothing+walk (h:|t) tree = Prelude.lookup h tree >>= walk' t++walk' :: (Ord a) => [a] -> Tree a t -> Maybe (Tree a t)+walk' []    tree       = Just tree+walk' (h:t) (Branch b) = walk (h:|t) (NE.toList b)+walk' _     _          = Nothing++-- | Insert new binding into a tree-structured bindings list+insert :: (Ord m, Ord s) => Binding s a -> m -> ModalBindings m s a -> ModalBindings m s a+insert binding theMode = M.insertWith (flip merge) theMode (toBranch binding)+-- }}}++-- | Global state including any necessary information to handle key bindings+data Status keystroke mode action = Status+    { _mode       :: mode                                -- ^ Current mode+    , _keyStrokes :: [keystroke]                         -- ^ Previous keystrokes+    , _bindings   :: ModalBindings mode keystroke action -- ^ Current bindings+    }++makeLensesWith ?? ''Status $ lensRules+    & lensField .~ (\name -> Just (tail name ++ "L"))++instance (Default mode) => Default (Status keystroke mode action) where+    def = Status def [] M.empty+++bind' :: (Ord mode, Ord keystroke, ToNonEmpty keystroke s)+      => mode -> s -> action -> Status keystroke mode action -> Status keystroke mode action+bind' theMode theStrokes action (Status a b c) = Status a b $ insert (theStrokes --> action) theMode c++-- | Same as 'bind' with default mode.+bind :: (Ord mode, Default mode, Ord keystroke, ToNonEmpty keystroke s)+      => s -> action -> Status keystroke mode action -> Status keystroke mode action+bind s f = bind' def s f++setMode :: mode -> Status keystroke mode action -> Status keystroke mode action+setMode newMode = set modeL newMode . set keyStrokesL []++press :: (Ord mode, Ord keystroke) => keystroke -> Status keystroke mode action -> Status keystroke mode action+press keystroke status = set keyStrokesL newKeyStrokes status+  where+    oldKeyStrokes   = status^.keyStrokesL+    bindings        = M.lookup (status^.modeL) (status^.bindingsL)+    validKeyStrokes = isJust . join $ walk   <$> nonEmpty oldKeyStrokes <*> bindings+    boundKeyStroke  = isJust . join $ lookup <$> nonEmpty oldKeyStrokes <*> bindings+    newKeyStrokes   = (oldKeyStrokes ++ [keystroke]) <| (validKeyStrokes && not boundKeyStroke) |> [keystroke]++getBoundFunction :: (Ord mode, Ord keystroke) => Status keystroke mode action -> Maybe action+getBoundFunction status = do+    theStrokes  <- nonEmpty $ status^.keyStrokesL+    theBindings <- M.lookup (status^.modeL) (status^.bindingsL)+    lookup theStrokes theBindings++resetStrokes :: Status keystroke mode action -> Status keystroke mode action+resetStrokes = set keyStrokesL []
+ library/Hbro/Keys/Monadic.hs view
@@ -0,0 +1,45 @@+module Hbro.Keys.Monadic where++-- {{{ Imports+import Hbro.Keys+import qualified Hbro.Keys.Model as Keys+import Hbro.Prelude++import Control.Lens.Type+import Control.Monad.Reader++-- import Data.List.NonEmpty as NE+-- import Data.Map as M+-- import Data.Set (Set)+-- }}}+++modify :: (MonadReader r m, BaseIO m, HasHooks n r) => Lens' (Hooks n) (TVar a) -> (a -> a) -> m ()+modify l f = io . atomically . (`modifyTVar` f) =<< askL (_hooks.l)++bind' :: (HasHooks n r, ToNonEmpty KeyStroke s, BaseIO m, MonadReader r m)+      => Mode -> s -> n () -> m ()+bind' mode strokes action = modify statusL $ Keys.bind' mode strokes action++bind :: (HasHooks n r, ToNonEmpty KeyStroke s, BaseIO m, MonadReader r m)+     => s -> n () -> m ()+bind strokes action = modify statusL $ Keys.bind strokes action++-- setMode :: mode -> Status stroke mode action -> Status stroke mode action+-- setMode newMode = set _mode newMode . set _strokes []++-- press :: (Ord mode, Ord stroke) => stroke -> Status stroke mode action -> Status stroke mode action+-- press stroke status = set _strokes newStrokes status+--   where+--     newStrokes     = maybe [stroke] (const chainedStrokes) $ walk (NE.fromList chainedStrokes) =<< bindings+--     chainedStrokes = status^._strokes ++ [stroke]+--     bindings       = M.lookup (status^._mode) (status^._bindings)++-- getBoundFunction :: (Ord mode, Ord stroke) => Status stroke mode action -> Maybe action+-- getBoundFunction status = do+--     theStrokes  <- nonEmpty $ status^._strokes+--     theBindings <- M.lookup (status^._mode) (status^._bindings)+--     lookup theStrokes theBindings++-- resetStrokes :: Status stroke mode action -> Status stroke mode action+-- resetStrokes = set _strokes []
+ library/Hbro/Keys/Signals.hs view
@@ -0,0 +1,39 @@+module Hbro.Keys.Signals where++-- {{{ Imports+import Hbro.Error+-- import Hbro.Gdk.KeyVal+import Hbro.Keys as Keys+import Hbro.Keys.Model hiding(KeyStroke)+import Hbro.Logger+import Hbro.Prelude++import Control.Lens.Getter+import Control.Monad.Reader hiding(forM_)+-- }}}++data KeyPressed = KeyPressed KeyStroke+++dequeue :: (BaseIO m) => a -> TMVar KeyPressed -> Keys.Hooks (ExceptT Text (ReaderT a m)) -> m ()+dequeue globalContext signal hooks = forever $ do+    -- debugM "hbro.hooks" "Listening for key-pressed signal..."+    (KeyPressed stroke) <- atomically $ takeTMVar signal+    theStatus           <- atomically $ readTVar (hooks^.statusL)++    let newStatus    = press stroke theStatus+        newChain     = newStatus^.keyStrokesL+        f            = getBoundFunction newStatus++    debugM "hbro.hooks" $ "Key pressed signal acknowledged: " ++ unwords (map describe newChain)++    g <- atomically . tryReadTMVar $ hooks^.onKeyPressedL+    forM_ g $ \g' -> do+        debugM "hbro.hooks" "Global callback defined, executing it."+        (`runReaderT` globalContext) . logErrors_ $ g' newChain++    forM_ f $ \f' -> do+        debugM "hbro.hooks" "Key is bound, executing callback..."+        (`runReaderT` globalContext) . logErrors_ $ f'++    atomically . modifyTVar (hooks^.statusL) $ const newStatus
+ library/Hbro/Logger.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE OverloadedStrings #-}+module Hbro.Logger+    ( module X+    , initialize+-- * Redefinitions+    , debugM+    , errorM+    , infoM+) where++-- {{{ Imports+import Hbro.Prelude++import Control.Concurrent (myThreadId)++import Data.Text (justifyLeft, replace)++import System.Log as X (Priority(..))+import System.Log.Formatter+import System.Log.Handler.Simple+import System.Log.Logger (Logger, rootLoggerName, setLevel, setHandlers, updateGlobalLogger)+import qualified System.Log.Logger as L+-- }}}++initialize :: (BaseIO m) => Priority -> m ()+initialize = io . updateGlobalLogger rootLoggerName . setup++setup :: Priority -> Logger -> Logger+setup level = setLevel level . setHandlers [logHandler]++logHandler :: GenericHandler ()+logHandler = GenericHandler+    { priority  = DEBUG+    , formatter = logFormatter "$my_time $my_prio $my_tid $msg"+    , privData  = ()+    , writeFunc = \_ t -> putStrLn $ pack t+    , closeFunc = \_ -> return ()+    }++logFormatter :: String -> LogFormatter a+logFormatter string handler (prio, message) loggername = varFormatter+    [ ("my_prio", return $ formatPriority prio)+    , ("my_time", formatTime defaultTimeLocale "%F %T" <$> getCurrentTime)+    , ("my_tid",  unpack . justifyLeft 5 ' ' . replace "ThreadId " "#" . tshow <$> myThreadId)+    ]+    string handler (prio, message) loggername++formatPriority :: Priority -> String+formatPriority WARNING   = "WARN "+formatPriority CRITICAL  = "CRIT "+formatPriority INFO      = "INFO "+formatPriority p         = unpack . justifyLeft 5 ' ' . take 5 $ tshow p++-- | Better version of 'debugM'+debugM :: (BaseIO m) => Text -> Text -> m ()+debugM a b = io $ L.debugM (unpack a) (unpack b)++-- | Better version of 'errorM'+errorM :: (BaseIO m) => Text -> Text -> m ()+errorM a b = io $ L.errorM (unpack a) (unpack b)++-- | Better version of 'infoM'+infoM :: (BaseIO m) => Text -> Text -> m ()+infoM a b = io $ L.infoM (unpack a) (unpack b)
+ library/Hbro/Options.hs view
@@ -0,0 +1,182 @@+{-# LANGUAGE TemplateHaskell, ViewPatterns #-}+-- | Commandline options tools.+module Hbro.Options (+-- * Types+      CliOptions()+    , startURIL+    , socketPathL+    , dyreModeL+    , uiFileL+    , dyreDebugL+-- * Util+    , parseOptions+    , usage+    , getSocketURI+) where++-- {{{ Imports+import qualified Hbro.Dyre as Dyre+import Hbro.Error+import Hbro.Logger as Logger+import Hbro.Prelude++import Control.Lens.Getter+import Control.Lens.Lens+import Control.Lens.Setter+import Control.Lens.TH++import Data.Version++import Filesystem++import Network.URI.Monadic++import Paths_hbro++import System.Console.GetOpt+import System.Posix.Process+import qualified System.ZMQ4 as ZMQ (version)++import Text.Read hiding(get, lift)+-- }}}++-- {{{ Types+-- | Available commandline options (cf @hbro -h@).+data CliOptions = CliOptions+    { _startURI   :: Maybe URI+    , _socketPath :: Maybe FilePath+    , _uiFile     :: Maybe FilePath+    , _dyreMode   :: Dyre.Mode+    , _dyreDebug  :: Bool+    } deriving(Eq)++makeLensesWith ?? ''CliOptions $ lensRules+    & lensField .~ (\name -> Just (tail name ++ "L"))++instance Describable CliOptions where+    describe opts = unwords $ catMaybes+        [ ("URI=" ++) . tshow <$> (opts^.startURIL)+        , ("SOCKET=" ++) . fpToText  <$> (opts^.socketPathL)+        , ("UI_FILE=" ++) . fpToText <$> (opts^.uiFileL)+        , Just . ("DYRE_MODE=" ++) . tshow $ opts^.dyreModeL+        , Just "DYRE_DEBUG" <| opts^.dyreDebugL |> Nothing+        ]++instance Default CliOptions where+    def = CliOptions+        { _startURI   = Nothing+        , _socketPath = Nothing+        , _uiFile     = Nothing+        , _dyreMode   = def+        , _dyreDebug  = False+        }+-- }}}++-- {{{ Util+action :: (BaseIO m, MonadPlus m) => m () -> ArgDescr (a -> m b)+action f = NoArg . const $ f >> abort++flag :: (Monad m) => Lens' CliOptions a -> a -> ArgDescr (CliOptions -> m CliOptions)+flag attribute value = NoArg $ return . set attribute value++optional :: (Monad m, IsString s) => Lens' CliOptions (Maybe s) -> String -> ArgDescr (CliOptions -> m CliOptions)+optional attribute name = ReqArg (\x -> return . set attribute (Just $ fromString x)) name+-- }}}++description :: (BaseIO m, MonadPlus m) => [OptDescr (CliOptions -> m CliOptions)]+description =+-- Action+    [ Option ['h']     ["help"]               (action help)+        "Print this help."+    , Option ['r']     ["recompile"]          (action recompile)+        "Recompile configuration file and exit."+    , Option ['V']     ["version"]            (action printVersion)+        "Print version."+-- Log level+    , Option ['v']     ["verbose"]            (setLogLevel DEBUG)+        "Equivalent to -l DEBUG."+    , Option ['q']     ["quiet"]              (setLogLevel ERROR)+        "Equivalent to -l ERROR."+    , Option ['l']     ["log-level"]          (ReqArg setCustomLogLevel "VALUE")+        "Set log level. VALUE may be one of DEBUG|INFO|NOTICE|WARNING|ERROR|CRITICAL|ALERT|EMERGENCY."+-- Paths+    , Option ['u']     ["uri"]                (ReqArg setStartURI "URI")+        "URI to load at start-up."+    , Option ['S']     ["socket"]             (optional socketPathL "PATH")+        "Where to open IPC socket"+    , Option ['U']     ["ui"]                 (optional uiFileL "PATH")+        "Path to UI descriptor (XML file)"+-- Dynamic reconfiguration+    , Option ['1']     ["vanilla"]            (flag dyreModeL Dyre.Vanilla)+        "Do not read custom configuration file"+    , Option []        ["force-reconf"]       (flag dyreModeL Dyre.ForceReconfiguration)+        "Recompile configuration file before starting the program"+    , Option []        ["dyre-master-binary"] (ReqArg (const return) "PATH")+        "Internal flag used for dynamic reconfiguration."+    , Option []        ["deny-reconf"]        (flag dyreModeL Dyre.IgnoreReconfiguration)+        "Do not recompile configuration file even if it has changed"+    , Option []        ["dyre-debug"]         (NoArg return)+        "Use './cache/' as the cache directory and ./ as the configuration directory. Useful to debug the program."+    ]+++help, printVersion, recompile :: (BaseIO m, MonadPlus m) => m ()+help         = putStrLn usage+recompile    = Dyre.recompile >>= mapM_ putStrLn+printVersion = do+    (a, b, c) <- io ZMQ.version+    putStrLn $ "hbro: v" ++ pack (showVersion version)+    putStrLn $ "0MQ library: v" ++ intercalate "." (map tshow [a, b, c])++setLogLevel :: (BaseIO m, MonadPlus m) => Priority -> ArgDescr (a -> m a)+setLogLevel priority = NoArg $ \options -> do+    Logger.initialize priority+    return options++setCustomLogLevel :: (BaseIO m) => String -> (a -> m a)+setCustomLogLevel level options = do+    maybe (errorM "hbro.options" message) Logger.initialize $ readMaybe level+    return options+  where message = "Invalid log level '" ++ pack level ++ "'."++-- | Parse URI passed in commandline, check whether it is a file path or an internet URI+-- and return the corresponding normalized URI (that is: prefixed with "file://" or "http://")+setStartURI :: (BaseIO m, MonadPlus m) => String -> (CliOptions -> m CliOptions)+setStartURI (pack -> uri) options = do+    fileURI    <- io . isFile $ fpFromText uri+    workingDir <- io getWorkingDirectory++    let fileURI' = ("file://" ++ fpToText workingDir ++ "/" ++ uri) <| fileURI |> uri+    parsedURI <- maybe abort return =<< logErrors (parseURIReference fileURI')++    return $ set startURIL (Just parsedURI) options++-- | Usage text (cf @hbro -h@)+usage :: Text+usage = pack $ usageInfo "Usage: hbro [OPTIONS]" (description :: [OptDescr (CliOptions -> IO CliOptions)])++-- | Get and parse commandline options+parseOptions :: (BaseIO m, MonadPlus m) => m CliOptions+parseOptions = do+    Logger.initialize INFO++    (opts, input', unknown', errors') <- io $ getOpt' Permute description . map unpack <$> getArgs+    let (input, unknown, errors) = (tailSafe $ (pack <$> input'), pack <$> unknown', pack <$> errors')++    unless (null errors)  $ errorM "hbro.options" (unlines errors) >> abort+    unless (null unknown) . infoM "hbro.options" $ "Unrecognized options: " ++ unwords unknown+    unless (null input) . infoM "hbro.options" $ "Ignored input: " ++ unlines input++    options <- foldl' (>>=) (return def) opts+    debugM "hbro.options" $ "Used options: " ++ describe options+    return options++-- | Return socket URI used by this instance+getSocketURI :: (BaseIO m) => CliOptions -> m Text+getSocketURI options = maybe getDefaultSocketURI (return . normalize) $ options^.socketPathL+  where+    normalize = ("ipc://" ++) . fpToText+    getDefaultSocketURI = do+      dir <- fpToText <$> (io $ getAppCacheDirectory "hbro")+      pid <- io getProcessID+      return $ "ipc://" ++ dir ++ "/hbro." ++ tshow pid
+ library/Hbro/Prelude.hs view
@@ -0,0 +1,202 @@+{-# LANGUAGE ConstraintKinds #-}+-- | Replacement for the traditional @Prelude@ module. This module doesn't import any other Hbro.* module, so it can be safely imported from anywhere in the project.+module Hbro.Prelude+    ( module X+-- * Typeclass+    , ToList(..)+    , ToSet(..)+    , ToNonEmpty(..)+    , Describable(..)+    , BaseIO+    , ControlIO+-- * Generic aliases/shortcuts+    , leftM+    , io+    , (>/>)+    , abort+    , doNothing+-- * Lens util+    , withM+    , withM_+    , fwd+    , askL+-- * Concurrent util+    , writeTMVar+    , withAsyncList+    , withAsyncList_+-- * Gtk util+    , gSync+    , gAsync+-- * Process control+    , spawn+-- * Pango util+    , allItalic+    , allBold+    , black+    , gray+    , red+    , green+    , blue+    , yellow+) where++-- {{{ Imports+import ClassyPrelude as X hiding(Builder(..), log, toList)++import Control.Applicative as X (Alternative(..), WrappedMonad)+import Control.Arrow as X (Kleisli(..), left, right)+import Control.Concurrent.Async.Lifted+import Control.Conditional as X (ToBool(..), (<|), (|>), (<<|), (|>>))+import Control.Lens+import Control.Monad.Base as X (MonadBase(..))+import Control.Monad.Trans.Control as X+import Control.Monad.Reader++import Data.Default as X+import Data.Foldable as X (asum)+import Data.Functor as X+import Data.List as X (tail)+import Data.List.NonEmpty (NonEmpty(..))+import Data.Maybe as X (fromJust)++import Graphics.Rendering.Pango.Enums+import Graphics.UI.Gtk.General.General++import Safe as X (initSafe, tailSafe)++import System.Log.Logger+-- import System.Posix.Process+-- import System.Posix.Types+import System.Process+-- }}}++-- | We often want to use a single object where a list is expected.+class ToList m t | t -> m where toList :: t -> [m]++instance ToList m [m] where toList = id++-- | We often want to use a single object where a set is expected.+class ToSet m t | t -> m where toSet :: t -> Set m++instance ToSet m (Set m) where toSet = id++-- | We often want to use a single object where a non-empty list is expected.+class ToNonEmpty s t | t -> s where toNonEmpty :: t -> NonEmpty s++instance ToNonEmpty s (NonEmpty s) where toNonEmpty = id++-- | Like 'Show', for 'Text'+class Describable a where describe :: a -> Text++-- | Mix of 'MonadBase IO' and 'MonadIO'+type BaseIO m = (MonadBase IO m, MonadIO m)++-- | Mix of 'MonadBaseControl IO' and 'MonadIO'+type ControlIO m = (MonadBaseControl IO m, MonadIO m)++-- {{{ Generic aliases/shortcuts+-- 'left' for 'Kleisli' arrows+leftM :: Monad m => (a -> m b) -> Either a c -> m (Either b c)+leftM f = runKleisli (left $ Kleisli f)++-- | Alias for 'liftIO'+io :: MonadIO m => IO a -> m a+io = liftIO++-- | Like '(\</\>)' with first argument in @IO@ to build platform-dependent paths.+(>/>) :: (BaseIO m) => IO FilePath -> FilePath -> m FilePath+(>/>) a b = io $ (</> b) <$> a++-- | Alias for 'mzero'+abort :: MonadPlus m => m a+abort = mzero++-- | Alias for @return ()@+doNothing :: Monad m => m ()+doNothing = return ()+-- }}}++-- {{{ Lens util+-- | Alias for 'mapMOf'+withM :: Profunctor p => Over p (WrappedMonad m) s t a b -> p a (m b) -> s -> m t+withM = mapMOf++withM_ :: Monad m => Over (->) (WrappedMonad m) s t a a -> (a -> m ()) -> s -> m t+withM_ l f = mapMOf l (fwd f)++fwd :: (Monad m) => (a -> m ()) -> a -> m a+fwd f x = f x >> return x++-- | Call 'asks' with the given lens getter.+askL ::(MonadReader t m) => Lens' t a -> m a+askL l = asks $ view l+-- }}}++-- {{{ Concurrent util+-- | This is a combination of 'tryTakeTMVar' and 'putTMVar';+-- ie. it empties the 'TMVar' if needed, and puts the new value instead.+writeTMVar :: TMVar a -> a -> STM ()+writeTMVar var val = do+    tryTakeTMVar var+    putTMVar var val++-- | Recursive 'withAsync'+withAsyncList :: (ControlIO m) => [m a] -> ([Async (StM m a)] -> m b) -> m b+withAsyncList a f = withAsyncList' a [] f++-- | Same as 'withAsyncList', but discards the result+withAsyncList_ :: (ControlIO m) => [m a] -> ([Async (StM m a)] -> m b) -> m ()+withAsyncList_ a f = void $ withAsyncList a f++withAsyncList' :: (ControlIO m) => [m a] -> [Async (StM m a)] -> ([Async (StM m a)] -> m b) -> m b+withAsyncList' [] x f  = f x+withAsyncList' (a:b) x f = withAsync a $ \x' -> withAsyncList' b (x':x) f+-- }}}++-- {{{ Gtk util+-- | Lifted alias for 'postGUISync'+gSync :: (BaseIO m) => IO a -> m a+gSync  = io . postGUISync++-- | Lifted alias for 'postGUIAsync'+gAsync :: (BaseIO m) => IO () -> m ()+gAsync = io . postGUIAsync+-- }}}++-- {{{ Process management+-- | Run external command and don't die when parent process exits.+spawn :: (BaseIO m) => String -> [String] -> m ()+spawn command options = io $ do+    debugM "hbro.prelude" $ "Executing command: " ++ unwords (command:options)+    void $ createProcess (proc command options) { std_in = CreatePipe,  std_out = CreatePipe, std_err = CreatePipe, close_fds = True }++-- Return the list of process IDs corresponding to all running instances of the browser.+-- getAllProcessIDs :: MonadIO m => m [ProcessID]+-- getAllProcessIDs = do+--     (_, pids, _)  <- io $ readProcessWithExitCode "pidof" ["hbro"] []+--     (_, pids', _) <- io $ readProcessWithExitCode "pidof" ["hbro-" ++ Sys.os ++ "-" ++ Sys.arch] []+--     myPid         <- io $ getProcessID++--     return $ delete myPid . map (read :: String -> ProcessID) . nub . words $ pids ++ " " ++ pids'+-- }}}+++{-errorHandler :: (MonadIO m, MonadReader r m, HasOptions r) => FilePath -> IOError -> m ()+errorHandler file e = do+  when (isAlreadyInUseError e) $ unlessQuiet . io . putStrLn $ "ERROR: file <" ++ file ++ "> is already opened and cannot be reopened."+  when (isDoesNotExistError e) $ unlessQuiet . io . putStrLn $ "ERROR: file <" ++ file ++ "> doesn't exist."+  when (isPermissionError   e) $ unlessQuiet . io . putStrLn $ "ERROR: user doesn't have permission to open file <" ++ file ++ ">."-}++-- {{{ Pango util+allItalic, allBold :: PangoAttribute+allItalic = AttrStyle  {paStart = 0, paEnd = -1, paStyle  = StyleItalic}+allBold   = AttrWeight {paStart = 0, paEnd = -1, paWeight = WeightBold}++black, gray, red, green, blue, yellow :: Color+black  = Color     0     0     0+gray   = Color 32767 32767 32767+red    = Color 65535     0     0+green  = Color     0 65535     0+blue   = Color     0     0 65535+yellow = Color 65535 65535     0+-- }}}
+ library/Hbro/Signals.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE TemplateHaskell #-}+module Hbro.Signals (+-- * Signals+      Signals+    , _ipcSignals+    , _promptSignals+    , _webViewSignals+    , initialize+    , attachGuiSignals+) where++-- {{{ Imports+-- import Hbro.Error+import Hbro.Gui hiding(initialize)+import Hbro.Gui.PromptBar (entryL)+import qualified Hbro.IPC.Signals as IPC+import qualified Hbro.Gui.PromptBar.Signals as Prompt+import Hbro.Prelude+import qualified Hbro.WebView.Signals as WebView++import Control.Lens hiding((??))+-- }}}++-- {{{ Signals+data Signals = Signals {+    __ipcSignals     :: IPC.Signals,+    __promptSignals  :: Prompt.Signals,+    __webViewSignals :: WebView.Signals }++makeLenses ''Signals++initialize :: (BaseIO m) => m Signals+initialize = Signals <$> IPC.initSignals+                     <*> Prompt.initSignals+                     <*> WebView.initSignals++attachGuiSignals :: (BaseIO m) => GUI -> Signals -> m ()+attachGuiSignals gui signals = do+    WebView.attach    (gui^.webViewL)          (signals^._webViewSignals)+    Prompt.attach     (gui^.promptBarL.entryL) (signals^._promptSignals)+-- }}}
+ library/Hbro/WebView/Hooks.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE TemplateHaskell #-}+module Hbro.WebView.Hooks (+-- * Types+      DownloadHook(..)+    , LinkClickedHook(..)+    , LoadRequestedHook(..)+    , NewWindowHook(..)+    , ResourceOpenedHook(..)+    , TitleChangedHook(..)+    , Hooks+    , onDownloadL+    , onLinkClickedL+    , onLinkHoveredL+    , onLoadRequestedL+    , onLoadStartedL+    , onLoadFinishedL+    , onNewWindowL+    , onResourceOpenedL+    , onTitleChangedL+    , HasHooks(..)+-- * Functions+    , set+    , initHooks+) where++-- {{{ Imports+import Hbro.Prelude+import Hbro.WebView.Signals++import Control.Lens.Lens+import Control.Lens.Setter hiding(set)+import Control.Lens.TH+import Control.Monad.Reader+-- }}}+++newtype DownloadHook m       = DownloadHook (Download -> m ())+newtype LinkClickedHook m    = LinkClickedHook (LinkClicked -> m ())+newtype LoadRequestedHook m  = LoadRequestedHook (LoadRequested -> m ())+newtype NewWindowHook m      = NewWindowHook (NewWindow -> m ())+newtype ResourceOpenedHook m = ResourceOpenedHook (ResourceOpened -> m ResourceAction)+newtype TitleChangedHook m   = TitleChangedHook (TitleChanged -> m ())+++data Hooks m = Hooks+    { _onDownload       :: TMVar (Download -> m ())+    , _onLinkClicked    :: TMVar (LinkClicked -> m ())+    , _onLinkHovered    :: TMVar (LinkHovered -> m ())+    , _onLoadRequested  :: TMVar (LoadRequested -> m ())+    , _onLoadStarted    :: TMVar (LoadStarted -> m ())+    , _onLoadFinished   :: TMVar (LoadFinished -> m ())+    , _onNewWindow      :: TMVar (NewWindow -> m ())+    , _onResourceOpened :: TMVar (ResourceOpened -> m ())+    , _onTitleChanged   :: TMVar (TitleChanged -> m ())+    }++makeLensesWith ?? ''Hooks $ lensRules+    & lensField .~ (\name -> Just (tail name ++ "L"))+    -- & lensClass .~ (\name -> Just ("Has" ++ name, map toLower name))++class HasHooks n t | t -> n where _hooks :: Lens' t (Hooks n)++set :: (BaseIO m, MonadReader r m, HasHooks n r) => Lens' (Hooks n) (TMVar a) -> a -> m ()+set l v = atomically . (`writeTMVar` v) =<< askL (_hooks.l)+++initHooks :: (Functor n, BaseIO m, Default (LinkClickedHook n), Default (LoadRequestedHook n), Default (NewWindowHook n), Default (ResourceOpenedHook n), Default (TitleChangedHook n))+          => m (Hooks n)+initHooks = io (Hooks <$> newEmptyTMVarIO+                      <*> newTMVarIO lc+                      <*> newEmptyTMVarIO+                      <*> newTMVarIO lr+                      <*> newEmptyTMVarIO+                      <*> newEmptyTMVarIO+                      <*> newTMVarIO nw+                      <*> newTMVarIO (void . ro)+                      <*> newTMVarIO tc)+  where+      LinkClickedHook    lc = def+      LoadRequestedHook  lr = def+      NewWindowHook      nw = def+      ResourceOpenedHook ro = def+      TitleChangedHook   tc = def
+ library/Hbro/WebView/Signals.hs view
@@ -0,0 +1,250 @@+{-# LANGUAGE TemplateHaskell #-}+module Hbro.WebView.Signals where++-- {{{ Imports+import Hbro.Error+import Hbro.Gdk.KeyVal+import Hbro.Keys as Keys hiding(Hooks)+import Hbro.Keys.Model ((.|))+import Hbro.Keys.Signals as Keys+import Hbro.Logger+import Hbro.Prelude hiding(on)++import Graphics.UI.Gtk.WebKit.Lifted as Lifted++import Control.Lens.Lens+import Control.Lens.Getter+import Control.Lens.Setter+import Control.Lens.TH++import Data.Set as S hiding(map)++import Graphics.UI.Gtk.Abstract.Widget hiding(KeyVal)+import Graphics.UI.Gtk.Gdk.EventM as Gdk+import Graphics.UI.Gtk.WebKit.Download as W hiding(Download, downloadGetUri, downloadGetSuggestedFilename)+import Graphics.UI.Gtk.WebKit.WebNavigationAction+import Graphics.UI.Gtk.WebKit.WebPolicyDecision+import Graphics.UI.Gtk.WebKit.WebView as W hiding(LoadFinished)++import Network.URI++import System.Glib.Signals hiding(Signal)+-- }}}+++data ResourceAction = Load | Download'++data Download       = Download URI Text (Maybe Int)+instance Describable Download where describe _ = "Download"++data LinkHovered    = LinkHovered URI (Maybe Text)+instance Describable LinkHovered where describe _ = "LinkHovered"++data LinkClicked    = LinkClicked URI MouseButton+instance Describable LinkClicked where describe _ = "LinkClicked"++data LoadRequested  = LoadRequested URI+instance Describable LoadRequested where describe _ = "LoadRequested"++data LoadStarted   = LoadStarted+instance Describable LoadStarted where describe _ = "LoadStarted"++data LoadFinished   = LoadFinished+instance Describable LoadFinished where describe _ = "LoadFinished"++data NewWindow      = NewWindow URI+instance Describable NewWindow where describe _ = "NewWindow"++data ResourceOpened = ResourceOpened URI Text+instance Describable ResourceOpened where describe _ = "ResourceOpened"++data TitleChanged   = TitleChanged Text+instance Describable TitleChanged where describe _ = "TitleChanged"+++data Signals = Signals+    { _download          :: TMVar Download+    , _keyPressed        :: TMVar KeyPressed+    , _linkClicked       :: TMVar LinkClicked+    , _linkHovered       :: TMVar LinkHovered+    , _loadRequested     :: TMVar LoadRequested+    , _loadStarted       :: TMVar LoadStarted+    , _loadFinished      :: TMVar LoadFinished+    -- _newWebView        :: TMVar URI,+    , _newWindow         :: TMVar NewWindow+    , _resourceOpened    :: TMVar ResourceOpened+    , _titleChanged      :: TMVar TitleChanged+    }+++makeLensesWith ?? ''Signals $ lensRules+    &  lensField .~ (\name -> Just (tailSafe name ++ "L"))++initSignals :: (BaseIO m) => m Signals+initSignals = io (Signals <$> newEmptyTMVarIO+                          <*> newEmptyTMVarIO+                          <*> newEmptyTMVarIO+                          <*> newEmptyTMVarIO+                          <*> newEmptyTMVarIO+                          <*> newEmptyTMVarIO+                          <*> newEmptyTMVarIO+                          <*> newEmptyTMVarIO+                          <*> newEmptyTMVarIO+                          <*> newEmptyTMVarIO)++-- | Sequentially bind all signals.+attach :: (BaseIO m) => WebView -> Signals -> m ()+attach webView signals = sequence_+    [ attachDownload          webView (signals^.downloadL)+    , attachLinkHovered       webView (signals^.linkHoveredL)+    , attachLoadStarted       webView (signals^.loadStartedL)+    , attachLoadFinished      webView (signals^.loadFinishedL)+    , attachNavigationRequest webView (signals^.linkClickedL, signals^.loadRequestedL)+    , attachNewWebView        webView (signals^.newWindowL)+    , attachNewWindow         webView (signals^.newWindowL)+    , attachResourceOpened    webView (signals^.resourceOpenedL)+    , attachTitleChanged      webView (signals^.titleChangedL)+    , attachKeyPressed        webView (signals^.keyPressedL)+    ]+++attachDownload :: (BaseIO m) => WebView -> TMVar Download -> m (ConnectId WebView)+attachDownload webView signal = gSync . on webView downloadRequested $ \d -> do+    logErrors $ do+        amount <- io $ downloadGetTotalSize d+        uri    <- downloadGetUri d+        name   <- downloadGetSuggestedFilename d++        debugM "hbro.signals" $ "Requested download <" ++ tshow uri ++ ">"++        atomically . tryPutTMVar signal $ Download uri name (Just amount)+    return False+++attachLinkHovered :: (BaseIO m) => WebView -> TMVar LinkHovered -> m (ConnectId WebView)+attachLinkHovered webView signal = gSync . on webView hoveringOverLink $ \title uri -> void . runMaybeT $ do+    debugM "hbro.signals" $ "Link hovered <" ++ tshow uri ++ ">"+    u <- MaybeT . return $ parseURI . unpack =<< uri++    atomically . tryPutTMVar signal $ LinkHovered u title+++-- Triggered in 2 cases:+--  1/ Javascript window.open()+--  2/ Context menu "Open in new window"+attachNewWebView :: (BaseIO m) => WebView -> TMVar NewWindow -> m (ConnectId WebView)+attachNewWebView webView signal = gSync . on webView createWebView $ \_frame -> do+    webView' <- webViewNew++    on webView' webViewReady $ return True+    on webView' navigationPolicyDecisionRequested $ \_ request _ decision -> do+        logErrors $ do+            uri <- networkRequestGetUri request+            debugM "hbro.signals" $ "New window <" ++ tshow uri ++ ">"+            atomically . tryPutTMVar signal $ NewWindow uri++        webPolicyDecisionIgnore decision+        return True++    return webView'+++attachLoadStarted :: (BaseIO m) => WebView -> TMVar LoadStarted -> m (ConnectId WebView)+attachLoadStarted webView signal = gSync . on webView loadStarted $ \_frame -> do+    debugM "hbro.signals" "Load started"+    void . atomically $ tryPutTMVar signal LoadStarted+++attachLoadFinished :: (BaseIO m) => WebView -> TMVar LoadFinished -> m (ConnectId WebView)+attachLoadFinished webView signal = gSync . on webView loadFinished $ \_frame -> do+    debugM "hbro.signals" "Load finished"+    void . atomically $ tryPutTMVar signal LoadFinished+++attachNavigationRequest :: (BaseIO m) => WebView -> (TMVar LinkClicked, TMVar LoadRequested) -> m (ConnectId WebView)+attachNavigationRequest webView (signal1, signal2) = gSync . on webView navigationPolicyDecisionRequested $ \_frame request action decision -> do+    reason <- webNavigationActionGetReason action+    button <- toMouseButton <$> webNavigationActionGetButton action++    -- io . putStrLn . ("Request data: " ++) =<< networkRequestGetBody request+    -- io . putStrLn . ("Request type: " ++) . describe =<< networkRequestGetContentType request+    -- io . putStrLn . ("Request type: " ++) . describe =<< networkRequestGetURI request++    logErrors $ do+        uri <- networkRequestGetUri request++        case (reason, button) of+            (WebNavigationReasonLinkClicked, Just b) -> io $ do+                debugM "hbro.signals" $ "Link clicked <" ++ tshow uri ++ ">"+                atomically . tryPutTMVar signal1 $ LinkClicked uri b+                webPolicyDecisionIgnore decision+            (WebNavigationReasonOther, _) -> io $ do+                debugM "hbro.signals" $ "Navigation request [" ++ tshow reason ++ "] to <" ++ tshow uri ++ ">"+                webPolicyDecisionUse decision+            (WebNavigationReasonBackForward, _) -> io $ do+                debugM "hbro.signals" $ "Navigation request [" ++ tshow reason ++ "] to <" ++ tshow uri ++ ">"+                webPolicyDecisionUse decision+            (WebNavigationReasonReload, _) -> io $ do+                debugM "hbro.signals" $ "Navigation request [" ++ tshow reason ++ "] to <" ++ tshow uri ++ ">"+                webPolicyDecisionUse decision+            (WebNavigationReasonFormSubmitted, _) -> io $ do+                debugM "hbro.signals" $ "Form submitted to <" ++ tshow uri ++ ">"+                webPolicyDecisionUse decision+            _ -> io $ do+                debugM "hbro.signals" $ "Navigation request [" ++ tshow reason ++ "] to <" ++ tshow uri ++ ">"+                void . atomically . tryPutTMVar signal2 $ LoadRequested uri+                webPolicyDecisionIgnore decision+      `catchError` \e -> io $ do+        errorM "hbro.signals" $ tshow e+        webPolicyDecisionUse decision++    return True+  where+    toMouseButton 1 = Just LeftButton+    toMouseButton 2 = Just MiddleButton+    toMouseButton 3 = Just RightButton+    toMouseButton _ = Nothing+++attachNewWindow :: (BaseIO m) => WebView -> TMVar NewWindow -> m (ConnectId WebView)+attachNewWindow webView signal = gSync . on webView newWindowPolicyDecisionRequested $ \_frame request _action decision -> do+    logErrors $ do+        uri <- networkRequestGetUri request+        debugM "hbro.signals" $ "New window request <" ++ tshow uri ++ ">"+        atomically . tryPutTMVar signal $ NewWindow uri++    webPolicyDecisionIgnore decision+    return True+++attachResourceOpened :: (BaseIO m) => WebView -> TMVar ResourceOpened -> m (ConnectId WebView)+attachResourceOpened webView signal = gSync . on webView mimeTypePolicyDecisionRequested $ \_frame request mimetype decision -> do+    logErrors $ do+        uri <- networkRequestGetUri request+        debugM "hbro.signals" $ "Opening resource [MIME type=" ++ mimetype ++ "] at <" ++ tshow uri ++ ">"+        atomically . tryPutTMVar signal $ ResourceOpened uri mimetype++    webPolicyDecisionUse decision+    return True+++attachTitleChanged :: (BaseIO m) => WebView -> TMVar TitleChanged -> m (ConnectId WebView)+attachTitleChanged webView signal = gSync . on webView W.titleChanged $ \_frame title -> do+    debugM "hbro.signals" $ "Title changed to: " ++ title+    void . atomically . tryPutTMVar signal $ TitleChanged title+++attachKeyPressed :: (BaseIO m) => WebView -> TMVar KeyPressed -> m (ConnectId WebView)+attachKeyPressed webView signal = gSync . on webView keyPressEvent $ do+    modifiers <- S.delete _Shift . S.fromList . map Keys.Modifier <$> Gdk.eventModifier+    key       <- KeyVal <$> Gdk.eventKeyVal++    io . runMaybeT $ do+        guard . not $ isModifier key || isModalKey key++        let theStroke = modifiers .| key+        debugM "hbro.signals" $ "Pressed: " ++ describe theStroke++        atomically . tryPutTMVar signal $ KeyPressed theStroke++    return False
+ library/Hbro/Webkit/WebSettings.hs view
@@ -0,0 +1,73 @@+-- | Designed to be imported as @qualified@.+module Hbro.Webkit.WebSettings where++-- {{{ Imports+import qualified Hbro.Gui as Gui (get)+import Hbro.Gui hiding(get)+import Hbro.Logger+import Hbro.Prelude++import Control.Monad.Reader++import Graphics.UI.Gtk.WebKit.WebSettings+import Graphics.UI.Gtk.WebKit.WebView++import System.Glib.Attributes (Attr, AttrOp(..))+import qualified System.Glib.Attributes as G+-- }}}+++set :: (BaseIO m, MonadReader t m, HasGUI t, Show a) => Attr WebSettings a -> a -> m ()+set element newValue = modify_ element $ const newValue++modify :: (BaseIO m, MonadReader t m, HasGUI t, Show a) => Attr WebSettings a -> (a -> a) -> m a+modify element modifier = do+    webView  <- Gui.get webViewL+    settings <- gSync $ webViewGetWebSettings webView+    oldValue <- gSync $ G.get settings element++    gAsync $ G.set settings [element := modifier oldValue]+    gAsync $ webViewSetWebSettings webView settings+    infoM "hbro.settings" $ "Set " ++ tshow element ++ " = " ++ tshow (modifier oldValue)+    return oldValue++-- | Same as 'modify', but discards the result+modify_ :: (BaseIO m, MonadReader t m, HasGUI t, Show a) => Attr WebSettings a -> (a -> a) -> m ()+modify_ e m = void $ modify e m++toggle :: (BaseIO m, MonadReader t m, HasGUI t) => Attr WebSettings Bool -> m Bool+toggle = (`modify` not)++-- | Same as 'toggle', but discards the result+toggle_ :: (BaseIO m, MonadReader t m, HasGUI t) => Attr WebSettings Bool -> m ()+toggle_ = (`modify_` not)++-- | Reset default settings+resetAll :: (BaseIO m, MonadReader t m, HasGUI t) => m ()+resetAll = do+    set webSettingsAutoLoadImages                    True+    set webSettingsAutoShrinkImages                  True+    set webSettingsEnableDefaultContextMenu          True+    set webSettingsDefaultEncoding                   (asText "utf8")+    set webSettingsEnableDeveloperExtras             False+    set webSettingsEnableDomPaste                    False+    set webSettingsEnableHtml5Database               False+    set webSettingsEnableHtml5LocalStorage           False+    set webSettingsEnableOfflineWebApplicationCache  False+    set webSettingsEnablePageCache                   True+    set webSettingsEnablePlugins                     False+    set webSettingsEnablePrivateBrowsing             False+    set webSettingsEnableScripts                     False+    set webSettingsEnableSpellChecking               False+    set webSettingsEnableSpatialNavigation           False+    set webSettingsEnableUniversalAccessFromFileUris True+    set webSettingsEnableSiteSpecificQuirks          False+    set webSettingsEnableXssAuditor                  False+    set webSettingsJSCanOpenWindowAuto               False+    set webSettingsMonospaceFontFamily               (asText "inconsolata")+    set webSettingsPrintBackgrounds                  True+    set webSettingsResizableTextAreas                True+    set webSettingsSpellCheckingLang                 (Nothing :: Maybe Text)+    set webSettingsTabKeyCyclesThroughElements       True+    set webSettingsUserStylesheetUri                 (Nothing :: Maybe Text)+    set webSettingsZoomStep                          0.1
+ library/Network/URI/Monadic.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE DeriveDataTypeable #-}+-- | Functions from 'Network.URI' rewritten with 'MonadError' instead of 'Maybe'.+module Network.URI.Monadic+    ( module X+    , parseURIReference+    , parseURI+    ) where++-- {{{ Imports+import Hbro.Prelude++import Control.Monad.Except (MonadError(..), throwError)++import Network.URI as X hiding(parseURIReference, parseURI)+import qualified Network.URI as N+-- }}}++-- | Error message+invalidURI :: Text -> Text+invalidURI uri = "Invalid URI: " ++ uri++parseURIReference :: (MonadError Text m) => Text -> m URI+parseURIReference uri = maybe (throwError $ invalidURI uri) return . N.parseURIReference $ unpack uri++parseURI :: (MonadError Text m) => Text -> m URI+parseURI uri = maybe (throwError $ invalidURI uri) return . N.parseURI $ unpack uri