<commit_before>-----------------------------------------------------------------------------
-- |
-- Module      :  Main.hs
-- Copyright   :  (c) <NAME> 2007
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  <EMAIL>
-- Stability   :  unstable
-- Portability :  not portable, uses mtl, X11, posix
--
-----------------------------------------------------------------------------
--
-- xmonad, a minimalist, tiling window manager for X11
--

import Data.Bits
import qualified Data.Map as M
import Control.Monad.Reader
import Control.Monad.State

import System.Environment (getArgs)

import Graphics.X11.Xlib hiding (refreshKeyboardMapping)
import Graphics.X11.Xlib.Extras
import Graphics.X11.Xinerama    (getScreenInfo)

import XMonad
import Config
import StackSet (new, floating, member)
import qualified StackSet as W
import Operations

import System.IO

--
-- The main entry point
--
main :: IO ()
main = do
    dpy   <- openDisplay ""
    let dflt = defaultScreen dpy
        initcolor c = fst `liftM` allocNamedColor dpy (defaultColormap dpy dflt) c

    rootw  <- rootWindow dpy dflt
    xinesc <- getScreenInfo dpy
    nbc    <- initcolor normalBorderColor
    fbc    <- initcolor focusedBorderColor
    hSetBuffering stdout NoBuffering
    args <- getArgs

    let winset | ("--resume" : s : _) <- args
               , [(x, "")]            <- reads s = x
               | otherwise = new (fromIntegral workspaces) (fromIntegral $ length xinesc)

        safeLayouts = case defaultLayouts of [] -> (full, []); (x:xs) -> (x,xs)
        cf = XConf
            { display       = dpy
            , theRoot       = rootw
            , normalBorder  = nbc
            , focusedBorder = fbc }
        st = XState
            { windowset     = winset
            , layouts       = M.fromList [(w, safeLayouts) | w <- [0 .. W workspaces - 1]]
            , statusGaps    = take (length xinesc) $ defaultGaps ++ repeat (0,0,0,0)
            , xineScreens   = xinesc }

    xSetErrorHandler -- in C, I'm too lazy to write the binding: dons

    -- setup initial X environment
    sync dpy False
    selectInput dpy rootw $  substructureRedirectMask .|. substructureNotifyMask
                         .|. enterWindowMask .|. leaveWindowMask .|. structureNotifyMask
    grabKeys dpy rootw
    grabButtons dpy rootw

    sync dpy False

    ws <- scan dpy rootw -- on the resume case, will pick up new windows
    allocaXEvent $ \e ->
        runX cf st $ do

            -- walk workspace, resetting X states/mask for windows
            -- TODO, general iterators for these lists.
            sequence_ [ setInitialProperties w >> reveal w
                      | wk <- map W.workspace (W.current winset : W.visible winset)
                      , w  <- W.integrate (W.stack wk) ]

            sequence_ [ setInitialProperties w >> hide w
                      | wk <- W.hidden winset
                      , w  <- W.integrate (W.stack wk) ]

            mapM_ manage ws -- find new windows
            when logging $ withWindowSet (io . hPrint stdout)

            -- main loop, for all you HOF/recursion fans out there.
            forever $ handle =<< io (nextEvent dpy e >> getEvent e)

      where forever a = a >> forever a

-- ---------------------------------------------------------------------
-- IO stuff. Doesn't require any X state
-- Most of these things run only on startup (bar grabkeys)

-- | scan for any new windows to manage. If they're already managed,
-- this should be idempotent.
scan :: Display -> Window -> IO [Window]
scan dpy rootw = do
    (_, _, ws) <- queryTree dpy rootw
    filterM ok ws
  where ok w = do wa <- getWindowAttributes dpy w
                  return $ not (wa_override_redirect wa)
                         && wa_map_state wa == waIsViewable

-- | Grab the keys back
grabKeys :: Display -> Window -> IO ()
grabKeys dpy rootw = do
    ungrabKey dpy anyKey anyModifier rootw
    forM_ (M.keys keys) $ \(mask,sym) -> do
         kc <- keysymToKeycode dpy sym
         -- "If the specified KeySym is not defined for any KeyCode,
         -- XKeysymToKeycode() returns zero."
         when (kc /= '\0') $ mapM_ (grab kc . (mask .|.)) extraModifiers

  where grab kc m = grabKey dpy kc m rootw True grabModeAsync grabModeAsync

grabButtons :: Display -> Window -> IO ()
grabButtons dpy rootw = do
    ungrabButton dpy anyButton anyModifier rootw
    mapM_ (\(m,b) -> mapM_ (grab b . (m .|.)) extraModifiers) (M.keys mouseBindings)
  where grab button mask = grabButton dpy button mask rootw False buttonPressMask
                                      grabModeAsync grabModeSync none none

extraModifiers :: [KeyMask]
extraModifiers = [0, numlockMask, lockMask, numlockMask .|. lockMask ]

cleanMask :: KeyMask -> KeyMask
cleanMask = (complement (numlockMask .|. lockMask) .&.)

