module System.Taffybar.Information.XDG.Protocol
( XDGMenu(..)
, DesktopEntryCondition(..)
, getApplicationEntries
, getDirectoryDirs
, getPreferredLanguages
, getXDGDesktop
, getXDGMenuFilenames
, matchesCondition
, readXDGMenu
) where
import Control.Applicative
import Control.Monad
import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe
import Data.Char (toLower)
import Data.List
import Data.Maybe
import qualified Debug.Trace as D
import GHC.IO.Encoding
import Prelude
import Safe (headMay)
import System.Directory
import System.Environment
import System.Environment.XDG.DesktopEntry
import System.FilePath.Posix
import System.Log.Logger
import System.Posix.Files
import System.Taffybar.Util
import Text.XML.Light
import Text.XML.Light.Helpers
getXDGMenuPrefix :: IO (Maybe String)
= String -> IO (Maybe String)
lookupEnv String
"XDG_MENU_PREFIX"
getXDGMenuFilenames
:: Maybe String
-> IO [FilePath]
Maybe String
mMenuPrefix = do
[String]
configDirs <-
(String -> [String] -> [String])
-> IO String -> IO [String] -> IO [String]
forall a b c. (a -> b -> c) -> IO a -> IO b -> IO c
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 (:) (XdgDirectory -> String -> IO String
getXdgDirectory XdgDirectory
XdgConfig String
"")
(XdgDirectoryList -> IO [String]
getXdgDirectoryList XdgDirectoryList
XdgConfigDirs)
Maybe String
maybePrefix <- (Maybe String
mMenuPrefix Maybe String -> Maybe String -> Maybe String
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>) (Maybe String -> Maybe String)
-> IO (Maybe String) -> IO (Maybe String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO (Maybe String)
getXDGMenuPrefix
let maybeAddDash :: String -> String
maybeAddDash String
t = if String -> Char
forall a. HasCallStack => [a] -> a
last String
t Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'-' then String
t else String
t String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-"
dashedPrefix :: String
dashedPrefix = String -> (String -> String) -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" String -> String
maybeAddDash Maybe String
maybePrefix
[String] -> IO [String]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> String
</> String
"menus" String -> String -> String
</> String
dashedPrefix String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"applications.menu") [String]
configDirs
data =
{ XDGMenu -> Maybe String
xmAppDir :: Maybe String
, XDGMenu -> Bool
xmDefaultAppDirs :: Bool
, XDGMenu -> Maybe String
xmDirectoryDir :: Maybe String
, XDGMenu -> Bool
xmDefaultDirectoryDirs :: Bool
, XDGMenu -> [String]
xmLegacyDirs :: [String]
, XDGMenu -> String
xmName :: String
, XDGMenu -> String
xmDirectory :: String
, XDGMenu -> Bool
xmOnlyUnallocated :: Bool
, XDGMenu -> Bool
xmDeleted :: Bool
, XDGMenu -> Maybe DesktopEntryCondition
xmInclude :: Maybe DesktopEntryCondition
, XDGMenu -> Maybe DesktopEntryCondition
xmExclude :: Maybe DesktopEntryCondition
, :: [XDGMenu]
, XDGMenu -> [XDGLayoutItem]
xmLayout :: [XDGLayoutItem]
} deriving (Int -> XDGMenu -> String -> String
[XDGMenu] -> String -> String
XDGMenu -> String
(Int -> XDGMenu -> String -> String)
-> (XDGMenu -> String)
-> ([XDGMenu] -> String -> String)
-> Show XDGMenu
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> XDGMenu -> String -> String
showsPrec :: Int -> XDGMenu -> String -> String
$cshow :: XDGMenu -> String
show :: XDGMenu -> String
$cshowList :: [XDGMenu] -> String -> String
showList :: [XDGMenu] -> String -> String
Show)
data XDGLayoutItem =
XliFile String | XliSeparator | String | XliMerge String
deriving(Int -> XDGLayoutItem -> String -> String
[XDGLayoutItem] -> String -> String
XDGLayoutItem -> String
(Int -> XDGLayoutItem -> String -> String)
-> (XDGLayoutItem -> String)
-> ([XDGLayoutItem] -> String -> String)
-> Show XDGLayoutItem
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> XDGLayoutItem -> String -> String
showsPrec :: Int -> XDGLayoutItem -> String -> String
$cshow :: XDGLayoutItem -> String
show :: XDGLayoutItem -> String
$cshowList :: [XDGLayoutItem] -> String -> String
showList :: [XDGLayoutItem] -> String -> String
Show)
getApplicationEntries
:: [String]
-> XDGMenu
-> IO [DesktopEntry]
getApplicationEntries :: [String] -> XDGMenu -> IO [DesktopEntry]
getApplicationEntries [String]
langs XDGMenu
xm = do
[DesktopEntry]
defEntries <- if XDGMenu -> Bool
xmDefaultAppDirs XDGMenu
xm
then do [String]
dataDirs <- IO [String]
getXDGDataDirs
[[DesktopEntry]] -> [DesktopEntry]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[DesktopEntry]] -> [DesktopEntry])
-> IO [[DesktopEntry]] -> IO [DesktopEntry]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String -> IO [DesktopEntry]) -> [String] -> IO [[DesktopEntry]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (String -> String -> IO [DesktopEntry]
listDesktopEntries String
".desktop" (String -> IO [DesktopEntry])
-> (String -> String) -> String -> IO [DesktopEntry]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
(String -> String -> String
</> String
"applications")) [String]
dataDirs
else [DesktopEntry] -> IO [DesktopEntry]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
[DesktopEntry] -> IO [DesktopEntry]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([DesktopEntry] -> IO [DesktopEntry])
-> [DesktopEntry] -> IO [DesktopEntry]
forall a b. (a -> b) -> a -> b
$ (DesktopEntry -> DesktopEntry -> Ordering)
-> [DesktopEntry] -> [DesktopEntry]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (\DesktopEntry
de1 DesktopEntry
de2 -> String -> String -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ((Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower ([String] -> DesktopEntry -> String
deName [String]
langs DesktopEntry
de1))
((Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower ([String] -> DesktopEntry -> String
deName [String]
langs DesktopEntry
de2))) [DesktopEntry]
defEntries
parseMenu :: Element -> Maybe XDGMenu
Element
elt =
let appDir :: Maybe String
appDir = String -> Element -> Maybe String
getChildData String
"AppDir" Element
elt
defaultAppDirs :: Bool
defaultAppDirs = Maybe String -> Bool
forall a. Maybe a -> Bool
isJust (Maybe String -> Bool) -> Maybe String -> Bool
forall a b. (a -> b) -> a -> b
$ String -> Element -> Maybe String
getChildData String
"DefaultAppDirs" Element
elt
directoryDir :: Maybe String
directoryDir = String -> Element -> Maybe String
getChildData String
"DirectoryDir" Element
elt
defaultDirectoryDirs :: Bool
defaultDirectoryDirs = Maybe String -> Bool
forall a. Maybe a -> Bool
isJust (Maybe String -> Bool) -> Maybe String -> Bool
forall a b. (a -> b) -> a -> b
$ String -> Element -> Maybe String
getChildData String
"DefaultDirectoryDirs" Element
elt
name :: String
name = String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
"Name?" (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$ String -> Element -> Maybe String
getChildData String
"Name" Element
elt
dir :: String
dir = String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
"Dir?" (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$ String -> Element -> Maybe String
getChildData String
"Directory" Element
elt
onlyUnallocated :: Bool
onlyUnallocated =
case ( String -> Element -> Maybe String
getChildData String
"OnlyUnallocated" Element
elt
, String -> Element -> Maybe String
getChildData String
"NotOnlyUnallocated" Element
elt) of
(Maybe String
Nothing, Maybe String
Nothing) -> Bool
False
(Maybe String
Nothing, Just String
_) -> Bool
False
(Just String
_, Maybe String
Nothing) -> Bool
True
(Just String
_, Just String
_) -> Bool
False
deleted :: Bool
deleted = Bool
False
include :: Maybe DesktopEntryCondition
include = String -> Element -> Maybe DesktopEntryCondition
parseConditions String
"Include" Element
elt
exclude :: Maybe DesktopEntryCondition
exclude = String -> Element -> Maybe DesktopEntryCondition
parseConditions String
"Exclude" Element
elt
layout :: [XDGLayoutItem]
layout = Element -> [XDGLayoutItem]
parseLayout Element
elt
subMenus :: [XDGMenu]
subMenus = [XDGMenu] -> Maybe [XDGMenu] -> [XDGMenu]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [XDGMenu] -> [XDGMenu]) -> Maybe [XDGMenu] -> [XDGMenu]
forall a b. (a -> b) -> a -> b
$ String -> Element -> (Element -> Maybe XDGMenu) -> Maybe [XDGMenu]
forall a. String -> Element -> (Element -> Maybe a) -> Maybe [a]
mapChildren String
"Menu" Element
elt Element -> Maybe XDGMenu
parseMenu
in XDGMenu -> Maybe XDGMenu
forall a. a -> Maybe a
Just
XDGMenu
{ xmAppDir :: Maybe String
xmAppDir = Maybe String
appDir
, xmDefaultAppDirs :: Bool
xmDefaultAppDirs = Bool
defaultAppDirs
, xmDirectoryDir :: Maybe String
xmDirectoryDir = Maybe String
directoryDir
, xmDefaultDirectoryDirs :: Bool
xmDefaultDirectoryDirs = Bool
defaultDirectoryDirs
, xmLegacyDirs :: [String]
xmLegacyDirs = []
, xmName :: String
xmName = String
name
, xmDirectory :: String
xmDirectory = String
dir
, xmOnlyUnallocated :: Bool
xmOnlyUnallocated = Bool
onlyUnallocated
, xmDeleted :: Bool
xmDeleted = Bool
deleted
, xmInclude :: Maybe DesktopEntryCondition
xmInclude = Maybe DesktopEntryCondition
include
, xmExclude :: Maybe DesktopEntryCondition
xmExclude = Maybe DesktopEntryCondition
exclude
, xmSubmenus :: [XDGMenu]
xmSubmenus = [XDGMenu]
subMenus
, xmLayout :: [XDGLayoutItem]
xmLayout = [XDGLayoutItem]
layout
}
parseConditions :: String -> Element -> Maybe DesktopEntryCondition
parseConditions :: String -> Element -> Maybe DesktopEntryCondition
parseConditions String
key Element
elt = case QName -> Element -> Maybe Element
findChild (String -> QName
unqual String
key) Element
elt of
Maybe Element
Nothing -> Maybe DesktopEntryCondition
forall a. Maybe a
Nothing
Just Element
inc -> [Element] -> Maybe DesktopEntryCondition
doParseConditions (Element -> [Element]
elChildren Element
inc)
where doParseConditions :: [Element] -> Maybe DesktopEntryCondition
doParseConditions :: [Element] -> Maybe DesktopEntryCondition
doParseConditions [] = Maybe DesktopEntryCondition
forall a. Maybe a
Nothing
doParseConditions [Element
e] = Element -> Maybe DesktopEntryCondition
parseSingleItem Element
e
doParseConditions [Element]
elts = DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a. a -> Maybe a
Just (DesktopEntryCondition -> Maybe DesktopEntryCondition)
-> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ [DesktopEntryCondition] -> DesktopEntryCondition
Or ([DesktopEntryCondition] -> DesktopEntryCondition)
-> [DesktopEntryCondition] -> DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ (Element -> Maybe DesktopEntryCondition)
-> [Element] -> [DesktopEntryCondition]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Element -> Maybe DesktopEntryCondition
parseSingleItem [Element]
elts
parseSingleItem :: Element -> Maybe DesktopEntryCondition
parseSingleItem Element
e = case QName -> String
qName (Element -> QName
elName Element
e) of
String
"Category" -> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a. a -> Maybe a
Just (DesktopEntryCondition -> Maybe DesktopEntryCondition)
-> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ String -> DesktopEntryCondition
Category (String -> DesktopEntryCondition)
-> String -> DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ Element -> String
strContent Element
e
String
"Filename" -> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a. a -> Maybe a
Just (DesktopEntryCondition -> Maybe DesktopEntryCondition)
-> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ String -> DesktopEntryCondition
Filename (String -> DesktopEntryCondition)
-> String -> DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ Element -> String
strContent Element
e
String
"And" -> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a. a -> Maybe a
Just (DesktopEntryCondition -> Maybe DesktopEntryCondition)
-> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ [DesktopEntryCondition] -> DesktopEntryCondition
And ([DesktopEntryCondition] -> DesktopEntryCondition)
-> [DesktopEntryCondition] -> DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ (Element -> Maybe DesktopEntryCondition)
-> [Element] -> [DesktopEntryCondition]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Element -> Maybe DesktopEntryCondition
parseSingleItem
([Element] -> [DesktopEntryCondition])
-> [Element] -> [DesktopEntryCondition]
forall a b. (a -> b) -> a -> b
$ Element -> [Element]
elChildren Element
e
String
"Or" -> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a. a -> Maybe a
Just (DesktopEntryCondition -> Maybe DesktopEntryCondition)
-> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ [DesktopEntryCondition] -> DesktopEntryCondition
Or ([DesktopEntryCondition] -> DesktopEntryCondition)
-> [DesktopEntryCondition] -> DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ (Element -> Maybe DesktopEntryCondition)
-> [Element] -> [DesktopEntryCondition]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Element -> Maybe DesktopEntryCondition
parseSingleItem
([Element] -> [DesktopEntryCondition])
-> [Element] -> [DesktopEntryCondition]
forall a b. (a -> b) -> a -> b
$ Element -> [Element]
elChildren Element
e
String
"Not" -> case Element -> Maybe DesktopEntryCondition
parseSingleItem ([Element] -> Element
forall a. HasCallStack => [a] -> a
head (Element -> [Element]
elChildren Element
e)) of
Maybe DesktopEntryCondition
Nothing -> Maybe DesktopEntryCondition
forall a. Maybe a
Nothing
Just DesktopEntryCondition
rule -> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a. a -> Maybe a
Just (DesktopEntryCondition -> Maybe DesktopEntryCondition)
-> DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a b. (a -> b) -> a -> b
$ DesktopEntryCondition -> DesktopEntryCondition
Not DesktopEntryCondition
rule
String
unknown -> String
-> Maybe DesktopEntryCondition -> Maybe DesktopEntryCondition
forall a. String -> a -> a
D.trace (String
"Unknown Condition item: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
unknown) Maybe DesktopEntryCondition
forall a. Maybe a
Nothing
data DesktopEntryCondition = Category String
| Filename String
| Not DesktopEntryCondition
| And [DesktopEntryCondition]
| Or [DesktopEntryCondition]
| All
| None
deriving (ReadPrec [DesktopEntryCondition]
ReadPrec DesktopEntryCondition
Int -> ReadS DesktopEntryCondition
ReadS [DesktopEntryCondition]
(Int -> ReadS DesktopEntryCondition)
-> ReadS [DesktopEntryCondition]
-> ReadPrec DesktopEntryCondition
-> ReadPrec [DesktopEntryCondition]
-> Read DesktopEntryCondition
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS DesktopEntryCondition
readsPrec :: Int -> ReadS DesktopEntryCondition
$creadList :: ReadS [DesktopEntryCondition]
readList :: ReadS [DesktopEntryCondition]
$creadPrec :: ReadPrec DesktopEntryCondition
readPrec :: ReadPrec DesktopEntryCondition
$creadListPrec :: ReadPrec [DesktopEntryCondition]
readListPrec :: ReadPrec [DesktopEntryCondition]
Read, Int -> DesktopEntryCondition -> String -> String
[DesktopEntryCondition] -> String -> String
DesktopEntryCondition -> String
(Int -> DesktopEntryCondition -> String -> String)
-> (DesktopEntryCondition -> String)
-> ([DesktopEntryCondition] -> String -> String)
-> Show DesktopEntryCondition
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> DesktopEntryCondition -> String -> String
showsPrec :: Int -> DesktopEntryCondition -> String -> String
$cshow :: DesktopEntryCondition -> String
show :: DesktopEntryCondition -> String
$cshowList :: [DesktopEntryCondition] -> String -> String
showList :: [DesktopEntryCondition] -> String -> String
Show, DesktopEntryCondition -> DesktopEntryCondition -> Bool
(DesktopEntryCondition -> DesktopEntryCondition -> Bool)
-> (DesktopEntryCondition -> DesktopEntryCondition -> Bool)
-> Eq DesktopEntryCondition
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DesktopEntryCondition -> DesktopEntryCondition -> Bool
== :: DesktopEntryCondition -> DesktopEntryCondition -> Bool
$c/= :: DesktopEntryCondition -> DesktopEntryCondition -> Bool
/= :: DesktopEntryCondition -> DesktopEntryCondition -> Bool
Eq)
parseLayout :: Element -> [XDGLayoutItem]
parseLayout :: Element -> [XDGLayoutItem]
parseLayout Element
elt = case QName -> Element -> Maybe Element
findChild (String -> QName
unqual String
"Layout") Element
elt of
Maybe Element
Nothing -> []
Just Element
lt -> (Element -> Maybe XDGLayoutItem) -> [Element] -> [XDGLayoutItem]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Element -> Maybe XDGLayoutItem
parseLayoutItem (Element -> [Element]
elChildren Element
lt)
where parseLayoutItem :: Element -> Maybe XDGLayoutItem
parseLayoutItem :: Element -> Maybe XDGLayoutItem
parseLayoutItem Element
e = case QName -> String
qName (Element -> QName
elName Element
e) of
String
"Separator" -> XDGLayoutItem -> Maybe XDGLayoutItem
forall a. a -> Maybe a
Just XDGLayoutItem
XliSeparator
String
"Filename" -> XDGLayoutItem -> Maybe XDGLayoutItem
forall a. a -> Maybe a
Just (XDGLayoutItem -> Maybe XDGLayoutItem)
-> XDGLayoutItem -> Maybe XDGLayoutItem
forall a b. (a -> b) -> a -> b
$ String -> XDGLayoutItem
XliFile (String -> XDGLayoutItem) -> String -> XDGLayoutItem
forall a b. (a -> b) -> a -> b
$ Element -> String
strContent Element
e
String
unknown -> String -> Maybe XDGLayoutItem -> Maybe XDGLayoutItem
forall a. String -> a -> a
D.trace (String
"Unknown layout item: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
unknown) Maybe XDGLayoutItem
forall a. Maybe a
Nothing
matchesCondition :: DesktopEntry -> DesktopEntryCondition -> Bool
matchesCondition :: DesktopEntry -> DesktopEntryCondition -> Bool
matchesCondition DesktopEntry
de (Category String
cat) = DesktopEntry -> String -> Bool
deHasCategory DesktopEntry
de String
cat
matchesCondition DesktopEntry
de (Filename String
fn) = String
fn String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== DesktopEntry -> String
deFilename DesktopEntry
de
matchesCondition DesktopEntry
de (Not DesktopEntryCondition
cond) = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ DesktopEntry -> DesktopEntryCondition -> Bool
matchesCondition DesktopEntry
de DesktopEntryCondition
cond
matchesCondition DesktopEntry
de (And [DesktopEntryCondition]
conds) = (DesktopEntryCondition -> Bool) -> [DesktopEntryCondition] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (DesktopEntry -> DesktopEntryCondition -> Bool
matchesCondition DesktopEntry
de) [DesktopEntryCondition]
conds
matchesCondition DesktopEntry
de (Or [DesktopEntryCondition]
conds) = (DesktopEntryCondition -> Bool) -> [DesktopEntryCondition] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (DesktopEntry -> DesktopEntryCondition -> Bool
matchesCondition DesktopEntry
de) [DesktopEntryCondition]
conds
matchesCondition DesktopEntry
_ DesktopEntryCondition
All = Bool
True
matchesCondition DesktopEntry
_ DesktopEntryCondition
None = Bool
False
getPreferredLanguages :: IO [String]
getPreferredLanguages :: IO [String]
getPreferredLanguages = do
Maybe String
mLcMessages <- String -> IO (Maybe String)
lookupEnv String
"LC_MESSAGES"
Maybe String
lang <- case Maybe String
mLcMessages of
Maybe String
Nothing -> String -> IO (Maybe String)
lookupEnv String
"LANG"
Just String
lm -> Maybe String -> IO (Maybe String)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Maybe String
forall a. a -> Maybe a
Just String
lm)
case Maybe String
lang of
Maybe String
Nothing -> [String] -> IO [String]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
Just String
l -> [String] -> IO [String]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$
let woEncoding :: String
woEncoding = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'.') String
l
(String
language, String
_cm) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'_') String
woEncoding
(String
country, String
_m) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'@') (if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
_cm then String
"" else String -> String
forall a. HasCallStack => [a] -> [a]
tail String
_cm)
modifier :: String
modifier = if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
_m then String
"" else String -> String
forall a. HasCallStack => [a] -> [a]
tail String
_m
in String -> String -> String -> [String]
dgl String
language String
country String
modifier
where dgl :: String -> String -> String -> [String]
dgl String
"" String
"" String
"" = []
dgl String
l String
"" String
"" = [String
l]
dgl String
l String
c String
"" = [String
l String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
c, String
l]
dgl String
l String
"" String
m = [String
l String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"@" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
m, String
l]
dgl String
l String
c String
m = [String
l String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
c String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"@" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
m, String
l String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
c,
String
l String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"@" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
m]
getXDGDesktop :: IO String
getXDGDesktop :: IO String
getXDGDesktop = do
Maybe String
mCurDt <- String -> IO (Maybe String)
lookupEnv String
"XDG_CURRENT_DESKTOP"
String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
"???" Maybe String
mCurDt
getDirectoryDirs :: IO [FilePath]
getDirectoryDirs :: IO [String]
getDirectoryDirs = do
[String]
dataDirs <- IO [String]
getXDGDataDirs
(String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM (String -> IO Bool
fileExist (String -> IO Bool) -> (String -> String) -> String -> IO Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String -> String
</> String
"desktop-directories")) [String]
dataDirs
readXDGMenu :: Maybe String -> IO (Maybe (XDGMenu, [DesktopEntry]))
Maybe String
mMenuPrefix = do
TextEncoding -> IO ()
setLocaleEncoding TextEncoding
utf8
[String]
filenames <- Maybe String -> IO [String]
getXDGMenuFilenames Maybe String
mMenuPrefix
[(XDGMenu, [DesktopEntry])] -> Maybe (XDGMenu, [DesktopEntry])
forall a. [a] -> Maybe a
headMay ([(XDGMenu, [DesktopEntry])] -> Maybe (XDGMenu, [DesktopEntry]))
-> ([Maybe (XDGMenu, [DesktopEntry])]
-> [(XDGMenu, [DesktopEntry])])
-> [Maybe (XDGMenu, [DesktopEntry])]
-> Maybe (XDGMenu, [DesktopEntry])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe (XDGMenu, [DesktopEntry])] -> [(XDGMenu, [DesktopEntry])]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe (XDGMenu, [DesktopEntry])]
-> Maybe (XDGMenu, [DesktopEntry]))
-> IO [Maybe (XDGMenu, [DesktopEntry])]
-> IO (Maybe (XDGMenu, [DesktopEntry]))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String -> IO (Maybe (XDGMenu, [DesktopEntry])))
-> [String] -> IO [Maybe (XDGMenu, [DesktopEntry])]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse String -> IO (Maybe (XDGMenu, [DesktopEntry]))
maybeMenu [String]
filenames
maybeMenu :: FilePath -> IO (Maybe (XDGMenu, [DesktopEntry]))
String
filename =
IO Bool
-> IO (Maybe (XDGMenu, [DesktopEntry]))
-> IO (Maybe (XDGMenu, [DesktopEntry]))
-> IO (Maybe (XDGMenu, [DesktopEntry]))
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM (String -> IO Bool
doesFileExist String
filename)
(do
String
contents <- String -> IO String
readFile String
filename
[String]
langs <- IO [String]
getPreferredLanguages
MaybeT IO (XDGMenu, [DesktopEntry])
-> IO (Maybe (XDGMenu, [DesktopEntry]))
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT (MaybeT IO (XDGMenu, [DesktopEntry])
-> IO (Maybe (XDGMenu, [DesktopEntry])))
-> MaybeT IO (XDGMenu, [DesktopEntry])
-> IO (Maybe (XDGMenu, [DesktopEntry]))
forall a b. (a -> b) -> a -> b
$ do
XDGMenu
m <- IO (Maybe XDGMenu) -> MaybeT IO XDGMenu
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (IO (Maybe XDGMenu) -> MaybeT IO XDGMenu)
-> IO (Maybe XDGMenu) -> MaybeT IO XDGMenu
forall a b. (a -> b) -> a -> b
$ Maybe XDGMenu -> IO (Maybe XDGMenu)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe XDGMenu -> IO (Maybe XDGMenu))
-> Maybe XDGMenu -> IO (Maybe XDGMenu)
forall a b. (a -> b) -> a -> b
$ String -> Maybe Element
forall s. XmlSource s => s -> Maybe Element
parseXMLDoc String
contents Maybe Element -> (Element -> Maybe XDGMenu) -> Maybe XDGMenu
forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Element -> Maybe XDGMenu
parseMenu
[DesktopEntry]
des <- IO [DesktopEntry] -> MaybeT IO [DesktopEntry]
forall (m :: * -> *) a. Monad m => m a -> MaybeT m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO [DesktopEntry] -> MaybeT IO [DesktopEntry])
-> IO [DesktopEntry] -> MaybeT IO [DesktopEntry]
forall a b. (a -> b) -> a -> b
$ [String] -> XDGMenu -> IO [DesktopEntry]
getApplicationEntries [String]
langs XDGMenu
m
(XDGMenu, [DesktopEntry]) -> MaybeT IO (XDGMenu, [DesktopEntry])
forall a. a -> MaybeT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (XDGMenu
m, [DesktopEntry]
des))
(do
String -> Priority -> String -> IO ()
logM String
"System.Taffybar.Information.XDG.Protocol" Priority
WARNING (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
String
"Menu file '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' does not exist!"
Maybe (XDGMenu, [DesktopEntry])
-> IO (Maybe (XDGMenu, [DesktopEntry]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (XDGMenu, [DesktopEntry])
forall a. Maybe a
Nothing)