5

I'm a Haskell beginner and I'm using xmonad. I'm trying to make it prompt me before quitting as I occasionally hit mod+q by accident. I've found two ways of doing that, but I must be doing something wrong because neither of them work for me: https://bbs.archlinux.org/viewtopic.php?id=120298 http://comments.gmane.org/gmane.comp.lang.haskell.xmonad/11699

Here's my xmonad.hs:

import XMonad
import XMonad.Config.Gnome
import XMonad.Actions.Plane
import XMonad.Util.EZConfig
import XMonad.Util.Run(spawnPipe)
import qualified Data.Map as M
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.UrgencyHook
import System.IO(Handle, hPutStrLn)
import System.Exit
import Control.Monad
import XMonad
import XMonad.Util.EZConfig
import XMonad.Util.Dmenu
import XMonad.Util.Run

workspaces' = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

quit_confirm :: X ()
quit_confirm = do
  let m = "confirm restart"
  s <- dmenu [m]
  when (m == s) (spawn "xmonad --restart")

conf_quit = do
  response <- runProcessWithInput "dmenu" ["-p", "Quit?"] "yes\nno\n"
  when (response == "yes") (spawn "xmonad --restart")

main = do
        dzen2Pipe <- spawnPipe "dzen2 -w 1200 -xs 1 -ta l -fn '-*-terminus-*-*-*-*-16-*-*-*-*-*-*-*' -bg black -fg #d3d7cf "
        dzen2Right <- spawnPipe "~/.xmonad/status-dzen.sh"
        startupProgs <- spawnPipe "~/.xmonad/startups.sh"
        xmonad $ defaultConfig
             {
             workspaces = workspaces'
             , manageHook = manageHook' <+> manageHook defaultConfig
             , modMask = mod4Mask
             , terminal = "gnome-terminal"
     , layoutHook = layoutHook'
         , logHook = logHook' dzen2Pipe
             }
            `additionalKeysP`
               [ -- Lock Screen
                ("M-S-l",    spawn "gnome-screensaver-command -l")
                -- Sleep
                , ("M-S-;",   spawn "gnome-screensaver-command -l; pmi action suspend")
                -- wireless
                , ("M-S-C-w", spawn "~/.xmonad/wireless.sh")
                -- 1 screen reconf
                , ("M-S-C-1", spawn "~/.xmonad/1-screen.sh")
                -- 2 screen reconf
                , ("M-S-C-2", spawn "~/.xmonad/2-screen.sh")
                -- confirm for quit
                , ("M-q", conf_quit)
                ]
             `additionalKeys`
             M.toList (planeKeys mod4Mask GConf Finite)

layoutHook' = avoidStruts $ layoutHook defaultConfig

logHook' = dynamicLogWithPP . dzenPP'

dzenPP' h = defaultPP
            {
            ppOutput = hPutStrLn h
            }

manageHook' = composeAll
  [ className =? "Pidgin" --> doShift "1" ,
    className =? "Firefox" --> doShift "2" ,
    className =? "Thunderbird" --> doShift "3" ,
    className =? "OpenOffice.org 3.2" --> doShift "4",
    manageDocks ]

Thanks!

Edit: the menu is displayed, but spawn process doesn't seem to work.

Adrian Muresan
  • 199
  • 1
  • 1
  • 7
  • You named it `conf_quit`, but it does a restart. Do you want it to quit or restart after a successful confirmation? – Daniel Wagner Apr 03 '12 at 15:59
  • I went through both, but it doesn't perform the spawn process. I'm starting to think that my problem comes from somewhere else since the code works for other people. – Adrian Muresan Apr 03 '12 at 16:34
  • What exactly happens? What makes you think the `spawn` isn't happening? What happens when you bind the key to something more obvious than a spawn, say, an actual quit? Can you check that your xmonad executable is in xmonad's `PATH` (which may differ from your terminal's `PATH` and your console's `PATH`)? – Daniel Wagner Apr 03 '12 at 16:49