-- ---------------------------------------------------------------------
-- | Event handler. Map X events onto calls into Operations.hs, which
-- modify our internal model of the window manager state.
--
-- Events dwm handles that we don't:
--
--    [ButtonPress]    = buttonpress,
--    [Expose]         = expose,
--    [PropertyNotify] = propertynotify,
--

handle :: Event -> X ()

-- run window manager command
handle (KeyEvent {ev_event_type = t, ev_state = m, ev_keycode = code})
    | t == keyPress = withDisplay $ \dpy -> do
        s  <- io $ keycodeToKeysym dpy code 0
        whenJust (M.lookup (cleanMask m,s) keys) id

-- manage a new window
handle (MapRequestEvent    {ev_window = w}) = withDisplay $ \dpy -> do
    wa <- io $ getWindowAttributes dpy w -- ignore override windows
    -- need to ignore mapping requests by managed windows not on the current workspace
    managed <- isClient w
    when (not (wa_override_redirect wa) && not managed) $ do manage w

-- window destroyed, unmanage it
-- window gone,      unmanage it
handle (DestroyWindowEvent {ev_window = w}) = whenX (isClient w) $ unmanage w

-- We only handle synthetic unmap events, because real events are confusable
-- with the events produced by 'hide'.  ICCCM says that all clients should send
-- synthetic unmap events immediately after unmapping, and later describes
-- clients that do not follow the rule as "obsolete".  For now, we make the
-- simplifying assumption that nobody uses clients that were already obsolete
-- in 1994.  Note that many alternative methods for resolving the hide/withdraw
-- ambiguity are racy.

handle (UnmapEvent         {ev_window = w, ev_send_event = True}) = whenX (isClient w) $ unmanage w

-- set keyboard mapping
handle e@(MappingNotifyEvent {ev_window = w}) = do
    io $ refreshKeyboardMapping e
    when (ev_request e == mappingKeyboard) $ withDisplay $ io . flip grabKeys w

-- click on an unfocused window, makes it focused on this workspace
handle e@(ButtonEvent {ev_window = w,ev_event_type = t,ev_button = b })
    | t == buttonPress = do
    isr <- isRoot w
    if isr then whenJust (M.lookup (cleanMask (ev_state e), b) mouseBindings) ($ ev_subwindow e)<commit_msg>whitespace<commit_after>-----------------------------------------------------------------------------
-- |
-- Module      :  Main.hs
-- Copyright   :  (c) <NAME> 2007
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  <EMAIL>
-- Stability   :  unstable
-- Portability :  not portable, uses mtl, X11, posix
--
-----------------------------------------------------------------------------
--
-- xmonad, a minimalist, tiling window manager for X11
--

import Data.Bits
import qualified Data.Map as M
import Control.Monad.Reader
import Control.Monad.State

import System.Environment (getArgs)

import Graphics.X11.Xlib hiding (refreshKeyboardMapping)
import Graphics.X11.Xlib.Extras
import Graphics.X11.Xinerama    (getScreenInfo)

import XMonad
import Config
import StackSet (new, floating, member)
import qualified StackSet as W
import Operations

import System.IO

--
-- The main entry point
--
main :: IO ()
main = do
    dpy   <- openDisplay ""
    let dflt = defaultScreen dpy
        initcolor c = fst `liftM` allocNamedColor dpy (defaultColormap dpy dflt) c

    rootw  <- rootWindow dpy dflt
    xinesc <- getScreenInfo dpy
    nbc    <- initcolor normalBorderColor
    fbc    <- initcolor focusedBorderColor
    hSetBuffering stdout NoBuffering
    args <- getArgs

    let winset | ("--resume" : s : _) <- args
               , [(x, "")]            <- reads s = x
               | otherwise = new (fromIntegral workspaces) (fromIntegral $ length xinesc)

        safeLayouts = case defaultLayouts of [] -> (full, []); (x:xs) -> (x,xs)
        cf = XConf
            { display       = dpy
            , theRoot       = rootw
            , normalBorder  = nbc
            , focusedBorder = fbc }
        st = XState
            { windowset     = winset
            , layouts       = M.fromList [(w, safeLayouts) | w <- [0 .. W workspaces - 1]]
            , statusGaps    = take (length xinesc) $ defaultGaps ++ repeat (0,0,0,0)
            , xineScreens   = xinesc }

    xSetErrorHandler -- in C, I'm too lazy to write the binding: dons

    -- setup initial X environment
    sync dpy False
    selectInput dpy rootw $  substructureRedirectMask .|. substructureNotifyMask
                         .|. enterWindowMask .|. leaveWindowMask .|. structureNotifyMask
    grabKeys dpy rootw
    grabButtons dpy rootw

    sync dpy False

    ws <- scan dpy rootw -- on the resume case, will pick up new windows
    allocaXEvent $ \e ->
        runX cf st $ do

            -- walk workspace, resetting X states/mask for windows
            -- TODO, general iterators for these lists.
            sequence_ [ setInitialProperties w >> reveal w
                      | wk <- map W.workspace (W.current winset : W.visible winset)
                      , w  <- W.integrate (W.stack wk) ]

            sequence_ [ setInitialProperties w >> hide w
                      | wk <- W.hidden winset
                      , w  <- W.integrate (W.stack wk) ]

            mapM_ manage ws -- find new windows
            when logging $ withWindowSet (io . hPrint stdout)

            -- main loop, for all you HOF/recursion fans out there.
            forever $ handle =<< io (nextEvent dpy e >> getEvent e)

      where forever a = a >> forever a

