{-# OPTIONS_GHC -fno-warn-missing-signatures #-}

-----------------------------------------------------------------------------
-- |
-- Module       : XMonad.Config.Gnome
-- Description  : Config for integrating xmonad with GNOME.
-- Copyright    : (c) Spencer Janssen <spencerjanssen@gmail.com>
-- License      : BSD
--
-- Maintainer   : Spencer Janssen <spencerjanssen@gmail.com>
-- Stability    :  unstable
-- Portability  :  unportable
--
-- This module provides a config suitable for use with the GNOME desktop
-- environment.

module XMonad.Config.Gnome (
    -- * Usage
    -- $usage
    gnomeConfig,
    gnomeRun,
    gnomeRegister,
    desktopLayoutModifiers
    ) where

import XMonad
import XMonad.Config.Desktop
import XMonad.Util.Run (safeSpawn)

import qualified Data.Map as M

import System.Environment (getEnvironment)

-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Gnome
-- >
-- > main = xmonad gnomeConfig
--
-- For examples of how to further customize @gnomeConfig@ see "XMonad.Config.Desktop".

gnomeConfig :: XConfig
  (ModifiedLayout
     AvoidStruts (Choose Tall (Choose (Mirror Tall) Full)))
gnomeConfig = XConfig
  (ModifiedLayout
     AvoidStruts (Choose Tall (Choose (Mirror Tall) Full)))
desktopConfig
    { terminal :: String
terminal = String
"gnome-terminal"
    , keys :: XConfig Layout -> Map (KeyMask, Time) (X ())
keys     = XConfig Layout -> Map (KeyMask, Time) (X ())
forall {l :: * -> *}. XConfig l -> Map (KeyMask, Time) (X ())
gnomeKeys (XConfig Layout -> Map (KeyMask, Time) (X ()))
-> (XConfig Layout -> Map (KeyMask, Time) (X ()))
-> XConfig Layout
-> Map (KeyMask, Time) (X ())
forall a. Semigroup a => a -> a -> a
<> XConfig
  (ModifiedLayout
     AvoidStruts (Choose Tall (Choose (Mirror Tall) Full)))
-> XConfig Layout -> Map (KeyMask, Time) (X ())
forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (KeyMask, Time) (X ())
keys XConfig
  (ModifiedLayout
     AvoidStruts (Choose Tall (Choose (Mirror Tall) Full)))
desktopConfig
    , startupHook :: X ()
startupHook = X ()
forall (m :: * -> *). MonadIO m => m ()
gnomeRegister X () -> X () -> X ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> XConfig
  (ModifiedLayout
     AvoidStruts (Choose Tall (Choose (Mirror Tall) Full)))
-> X ()
forall (l :: * -> *). XConfig l -> X ()
startupHook XConfig
  (ModifiedLayout
     AvoidStruts (Choose Tall (Choose (Mirror Tall) Full)))
desktopConfig }

gnomeKeys :: XConfig l -> Map (KeyMask, Time) (X ())
gnomeKeys XConfig{modMask :: forall (l :: * -> *). XConfig l -> KeyMask
modMask = KeyMask
modm} = [((KeyMask, Time), X ())] -> Map (KeyMask, Time) (X ())
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList
    [ ((KeyMask
modm, Time
xK_p), X ()
gnomeRun)
    , ((KeyMask
modm KeyMask -> KeyMask -> KeyMask
forall a. Bits a => a -> a -> a
.|. KeyMask
shiftMask, Time
xK_q), String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
spawn String
"gnome-session-quit --logout") ]

-- | Launch the "Run Application" dialog.  gnome-panel must be running for this
-- to work.
gnomeRun :: X ()
gnomeRun :: X ()
gnomeRun = (Display -> X ()) -> X ()
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X ()) -> X ()) -> (Display -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
    Time
rw <- (XConf -> Time) -> X Time
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> Time
theRoot
    Time
gnome_panel <- String -> X Time
getAtom String
"_GNOME_PANEL_ACTION"
    Time
panel_run   <- String -> X Time
getAtom String
"_GNOME_PANEL_ACTION_RUN_DIALOG"

    IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ (XEventPtr -> IO ()) -> IO ()
forall a. (XEventPtr -> IO a) -> IO a
allocaXEvent ((XEventPtr -> IO ()) -> IO ()) -> (XEventPtr -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \XEventPtr
e -> do
        XEventPtr -> EventType -> IO ()
setEventType XEventPtr
e EventType
clientMessage
        XEventPtr -> Time -> Time -> CInt -> Time -> Time -> IO ()
setClientMessageEvent XEventPtr
e Time
rw Time
gnome_panel CInt
32 Time
panel_run Time
0
        Display -> Time -> Bool -> Time -> XEventPtr -> IO ()
sendEvent Display
dpy Time
rw Bool
False Time
structureNotifyMask XEventPtr
e
        Display -> Bool -> IO ()
sync Display
dpy Bool
False

-- | Register xmonad with gnome. 'dbus-send' must be in the $PATH with which
-- xmonad is started.
--
-- This action reduces a delay on startup only only if you have configured
-- gnome-session>=2.26: to start xmonad with a command as such:
--
-- > gconftool-2 -s /desktop/gnome/session/required_components/windowmanager xmonad --type string
gnomeRegister :: MonadIO m => m ()
gnomeRegister :: forall (m :: * -> *). MonadIO m => m ()
gnomeRegister = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ do
    Maybe String
x <- String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
"DESKTOP_AUTOSTART_ID" ([(String, String)] -> Maybe String)
-> IO [(String, String)] -> IO (Maybe String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO [(String, String)]
getEnvironment
    Maybe String -> (String -> IO ()) -> IO ()
forall (m :: * -> *) a. Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust Maybe String
x ((String -> IO ()) -> IO ()) -> (String -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \String
sessionId -> String -> [String] -> IO ()
forall (m :: * -> *). MonadIO m => String -> [String] -> m ()
safeSpawn String
"dbus-send"
            [String
"--session"
            ,String
"--print-reply=literal"
            ,String
"--dest=org.gnome.SessionManager"
            ,String
"/org/gnome/SessionManager"
            ,String
"org.gnome.SessionManager.RegisterClient"
            ,String
"string:xmonad"
            ,String
"string:"String -> String -> String
forall a. [a] -> [a] -> [a]
++String
sessionId]