-- | Bind media keys for Spotify using @dbus@.
module XMonad.Util.Spotify ( -- * default keybindings
                             mediaKeys
                           , mediaKeysWith
                           -- * Media control in the 'X' monad
                           , audioPrev
                           , audioNext
                           , audioPlayPause
                           , audioStop
                           , audioNextWith
                           , audioPrevWith
                           , audioPlayPauseWith
                           , audioStopWith
                           ) where

import           Control.Monad                (void)
import           Control.Monad.IO.Class
import qualified Data.Map                     as M
import           DBus
import           DBus.Client
import           Graphics.X11.ExtraTypes.XF86
import           Graphics.X11.Types

-- | @since 0.1.2.0
mediaKeys :: MonadIO m => M.Map (KeyMask, KeySym) (m ()) -> M.Map (KeyMask, KeySym) (m ())
mediaKeys :: forall (m :: * -> *).
MonadIO m =>
Map (KeyMask, KeySym) (m ()) -> Map (KeyMask, KeySym) (m ())
mediaKeys = Map (KeyMask, KeySym) (m ())
-> Map (KeyMask, KeySym) (m ()) -> Map (KeyMask, KeySym) (m ())
forall k a. Ord k => Map k a -> Map k a -> Map k a
M.union Map (KeyMask, KeySym) (m ())
mediaKeyMap
    where mediaKeyMap :: Map (KeyMask, KeySym) (m ())
mediaKeyMap = [((KeyMask, KeySym), m ())] -> Map (KeyMask, KeySym) (m ())
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [((KeyMask, KeySym), m ())]
forall (m :: * -> *). MonadIO m => [((KeyMask, KeySym), m ())]
mediaKeyList

mediaKeyList :: MonadIO m => [((KeyMask, KeySym), m ())]
mediaKeyList :: forall (m :: * -> *). MonadIO m => [((KeyMask, KeySym), m ())]
mediaKeyList = [ ((KeyMask
0, KeySym
xF86XK_AudioNext), m ()
forall (m :: * -> *). MonadIO m => m ()
audioNext)
               , ((KeyMask
0, KeySym
xF86XK_AudioPrev), m ()
forall (m :: * -> *). MonadIO m => m ()
audioPrev)
               , ((KeyMask
0, KeySym
xF86XK_AudioPlay), m ()
forall (m :: * -> *). MonadIO m => m ()
audioPlayPause)
               , ((KeyMask
0, KeySym
xF86XK_AudioStop), m ()
forall (m :: * -> *). MonadIO m => m ()
audioStop)
               ]

-- | Given your keymaps, add the media keybindings. Currently they are set up
-- for Spotify.
mediaKeysWith :: MonadIO m => Client -> M.Map (KeyMask, KeySym) (m ()) -> M.Map (KeyMask, KeySym) (m ())
mediaKeysWith :: forall (m :: * -> *).
MonadIO m =>
Client
-> Map (KeyMask, KeySym) (m ()) -> Map (KeyMask, KeySym) (m ())
mediaKeysWith Client
client = Map (KeyMask, KeySym) (m ())
-> Map (KeyMask, KeySym) (m ()) -> Map (KeyMask, KeySym) (m ())
forall k a. Ord k => Map k a -> Map k a -> Map k a
M.union Map (KeyMask, KeySym) (m ())
mediaKeyMap
    where mediaKeyMap :: Map (KeyMask, KeySym) (m ())
mediaKeyMap = [((KeyMask, KeySym), m ())] -> Map (KeyMask, KeySym) (m ())
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList (Client -> [((KeyMask, KeySym), m ())]
forall (m :: * -> *).
MonadIO m =>
Client -> [((KeyMask, KeySym), m ())]
mediaKeyListWith Client
client)

mediaKeyListWith :: MonadIO m => Client -> [((KeyMask, KeySym), m ())]
mediaKeyListWith :: forall (m :: * -> *).
MonadIO m =>
Client -> [((KeyMask, KeySym), m ())]
mediaKeyListWith Client
client = [ ((KeyMask
0, KeySym
xF86XK_AudioNext), Client -> m ()
forall (m :: * -> *). MonadIO m => Client -> m ()
audioNextWith Client
client)
                          , ((KeyMask
0, KeySym
xF86XK_AudioPrev), Client -> m ()
forall (m :: * -> *). MonadIO m => Client -> m ()
audioPrevWith Client
client)
                          , ((KeyMask
0, KeySym
xF86XK_AudioPlay), Client -> m ()
forall (m :: * -> *). MonadIO m => Client -> m ()
audioPlayPauseWith Client
client)
                          , ((KeyMask
0, KeySym
xF86XK_AudioStop), Client -> m ()
forall (m :: * -> *). MonadIO m => Client -> m ()
audioStopWith Client
client)
                          ]

