Search code examples
haskellxmonad

xmonad: Check if a window is present in a workspace


In this certain section of my xmonad.hs config:

changeWorkspaces f i z = do
                windows $ f i
                when (z == True && windowsPresent /= "0") $ notifyWS i
                    where notifyWS i = spawn ("notify-send \"hello, workspace: " ++ i ++ "\"") 

                          windowsPresent :: XState -> String
                          windowsPresent = show . length . W.index . windowset 

And specifically in..

    when (z == True && windowsPresent /= "0") $ notifyWS i
                       ^^^^^^^^^^^^^^^^^^^^^

..I'm trying to check to see if a window or any number of windows (windowsPresent) is present in a workspace. If there are, as well as if z is equal to True, then run notifyWS.

The code above is one of my many experiements to solve this problem, and I'm aware that it's just a shot in the dark.

I've read through XMonad.StackSet and XMonad.Operations, and I have a hard time understanding their usage. I've tried the functions peek, index, and member, even looking through their source code, but getting them into boolean or arithmetic comparison is out of my limited knowledge for Haskell.


Provided error:
xmonad.hs:223:54: error:
    • Couldn't match type: [Char]
                     with: XState -> String
      Expected: XState -> String
        Actual: String
    • In the second argument of ‘(/=)’, namely ‘"0"’
      In the second argument of ‘(&&)’, namely ‘windowsPresent /= "0"’
      In the first argument of ‘when’, namely
        ‘(z == True && windowsPresent /= "0")’
    |
223 |                 when (z == True && windowsPresent /= "0") $ notifyWS i
    |

Code snippet:

    -- // workspace navigation
    -- mod-[1..9]         = Switch to workspace 
    -- mod-shift-[1..9]   = Move window to workspace
    -- mod-control-[1..9] = Move window to workspace and switch to that workspace
    [ ((modm .|. m, k), changeWorkspaces f i z)
        | (i, k) <- zip (myWorkspaces) [xK_1 .. xK_9]
        , (f, m, z) <- [ (W.greedyView, 0, False), 
                         (W.shift, shiftMask, True), 
                         (\i -> W.greedyView i . W.shift i, controlMask, True) ]
    ] 
        where 
            changeWorkspaces f i z = do
                windows $ f i
                when (z == True && windowsPresent /= "0") $ notifyWS i
                    where notifyWS i = spawn ("notify-send \"hello, workspace: " ++ i ++ "\"") 
 
                          windowsPresent :: XState -> String
                          windowsPresent = read . show . length . W.index . windowset

Solution

  • Ok, I think I understood what you want. I haven't tested the solution (no Xmonad available now). Let me know if it works

    -- You may need to import things
    
        [ ((modm .|. m, k), changeWorkspaces f i z)
            | (i, k) <- zip (myWorkspaces) [xK_1 .. xK_9]
            , (f, m, z) <- [ (W.greedyView, 0, False), 
                             (W.shift, shiftMask, True), 
                             (\i -> W.greedyView i . W.shift i, controlMask, True) ]
        ] 
            where 
                changeWorkspaces f i z = do
                    windows $ f i
                    stackset <- gets windowset  -- you need import Control.Monad.State.Class IIRC
                    --   Just check for z and windowsPresent.
                    when (z && windowsPresent stackset) $ notifyWS i
                        where notifyWS i = spawn ("notify-send \"hello, workspace: " ++ i ++ "\"") 
                              -- This should return True if workspace i has a windows
                              -- If workspace i doesn't exist; then checks if current
                              -- focused workspace has a window open
                              windowsPresent :: WindowSet -> Bool
                              windowsPresent = null . W.index . W.view i
    

    EDIT: For the checking if the current workspace has a window, you can define the function currentWorkSpaceHasWindow = isJust . peek.

    For example

    -- You may need to import things
    
        [ ((modm .|. m, k), changeWorkspaces f i z)
            | (i, k) <- zip (myWorkspaces) [xK_1 .. xK_9]
            , (f, m, z) <- [ (W.greedyView, 0, False), 
                             (W.shift, shiftMask, True), 
                             (\i -> W.greedyView i . W.shift i, controlMask, True) ]
        ] 
            where 
                changeWorkspaces f i z = do
                    windows $ f i
                    stackset <- gets windowset  -- you need import Control.Monad.State.Class IIRC
                    -- just move condition to its own line for clarity
                    let cond = z && not (windowsPresent stackset) && currentWorkSpaceHasWindow stackset  
                    when cond $ notifyWS i
                        where notifyWS i = spawn ("notify-send \"hello, workspace: " ++ i ++ "\"") 
                              -- This should return True if workspace i has a windows
                              -- If workspace i doesn't exist; then checks if current
                              -- focused workspace has a window open
                              windowsPresent :: WindowSet -> Bool
                              windowsPresent = null . W.index . W.view i
                              -- import Data.Maybe for isJust function.
                              -- True if the current ws has a window
                              currentWorkSpaceHasWindow :: WindowSet -> Bool
                              currentWorkSpaceHasWindow = isJust . peek