I am trying to configure my xmonad.hs so that when I start my session I start an array of different programs on different workspaces (like Terminal in 1 ; Firefox in 2 ; Pidgin in 3).
I already looked into the XMonad.Actions.SpawnOn, but as spawnOn returns with an X () and not with a common m () I can not use it in main = do ....
Is there a function that takes an X-monad and returns with IO () or is there another workaround?
The common way is to use startupHook which takes X () action and performs it on each startup.
E.g.
main = xmonad $ defaultConfig
{ startupHook = do
spawnOn "workspace1" "program1"
…
spawnOn "workspaceN" "programN"
}
Related
I'm currently authoring an application in Haskell that relies on Yesod and its web sockets implementation.
I was wondering what is the correct way to acquire and release resources for a WebSocketT handler.
For example, in the following naive case...
chatApp :: WebSocketsT Handler ()
chatApp = do
let outgoingFlow = forever $ deliverOutgoingMessages
let incomingFlow = forever $ deliverIncomingMessages
bracket_ acquireResource
releaseResource
(race_ outgoingFlow incomingFlow)
... releaseResource does not seem to be called when a client disconnects abruptly or purposefully.
This is what I ended up doing over the weekend. This is essentially a replication of how web socket background ping process works, apart for the fact that I'm not swallowing the ping send exception when the other end is no longer reachable, but rather using it to detect the disconnection.
echoApp' :: WebSocketsT Handler ()
echoApp' = do
conn <- ask
let acquire = putStrLn "Acquiring..."
release = putStrLn "Releasing"
hardWork = (threadDelay 600000000)
ping i = do
threadDelay (30 * 1000 * 1000)
WS.sendPing conn (T.pack $ show i)
ping (i + 1)
liftIO $ bracket_ acquire release $ race_ hardWork (ping 1)
The downside of this approach is that there's still an up to 30 seconds window when the web socket process is lingering, but at least the resource gets eventually released in a more or less controllable way.
http://zguide.zeromq.org/hs:asyncsrv
hope to terminate the program by press q to exit
main :: IO ()
main =
runZMQ $ do
async $ clientTask "A"
async $ clientTask "B"
async $ clientTask "C"
async serverTask
liftIO $ threadDelay $ 5 * 1000 * 1000
Process-to-process message passing is the very power of the ZeroMQ, so use it:
design a central aKbdMONITOR-thread, that monitors Keyboard and scans for Q | q
async $ clientTask "C"
async $ aKbdMONITOR -- Add central-service async thread
equip this aKbdMONITOR-thread with a PUB service to broadcast to any SUB-side an appearance of such event
aKbdSCANNER <- socket Pub -- PUB-side adequate ZeroMQ Archetype
bind aKbdSCANNER "tcp://*:8123" -- yes, can serve even for remote hosts
equip all other threads with a SUB pattern part and review any subsequent arriving event-notification from aKbdMONITOR-thread to decide locally about self-termination in case aKbdMONITOR-thread announces such case as requested above to exit
aKbdSCANNER <- socket Sub -- SUB-side adequate ZeroMQ Archetype
connect aKbdSCANNER "tcp://ipKBD:8123" -- tcp transport-class remote ipKBD
--
-- + do not forget to subscribe
-- + use poll to scan
I try to automate tests with the help of hs-webdriver, code see below. I have a selenium-server instance started. Everytime I run the main function in ghci I get an *** Exception: TimeoutTriggered and also the given page isn't opened. Do you have any idea, what's going wrong?
:set -XOverloadedStrings
:m + Test.WebDriver Control.Monad Test.WebDriver.Commands.Wait
let main :: IO() ; main = runSession defaultConfig $ do { openPage "http://stackoverflow.com/questions/ask" ; waitUntil 60 (findElem $ ByXPath ".//div") ; return () }
I'm using runCommand from System.Process but I use
"cd " ++ path ++ " & " ++ args
And it's not good, even will not work if path is on different local drive in windows.
How can I handle current directory change for runCommand ?
setCurrentDirectory from System.Directory changes the working directory of the main program.
If you do that before using runCommand, the command should use that directory too.
By looking at the source code of runCommand you can realize is just a thin wrapper for createProcess which is the one doing the real work. Here is an example taken from the createProcess documentation, which has been edited for convenience to address this question.
(_, Just hout, _, _) <- createProcess (proc "/path/to/my/executable" [])
{ cwd = Just "/path/to/working-directory"
, std_out = CreatePipe }
Is there a simple, direct way to play a WAV file from Haskell using some library and possibly such that I play many sounds at once?
I'm aware of OpenAL but I'm not writing some advanced audio synthesis program, I just want to play some sounds for a little play thing. Ideally the API might be something like:
readWavFile :: FilePath -> IO Wave
playWave :: Wave -> IO ()
playWaveNonBlocking :: Wave -> IO ()
I'm this close to merely launching mplayer or something. Or trying to cat the wav directly to /dev/snd/ or somesuch.
This is how to play multiple sounds on multiple channels at once with SDL. I think this answers the question criteria. WAV files, simple, Haskell, multiple channels.
import Control.Monad
import Control.Monad.Fix
import Graphics.UI.SDL as SDL
import Graphics.UI.SDL.Mixer as Mix
main = do
SDL.init [SDL.InitAudio]
result <- openAudio audioRate audioFormat audioChannels audioBuffers
classicJungle <- Mix.loadWAV "/home/chris/Samples/ClassicJungle/A4.wav"
realTech <- Mix.loadWAV "/home/chris/Samples/RealTech/A4.wav"
ch1 <- Mix.playChannel anyChannel classicJungle 0
SDL.delay 1000
ch2 <- Mix.playChannel anyChannel realTech 0
fix $ \loop -> do
SDL.delay 50
stillPlaying <- numChannelsPlaying
when (stillPlaying /= 0) loop
Mix.closeAudio
SDL.quit
where audioRate = 22050
audioFormat = Mix.AudioS16LSB
audioChannels = 2
audioBuffers = 4096
anyChannel = (-1)
I realize this is not actually a convenient way to do it, but I had the test code lying around, so...
{-# LANGUAGE NoImplicitPrelude #-}
module Wav (main) where
import Fay.W3C.Events
import Fay.W3C.Html5
import Language.Fay.FFI
import Language.Fay.Prelude
main :: Fay ()
main = addWindowEventListener "load" run
run :: Event -> Fay Bool
run _ = do
aud <- mkAudio
setSrc aud "test.wav"
play aud
return False
mkAudio :: Fay HTMLAudioElement
mkAudio = ffi "new Audio()"
addWindowEventListener :: String -> (Event -> Fay Bool) -> Fay ()
addWindowEventListener = ffi "window['addEventListener'](%1,%2,false)"
There you go--playing a WAV file in Haskell thanks to the power of HTML5! All you have to do is launch a web browser instead of mplayer. :D
using OpenAL through ALUT:
import Control.Monad
import Sound.ALUT
playSound :: IO ()
playSound =
withProgNameAndArgs runALUTUsingCurrentContext $ \_ _ ->
do
(Just device) <- openDevice Nothing
(Just context) <- createContext device []
currentContext $= Just context
buffer1 <- createBuffer $ Sine 440 0 1
buffer2 <- createBuffer HelloWorld
[source] <- genObjectNames 1
queueBuffers source [buffer1,buffer2]
play [source]
sleep 4
closeDevice device
return ()
main = playSound
to load a wav file:
buffer3 <- createBuffer $ File "/path/to/file.wav"
credit goes to Chris Double: http://bluishcoder.co.nz/articles/haskell/openal.html
module Main (main) where
import qualified SDL
import SDL.Mixer
main :: IO ()
main = do
SDL.initialize [SDL.InitAudio]
withAudio defaultAudio 4096 $ do
load "test.wav" >>= play
SDL.delay 1000
SDL.quit
I was trying to play sound with Haskell and I found this board when I searched how to do this. Actually, I want to know some kind of solution in Japanese sites because I am Japanese, but I couldn't find such sites.
I tried the OpenAl one above and with a little revision I succeeded, but I want to have a result with a simpler way.
I use 'sdl2' and 'sdl2-mixer' library. To do this, I had to install sdl2 and sdl2-mixer library into my OS.
I am using DebianOS and I installed 'libsdl2-dev' and 'libsdl2-mixer-dev' with apt command.
sudo apt instll libsdl2-dev libsdl2-mixer-dev
(Because I installed these files many months ago, so my memory is ambiguous.)
I use 'stack' to launch a Haskell project.
stack new myproject
(myproject is the project name)
In the myproject folder I edited the package.yaml file:
dependencies:
- base >= 4.7 && < 5
- sdl2
- sdl2-mixer
and I also edited then Main.hs file in the app folder. That is the above code.
I put the test.wav file in the myproject folder and with the command:
stack run
I could play the test sound.