spWith :: MonadIO m => Client -> String -> m ()
spWith :: forall (m :: * -> *). MonadIO m => Client -> String -> m ()
spWith Client
client String
str = m MethodReturn -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m MethodReturn -> m ()) -> m MethodReturn -> m ()
forall a b. (a -> b) -> a -> b
$ IO MethodReturn -> m MethodReturn
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO MethodReturn -> m MethodReturn)
-> IO MethodReturn -> m MethodReturn
forall a b. (a -> b) -> a -> b
$
    Client -> MethodCall -> IO MethodReturn
call_ Client
client (ObjectPath -> InterfaceName -> MemberName -> MethodCall
methodCall (String -> ObjectPath
objectPath_ String
"/org/mpris/MediaPlayer2") (String -> InterfaceName
interfaceName_ String
"org.mpris.MediaPlayer2.Player") (String -> MemberName
memberName_ String
str))
      { methodCallDestination :: Maybe BusName
methodCallDestination = BusName -> Maybe BusName
forall a. a -> Maybe a
Just (String -> BusName
busName_ String
"org.mpris.MediaPlayer2.spotify") }

sp :: MonadIO m => String -> m ()
sp :: forall (m :: * -> *). MonadIO m => String -> m ()
sp String
str = do
    Client
client <- IO Client -> m Client
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Client
connectSession
    Client -> String -> m ()
forall (m :: * -> *). MonadIO m => Client -> String -> m ()
spWith Client
client String
str
    IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ Client -> IO ()
disconnect Client
client

-- | @since 0.1.2.0
audioNextWith :: MonadIO m => Client -> m ()
audioNextWith :: forall (m :: * -> *). MonadIO m => Client -> m ()
audioNextWith = (Client -> String -> m ()) -> String -> Client -> m ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Client -> String -> m ()
forall (m :: * -> *). MonadIO m => Client -> String -> m ()
spWith String
"Next"

-- | @since 0.1.2.0
audioPrevWith :: MonadIO m => Client -> m ()
audioPrevWith :: forall (m :: * -> *). MonadIO m => Client -> m ()
audioPrevWith = (Client -> String -> m ()) -> String -> Client -> m ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Client -> String -> m ()
forall (m :: * -> *). MonadIO m => Client -> String -> m ()
spWith String
"Previous"

-- | @since 0.1.2.0
audioPlayPauseWith :: MonadIO m => Client -> m ()
audioPlayPauseWith :: forall (m :: * -> *). MonadIO m => Client -> m ()
audioPlayPauseWith = (Client -> String -> m ()) -> String -> Client -> m ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Client -> String -> m ()
forall (m :: * -> *). MonadIO m => Client -> String -> m ()
spWith String
"PlayPause"

-- | @since 0.1.2.0
audioStopWith :: MonadIO m => Client -> m ()
audioStopWith :: forall (m :: * -> *). MonadIO m => Client -> m ()
audioStopWith = (Client -> String -> m ()) -> String -> Client -> m ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Client -> String -> m ()
forall (m :: * -> *). MonadIO m => Client -> String -> m ()
spWith String
"Stop"

-- | Action in the 'X' monad to go to next
audioNext :: MonadIO m => m ()
audioNext :: forall (m :: * -> *). MonadIO m => m ()
audioNext = String -> m ()
forall (m :: * -> *). MonadIO m => String -> m ()
sp String
"Next"

-- | Action in the 'X' monad to go the previous
audioPrev :: MonadIO m => m ()
audioPrev :: forall (m :: * -> *). MonadIO m => m ()
audioPrev = String -> m ()
forall (m :: * -> *). MonadIO m => String -> m ()
sp String
"Previous"

-- | Action in the 'X' monad to play/pause
audioPlayPause :: MonadIO m => m ()
audioPlayPause :: forall (m :: * -> *). MonadIO m => m ()
audioPlayPause = String -> m ()
forall (m :: * -> *). MonadIO m => String -> m ()
sp String
"PlayPause"

audioStop :: MonadIO m => m ()
audioStop :: forall (m :: * -> *). MonadIO m => m ()
audioStop = String -> m ()
forall (m :: * -> *). MonadIO m => String -> m ()
sp String
"Stop"