-- ---------------------------------------------------------------------
-- IO stuff. Doesn't require any X state
-- Most of these things run only on startup (bar grabkeys)

-- | scan for any new windows to manage. If they're already managed,
-- this should be idempotent.
scan :: Display -> Window -> IO [Window]
scan dpy rootw = do
    (_, _, ws) <- queryTree dpy rootw
    filterM ok ws
  where ok w = do wa <- getWindowAttributes dpy w
                  return $ not (wa_override_redirect wa)
                         && wa_map_state wa == waIsViewable

-- | Grab the keys back
grabKeys :: Display -> Window -> IO ()
grabKeys dpy rootw = do
    ungrabKey dpy anyKey anyModifier rootw
    forM_ (M.keys keys) $ \(mask,sym) -> do
         kc <- keysymToKeycode dpy sym
         -- "If the specified KeySym is not defined for any KeyCode,
         -- XKeysymToKeycode() returns zero."
         when (kc /= '\0') $ mapM_ (grab kc . (mask .|.)) extraModifiers

  where grab kc m = grabKey dpy kc m rootw True grabModeAsync grabModeAsync

grabButtons :: Display -> Window -> IO ()
grabButtons dpy rootw = do
    ungrabButton dpy anyButton anyModifier rootw
    mapM_ (\(m,b) -> mapM_ (grab b . (m .|.)) extraModifiers) (M.keys mouseBindings)
  where grab button mask = grabButton dpy button mask rootw False buttonPressMask
                                      grabModeAsync grabModeSync none none

extraModifiers :: [KeyMask]
extraModifiers = [0, numlockMask, lockMask, numlockMask .|. lockMask ]

cleanMask :: KeyMask -> KeyMask
cleanMask = (complement (numlockMask .|. lockMask) .&.)

-- ---------------------------------------------------------------------
-- | Event handler. Map X events onto calls into Operations.hs, which
-- modify our internal model of the window manager state.
--
-- Events dwm handles that we don't:
--
--    [ButtonPress]    = buttonpress,
--    [Expose]         = expose,
--    [PropertyNotify] = propertynotify,
--

handle :: Event -> X ()

-- run window manager command
handle (KeyEvent {ev_event_type = t, ev_state = m, ev_keycode = code})
    | t == keyPress = withDisplay $ \dpy -> do
        s  <- io $ keycodeToKeysym dpy code 0
        whenJust (M.lookup (cleanMask m,s) keys) id

-- manage a new window
handle (MapRequestEvent    {ev_window = w}) = withDisplay $ \dpy -> do
    wa <- io $ getWindowAttributes dpy w -- ignore override windows
    -- need to ignore mapping requests by managed windows not on the current workspace
    managed <- isClient w
    when (not (wa_override_redirect wa) && not managed) $ do manage w

-- window destroyed, unmanage it
-- window gone,      unmanage it
handle (DestroyWindowEvent {ev_window = w}) = whenX (isClient w) $ unmanage w

-- We only handle synthetic unmap events, because real events are confusable
-- with the events produced by 'hide'.  ICCCM says that all clients should send
-- synthetic unmap events immediately after unmapping, and later describes
-- clients that do not follow the rule as "obsolete".  For now, we make the
-- simplifying assumption that nobody uses clients that were already obsolete
-- in 1994.  Note that many alternative methods for resolving the hide/withdraw
-- ambiguity are racy.

handle (UnmapEvent {ev_window = w, ev_send_event = True}) = whenX (isClient w) $ unmanage w

-- set keyboard mapping
handle e@(MappingNotifyEvent {ev_window = w}) = do
    io $ refreshKeyboardMapping e
    when (ev_request e == mappingKeyboard) $ withDisplay $ io . flip grabKeys w

-- click on an unfocused window, makes it focused on this workspace
handle e@(ButtonEvent {ev_window = w,ev_event_type = t,ev_button = b })
    | t == buttonPress = do
    isr <- isRoot w
    if isr then whenJust (M.lookup (cleanMask (ev_state e), b) mouseBindings) ($ ev_subwindow e)
{'fraction_non_alphanumeric': 0.13332383733352327, 'fraction_numerical': 0.003988319920233602, 'mean_word_length': 2.058592899150512, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2569048', 'n_tokens_mistral': 4122, 'n_tokens_neox': 3960, 'n_words': 1465}