0

I have an issue with a function I took from XMonad.Util.Dmenu, namely dmenuXinerama (see below). It seems like this is happening:

These functions block xmonad's event loop until dmenu exits; this means that programs will not be able to open new windows and you will not be able to change workspaces or input focus until you have responded to the prompt one way or another.

What happens is that I spawn a menu instance and it appears, but once I run something from there, everything is blocked, and I can't do anything.

This is the function:

dmenuXinerama :: [String] -> X String
dmenuXinerama opts = do
    curscreen <- (fromIntegral . W.screen . W.current) `fmap` gets windowset :: X Int
    io $ runProcessWithInput "dmenu_run" ["-m", show curscreen] (unlines opts)

... and a binding:

-- Spawn dmenu
, ((modMask, xK_p), void $ dmenuXinerama [])

I've also tried this:

dmenuXinerama :: [String] -> X String
dmenuXinerama opts = do
    curscreen <-
      (fromIntegral . W.screen . W.current) `fmap` gets windowset :: X Int
    _ <-
      runProcessWithInput "dmenu_run" ["-m", show curscreen] (unlines opts)
    menuArgs "dmenu_run" ["-m", show curscreen] opts

-- | Like 'menu' but also takes a list of command line arguments.
menuArgs :: MonadIO m => String -> [String] -> [String] -> m String
menuArgs menuCmd args opts = liftM (filter (/='\n')) $
  runProcessWithInput menuCmd args (unlines opts)

I'd appreciate it if someone explained what's going on and how can I overcome the issue.

adder
  • 3,512
  • 1
  • 16
  • 28

1 Answers1

1

I think dmenu_run doesn't exit (until the program you start with it does), so it is not suitable for use with runProcessWithInput. Use dmenu_path and dmenu instead, then spawn the result.

pickExe :: X ()
pickExe = do
    exes <- runProcessWithInput "dmenu_path" [] ""
    exe <- dmenuXinerama (lines exes)
    spawn exe

The dmenuXinerama in the above snippet is the one you can import from XMonad.Util.Dmenu, not your modified one from the question. (And spawn is from XMonad.Core.)

If you are comfortable with the Monad interface, you might prefer to write that without the temporary names like this:

pickExe = spawn =<< dmenuXinerama . lines =<< runProcessWithInput "dmenu_path" [] ""
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • Thanks for the help, however, I see that the `XMonad.Util.Dmenu` module uses `-xs`, and there are no `-x` and `-s` options in my `dmenu`, which is a reason why I defined my own function in the first place. The second reason was that dmenu gets spawned on the wrong screen because that `+1` in the code. If I remove that, it gets spawned on the right screen. When it comes to your snippets, I have tried them, and the first snippet wouldn't work, I had to wrap `exes` in a list (`[exes]`), and once it compiled, `dmenu` was not getting spawned at all. – adder Dec 14 '20 at 06:47
  • As for your second snippet, I get an error, too, saying `Couldn't match type ‘Char’ with ‘[Char]’ Expected type: String -> X String Actual type: [String] -> X String`, that's a red squiggly line under `dmenuXinerama` in my editor. I'd appreciate suggestions as to how to make the function I defined work correctly, because my dmenu hasn't got those options, and it gets spawned on the wrong screen. dmenu version is `dmenu-4.8`. – adder Dec 14 '20 at 06:47
  • Seems like I got it to work with combination of my function and your thing. – adder Dec 14 '20 at 06:52
  • @adder As discussed in the documentation, the `-xs` used by `dmenuXinerama` requires that you apply jcreigh's multi-monitor patch to dmenu. (You *did* read the documentation, right?) Apologies about the `String`/`[String]` bit. I was a bit sloppy. The correct way is `dmenuXinerama (lines exes)` (or `dmenu (lines exes)` if you don't want to use `dmenuXinerama`). The analogous fix to the second version is `spawn =<< dmenuXinerama . lines =<< runProcessWithInput "dmenu_path" [] ""`. – Daniel Wagner Dec 14 '20 at 07:31