summaryrefslogtreecommitdiffhomepage
path: root/UI
diff options
context:
space:
mode:
authorJoey Hess <joeyh@joeyh.name>2016-08-12 07:52:36 -0400
committerJoey Hess <joeyh@joeyh.name>2016-08-12 07:52:36 -0400
commitd813bbc0dc7357f23b647a3a05ef61067c53195f (patch)
tree0c15d3c0703bea3ffee48ac16347aef265a028fc /UI
parentddb4e6839fa2d7b589159c661815f89c8bb08c5f (diff)
downloadkeysafe-d813bbc0dc7357f23b647a3a05ef61067c53195f.tar.gz
pluggable UI
using zenity for GUI in X
Diffstat (limited to 'UI')
-rw-r--r--UI/Zenity.hs111
1 files changed, 111 insertions, 0 deletions
diff --git a/UI/Zenity.hs b/UI/Zenity.hs
new file mode 100644
index 0000000..2601f68
--- /dev/null
+++ b/UI/Zenity.hs
@@ -0,0 +1,111 @@
+{- Copyright 2016 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+module UI.Zenity (zenityUI) where
+
+import UI
+import Types
+import Control.Monad
+import System.Process
+import Control.Exception
+import System.IO
+import System.FilePath
+import System.Directory
+import System.Exit
+import qualified Data.ByteString.UTF8 as BU8
+
+zenityUI :: UI
+zenityUI = UI
+ { isAvailable = do
+ ps <- getSearchPath
+ loc <- filterM (\p -> doesFileExist (p </> "zenity")) ps
+ return (not (null loc))
+ , promptName = name
+ , promptPassword = password
+ , withProgress = progress
+ }
+
+name :: Title -> Desc -> (Name -> Maybe String) -> IO (Maybe Name)
+name title desc checkproblem = go ""
+ where
+ go extradesc = do
+ h <- runZenity
+ [ "--entry"
+ , "--title", title
+ , "--text", desc ++ "\n" ++ extradesc
+ ]
+ (ret, ok) <- waitZenity h
+ if ok
+ then
+ let n = Name $ BU8.fromString ret
+ in case checkproblem n of
+ Nothing -> return $ Just n
+ Just problem -> go problem
+ else return Nothing
+
+password :: Title -> Desc -> (Password -> Maybe String) -> IO (Maybe Password)
+password title desc checkproblem = go ""
+ where
+ go extradesc = do
+ h <- runZenity
+ [ "--forms"
+ , "--title", title
+ , "--text", desc ++ "\n" ++ extradesc ++ "\n"
+ , "--add-password", "Enter password"
+ , "--add-password", "Confirm password"
+ , "--separator", "\BEL"
+ ]
+ (ret, ok) <- waitZenity h
+ if ok
+ then
+ let (p1, _:p2) = break (== '\BEL') ret
+ in if p1 /= p2
+ then go "Passwords didn't match, try again..."
+ else
+ let p = Password $ BU8.fromString p1
+ in case checkproblem p of
+ Nothing -> return $ Just p
+ Just problem -> go problem
+ else return Nothing
+
+progress :: Title -> Desc -> ((Percent -> IO ()) -> IO ()) -> IO ()
+progress title desc a = bracket setup teardown (a . sendpercent)
+ where
+ setup = do
+ h <- runZenity
+ [ "--progress"
+ , "--title", title
+ , "--text", desc
+ , "--auto-close"
+ , "--auto-kill"
+ ]
+ return h
+ sendpercent h p = sendZenity h (show p)
+ teardown h = do
+ _ <- waitZenity h
+ return ()
+
+data ZenityHandle = ZenityHandle Handle Handle ProcessHandle
+
+runZenity :: [String] -> IO ZenityHandle
+runZenity ps = do
+ (Just hin, Just hout, Nothing, ph) <- createProcess
+ (proc "zenity" ps)
+ { std_out = CreatePipe
+ , std_in = CreatePipe
+ }
+ return $ ZenityHandle hin hout ph
+
+sendZenity :: ZenityHandle -> String -> IO ()
+sendZenity (ZenityHandle hin _ _) s = do
+ hPutStrLn hin s
+ hFlush hin
+
+waitZenity :: ZenityHandle -> IO (String, Bool)
+waitZenity (ZenityHandle hin hout ph) = do
+ hClose hin
+ ret <- hGetContents hout
+ exit <- waitForProcess ph
+ return (takeWhile (/= '\n') ret, exit == ExitSuccess)