Skip to content

Instantly share code, notes, and snippets.

@altercation
Created January 10, 2017 03:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save altercation/87fd85a7cd9c840134026c84e14cdadf to your computer and use it in GitHub Desktop.
Save altercation/87fd85a7cd9c840134026c84e14cdadf to your computer and use it in GitHub Desktop.
XMonad Config for video bug report re: screenlock obscured by windows after switching displays
{-# LANGUAGE AllowAmbiguousTypes, DeriveDataTypeable, TypeSynonymInstances, MultiParamTypeClasses #-}
-- a little messy, I know, but it's WIP
---------------------------------------------------------------------------
-- Ethan Schoonover <es@ethanschoonover.com> @ethanschoonover --
-- https://github.com/altercation --
---------------------------------------------------------------------------
-- current as of XMonad 0.12
------------------------------------------------------------------------}}}
-- TODO {{{
---------------------------------------------------------------------------
{-|
GENERAL
* look into X.H.Scripts -- there are things I want to run at startup, for example
* X.U.SpawnNamedPipe? xmobars. multiple screens.
* X.U.WindowState
* review XMonad.ManageHook https://hackage.haskell.org/package/xmonad-0.12/docs/XMonad-ManageHook.html
* ? X.A.LinkWorkspaces
* ? X.A.Search
* ? X.A.ShowText
* ? X.A.SimpleDate
* ? X.A.Warp
* ? X.A.WindowBringer
* ? X.A.WorkspaceCursors
* ? XMonad.Hooks.Minimize / X.H.Minimize or XMonad.Layout.Hidden
* ? X.L.avoidFloats - tried and couldn't get it to work immediately but seemed interesting
NON XMONAD SPECIFIC
* switch to urxvt with dynamic font sizing?
ACTIVE
* Refine bindings. consider greater use of submaps
* work on helper scripts in general (vol, etc.)
* power (test tlp again? need way to see if it's doing a whole lot of good, or should I just use manual options... either way nvidia is power hungry)
* screensaver and screen stuff, caffeine
DEFER (should do but uncertain how to solve after initial cursory review, so will defer till have more time to research)
* quickly swapping two windows between master and slave works nicely. I get a little of this with promote, but I'm
sure there is a more comprehensive solution I could implement (cycle windows / recent windows?)
! Want to be able to spawn a new window directly into a sublayout, not
spawn/merge as I'm doing now (this would be a SIGNIFICANT improvement)
! add tab/alt-tab cycling through windows
* add a shutdown hook to spin down tray/other processes that throw unnecessary errors into xorg
* add withall to send all windows to different workspace
* look fully into resizing current layout including vertical on 3Col
* make focused window master automatically on floating
* see if there is a way to maintain tiled focus post toggle of scratchpad (cf X.L.TrackFloating)
* move NSP windows that are tiled into workspace AT END or AS MASTER depending on management
* https://github.com/pjones/xmonadrc has a focus-follows in the tiled layer only
also has some dynamic project helper functions
* if not using dynamic workspaces (just projects) then remove the dynamic workspaces functions from window shifting
* consider IfMax for further dynamic layout properties
* revisit mouse resizing of windows in tiled layouts (nice to have not crit)
* any utility in XMonad-Hooks-ServerMode (tested briefly, couldn't get it working properly)
* work on my handling of x selection for utility functions ... timer/delay issue?
DONE
* DynamicWorkspaces ... will DynamicProjects replace it entirely? Do I not need it
* keybindings for unmerge are weird... sublayout not great for what might be a common op
could do M-u and M-S-u for mergeall
* capture f11 and pass it along to window, then shift window (or come up with other way to redraw boundaries)
* set conditional key bindings depending on layout for tabs view
(other pseudo-conditional bindings are handled with a trymessage construct)
* add in full tabbed layout in standard sequence?
* fix scratchpad float position - more or less ok now
* test alternate sublayout style in order to explode current view
* XMonad.Hooks.DynamicProperty - could be used for Chrome windows that pop up
if not already assigned a custom class via flags
* change keybinding for cycling through tabs quickly.... this should be "top level" mod+something
* would be nice to have fullscreen work the way I had it where I could fit it in a window as desired
* make a partial full screen that respects struts
* X.H.InsertPosition ... do I want to use this for different spawn location? can I use
it for only certain windows?
* XMonad-Hooks-ToggleHook
! hotplug monitor scripts
* fix alert styles
* dealing with screens/workspaces (binding to move/shift to workspace)
! XMonad-Actions-Navigation2D has a lot of features I'm not yet using.
E.g. screen related
Review the documentation and consider adding.
TESTED/REJECTED/WONTFIX
* consider switching to X.L.SimpleFloat + SimpleDecoration for titlebars
* planekeys? also the new ws project thing i read in change log. also link workspaces
RESULT: for now just using projects the prompt to move around ws
* revisit whether my current use of top level tabbed layout is confusing or best case
- does it make sense?
- do I actually switch to it a lot? would I?
- maybe I could just use Tabs as an orphan layout that I jump to
RESULT: i'm ocnvinced the current top level tabs which is always in the
layout cycle is, if not optimal, the best I'm going to get for now
* ? X.A.RotSlaves - not much use since I just use nav2D
NON XMONAD SPECIFIC TODO
* check if unclutter is being launched and if the new version is crashing
-}
------------------------------------------------------------------------}}}
-- Modules {{{
---------------------------------------------------------------------------
--import Control.Monad (liftM2) -- myManageHookShift
import Control.Monad (liftM, liftM2, join) -- myManageHookShift
import Data.List
import qualified Data.Map as M
import Data.Monoid
import System.Exit
import System.IO -- for xmonbar
import System.Posix.Process(executeFile)
import XMonad hiding ( (|||) ) -- ||| from X.L.LayoutCombinators
import qualified XMonad.StackSet as W -- myManageHookShift
-- to get my old keys working
import XMonad.Prompt
import XMonad.Prompt.ConfirmPrompt
import XMonad.Actions.WithAll
import XMonad.Actions.Commands
import XMonad.Actions.ConditionalKeys
import XMonad.Actions.CopyWindow
-- recent windows from cycle windows -- couldn't get it working on quick try: revisit this
-- import XMonad.Actions.CycleWindows
import XMonad.Actions.CycleWS
-- import XMonad.Actions.CycleSelectedLayouts -- nice but doesn't work well with sublayouts
import XMonad.Actions.DynamicWorkspaces
import XMonad.Actions.Navigation2D
-- import XMonad.Actions.Plane
import XMonad.Actions.Volume
import XMonad.Actions.WindowGo
import XMonad.Hooks.DynamicLog -- for xmobar
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.FadeWindows
import XMonad.Hooks.UrgencyHook
import XMonad.Hooks.ManageDocks -- avoid xmobar
import XMonad.Hooks.ManageHelpers
import XMonad.Layout hiding ( (|||) ) -- ||| from X.L.LayoutCombinators
import XMonad.Layout.Accordion
import XMonad.Layout.BinarySpacePartition
import XMonad.Layout.BorderResize
import XMonad.Layout.ComboP
import XMonad.Layout.Combo
import XMonad.Layout.Dishes
import XMonad.Layout.DragPane
import XMonad.Layout.Drawer
import XMonad.Layout.Gaps
--import XMonad.Layout.IndependentScreens
import XMonad.Layout.LayoutScreens
import XMonad.Layout.OneBig
-- import XMonad.Layout.NoBorders -- NOT actually using?
import XMonad.Layout.NoFrillsDecoration
import XMonad.Layout.DecorationMadness -- testing alternative accordion styles
import XMonad.Layout.PerScreen -- Check screen width & adjust layouts
import XMonad.Layout.PerWorkspace -- Configure layouts on a per-workspace
import XMonad.Layout.Renamed
import XMonad.Layout.ResizableTile -- Resizable Horizontal border
import XMonad.Layout.Simplest
import XMonad.Layout.SimplestFloat
import XMonad.Layout.StackTile
import XMonad.Layout.Spacing -- this makes smart space around windows
import XMonad.Layout.ThreeColumns
import XMonad.Layout.ToggleLayouts -- Full window at any time
import XMonad.Layout.TwoPane
import XMonad.Layout.WindowNavigation
import XMonad.Layout.ShowWName
import XMonad.Layout.SubLayouts -- Layouts inside windows. Excellent.
-- following for the combocombo test from
-- http://xmonad.org/xmonad-docs/xmonad-contrib/src/XMonad-Config-Droundy.html
import XMonad.Layout.Square ( Square(Square) )
import XMonad.Layout.LayoutCombinators -- hiding ( (|||) )
import XMonad.Layout.BoringWindows
import XMonad.Layout.Grid
import XMonad.Actions.Promote -- promote window to master
-- used for full screen toggle
import XMonad.Layout.MultiToggle
import XMonad.Layout.MultiToggle.Instances
import XMonad.Layout.Reflect
-- keeping
-- testing message feedback to see if I can use it to send resize commands
-- to BSP on standard expand/mirrorexpand key bindings
import XMonad.Actions.MessageFeedback -- Enables single key bind, multiple variable actions
-- to demo and comment out or remove
import XMonad.Layout.Master -- used to test a dynamic layout. worked, but will remove in lieu of sublayouts
-- testing - keeping
import XMonad.Actions.FloatSnap
-- testing - keeping
import XMonad.Hooks.InsertPosition
-- testing -- couldn't get this to work
-- import XMonad.Layout.TrackFloating
-- testing -- keeping
import qualified XMonad.Actions.ConstrainedResize as Sqr
-- testing -- keeping (works with github version)
import XMonad.Hooks.DynamicProperty
-- testing
import XMonad.Util.Paste as P
-- testing
import XMonad.Hooks.ServerMode
import XMonad.Actions.Commands
-- testing
import Control.Concurrent (threadDelay)
-- testing
import XMonad.Actions.DynamicProjects
import XMonad.Layout.LayoutBuilder
import XMonad.Layout.Column
-- testing
-- specifically getSelection
import XMonad.Util.XSelection
import XMonad.Util.Timer
-- testing -- not a lot of value added, or am I missing something
-- import XMonad.Hooks.Place
-- experimenting with tripane
import XMonad.Layout.Decoration
import XMonad.Layout.ResizableTile
import XMonad.Layout.Tabbed
import XMonad.Layout.Maximize
import XMonad.Layout.SimplestFloat
import XMonad.Layout.Fullscreen
import XMonad.Layout.NoBorders
import XMonad.Util.Cursor
import XMonad.Util.EZConfig -- removeKeys, additionalKeys
import XMonad.Util.Loggers
import XMonad.Util.NamedActions
import XMonad.Util.NamedScratchpad
import XMonad.Util.Run -- for spawnPipe and hPutStrLn
import XMonad.Util.SpawnOnce
import XMonad.Util.WorkspaceCompare -- custom WS functions filtering NSP
-- taffybar specific
-- import System.Taffybar.Hooks.PagerHints (pagerHints)
------------------------------------------------------------------------}}}
-- Main {{{
---------------------------------------------------------------------------
main = do
xmproc <- spawnPipe myStatusBar
-- for independent screens
-- nScreens <- countScreens
xmonad
-- for taffybar, add pagerHints
-- $ fullscreenSupport -- not using this in lieu of ewmh, but ?
$ dynamicProjects projects
$ withNavigation2DConfig myNav2DConf
$ withUrgencyHook NoUrgencyHook
-- $ withUrgencyHook focusHook
$ ewmh
$ addDescrKeys' ((mod1Mask, xK_F1), showKeybindings) myKeys
$ myConfig xmproc
myConfig p = def
{ borderWidth = border
, clickJustFocuses = myClickJustFocuses
, focusFollowsMouse = myFocusFollowsMouse
, focusedBorderColor = myFocusedBorderColor
, handleEventHook = myHandleEventHook
, layoutHook = myLayoutHook
, logHook = myLogHook p
, manageHook = myManageHook
, modMask = myModMask
, mouseBindings = myMouseBindings
, normalBorderColor = myNormalBorderColor
, startupHook = myStartupHook
, terminal = myTerminal
, workspaces = myWorkspaces
}
------------------------------------------------------------------------}}}
-- Workspaces {{{
---------------------------------------------------------------------------
-- myWorkspaces = map show [1..9]
myWorkspaces = ["gen", "wrk", "com", "sys", "flo", "av", "rw", "tmp"]
projects :: [Project]
projects =
[ Project { projectName = "gen"
, projectDirectory = "~/"
, projectStartHook = Nothing
}
, Project { projectName = "sys"
, projectDirectory = "~/"
, projectStartHook = Nothing
}
, Project { projectName = "wrk"
, projectDirectory = "~/wrk"
, projectStartHook = Just $ do spawn myTerminal
spawn myBrowser
}
, Project { projectName = "rad"
, projectDirectory = "~/"
, projectStartHook = Just $ do spawn myBrowser
}
]
--spawn' :: Host -> Topic -> X ()
--spawn' p = do
-- spawn p
-- --switchHook $ switchTopic' W.view (myTopicConfig host) t
------------------------------------------------------------------------}}}
-- Applications {{{
---------------------------------------------------------------------------
myTerminal = "terminator"
myTerminalClass = "Terminator"
myAltTerminal = "cool-retro-term"
myBrowser = "$HOME/bin/browser" -- chrome with WS profile dirs
myBrowserClass = "Google-chrome-beta"
myStatusBar = "xmobar -x0 $HOME/.xmonad/xmobarrc"
myLauncher = "dmenu_run"
--myStatusBar = "polybar primary"
-- bring up different hangouts on different workspaces using a combination
-- of my workspace aware browser command, X.U.NamedScratchPads, and bindOn
-- per workspace bindings via X.A.PerWorkspaceKeys
hangoutsCommand = myBrowser ++ " --app-id=knipolnnllmklapflnccelgolnpehhpl"
myHangoutsTitle = "Google Hangouts - es@ethanschoonover.com"
hangoutsPrefix = "Google Hangouts"
hangoutsResource = "crx_nckgahadagoaajjgafhacjanaoiihapd"
isHangoutsFor s = (className =? myBrowserClass <&&> fmap (isPrefixOf hangoutsPrefix) title <&&> fmap (isInfixOf s) title)
isPersonalHangouts = isHangoutsFor "ethanschoonover"
isWorkHangouts = isHangoutsFor "eschoonover"
-- trello
-- trelloCommand = myBrowser ++ "--app-id=jijnmpkkfkjaihbhffejemnpbbglahim"
trelloCommand = "dex $HOME/.local/share/applications/Trello.desktop"
trelloWorkCommand = "dex $HOME/.local/share/applications/TrelloWork.desktop"
trelloInfix = "Trello"
trelloResource = "crx_jijnmpkkfkjaihbhffejemnpbbglahim"
trelloWorkResource = "crx_fkbbihpadkgbnhphndjgblgelahbiede"
isTrello = (resource =? trelloResource)
isTrelloWork = (resource =? trelloWorkResource)
-- google music
avMusicCommand = "dex $HOME/.local/share/applications/Music.desktop"
avMusicInfix = "Google Play Music"
avMusicResource = "crx_ioljlgoncmlkbcepmminebblkddfjofl"
isAvMusic = (resource =? avMusicResource)
-- google music
plexCommand = "dex $HOME/.local/share/applications/Plex.desktop"
plexInfix = "Plex"
plexResource = "crx_fpniocchabmgenibceglhnfeimmdhdfm"
isPlex = (resource =? plexResource)
-- HACK: first key is eaten by gremlins so it's something hopefully innocuous
--xdotest = "xdotool getwindowfocus windowfocus --sync key --delay 200 F20 F11"
sendF11 = "xdotool getwindowfocus windowfocus --sync key --delay 200 F20 F11"
isConsole = (className =? myTerminalClass) <&&> (stringProperty "WM_WINDOW_ROLE" =? "Scratchpad")
myConsole = "terminator -T console -p console --role=Scratchpad"
scratchpads =
-- [ (NS "htop" "xterm -e htop"
-- (title =? "htop")
-- (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3))
-- )
[ (NS "console" myConsole isConsole nonFloating)
, (NS "hangoutsPersonal" hangoutsCommand isPersonalHangouts defaultFloating)
, (NS "hangoutsWork" hangoutsCommand isWorkHangouts defaultFloating)
, (NS "trello" trelloCommand isTrello nonFloating)
, (NS "trelloWork" trelloWorkCommand isTrelloWork nonFloating)
, (NS "avMusic" avMusicCommand isAvMusic nonFloating)
, (NS "plex" plexCommand isPlex defaultFloating)
]
where
role = stringProperty "WM_WINDOW_ROLE"
-- cribbed this idea from
-- https://github.com/openprivacy/dotfen/blob/master/home/.xmonad/xmonad.hs
-- for multiple screens, but there are better ways
--myStatusBar = "bash -c \"tee >(xmobar -x0 $HOME/.xmonad/xmobarrc) "
-- ++ "| xmobar -x1 $HOME/.xmonad/xmobarrc\""
------------------------------------------------------------------------}}}
-- Theme {{{
---------------------------------------------------------------------------
myFocusFollowsMouse = False
myClickJustFocuses = True
--myFocusFollowsMouse = True
--myClickJustFocuses = False
base03 = "#002b36"
base02 = "#073642"
base01 = "#586e75"
base00 = "#657b83"
base0 = "#839496"
base1 = "#93a1a1"
base2 = "#eee8d5"
base3 = "#fdf6e3"
yellow = "#b58900"
orange = "#cb4b16"
red = "#dc322f"
magenta = "#d33682"
violet = "#6c71c4"
blue = "#268bd2"
cyan = "#2aa198"
green = "#859900"
-- sizes
gap = 9
topbar = 5
border = 0
prompt = 20
status = 20
myNormalBorderColor = base03
myFocusedBorderColor = active
active = cyan
activeWarn = red
inactive = base02
focusColor = blue
unfocusColor = base02
myFont = "-*-terminus-medium-*-*-*-*-160-*-*-*-*-*-*"
myBigFont = "-*-terminus-medium-*-*-*-*-240-*-*-*-*-*-*"
-- this is a "fake title" used as a highlight bar in lieu of full borders
-- (I find this a cleaner and less visually intrusive solution)
--topBarTheme= defaultTheme
topBarTheme= def
{ fontName = myFont
, inactiveBorderColor = base03
, inactiveColor = base03
, inactiveTextColor = base03
, activeBorderColor = active
, activeColor = active
, activeTextColor = active
, urgentBorderColor = red
, urgentTextColor = yellow
, decoHeight = topbar
}
--myTabTheme = defaultTheme
myTabTheme = def
{ fontName = myFont
, activeColor = active
, inactiveColor = base02
, activeBorderColor = active
, inactiveBorderColor = base02
, activeTextColor = base03
, inactiveTextColor = base00
}
-- Prompt
myPromptTheme = defaultXPConfig
{ font = myFont
, bgColor = base03
, fgColor = active
, fgHLight = base03
, bgHLight = active
, borderColor = base03
, promptBorderWidth = 0
, height = prompt
}
hotPromptTheme = myPromptTheme
{ bgColor = red
, fgColor = base3
, position = Top
}
--myShowWNameTheme = defaultSWNConfig
myShowWNameTheme = def
--{ swn_font = "xft:Monospace:pixelsize=120:regular:antialias=true:hinting=true"
{ swn_font = "xft:Roboto:pixelsize=120:regular:antialias=true:hinting=true"
--{ swn_font = myBigFont
, swn_fade = 0.25
, swn_bgcolor = base03
, swn_color = active
}
------------------------------------------------------------------------}}}
-- Layouts {{{
---------------------------------------------------------------------------
-- Tell X.A.Navigation2D about specific layouts and how to handle them
myNav2DConf = def
{ defaultTiledNavigation = centerNavigation
, floatNavigation = centerNavigation
, screenNavigation = lineNavigation
, layoutNavigation = [("Full", centerNavigation)
-- line/center same results ,("Simple Tabs", lineNavigation)
-- ,("Simple Tabs", centerNavigation)
]
, unmappedWindowRect = [("Full", singleWindowRect)
-- works but breaks tab deco ,("Simple Tabs", singleWindowRect)
-- doesn't work but deco ok ,("Simple Tabs", fullScreenRect)
]
}
data FULLBAR = FULLBAR deriving (Read, Show, Eq, Typeable)
instance Transformer FULLBAR Window where
transform FULLBAR x k = k barFull (\_ -> x)
-- tabBarFull = avoidStruts $ noFrillsDeco shrinkText topBarTheme $ addTabs shrinkText myTabTheme $ Simplest
barFull = avoidStruts $ Simplest
-- cf
-- http://xmonad.org/xmonad-docs/xmonad-contrib/src/XMonad-Config-Droundy.html
myLayoutHook = showWorkspaceName
-- $ renamed [(XMonad.Layout.Renamed.CutWordsLeft 1)]
-- $ maximize -- probably just going to use fullScreenToggle
$ onWorkspace ":6" floatWorkSpace
$ fullScreenToggle
$ fullBarToggle
$ mirrorToggle
$ reflectToggle
$ flex ||| tabs -- ||| threeCol
where
testTall = Tall 1 (1/50) (2/3)
floatWorkSpace = simplestFloat
fullBarToggle = mkToggle (single FULLBAR)
fullScreenToggle = mkToggle (single FULL)
mirrorToggle = mkToggle (single MIRROR)
reflectToggle = mkToggle (single REFLECTX)
smallMonResWidth = 1920
showWorkspaceName = showWName' myShowWNameTheme
named n = renamed [(XMonad.Layout.Renamed.Replace n)]
trimNamed w n = renamed [(XMonad.Layout.Renamed.CutWordsLeft w),
(XMonad.Layout.Renamed.PrependWords n)]
suffixed n = renamed [(XMonad.Layout.Renamed.AppendWords n)]
addTopBar = noFrillsDeco shrinkText topBarTheme
mySpacing = spacing gap
sGap = quot gap 2
myGaps = gaps [(U, gap),(D, gap),(L, gap),(R, gap)]
mySmallGaps = gaps [(U, sGap),(D, sGap),(L, sGap),(R, sGap)]
myBigGaps = gaps [(U, gap*2),(D, gap*2),(L, gap*2),(R, gap*2)]
--------------------------------------------------------------------------
-- Tabs Layout --
--------------------------------------------------------------------------
threeCol = named "Unflexed"
$ avoidStruts
$ addTopBar
$ myGaps
$ mySpacing
$ ThreeColMid 1 (1/10) (1/2)
tabs = named "Tabs"
$ avoidStruts
$ addTopBar
$ addTabs shrinkText myTabTheme
$ Simplest
-- twoCols = avoidStruts
-- -- don't forget: even though we are using X.A.Navigation2D
-- -- we need windowNavigation for merging to sublayouts
-- $ windowNavigation
-- $ addTopBar
-- $ myGaps
-- $ mySpacing
-- $ layoutLeft layoutRight where
-- leftHalf = relBox 0.0 0.0 0.5 1.0
-- rightHalf = relBox 0.5 0.0 1.0 1.0
-- fullScreen = relBox 0.0 0.0 1.0 1.0
-- layoutLeft = layoutN 1 leftHalf (Just fullScreen) (Column 1.6)
-- layoutRight = layoutAll rightHalf (tabbedBottom shrinkText myTabTheme)
-- --layoutRight = layoutAll rightHalf (addTabs shrinkText myTabTheme)
-----------------------------------------------------------------------
-- Flexi SubLayouts --
-----------------------------------------------------------------------
--
-- In many ways the best solution. Acts like ThreeColumns, Tall, BSP,
-- or any other container layout style. Can use this layout just as you
-- would those without tabs at all, or you can easily merge any windows
-- into a tabbed group.
--
-- Diagrams:
--
-- (examples only... this is a very flexible layout and as such the
-- layout style and arrangement isn't limited as much as the other
-- attempts below)
--
-- Ultrawide:
-- --------------------------------------------
-- | | | |
-- | | | Tabs |
-- | | | |
-- |----------| Master |----------|
-- | | | |
-- | Tabs | | |
-- | | | |
-- --------------------------------------------
--
-- Standard:
-- ---------------------------------
-- | | |
-- | | |
-- | | |
-- | Master |----------|
-- | | |
-- | | Tabs |
-- | | |
-- ---------------------------------
--
--
-- Advantages
--
-- * tab group is movable as a unit and acts like any other window
--
-- * this is the "cleanest" of the dynamic layouts I've worked with
-- and leaves no "pixel dust" on the screen when switching to a WS
-- on a different monitor
--
-- * navigation and window/group movement is trivial with
-- X.A.Navigation2D
--
-- * master window remains master when switching screens (unlike
-- the "X.L.Master" based solution below)
--
-- * unlike some of the other solutions, it is trivial to change
-- the exterior layout format and so I could potentially add in
-- some layout change to BSP or other layout that I want to test
-- while still retaining the tab functionality
--
-- Disadvantages
--
-- * layout starts without any tabs (could be considered a feature
-- since in that case the layout performs exactly as the parent/
-- container layout does)
--
-- * To move a window into or out of the tabbed group requires
-- special key bindings unique to X.L.SubLayouts
--
-- Understanding XMonad.Layouts.SubLayouts
--
-- It took me a while to grok this.
--
-- the subLayout hook is used with the following format:
--
-- subLayout advanceInnerLayouts innerLayout outerLayout
--
-- It works like this: subLayout modifies an entire other layout (or
-- layouts), enabling you to turn what would be a normal window into
-- a little group of windows managed by an entirely different layout.
--
-- In my case, I'm using layouts like "Three Column" and "Tall" as the
-- nominal "container" layout (what SubLayouts calls the "outerLayout").
--
-- The "inner layout" in my case is just "Simplest". I'm also adding tabs
-- which are only applied to my sublayouts. Not sure how that works
-- but it's apparent from the X.L.SubLayouts documentation that this is
-- the intended use/behavior. Essential X.L.SubLayouts is hijacking these
-- added tabs and applying them just to the Simplest layout, and then that
-- in turn is stuck inside the rectangle that would normally hold a window
-- in my normal layouts.
--
-- One of the confusing things for me at first was that the layout doesn't
-- start with any subLayouts. So it appears to just be a normal layout.
-- You have to "merge all" to suck everything up into a Simplest tabbed
-- group and then you can add other windows normally and you'll
-- have a sublayout with tabs.
--
-- Note: subLayouts has some other features. For example, you can give it
-- a list of layouts to work through and it will advance through them in
-- series (or possibly in an order your provide) and will apply different
-- layouts to different subLayout groups. Each time you add a new window
-- to your layout, it acquires the sublayout, even if you don't know it.
--
-- In my case, my list is one long and is just the first window I add.
--
-- Ex. The second group is Tall, the third is Circle, all others are
-- tabbed with:
--
-- myLayout = addTabs shrinkText def
-- $ subLayout [0,1,2] (Simplest ||| Tall 1 0.2 0.5 ||| Circle)
-- $ Tall 1 0.2 0.5 ||| Full
-- this is a flexible sublayout layout that has only one container
-- layout style (depending on screen)
-- flexiSub = named "Flexi SubLayouts"
-- $ avoidStruts
-- $ windowNavigation
-- $ addTopBar
-- $ myGaps
-- $ addTabs shrinkText myTabTheme
-- $ mySpacing
-- $ subLayout [] Simplest
-- $ ifWider smallMonResWidth wideLayout standardLayout
-- where
-- wideLayout = ThreeColMid 1 (1/100) (1/2)
-- standardLayout = ResizableTall 1 (1/50) (2/3) []
-- retained during development: safe to remove later
flex = trimNamed 5 "Flex"
$ avoidStruts
-- don't forget: even though we are using X.A.Navigation2D
-- we need windowNavigation for merging to sublayouts
$ windowNavigation
$ addTopBar
$ addTabs shrinkText myTabTheme
$ subLayout [] (Simplest ||| (mySpacing $ Accordion))
-- $ subLayout [] Simplest
$ ifWider smallMonResWidth wideLayouts standardLayouts
where
wideLayouts = myGaps $ mySpacing
$ (suffixed "Wide 3Col" $ ThreeColMid 1 (1/20) (1/2))
||| (suffixed "Wide BSP" $ emptyBSP)
-- ||| fullTabs
standardLayouts = myGaps $ mySpacing
$ (suffixed "Std 2/3" $ ResizableTall 1 (1/20) (2/3) [])
||| (suffixed "Std 1/2" $ ResizableTall 1 (1/20) (1/2) [])
-- ||| fullTabs
--fullTabs = suffixed "Tabs Full" $ Simplest
--
-- NOTE: removed this from the two (wide/std) sublayout
-- sequences. if inside the ifWider, the ||| combinator
-- from X.L.LayoutCombinators can't jump to it directly (
-- or I'm doing something wrong, either way, it's simpler
-- to solve it by just using a tabbed layout in the main
-- layoutHook). The disadvantage is that I lose the "per
-- screen" memory of which layout was where if using the
-- tabbed layout (if using the the ifWider construct as
-- I am currently, it seems to work fine)
--
-- Using "Full" here (instead of Simplest) will retain the
-- tabbed sublayout structure and allow paging through each
-- group/window in full screen mode. However my preference
-- is to just see all the windows as tabs immediately.
-- Using "Simplest" here will do this: display all windows
-- as tabs across the top, no "paging" required. However
-- this is misleading as the sublayouts are of course still
-- there and you will have to use the nornmal W.focusUp/Down
-- to successfully flip through them. Despite this
-- limitation I prefer this to the results with "Full".
{-|
-----------------------------------------------------------------------
-- Simple Flexi --
-----------------------------------------------------------------------
--
-- Simple dynamically resizing layout as with the other variations in
-- this config. This layout has not tabs in it and simply uses
-- Resizable Tall and Three Column layouts.
simpleFlexi = named "Simple Flexible"
$ ifWider smallMonResWidth simpleThree simpleTall
simpleTall = named "Tall"
$ addTopBar
$ avoidStruts
$ mySpacing
$ myGaps
$ ResizableTall 1 (1/300) (2/3) []
simpleThree = named "Three Col"
$ avoidStruts
$ addTopBar
$ mySpacing
$ myGaps
$ ThreeColMid 1 (3/100) (1/2)
-----------------------------------------------------------------------
-- Other Misc Layouts --
-----------------------------------------------------------------------
--
--
masterTabbedP = named "MASTER TABBED"
$ addTopBar
$ avoidStruts
$ mySpacing
$ myGaps
$ mastered (1/100) (1/2) $ tabbed shrinkText myTabTheme
bsp = named "BSP"
$ borderResize (avoidStruts
$ addTopBar
$ mySpacing
$ myGaps
$ emptyBSP )
-- $ borderResize (emptyBSP)
oneBig = named "1BG"
$ avoidStruts
$ addTopBar
$ mySpacing
$ myGaps
$ OneBig (3/4) (3/4)
tiledP = named "TILED"
$ addTopBar
$ avoidStruts
$ mySpacing
$ myGaps
$ consoleOn
$ tiled'
oneUp = named "1UP"
$ avoidStruts
$ myGaps
$ combineTwoP (ThreeCol 1 (3/100) (1/2))
(Simplest)
(Tall 1 0.03 0.5)
(ClassName "Google-chrome-beta")
-----------------------------------------------------------------------
-- Master-Tabbed Dymamic --
-----------------------------------------------------------------------
--
-- Dynamic 3 pane layout with one tabbed panel using X.L.Master
-- advantage is that it can do a nice 3-up on both ultrawide and
-- standard (laptop in my case) screen sizes, where the layouts
-- look like this:
--
-- Ultrawide:
-- --------------------------------------------
-- | | | |
-- | | | |
-- | | | |
-- | Master | Master | Tabs |
-- | | | |
-- | | | |
-- | | | |
-- --------------------------------------------
-- \____________________ _____________________/
-- '
-- all one layout
--
-- Standard:
-- ---------------------------------
-- | | |
-- | | |
-- | | |
-- | Master | Tabs |
-- | | |
-- | | |
-- | | |
-- ---------------------------------
-- \_______________ _______________/
-- '
-- all one layout
--
-- Advantages to this use of X.L.Master to created this dynamic
-- layout include:
--
-- * No fussing with special keys to swap windows between the
-- Tabs and Master zones
--
-- * Window movement and resizing is very straightforward
--
-- * Limited need to maintain a mental-map of the layout
-- (pretty easy to understand... it's just a layout)
--
-- Disadvantages include:
--
-- * Swapping a window from tabbed area will of necessity swap
-- one of the Master windows back into tabs (since there can
-- only be two master windows)
--
-- * Master area can have only one/two windows in std/wide modes
-- respectively
--
-- * When switching from wide to standard, the leftmost pane
-- (which is visually secondary to the large central master
-- window) becomes the new dominant master window on the
-- standard display (this is easy enough to deal with but
-- is a non-intuitive effect)
masterTabbedDynamic = named "Master-Tabbed Dynamic"
$ ifWider smallMonResWidth masterTabbedWide masterTabbedStd
masterTabbedStd = named "Master-Tabbed Standard"
$ addTopBar
$ avoidStruts
$ gaps [(U, gap*2),(D, gap*2),(L, gap*2),(R, gap*2)]
$ mastered (1/100) (2/3)
$ gaps [(U, 0),(D, 0),(L, gap*2),(R, 0)]
$ tabbed shrinkText myTabTheme
masterTabbedWide = named "Master-Tabbed Wide"
$ addTopBar
$ avoidStruts
$ gaps [(U, gap*2),(D, gap*2),(L, gap*2),(R, gap*2)]
$ mastered (1/100) (1/4)
$ gaps [(U, 0),(D, 0),(L, gap*2),(R, 0)]
$ mastered (1/100) (2/3)
$ gaps [(U, 0),(D, 0),(L, gap*2),(R, 0)]
$ tabbed shrinkText myTabTheme
-----------------------------------------------------------------------
-- Tall-Tabbed Dymamic --
-----------------------------------------------------------------------
--
-- Dynamic 3 pane layout with one tabbed panel using X.L.ComboP
-- advantage is that it can do a nice 3-up on both ultrawide and
-- standard (laptop in my case) screen sizes, where the layouts
-- look like this:
--
-- Ultrawide:
-- --------------------------------------------
-- | | | |
-- | | | |
-- | | | |
-- |----------| Master | Tabs |
-- | | | |
-- | | | |
-- | | | |
-- --------------------------------------------
-- \______________ _______________/\____ _____/
-- ' '
-- this set of panes is This is a
-- its' own layout in a separate
-- Tall configuration tab format
-- layout
--
-- Standard:
-- ---------------------------------
-- | | |
-- | | |
-- | | |
-- | Master | Tabs |
-- | | |
-- |--------------------| |
-- | | | |
-- ---------------------------------
-- \_________ _________/\____ _____/
-- ' '
-- this set of panes is This is a
-- its' own layout in a separate
-- Tall configuration tab format
-- layout
--
-- Advantages to this use of ComboP to created this dynamic
-- layout include:
--
-- * the center Master stays the same when the layout
-- changes (unlike the X.L.Master based dyn. layout)
--
-- * the Master can have a set of panes under it on the
-- small screen (standard) layout
--
-- * on ultrawide the leftmost pane may be divided into
-- multiple windows
--
-- * possible to toss a tabbed window to the "Master" area
-- without swapping a window back into tabs
--
-- * use of ComboP allows redirection windows to either
-- left or right section
--
-- Disadvantages include:
--
-- * normal window swaps fail between the two separate
-- layouts. There must be a special swap-between-layouts
-- binding (normal window NAVIGATION works, at least using
-- X.A.Navigation2D).
--
-- * switching between screens can leave title bar clutter
-- that hasn't been cleaned up properly (restarting
-- XMonad works to clean this up, but that's hacky)
--
-- * somewhat greater need to maintain a mental-map of the
-- layout (you need to have a sense for the windows being
-- in separate sections of the different layouts)
smartTallTabbed = named "Smart Tall-Tabbed"
$ avoidStruts
$ ifWider smallMonResWidth wideScreen normalScreen
where
wideScreen = combineTwoP (TwoPane 0.03 (3/4))
(smartTall)
(smartTabbed)
(ClassName "Google-chrome-beta")
normalScreen = combineTwoP (TwoPane 0.03 (2/3))
(smartTall)
(smartTabbed)
(ClassName "Google-chrome-beta")
smartTall = named "Smart Tall"
$ addTopBar
$ mySpacing
$ myGaps
$ boringAuto
$ ifWider smallMonResWidth wideScreen normalScreen
where
wideScreen = reflectHoriz $ Tall 1 0.03 (2/3)
normalScreen = Mirror $ Tall 1 0.03 (4/5)
smartTabbed = named "Smart Tabbed"
$ addTopBar
$ myCustomGaps
$ tabbed shrinkText myTabTheme
-}
-----------------------------------------------------------------------
-- Flexi Combinators --
-----------------------------------------------------------------------
--
-- failed attempt. creates a nice looking layout but I'm not sure
-- how to actually direct tabs to the tabbed area
--
-- flexiCombinators = named "Flexi Combinators"
-- $ avoidStruts
-- $ ifWider smallMonResWidth wideScreen normalScreen
-- where
-- wideScreen = smartTall ****||* smartTabbed
-- normalScreen = smartTall ***||** smartTabbed
------------------------------------------------------------------------}}}
-- Bindings {{{
---------------------------------------------------------------------------
-- Display keyboard mappings using zenity
-- from https://github.com/thomasf/dotfiles-thomasf-xmonad/
-- blob/master/.xmonad/lib/XMonad/Config/A00001.hs
showKeybindings :: [((KeyMask, KeySym), NamedAction)] -> NamedAction
showKeybindings x = addName "Show Keybindings" $ io $ do
h <- spawnPipe "zenity --text-info --font=terminus"
hPutStr h (unlines $ showKm x)
hClose h
return ()
-- cleverness and structure of following cribbed from
-- https://github.com/SimSaladin/configs/blob/master/.xmonad/xmonad.hs
-- cf https://github.com/paul-axe/dotfiles/blob/master/.xmonad/xmonad.hs
-- wsKeys = map (\x -> "; " ++ [x]) ['1'..'9']
-- this along with workspace section below results in something link
-- M1-semicolon 1 View ws
-- M1-semicolon 2 View ws
-- M1-Shift-semicolon 1 Move w to ws
-- M1-Shift-semicolon 2 Move w to ws
-- M1-C-Shift-semicolon 1 Copy w to ws
-- M1-C-Shift-semicolon 2 Copy w to ws
-- wsKeys = map show $ [1..9] ++ [0]
-- wsKeys = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
wsKeys = map show $ [1..9] ++ [0]
--wsBrowser :: WorkspaceId -> String -> X ()
--wsBrowser ws = spawn "notify-send " ++ ws
notSP = (return $ ("NSP" /=) . W.tag) :: X (WindowSpace -> Bool)
-- | any workspace but scratchpad
shiftAndView dir = findWorkspace getSortByIndex dir (WSIs notSP) 1
>>= \t -> (windows . W.shift $ t) >> (windows . W.greedyView $ t)
-- | hidden, non-empty workspaces less scratchpad
shiftAndView' dir = findWorkspace getSortByIndexNoSP dir HiddenNonEmptyWS 1
>>= \t -> (windows . W.shift $ t) >> (windows . W.greedyView $ t)
nextNonEmptyWS = findWorkspace getSortByIndexNoSP Next HiddenNonEmptyWS 1
>>= \t -> (windows . W.view $ t)
prevNonEmptyWS = findWorkspace getSortByIndexNoSP Prev HiddenNonEmptyWS 1
>>= \t -> (windows . W.view $ t)
getSortByIndexNoSP =
fmap (.namedScratchpadFilterOutWorkspace) getSortByIndex
-- | toggle any workspace but scratchpad
myToggle = windows $ W.view =<< W.tag . head . filter
((\x -> x /= "NSP" && x /= "SP") . W.tag) . W.hidden
myKeys conf = let
subKeys str ks = subtitle str : mkNamedKeymap conf ks
screenKeys = ["w","v","z"]
dirKeys = ["j","k","h","l"]
arrowKeys = ["<D>","<U>","<L>","<R>"]
dirs = [ D, U, L, R ]
--screenAction f = screenWorkspace >=> flip whenJust (windows . f)
zipM m nm ks as f = zipWith (\k d -> (m ++ k, addName nm $ f d)) ks as
zipM' m nm ks as f b = zipWith (\k d -> (m ++ k, addName nm $ f d b)) ks as
-- from xmonad.layout.sublayouts
focusMaster' st = let (f:fs) = W.integrate st
in W.Stack f [] fs
swapMaster' (W.Stack f u d) = W.Stack f [] $ reverse u ++ d
-- try sending one message, fallback if unreceived, then refresh
tryMsgR x y = sequence_ [(tryMessage_ x y), refresh]
-- warpCursor = warpToWindow (9/10) (9/10)
--restart = spawn "xmonad --restart"
-- slowRestart = spawn "sleep 0.3 && xmonad --restart"
-- cf https://github.com/pjones/xmonadrc
--switch :: ProjectTable -> ProjectName -> X ()
--switch ps name = case Map.lookup name ps of
-- Just p -> switchProject p
-- Nothing | null name -> return ()
-- sdcv word = do
-- output <- runProcessWithInput "sdcv" ["-n", word] ""
-- mySafeSpawn "notify-send" [word, trString output]
-- do something with current X selection
unsafeWithSelection app = join $ io $ liftM unsafeSpawn $ fmap (\x -> app ++ " " ++ x) getSelection
in
-----------------------------------------------------------------------
-- Global leader
-----------------------------------------------------------------------
subKeys "Global Leader"
[ ("C-' '" , addName "Cancel submap" $ return ())
, ("C-' C-'" , addName "Cancel submap" $ return ())
-- perhaps should have a pass through C-' to application option here
] ^++^
-----------------------------------------------------------------------
-- Window management
-----------------------------------------------------------------------
subKeys "Kill Windows"
[ ("M-<Backspace>" , addName "Kill" kill1)
, ("M-S-<Backspace>" , addName "Kill all" $ confirmPrompt hotPromptTheme "kill all" $ killAll)
, ("C-<Backspace>" , addName "Kill" kill1)
, ("C-S-<Backspace>" , addName "Kill all" $ confirmPrompt hotPromptTheme "kill all" $ killAll)
] ^++^
subKeys "Window Copies"
[ ("M-c" , addName "Copy w to all ws" $ windows copyToAll)
, ("M-S-c" , addName "Kill other copies" $ killAllOtherCopies)
, ("C-' c" , addName "Copy w to all ws" $ windows copyToAll)
, ("C-' S-c" , addName "Kill other copies" $ killAllOtherCopies)
--, ("M4-u" , addName "Test" $ )
] ^++^
-----------------------------------------------------------------------
-- Workspaces & Projects
-----------------------------------------------------------------------
subKeys "Workspaces & Projects"
[ ("M-w" , addName "Switch to Project" $ switchProjectPrompt myPromptTheme)
, ("M-S-w" , addName "Shift to Project" $ shiftToProjectPrompt myPromptTheme)
-- , ("M4-<L>" , addName "Prev workspace" $ prevWS)
-- , ("M4-<R>" , addName "Next workspace" $ nextWS)
, ("M-p" , addName "Prev non-empty workspace" $ prevNonEmptyWS)
, ("M-n" , addName "Next non-empty workspace" $ nextNonEmptyWS)
, ("M-C-p" , addName "Prev workspace" $ prevWS)
, ("M-C-n" , addName "Next workspace" $ nextWS)
, ("M-S-p" , addName "Shift to prev ws" $ shiftAndView' Prev)
, ("M-S-n" , addName "Shift to next ws" $ shiftAndView' Next)
, ("M-C-S-p" , addName "Shift to prev workspace" $ shiftToPrev)
, ("M-C-S-n" , addName "Shift to next workspace" $ shiftToNext)
, ("M-o" , addName "Toggle last workspace" $ toggleWS' ["NSP"])
] ^++^
-----------------------------------------------------------------------
-- Navigation
-----------------------------------------------------------------------
subKeys "Window Navigation and Movement"
[ ("M-e" , addName "Focus urgent" focusUrgent)
, ("M-m" , addName "Focus master" $ windows W.focusMaster)
, ("M-<Tab>" , addName "Focus down" $ windows W.focusDown)
, ("M-S-<Tab>" , addName "Focus up" $ windows W.focusUp)
-- recent windows not working
-- , ("M4-<Tab>", , addName "Cycle recent windows" $ (cycleRecentWindows [xK_Super_L] xK_Tab xK_Tab))
-- either not using these much or (in case of two tab items below), they conflict with other bindings
-- so I'm just turning off this whole section for now. retaining for refernce after a couple months
-- of working with my bindings to see if I want them back. TODO REVIEW
--, ("M-s m" , addName "Swap master" $ windows W.shiftMaster)
--, ("M-s p" , addName "Swap next" $ windows W.swapUp)
--, ("M-s n" , addName "Swap prev" $ windows W.swapDown)
--, ("M-<Tab>" , addName "Cycle up" $ windows W.swapUp)
--, ("M-S-<Tab>" , addName "Cycle down" $ windows W.swapDown)
-- sublayout specific (unused)
-- , ("M4-C-S-m" , addName "onGroup focusMaster" $ onGroup focusMaster')
-- , ("M4-C-S-]" , addName "toSubl IncMasterN 1" $ toSubl $ IncMasterN 1)
-- , ("M4-C-S-[" , addName "toSubl IncMasterN -1" $ toSubl $ IncMasterN (-1))
-- , ("M4-C-S-<Return>" , addName "onGroup swapMaster" $ onGroup swapMaster')
, ("M-S-p" , addName "Promote" $ promote)
, ("M-u" , addName "Un-merge from sublayout" $ withFocused (sendMessage . UnMerge))
, ("M-S-u" , addName "Merge all into sublayout" $ withFocused (sendMessage . MergeAll))
-- ComboP specific (can remove after demo)
, ("M4-C-S-m" , addName "Combo swap" $ sendMessage $ SwapWindow)
] ^++^
-- subKeys "Tab Sub-Group Navigation"
subKeys "Directional Navigation and Movement" (
--[]
[ ("M-'" , addName "Cycle current tabs D" $ bindOn LD [("Tabs", windows W.focusDown), ("", onGroup W.focusDown')])
, ("M-;" , addName "Cycle current tabs U" $ bindOn LD [("Tabs", windows W.focusUp), ("", onGroup W.focusUp')])
]
-- Navigation and Movement via X.A.Navigation2D (with window wrap=True)
++ zipM' "M-" "Navigate window" dirKeys dirs windowGo True
++ zipM' "M-S-" "Move window" dirKeys dirs windowSwap True
++ zipM "M-C-" "Merge w/sublayout" dirKeys dirs (sendMessage . pullGroup)
++ zipM' "M4-" "Navigate screen" arrowKeys dirs screenGo True
++ zipM' "M4-S-" "Move window to screen" arrowKeys dirs windowToScreen True
++ zipM' "M4-C-" "Swap workspace to screen" arrowKeys dirs screenSwap True
--
-- ++ zipM' "C-" "Navigate window" dirKeys dirs windowGo True
-- ++ zipM' "C-S-" "Move window" dirKeys dirs windowSwap True
-- ++ zipM "C-C-" "Merge w/sublayout" dirKeys dirs (sendMessage . pullGroup)
) ^++^
-----------------------------------------------------------------------
-- Layouts & Sublayouts
-----------------------------------------------------------------------
subKeys "Layout Management"
[ ("M-<Space>" , addName "Cycle all layouts" $ sendMessage NextLayout)
, ("M-C-<Space>" , addName "Cycle sublayout" $ toSubl NextLayout)
, ("M-S-<Space>" , addName "Reset layout" $ setLayout $ XMonad.layoutHook conf)
--[ ("M-/" , addName "Cycle all layouts" $ sendMessage NextLayout)
-- doesn't work well with sublayouts, ("C-<Space>" , addName "Cycle main layouts" $ cycleThroughLayouts ["Full", "Tabs", "Flex Wide 3Col"])
--, ("M-C-/" , addName "Cycle sublayout" $ toSubl NextLayout)
--, ("M-S-/" , addName "Reset layout" $ setLayout $ XMonad.layoutHook conf)
-- refresh never seems to do anything
, ("M-S-C-<Space>" , addName "Refresh (candidate for removal)" refresh)
, ("M-S-t" , addName "Tile floating w" $ withFocused $ windows . W.sink)
--, ("M-m" , addName "Maximize toggle" $ withFocused (sendMessage . maximizeRestore))
, ("M-f" , addName "Fullscreen toggle" $ sendMessage $ XMonad.Layout.MultiToggle.Toggle FULL)
-- Fake fullscreen fullscreens into the window rect. The expand/shrink
-- is a hack to make the full screen paint into the rect properly.
-- The tryMsgR handles the BSP vs standard resizing functions.
--
, ("M-S-f" , addName "Fake fullscreen" $ sequence_ [ (P.sendKey P.noModMask xK_F11)
, (tryMsgR (ExpandTowards L) (Shrink))
, (tryMsgR (ExpandTowards R) (Expand)) ])
-- , ("M-C-f" , addName "Fullscreen + bar toggle" $ sendMessage $ XMonad.Layout.MultiToggle.Toggle FULLBAR)
, ("M-C-f" , addName "Toggle Struts" $ sendMessage ToggleStruts)
-- , ("M4-t" , addName "Jump to full + tabs layout" $ bindOn LD [("Tabs", sendMessage NextLayout), ("", sendMessage $ JumpToLayout "Tabs")])
] ^++^
-----------------------------------------------------------------------
-- Resizing
-----------------------------------------------------------------------
subKeys "Resize & Rotate"
[
-- following is a hacky hack hack
--
-- I want to be able to use the same resize bindings on both BinarySpacePartition and other
-- less sophisticated layouts. BSP handles resizing in four directions (amazing!) but other
-- layouts have less refined tastes and we're lucky if they just resize the master on a single
-- axis.
--
-- To this end, I am using X.A.MessageFeedback to test for success on using the BSP resizing
-- and, if it fails, defaulting to the standard (or the X.L.ResizableTile Mirror variants)
-- Expand and Shrink commands.
--
-- The "sequence_" wrapper is needed because for some reason the windows weren't resizing till
-- I moved to a different window or refreshed, so I added that here. Shrug.
-- mnemonic: less than / greater than
--, ("M4-<L>" , addName "Expand (L on BSP)" $ sequence_ [(tryMessage_ (ExpandTowards L) (Expand)), refresh])
("M-<L>" , addName "Expand (L on BSP)" $ tryMsgR (ExpandTowards L) (Shrink))
, ("M-<R>" , addName "Expand (R on BSP)" $ tryMsgR (ExpandTowards R) (Expand))
, ("M-<U>" , addName "Expand (U on BSP)" $ tryMsgR (ExpandTowards U) (MirrorShrink))
, ("M-<D>" , addName "Expand (D on BSP)" $ tryMsgR (ExpandTowards D) (MirrorExpand))
, ("M-S-<L>" , addName "Shrink (L on BSP)" $ tryMsgR (ShrinkFrom R) (Shrink))
, ("M-S-<R>" , addName "Shrink (R on BSP)" $ tryMsgR (ShrinkFrom L) (Expand))
, ("M-S-<U>" , addName "Shrink (U on BSP)" $ tryMsgR (ShrinkFrom D) (MirrorShrink))
, ("M-S-<D>" , addName "Shrink (D on BSP)" $ tryMsgR (ShrinkFrom U) (MirrorExpand))
, ("M-r" , addName "Reflect Layout" $ sendMessage (XMonad.Layout.MultiToggle.Toggle REFLECTX))
, ("M-S-r" , addName "Mirror (BSP rotate)" $ tryMsgR (Rotate) (XMonad.Layout.MultiToggle.Toggle MIRROR))
, ("M-S-C-m" , addName "Mirror (always)" $ sendMessage $ XMonad.Layout.MultiToggle.Toggle MIRROR)
, ("M4-r" , addName "BSP Rotate" $ sendMessage Rotate)
, ("M4-s" , addName "BSP Swap" $ sendMessage XMonad.Layout.BinarySpacePartition.Swap)
, ("M4-p" , addName "BSP Focus Parent" $ sendMessage FocusParent)
, ("M4-n" , addName "BSP Select Node" $ sendMessage SelectNode)
--, ("M4-m" , addName "BSP Move Node" $ sendMessage MoveNode)
-- sublayout specific (unused)
-- ("M4-C-S-." , addName "toSubl Shrink" $ toSubl Shrink)
--, ("M4-C-S-," , addName "toSubl Expand" $ toSubl Expand)
] ^++^
-----------------------------------------------------------------------
-- Workspaces
-----------------------------------------------------------------------
-- original version was for dynamic workspaces
-- subKeys "{a,o,e,u,i,d,...} focus and move window between workspaces"
-- ( zipMod "View ws" wsKeys [0..] "M-" (withNthWorkspace W.greedyView)
subKeys "{a,o,e,u,i,d,...} focus and move window between workspaces" (
[
-- works ("M4-u" , addName "Test" $ windows $ W.shift "wrk:2")
-- , ("M-S-C-g", workspacePrompt myXPConfig $ withAll' . W.shiftWin)
-- ("M4-u" , addName "Test" $ withAll' W.shift "wrk:2")
]
++ zipM "M-" "View ws" wsKeys [0..] (withNthWorkspace W.greedyView)
++ zipM "M-S-" "Move w to ws" wsKeys [0..] (withNthWorkspace W.shift)
++ zipM "M-S-C-" "Copy w to ws" wsKeys [0..] (withNthWorkspace copy)
-- ++ zipM "M-" "View ws" wsKeys [0..] (windows W.greedyView)
-- ++ zipM "M-S-" "Move w to ws" wsKeys [0..] (withNthWorkspace W.shift)
-- ++ zipM "M-S-C-" "Copy w to ws" wsKeys [0..] (withNthWorkspace copy)
) ^++^
-----------------------------------------------------------------------
-- Screens
-----------------------------------------------------------------------
-- subKeys "Screens"
-- ([("M-C-<Right>", addName "Focus prev screen" prevScreen)
-- , ("M-C-<Left>" , addName "Focus next screen" nextScreen)
-- ]
-- ++ zipMod "Focus screen" screenKeys [0..] "M-" (screenAction W.view)
-- ++ zipMod "Move client to screen" screenKeys [0..] "M-S-" (screenAction W.shift)
-- ++ zipMod "Swap workspace with screen" screenKeys [0..] "M-M1-" (screenAction W.greedyView)
-- ++ zipMod "Swap workspace with and focus screen" screenKeys [0..] "M-C-" (\s -> screenAction W.greedyView s >> screenAction W.view s)
-- ) ^++^
-----------------------------------------------------------------------
-- Utility Bindings
-----------------------------------------------------------------------
subKeys "Utility Bindings"
[
-- not working due to timing?
-- ("M4-a" , addName "Copy browser address" $ sequence_ [ (P.sendKey controlMask xK_l)
-- , (P.sendKey controlMask xK_c)
-- , unsafeWithSelection "notify-send"])
("M4-a" , addName "Notify w current X selection" $ unsafeWithSelection "notify-send")
] ^++^
-----------------------------------------------------------------------
-- Applications
-----------------------------------------------------------------------
-- ("C-<Return>" , addName "Terminal" $ spawn myTerminal)
-- , ("C-S-<Return>" , addName "Console Terminal" $ runOrCopy myConsole (title =? "console"))
-- , ("C-\\" , addName "Browser" $ spawn myBrowser)
subKeys "Applications & Utilities"
[ ("M4-<Space>" , addName "Terminal" $ spawn myLauncher)
, ("M-<Return>" , addName "Terminal" $ spawn myTerminal)
, ("M-\\" , addName "Browser" $ spawn myBrowser)
, ("C-<Return>" , addName "Terminal" $ spawn myTerminal)
, ("C-\\" , addName "Browser" $ spawn myBrowser)
, ("M-c" , addName "NSP Hangouts" $ bindOn WS [("wrk", namedScratchpadAction scratchpads "hangoutsWork"),
("", namedScratchpadAction scratchpads "hangoutsPersonal")])
, ("M-t" , addName "NSP Trello" $ bindOn WS [("wrk", namedScratchpadAction scratchpads "trelloWork"),
("", namedScratchpadAction scratchpads "trello")])
-- , ("M4-v" , addName "NSP AV Music" $ bindOn WS [("av", namedScratchpadAction scratchpads "avMusic"),
-- ("", return ())])
, ("M4-v" , addName "NSP AV Music" $ namedScratchpadAction scratchpads "avMusic")
, ("M4-c" , addName "NSP Console" $ namedScratchpadAction scratchpads "console")
, ("M4-p" , addName "NSP Console" $ namedScratchpadAction scratchpads "plex")
] ^++^
-----------------------------------------------------------------------
-- XMonad Controls
-----------------------------------------------------------------------
subKeys "XMonad Controls"
[ ("M-q" , addName "Restart XMonad" $ spawn "xmonad --restart")
, ("M-C-q" , addName "Rebuild & restart XMonad" $ spawn "xmonad --recompile && xmonad --restart")
, ("M-S-q" , addName "Quit XMonad" $ confirmPrompt hotPromptTheme "Quit XMonad" $ io (exitWith ExitSuccess))
, ("M4-l" , addName "Lock screen" $ spawn "$HOME/bin/lockscreen")
] ^++^
-----------------------------------------------------------------------
-- Multimedia & System Keys
-----------------------------------------------------------------------
subKeys "Multimedia & System Keys"
[("<XF86Sleep>" , addName "System sleep" $ spawn "notify-send system sleep")
,("<XF86PowerOff>" , addName "System power off" $ spawn "notify-send system off")
,("S-<XF86PowerOff>" , addName "System reboot" $ spawn "notify-send system reboot")
,("<XF86ScreenSaver>" , addName "Lock screen" $ spawn "notify-send displays lock")
,("<XF86Display>" , addName "Cycle display mode" $ spawn "$HOME/bin/autodisplay auto")
,("S-<XF86Display>" , addName "Span display mode" $ spawn "$HOME/bin/autodisplay span")
,("C-<XF86Display>" , addName "Span display mode" $ spawn "$HOME/bin/autodisplay toggle")
,("M-<XF86Display>" , addName "Mirror display mode" $ spawn "$HOME/bin/autodisplay mirror")
,("S-C-<XF86Display>" , addName "Mirror display mode" $ spawn "$HOME/bin/autodisplay unlock && $HOME/bin/autodisplay auto")
,("M-C-<XF86Display>" , addName "Mirror display mode" $ spawn "$HOME/bin/autodisplay unlock && $HOME/bin/autodisplay auto")
,("M-S-<XF86Display>" , addName "Mirror display mode" $ spawn "$HOME/bin/autodisplay unlock && $HOME/bin/autodisplay auto")
,("<XF86Launch1>" , addName "Bluetooth toggle" $ spawn "notify-send wireless bluetooth toggle")
,("<XF86TouchpadOn>" , addName "Trackpad toggle" $ spawn "notify-send trackpad toggle")
,("<Print>" , addName "Screendraw start/stop" $ spawn "notify-send screendraw")
,("S-<Print>" , addName "Screendraw force stop" $ spawn "notify-send screendraw finish")
,("M-<Print>" , addName "Screendraw cancel" $ spawn "notify-send screendraw cancel")
,("<XF86RotateWindows>" , addName "Screendraw clear" $ spawn "notify-send screendraw clear")
] ^++^
subKeys "Media Controls"
[("<XF86AudioRaiseVolume>" , addName "Volume Up" $ raiseVolume 5 >> return ())
,("<XF86AudioLowerVolume>" , addName "Volume Down" $ lowerVolume 5 >> return ())
,("<XF86AudioMute>" , addName "Volume Mute" $ toggleMute >> return ())
,("M4-m" , addName "Volume Mute" $ toggleMute >> return ())
,("<XF86AudioMicMute>" , addName "Mic Mute" $ spawn "notify-send mic mute")
]
myModMask = mod1Mask -- alt key
mySecondaryModMask = mod4Mask -- super key
-- Mouse bindings: default actions bound to mouse events
-- Includes window snapping on move/resize using X.A.FloatSnap
-- Includes window w/h ratio constraint (square) using X.H.ConstrainedResize
myMouseBindings (XConfig {XMonad.modMask = myModMask}) = M.fromList $
[ ((myModMask, button1) ,(\w -> focus w
>> mouseMoveWindow w
>> ifClick (snapMagicMove (Just 50) (Just 50) w)
>> windows W.shiftMaster))
, ((myModMask .|. shiftMask, button1), (\w -> focus w
>> mouseMoveWindow w
>> ifClick (snapMagicResize [L,R,U,D] (Just 50) (Just 50) w)
>> windows W.shiftMaster))
, ((myModMask, button3), (\w -> focus w
>> mouseResizeWindow w
>> ifClick (snapMagicResize [R,D] (Just 50) (Just 50) w)
>> windows W.shiftMaster))
, ((myModMask .|. shiftMask, button3), (\w -> focus w
>> Sqr.mouseResizeWindow w True
>> ifClick (snapMagicResize [R,D] (Just 50) (Just 50) w)
>> windows W.shiftMaster ))
, ((mySecondaryModMask, button4), (\w -> focus w
>> prevNonEmptyWS))
, ((mySecondaryModMask, button5), (\w -> focus w
>> nextNonEmptyWS))
]
------------------------------------------------------------------------}}}
-- Startup {{{
---------------------------------------------------------------------------
myStartupHook = do
setDefaultCursor xC_left_ptr
spawnOnce "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1"
spawnOnce "dex -a"
spawnOnce "dunst -config ~/.dunstrc"
-- https://aur.archlinux.org/packages/unclutter-xfixes-git/
spawnOnce "unclutter --timeout 2 --fork"
spawnOnce "feh --bg-fill ~/tmp/lowpoly6.jpg"
--spawnOnce "compton -b --config ~/.i3/compton.conf"
spawnOnce "compton -b --config ~/.i3/compton.conf --xrender-sync-fence" -- test as per https://github.com/chjj/compton/wiki/perf-guide
spawnOnce "spacefm -d"
spawn "$HOME/bin/init-tray"
spawn "nvidia-settings --load-config-only"
--spawn "$HOME/bin/autodisplay unlock && $HOME/bin/autodisplay"
--spawn "killall stalonetray && stalonetray -c $HOME/.xmonad/stalonetrayrc"
--spawn "$HOME/bin/init-polybars"
--spawn "$HOME/bin/init-taffybars"
quitXmonad :: X ()
quitXmonad = io (exitWith ExitSuccess)
rebuildXmonad :: X ()
rebuildXmonad = do
spawn "xmonad --recompile && xmonad --restart"
restartXmonad :: X ()
restartXmonad = do
spawn "xmonad --restart"
unspawn :: String -> X ()
unspawn p = spawn $ "for pid in $(pgrep " ++ p ++ "); do kill -9 $pid; done"
flash :: String -> X ()
flash s = spawn $ "flash "++ s
notify :: String -> X ()
notify s = spawn $ "notify "++ s
alert :: String -> X ()
alert s = spawn $ "alert "++ s
warn :: String -> X ()
warn s = spawn $ "warn "++ s
------------------------------------------------------------------------}}}
-- Log {{{
---------------------------------------------------------------------------
myLogHook h = do
-- following block for copy windows marking
copies <- wsContainingCopies
let check ws | ws `elem` copies =
pad . xmobarColor yellow red . wrap "*" " " $ ws
| otherwise = pad ws
fadeWindowsLogHook myFadeHook
ewmhDesktopsLogHook
--dynamicLogWithPP $ defaultPP
dynamicLogWithPP $ def
{ ppCurrent = xmobarColor active "" . wrap "[" "]"
, ppTitle = xmobarColor active "" . shorten 100
, ppVisible = wrap "(" ")"
, ppUrgent = xmobarColor red "" . wrap " " " "
, ppHidden = check
, ppHiddenNoWindows = const ""
, ppSep = xmobarColor red blue " : "
, ppWsSep = " "
, ppLayout = xmobarColor yellow ""
, ppOrder = id
, ppOutput = hPutStrLn h
, ppSort = fmap
(namedScratchpadFilterOutWorkspace.)
(ppSort def)
--(ppSort defaultPP)
, ppExtras = [] }
myFadeHook = composeAll
[ opaque -- default to opaque
, isUnfocused --> opacity 0.85
--, isFloating --> opacity 0.75
, (className =? "Terminator") <&&> (isUnfocused) --> opacity 0.9
, (className =? "Taffybar-linux-x86_64") --> opacity 0.5
, fmap ("Google" `isPrefixOf`) className --> opaque
--, isUnfocused --> opacity 0.55
--, isFloating --> opacity 0.75
, isDialog --> opaque
]
------------------------------------------------------------------------}}}
-- Actions {{{
---------------------------------------------------------------------------
--myPlacement = withGaps (status,0,status,0) (fixed (0.5,0.5))
--myPlacement = simpleSmart
--myManageHook = placeHook myPlacement
-- <+> manageDocks
-- good ideas from https://github.com/pjones/xmonadrc
---------------------------------------------------------------------------
-- New Window Actions
---------------------------------------------------------------------------
-- <+> manageHook defaultConfig
myManageHook :: ManageHook
myManageHook =
manageDocks
<+> namedScratchpadManageHook scratchpads
<+> composeOne
[
resource =? "sxlock" -?> tileBelow
, title =? "sxlock" -?> tileBelow
--, title =? "sxlock" -?> (insertPosition Master Newer <+> doIgnore)
, resource =? "desktop_window" -?> doIgnore
, resource =? "stalonetray" -?> doIgnore
, resource =? trelloResource -?> doFullFloat
, resource =? trelloWorkResource -?> doFullFloat
, resource =? avMusicResource -?> doFullFloat
, resource =? plexResource -?> doCenterFloat
, resource =? hangoutsResource -?> insertPosition End Newer
, transience
, isBrowserDialog -?> forceCenterFloat
, isConsole -?> forceCenterFloat
, isRole =? gtkFile -?> forceCenterFloat
, isDialog -?> doCenterFloat
, isRole =? "pop-up" -?> doCenterFloat
, isInProperty "_NET_WM_WINDOW_TYPE"
"_NET_WM_WINDOW_TYPE_SPLASH" -?> doCenterFloat
, resource =? "console" -?> tileBelowNoFocus
, isFullscreen -?> doFullFloat
, pure True -?> tileBelow
]
where
isBrowserDialog = isDialog <&&> className =? myBrowserClass
gtkFile = "GtkFileChooserDialog"
isRole = stringProperty "WM_WINDOW_ROLE"
-- insert WHERE and focus WHAT
tileBelow = insertPosition Below Newer
tileBelowNoFocus = insertPosition Below Older
---------------------------------------------------------------------------
-- X Event Actions
---------------------------------------------------------------------------
myHandleEventHook =
docksEventHook
<+> fadeWindowsEventHook
<+> dynamicTitle myDynHook
<+> handleEventHook def
<+> serverModeEventHook
<+> docksEventHook
-- following line same as dynamicTitle myDynHook
-- <+> dynamicPropertyChange "WM_NAME" myDynHook
-- I'm not really into full screens without my say so... I often like to
-- fullscreen a window but keep it constrained to a window rect (e.g.
-- for videos, etc. without the UI chrome cluttering things up). I can
-- always do that and then full screen the subsequent window if I want.
-- <+> XMonad.Hooks.EwmhDesktops.fullscreenEventHook
where
myDynHook = composeAll
[
resource =? "sxlock" --> doFullFloat
, title =? "sxlock" --> doFullFloat
-- make hangouts centered when it appears
-- (className =? myBrowserClass
-- <&&> title =? myHangoutsTitle
-- --> forceCenterFloat)
-- (className =? myBrowserClass
-- <&&> myHangoutsPrefix `isPrefixOf` title
-- --> forceCenterFloat)
-- (resource =? hangoutsResource
-- --> forceCenterFloat)
, resource =? hangoutsResource
--> insertPosition End Newer
]
---------------------------------------------------------------------------
-- Custom hook helpers
---------------------------------------------------------------------------
-- from:
-- https://github.com/pjones/xmonadrc/blob/master/src/XMonad/Local/Action.hs
--
-- Useful when a floating window requests stupid dimensions. There
-- was a bug in Handbrake that would pop up the file dialog with
-- almost no height due to one of my rotated monitors.
forceCenterFloat :: ManageHook
forceCenterFloat = doFloatDep move
where
move :: W.RationalRect -> W.RationalRect
move _ = W.RationalRect x y w h
w, h, x, y :: Rational
w = 1/3
h = 1/2
x = (1-w)/2
y = (1-h)/2
---- | If the given condition is 'True' then add the given tag name to
---- the window being mapped. Always returns 'Nothing' to continue
---- processing other manage hooks.
--addTagAndContinue :: Query Bool -> String -> MaybeManageHook
--addTagAndContinue p tag = do
-- x <- p
-- when x (liftX . addTag tag =<< ask)
-- return Nothing
-- https://wiki.haskell.org/Xmonad/General_xmonad.hs_config_tips#ManageHook_examples
--isTermScratchPad = (className =? "Gnome-terminal") <&&> (stringProperty "WM_WINDOW_ROLE" =? "Scratchpad")
--myPlacement = withGaps (status,0,status,0) (fixed (0.5,0.5))
--myManageHook = placeHook myPlacement
-- <+> manageDocks
-- <+> namedScratchpadManageHook scratchpads
-- <+> composeAll
-- [ className =? "MPlayer" --> doFloat
-- , className =? "Gimp" --> doFloat
-- , resource =? "desktop_window" --> doIgnore
-- , resource =? "kdesktop" --> doIgnore
-- , resource =? "stalonetray" --> doIgnore
---- , isFullscreen --> doFullFloat
-- , manageHook defaultConfig
-- ]
--
-- for ref
-- myManageHookFloat = composeAll
-- [ className =? "Gimp" --> doFloat
-- , className =? "Tk" --> doFloat
-- , className =? "mplayer2" --> doCenterFloat
-- , className =? "mpv" --> doCenterFloat
-- , className =? "feh" --> doCenterFloat
-- , className =? "Display.im6" --> doCenterFloat
-- , className =? "Shutter" --> doCenterFloat
-- , className =? "Thunar" --> doCenterFloat
-- , className =? "Nautilus" --> doCenterFloat
-- , className =? "Plugin-container" --> doCenterFloat
-- , className =? "Screenkey" --> (doRectFloat $ W.RationalRect 0.7 0.9 0.3 0.1)
-- , className =? "Websearch" --> doCenterFloat
-- , className =? "XClock" --> doSideFloat NE
-- , title =? "Speedbar" --> doCenterFloat
-- , title =? "urxvt_float" --> doSideFloat SC
-- , isFullscreen --> doFullFloat
-- , isDialog --> doCenterFloat
-- , stringProperty "WM_NAME" =? "LINE" --> (doRectFloat $ W.RationalRect 0.60 0.1 0.39 0.82)
-- , stringProperty "WM_NAME" =? "Google Keep" --> (doRectFloat $ W.RationalRect 0.3 0.1 0.4 0.82)
-- , stringProperty "WM_NAME" =? "tmptex.pdf - 1/1 (96 dpi)" --> (doRectFloat $ W.RationalRect 0.29 0.25 0.42 0.5)
-- , stringProperty "WM_NAME" =? "Figure 1" --> doCenterFloat
-- ]
-- vim: ft=haskell:foldmethod=marker:expandtab:ts=4:shiftwidth=4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment