packages feed

vision-0.0.5.0: src/Volume.hs

-- -*-haskell-*-
--  Vision (for the Voice): an XMMS2 client.
--
--  Author:  Oleg Belozeorov
--  Created: 22 Jun. 2010
--
--  Copyright (C) 2010, 2011 Oleg Belozeorov
--
--  This program is free software; you can redistribute it and/or
--  modify it under the terms of the GNU General Public License as
--  published by the Free Software Foundation; either version 3 of
--  the License, or (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
--  General Public License for more details.
--

{-# LANGUAGE DeriveDataTypeable #-}

module Volume
  ( initVolume
  , volumeEnv
  , makeVolumeControl
  ) where

import Control.Monad
import Control.Monad.Trans
import Control.Monad.EnvIO

import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TGVar

import qualified Data.Map as Map
import Data.Typeable
import Data.Env

import Graphics.UI.Gtk hiding (add, remove)

import XMMS2.Client

import XMMS
import Utils
import Registry


data Ix = Ix deriving (Typeable)
deriving instance Typeable Adjustment

volumeEnv :: Extract Ix Adjustment
volumeEnv = Extract

initVolume = do
  adj <- liftIO $ adjustmentNew 0 0 100 5 5 0
  addEnv Ix adj

  liftIO $ do
    cId <- adj `onValueChanged` do
      vol <- adjustmentGetValue adj
      setVolume $ round vol

    xcW <- atomically $ newTGWatch connectedV
    forkIO $ forever $ do
      conn <- atomically $ watch xcW
      if conn
        then do
        playbackVolumeGet xmms >>* do
          handleVolume adj cId
          liftIO $ broadcastPlaybackVolumeChanged xmms >>* do
            handleVolume adj cId
            persist
        else withoutVolumeChange cId $ adjustmentSetValue adj 0

  return ()

makeVolumeControl = do
  adj <- envx Ix
  liftIO $ do
    view <- hScaleNew adj
    scaleSetDrawValue view False
    rangeSetUpdatePolicy view UpdateContinuous
    widgetSetCanFocus view False

    xcW <- atomically $ newTGWatch connectedV
    tid <- forkIO $ forever $ do
      conn <- atomically $ watch xcW
      widgetSetSensitive view conn
    view `onDestroy` killThread tid

    return view

handleVolume adj cId = do
  vol <- catchResult 0 (maximum . Map.elems)
  liftIO $ withoutVolumeChange cId $
    adjustmentSetValue adj $ fromIntegral vol

setVolume vol =
  playbackVolumeGet xmms >>* do
    vols <- catchResult Map.empty id
    liftIO $ mapM_ (flip (playbackVolumeSet xmms) vol) $ Map.keys vols

withoutVolumeChange cId =
  bracket_ (signalBlock cId) (signalUnblock cId)