4 Answers4

2

The answers others gave missed that dmenu seems to add an extra whitespace to the end of the string it returns. You just need to do the following and it works for me:

confirm :: String -> X () -> X ()
confirm m f = do
  result <- dmenu [m]
  when (init result == m) f

And then, as @mariop suggested use either

confirm "Restart" $ spawn "xmonad --recompile && xmonad --restart"

or

confirm "Exit" $ io (exitWith ExitSuccess)
Doug Moore
  • 1,028
  • 2
  • 10
  • 20
2

Change the key binding to

("M-q", confirm "Confirm restart?" $ restart "xmonad" True)

And add a generic confirmation action that uses dmenu

confirm :: String -> X () -> X ()
confirm msg f = do
    a <- dmenu [msg,"y","n"]
    when (a=="y") f
mariop
  • 3,195
  • 1
  • 19
  • 29
  • Hi, I tried, but still didn't work. The menu is shown, but the doesn't seem to be executed and I can't find anything relevant in my .xsession-errors either – Adrian Muresan Apr 03 '12 at 16:20
  • I had problems sometimes while trying to restart xmonad and the solution was to restart the X session instead of reloading Xmonad (for example, restart gdm). Now I tried by myself and my code is working on xmonad 0.10-2 (debian package). – mariop Apr 03 '12 at 17:16
0

I wrote the following module, which doesn't require dmenu to be installed:

-----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Prompt
-- Copyright   :  (C) 2015 Antoine Beaupré
-- License     :  BSD3
--
-- Maintainer  :  Antoine Beaupré <anarcat@debian.org>
-- Stability   :  unstable
-- Portability :  unportable
--
-- A module for setting up simple confirmation prompts for keybindings.
--
-----------------------------------------------------------------------------
module XMonad.Prompt.ConfirmPrompt (confirmPrompt
                                    -- * Usage
                                    -- $usage
                                    , module XMonad.Prompt
                                    -- * Use case: confirming exit
                                    -- $tip
                                    , EnterPrompt
                                    ) where

import XMonad (X)
import XMonad.Prompt (XPConfig, XPrompt, showXPrompt, mkXPrompt, mkComplFunFromList)

{- $usage

This module makes it easy to add a confirmation prompt for specific
actions. Instead of just running the action, a simple confirmation
prompt will be created using 'XMonad.Prompt' primitives. The action
will then run normally if the user confirms.
-}

{- $tip
This should be used something like this:

> ...
> , ((modm , xK_l), confirmPrompt defaultXPConfig "exit" $ io (exitWith ExitSuccess))
> ...
-}

{- | Customized 'XPrompt' prompt that will ask to confirm the given string -}
data EnterPrompt = EnterPrompt String
instance XPrompt EnterPrompt where
    showXPrompt (EnterPrompt n) = "Confirm " ++ n ++ " (esc/ENTER)"

{- | Prompt the user to confirm a given action. We offer no completion
     and simply ask to confirm (ENTER) or cancel (ESCAPE). The actual key
     handling is done by mkXPrompt.-}
confirmPrompt :: XPConfig -> String -> X() -> X()
confirmPrompt config app func = mkXPrompt (EnterPrompt app) config (mkComplFunFromList []) $ const func

Install this in a ~/.xmonad/lib/XMonad/Prompt directory and enjoy!

(I submitted this to the XMonad mailing list and I'm waiting for feedback...)

anarcat
  • 5,605
  • 4
  • 32
  • 38
0

You say you want a quit confirm but your code does a restart confirm. If this is restart that you want, I tested and quit_confirm works.

What you most likely miss is the recompilation of xmonad to see your new configuration. Try this:

quit_confirm :: X ()
quit_confirm = do
  let m = "confirm restart"
  s <- dmenu [m]
  when (m == s) (spawn "xmonad recompile && xmonad --restart")
Nicolas Dudebout
  • 9,172
  • 2
  • 34
  • 43