Initial commit
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					dist/
 | 
				
			||||||
							
								
								
									
										5
									
								
								ChangeLog.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								ChangeLog.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					# Revision history for xmonad-masser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.1.0.0 -- YYYY-mm-dd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* First version. Released on an unsuspecting world.
 | 
				
			||||||
							
								
								
									
										30
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					Copyright (c) 2019, Mats Rauhala
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					      notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					      copyright notice, this list of conditions and the following
 | 
				
			||||||
 | 
					      disclaimer in the documentation and/or other materials provided
 | 
				
			||||||
 | 
					      with the distribution.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    * Neither the name of Mats Rauhala nor the names of other
 | 
				
			||||||
 | 
					      contributors may be used to endorse or promote products derived
 | 
				
			||||||
 | 
					      from this software without specific prior written permission.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
							
								
								
									
										3
									
								
								default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					{ haskellPackages }:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					haskellPackages.callCabal2nix "xmonad-masser" ./. {}
 | 
				
			||||||
							
								
								
									
										15
									
								
								release.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								release.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					{ nixpkgs ? import <nixpkgs> {} }:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rec {
 | 
				
			||||||
 | 
					  xmonad-masser = nixpkgs.callPackage ./default.nix {};
 | 
				
			||||||
 | 
					  shell = nixpkgs.buildEnv {
 | 
				
			||||||
 | 
					    name = "shell";
 | 
				
			||||||
 | 
					    paths = [];
 | 
				
			||||||
 | 
					    buildInputs = with nixpkgs.haskellPackages; [
 | 
				
			||||||
 | 
					      (ghcWithPackages (_: xmonad-masser.buildInputs ++ xmonad-masser.propagatedBuildInputs))
 | 
				
			||||||
 | 
					      ghcid
 | 
				
			||||||
 | 
					      cabal-install
 | 
				
			||||||
 | 
					      nixpkgs.pkgs.binutils
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								shell.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								shell.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					{ nixpkgs ? import <nixpkgs> {} }:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(nixpkgs.callPackage ./release.nix {}).shell
 | 
				
			||||||
							
								
								
									
										36
									
								
								src/XMonad/Config.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/XMonad/Config.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					{-# Language RecordWildCards #-}
 | 
				
			||||||
 | 
					{-# Language DeriveGeneric #-}
 | 
				
			||||||
 | 
					{-# Language OverloadedStrings #-}
 | 
				
			||||||
 | 
					module Config where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Dhall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data Applications = Applications { urxvt :: Text
 | 
				
			||||||
 | 
					                                 , prompt :: Text
 | 
				
			||||||
 | 
					                                 , browser :: Text
 | 
				
			||||||
 | 
					                                 , launcher :: Text -- xdg-open
 | 
				
			||||||
 | 
					                                 , screenshot :: Text
 | 
				
			||||||
 | 
					                                 }
 | 
				
			||||||
 | 
					                  deriving (Show, Generic)
 | 
				
			||||||
 | 
					data TopicRule = TopicRule { topicName :: Text
 | 
				
			||||||
 | 
					                           , topicHome :: Maybe Text
 | 
				
			||||||
 | 
					                           , topicAction :: Maybe Text }
 | 
				
			||||||
 | 
					               deriving (Show, Generic)
 | 
				
			||||||
 | 
					data ExtraConfig = ExtraConfig { applications :: Applications
 | 
				
			||||||
 | 
					                               , topics :: [TopicRule]}
 | 
				
			||||||
 | 
					                 deriving (Show, Generic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultExtraConfig :: ExtraConfig
 | 
				
			||||||
 | 
					defaultExtraConfig =
 | 
				
			||||||
 | 
					    let applications = Applications{..}
 | 
				
			||||||
 | 
					        urxvt = "urxvt"
 | 
				
			||||||
 | 
					        prompt = "xmobar"
 | 
				
			||||||
 | 
					        browser = "qutebrowser"
 | 
				
			||||||
 | 
					        launcher = "xdg-open"
 | 
				
			||||||
 | 
					        screenshot = "scrot ~/screenSel.png"
 | 
				
			||||||
 | 
					        topics = []
 | 
				
			||||||
 | 
					    in ExtraConfig{..}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance Interpret ExtraConfig
 | 
				
			||||||
 | 
					instance Interpret TopicRule
 | 
				
			||||||
 | 
					instance Interpret Applications
 | 
				
			||||||
							
								
								
									
										265
									
								
								src/XMonad/Config/MasseR.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								src/XMonad/Config/MasseR.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,265 @@
 | 
				
			|||||||
 | 
					{-# LANGUAGE OverloadedStrings #-}
 | 
				
			||||||
 | 
					module XMonad.Config.MasseR  where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           XMonad.Password
 | 
				
			||||||
 | 
					import           XMonad.CustomPrompt
 | 
				
			||||||
 | 
					import           XMonad.TopicSpace
 | 
				
			||||||
 | 
					import qualified Data.List                          as List
 | 
				
			||||||
 | 
					import           XMonad
 | 
				
			||||||
 | 
					import           XMonad.Actions.CycleWS             (swapNextScreen)
 | 
				
			||||||
 | 
					import           XMonad.Actions.Search
 | 
				
			||||||
 | 
					import           XMonad.Hooks.EwmhDesktops          (ewmh, ewmhDesktopsStartup)
 | 
				
			||||||
 | 
					import           XMonad.Hooks.SetWMName             (setWMName)
 | 
				
			||||||
 | 
					import           XMonad.Hooks.UrgencyHook           (args, dzenUrgencyHook,
 | 
				
			||||||
 | 
					                                                     withUrgencyHook)
 | 
				
			||||||
 | 
					import           XMonad.Layout.Accordion
 | 
				
			||||||
 | 
					import           XMonad.Layout.BinarySpacePartition (emptyBSP)
 | 
				
			||||||
 | 
					import           XMonad.Layout.Decoration           (Decoration,
 | 
				
			||||||
 | 
					                                                     DefaultShrinker)
 | 
				
			||||||
 | 
					import           XMonad.Layout.DwmStyle
 | 
				
			||||||
 | 
					import           XMonad.Layout.HintedGrid
 | 
				
			||||||
 | 
					import           XMonad.Layout.LayoutModifier       (ModifiedLayout)
 | 
				
			||||||
 | 
					import           XMonad.Layout.Master
 | 
				
			||||||
 | 
					import           XMonad.Layout.NoBorders            (smartBorders)
 | 
				
			||||||
 | 
					import           XMonad.Layout.PerWorkspace         (onWorkspace)
 | 
				
			||||||
 | 
					import           XMonad.Layout.Renamed
 | 
				
			||||||
 | 
					import           XMonad.Layout.Simplest             (Simplest)
 | 
				
			||||||
 | 
					import           XMonad.Layout.Spiral
 | 
				
			||||||
 | 
					import           XMonad.Layout.Tabbed               (TabbedDecoration,
 | 
				
			||||||
 | 
					                                                     Theme (..), shrinkText,
 | 
				
			||||||
 | 
					                                                     tabbed)
 | 
				
			||||||
 | 
					import           XMonad.Layout.ToggleLayouts        (ToggleLayout (..))
 | 
				
			||||||
 | 
					import           XMonad.Prompt.RunOrRaise           (runOrRaisePrompt)
 | 
				
			||||||
 | 
					import qualified XMonad.StackSet                    as W
 | 
				
			||||||
 | 
					import           XMonad.Util.EZConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           XMonad.XMobar                             (zenburnPP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           Data.Monoid                        (Endo, (<>))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           XMonad.Util.NamedScratchpad
 | 
				
			||||||
 | 
					import           XMonad.Util.SpawnOnce
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           System.IO                          (hClose, hPutStr)
 | 
				
			||||||
 | 
					import           XMonad.Actions.Navigation2D
 | 
				
			||||||
 | 
					import           XMonad.Util.NamedActions
 | 
				
			||||||
 | 
					import           XMonad.Util.Run                    (spawnPipe)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           XMonad.Config.MasseR.ExtraConfig
 | 
				
			||||||
 | 
					-- import Customizations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import qualified Data.Text                          as T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           XMonad.Hooks.DynamicLog            (statusBar)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import qualified Data.Set                           as S
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					spotify :: XConfig l -> NamedAction
 | 
				
			||||||
 | 
					spotify conf = submapName . mkNamedKeymap conf $
 | 
				
			||||||
 | 
					   [ ("M-p", addName "Play" $ spawn "sp play") ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					scratchpads :: [NamedScratchpad]
 | 
				
			||||||
 | 
					scratchpads = [
 | 
				
			||||||
 | 
					    NS "notes" "vim -g --role notes -c 'e ~/wikidata/index.md'" (wmRole =? "notes") nonFloating
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    where wmRole = stringProperty "WM_WINDOW_ROLE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					scratchSubmaps :: XConfig l -> NamedAction
 | 
				
			||||||
 | 
					scratchSubmaps conf = submapName . mkNamedKeymap conf $ [
 | 
				
			||||||
 | 
					    ("M-n", addName "Open notes" $ namedScratchpadAction scratchpads "notes")
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Search engines inside submaps
 | 
				
			||||||
 | 
					searchSubmaps :: XConfig l -> NamedAction
 | 
				
			||||||
 | 
					searchSubmaps conf =
 | 
				
			||||||
 | 
					    let mkBrowser = promptSearchBrowser def "qutebrowser"
 | 
				
			||||||
 | 
					        _googleP = addName "Search google" $ mkBrowser google
 | 
				
			||||||
 | 
					        ddgP = addName "Search duckduckgo" $ mkBrowser (searchEngine "duckduckgo" "http://duckduckgo.com/?q=")
 | 
				
			||||||
 | 
					    in submapName . mkNamedKeymap conf $
 | 
				
			||||||
 | 
					            [ ("d", ddgP) -- Training to use ddg again
 | 
				
			||||||
 | 
					            , ("g", ddgP) -- training to use ddg again
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					myNav2d :: Navigation2DConfig
 | 
				
			||||||
 | 
					myNav2d = def { defaultTiledNavigation = lineNavigation }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Layout
 | 
				
			||||||
 | 
					myTabConfig ::  Theme
 | 
				
			||||||
 | 
					myTabConfig = def {
 | 
				
			||||||
 | 
					      activeBorderColor = "#DCDCCC"
 | 
				
			||||||
 | 
					    , activeTextColor = "#DCDCCC"
 | 
				
			||||||
 | 
					    , activeColor = "#3F3F3F"
 | 
				
			||||||
 | 
					    , fontName = "xft:Inconsolata-9"
 | 
				
			||||||
 | 
					    , inactiveBorderColor = "#262626"
 | 
				
			||||||
 | 
					    , inactiveTextColor = "#9FAFAF"
 | 
				
			||||||
 | 
					    , inactiveColor = "#262626"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(=~?) :: XMonad.Query String -> String -> XMonad.Query Bool
 | 
				
			||||||
 | 
					q =~? x = fmap (x `List.isInfixOf`) q
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Manage hooks
 | 
				
			||||||
 | 
					-- Move programs to their workspaces
 | 
				
			||||||
 | 
					myManageHook :: XMonad.Query (Endo WindowSet)
 | 
				
			||||||
 | 
					myManageHook = composeAll $ concat [
 | 
				
			||||||
 | 
					      dynamicsHook
 | 
				
			||||||
 | 
					    , webHooks
 | 
				
			||||||
 | 
					    , pdfHooks
 | 
				
			||||||
 | 
					    , documentHooks
 | 
				
			||||||
 | 
					    , floatHooks
 | 
				
			||||||
 | 
					    , debuggerHooks
 | 
				
			||||||
 | 
					    , ideHooks
 | 
				
			||||||
 | 
					    , flowHook
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    classHook y = map (\x -> className =? x --> y)
 | 
				
			||||||
 | 
					    ideHooks = classHook (doShift "eclipse") [
 | 
				
			||||||
 | 
					            "Anypoint Studio"
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    webHooks = classHook (doShift "web") [
 | 
				
			||||||
 | 
					          "Firefox"
 | 
				
			||||||
 | 
					        , "qutebrowser"
 | 
				
			||||||
 | 
					        , "Midori"
 | 
				
			||||||
 | 
					        , "chromium-browser"
 | 
				
			||||||
 | 
					        , "Uzbl-tabbed"
 | 
				
			||||||
 | 
					        , "Uzbl-core"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    pdfHooks = classHook (doShift "pdf") [
 | 
				
			||||||
 | 
					          "Evince"
 | 
				
			||||||
 | 
					        , "Okular"
 | 
				
			||||||
 | 
					        , "Kpdf"
 | 
				
			||||||
 | 
					        , "Xdvi"
 | 
				
			||||||
 | 
					        , ".zathura-wrapped_"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    documentHooks = classHook (doShift "documents") [
 | 
				
			||||||
 | 
					          "libreoffice"
 | 
				
			||||||
 | 
					        , "libreoffice-calc"
 | 
				
			||||||
 | 
					        , "Assistant"
 | 
				
			||||||
 | 
					        , "Bouml"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    floatHooks = classHook doFloat [
 | 
				
			||||||
 | 
					          "SMplayer"
 | 
				
			||||||
 | 
					        , "Gimp"
 | 
				
			||||||
 | 
					        , "MPlayer"
 | 
				
			||||||
 | 
					        , "Kaffeine"
 | 
				
			||||||
 | 
					        , "Xmessage"
 | 
				
			||||||
 | 
					        , "Wfica_Seamless"
 | 
				
			||||||
 | 
					        , "mpv"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    debuggerHooks = classHook (doShift "debugger") [
 | 
				
			||||||
 | 
					          "JSwat Debugger",
 | 
				
			||||||
 | 
					          "DBeaver"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    dynamicsHook = [title =~? "Dynamics" --> doShift "dynamics"]
 | 
				
			||||||
 | 
					    flowHook = [title =~? "www.flowdock.com" --> doShift "flowdock"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					myKeys :: ExtraConfig -> XConfig l -> [((KeyMask, KeySym), NamedAction)]
 | 
				
			||||||
 | 
					myKeys extraConfig conf =
 | 
				
			||||||
 | 
					    let subKeys str ks = subtitle str : mkNamedKeymap conf ks in
 | 
				
			||||||
 | 
					    subKeys "Actions" [ ("M-S-r", addName "foo" $ spawn "xmonad --restart")
 | 
				
			||||||
 | 
					                      , ("M-C-l", addName "Lock screen" $ spawn locker)] ^++^
 | 
				
			||||||
 | 
					    subKeys "System" [ ("<XF86Sleep>", addName "Suspend machine" $ spawn "sudo pm-suspend")
 | 
				
			||||||
 | 
					                     , ("<XF86AudioRaiseVolume>", addName "Increase volume" $ spawn "amixer set Master 2%+")
 | 
				
			||||||
 | 
					                     , ("<XF86AudioLowerVolume>", addName "Decrease volume" $ spawn "amixer set Master 2%-")
 | 
				
			||||||
 | 
					                     , ("M-<plus>", addName "Increase volume" $ spawn "amixer set Master 2+")
 | 
				
			||||||
 | 
					                     , ("M-<minus>", addName "Decrease volume" $ spawn "amixer set Master 2-")
 | 
				
			||||||
 | 
					                     -- , ("<XF86AudioPlay>", addName "Play/pause spotify" $ spawn "/home/masse/.local/bin/sp play")
 | 
				
			||||||
 | 
					                     , ("<XF86AudioPlay>", addName "Play/pause mopidy" $ spawn "mpc toggle")
 | 
				
			||||||
 | 
					                     , ("M-m", spotify conf)
 | 
				
			||||||
 | 
					                     , ("M-S-<Space>", addName "Swap screens" swapNextScreen)
 | 
				
			||||||
 | 
					                     , ("M-<Backspace>", addName "Kill window" kill)
 | 
				
			||||||
 | 
					                     -- scrot requires `unGrab`
 | 
				
			||||||
 | 
					                     , ("M-<Print>", addName "Take screenshot" $ spawn (screenshot . applications $ extraConfig))] ^++^
 | 
				
			||||||
 | 
					    subKeys "Launchers" [ ("M-S-y", addName "Open youtube" $ spawn "mpv $(clip -o)")
 | 
				
			||||||
 | 
					                        , ("M-S-<Return>", addName "Open terminal" $ spawn $ XMonad.terminal conf)
 | 
				
			||||||
 | 
					                        , ("M-n", scratchSubmaps conf)
 | 
				
			||||||
 | 
					                        , ("M-s", searchSubmaps conf)
 | 
				
			||||||
 | 
					                        , ("M-p", addName "Retrieve password" $ passPrompt def)
 | 
				
			||||||
 | 
					                        , ("M-S-e", addName "Open with app" xdg_open)
 | 
				
			||||||
 | 
					                        , ("M-e", addName "Run app" $ runOrRaisePrompt def)] ^++^
 | 
				
			||||||
 | 
					    subKeys "Windows" [ ("M-j", addName "Go down" $ windowGo D False)
 | 
				
			||||||
 | 
					                      , ("M-k", addName "Go up" $ windowGo U False)
 | 
				
			||||||
 | 
					                      , ("M-h", addName "Go left" $ windowGo L False)
 | 
				
			||||||
 | 
					                      , ("M-l", addName "Go right" $ windowGo R False)
 | 
				
			||||||
 | 
					                      , ("M-S-j", addName "Shift window down" $ windowSwap D False)
 | 
				
			||||||
 | 
					                      , ("M-S-k", addName "Shift window up" $ windowSwap U False)
 | 
				
			||||||
 | 
					                      , ("M-S-h", addName "Shift window left" $ windowSwap L False)
 | 
				
			||||||
 | 
					                      , ("M-S-l", addName "Shift window right" $ windowSwap R False)
 | 
				
			||||||
 | 
					                      , ("M-.", addName "Go to previous window" $ windows W.focusDown)
 | 
				
			||||||
 | 
					                      , ("M-,", addName "Go to next window" $ windows W.focusUp)
 | 
				
			||||||
 | 
					                      , ("M-S-m", addName "Swap master" $ windows W.swapMaster)
 | 
				
			||||||
 | 
					                      ] ^++^
 | 
				
			||||||
 | 
					    subKeys "Projects & Workspaces" (topicKeys' extraConfig conf) ^++^
 | 
				
			||||||
 | 
					    subKeys "Layout management" [ ("M-C-<Space>", addName "Toggle layout" $ sendMessage ToggleLayout)
 | 
				
			||||||
 | 
					                                , ("M-<Space>", addName "Next layout" $ sendMessage NextLayout)] ^++^
 | 
				
			||||||
 | 
					    subKeys "Resize" []
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    locker = "sh ~/scripts/lock.sh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					myStartupHook :: X ()
 | 
				
			||||||
 | 
					myStartupHook = spawnOnce "$HOME/wminit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					masser :: ExtraConfig -> IO ()
 | 
				
			||||||
 | 
					masser extraConfig = xmonad =<< statusBar (bar extraConfig) zenburnPP toggleStrutsKey myConfig
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    toggleStrutsKey XConfig{modMask=modm} = (modm, xK_b)
 | 
				
			||||||
 | 
					    bar = prompt . applications
 | 
				
			||||||
 | 
					    myConfig = withUrgencyHook dzenUrgencyHook { args = ["-bg", "darkgreen", "-xs", "1"]} $
 | 
				
			||||||
 | 
					                     withNavigation2DConfig myNav2d $
 | 
				
			||||||
 | 
					                     ewmh $
 | 
				
			||||||
 | 
					                     addDescrKeys' ((mod4Mask, xK_F1), showKeybindings) (myKeys extraConfig) $
 | 
				
			||||||
 | 
					                     def {
 | 
				
			||||||
 | 
					                       modMask = mod4Mask -- Hyper
 | 
				
			||||||
 | 
					                       , terminal = urxvt . applications $ extraConfig
 | 
				
			||||||
 | 
					                       , keys = const mempty
 | 
				
			||||||
 | 
					                       , workspaces = let defaults = ["irc", "web", "mail"]
 | 
				
			||||||
 | 
					                                          external = map (T.unpack . topicName) . topics $ extraConfig
 | 
				
			||||||
 | 
					                                      in S.toList (S.fromList defaults <> S.fromList external)
 | 
				
			||||||
 | 
					                       , layoutHook = smartBorders myLayout
 | 
				
			||||||
 | 
					                       , clickJustFocuses = False
 | 
				
			||||||
 | 
					                       , startupHook = myStartupHook >> ewmhDesktopsStartup >> setWMName "LG3D"
 | 
				
			||||||
 | 
					                       , borderWidth = 2
 | 
				
			||||||
 | 
					                       , normalBorderColor = "#262626"
 | 
				
			||||||
 | 
					                       , focusedBorderColor = "#7F9F7F"
 | 
				
			||||||
 | 
					                       , manageHook = myManageHook
 | 
				
			||||||
 | 
					                       , focusFollowsMouse = False
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					    myLayout = onWorkspace "web" webLayout $
 | 
				
			||||||
 | 
					               onWorkspace "dynamics" webLayout $
 | 
				
			||||||
 | 
					               onWorkspace "pdf" pdfLayout $
 | 
				
			||||||
 | 
					               onWorkspace "documents" documentLayout $
 | 
				
			||||||
 | 
					               onWorkspace "mail" mailLayout $
 | 
				
			||||||
 | 
					               onWorkspace "irc" ircLayout
 | 
				
			||||||
 | 
					               defLayout
 | 
				
			||||||
 | 
					      where
 | 
				
			||||||
 | 
					        -- Default layout
 | 
				
			||||||
 | 
					        defLayout = tiled ||| tabLayout ||| readLayout ||| bspLayout ||| vimLayout ||| spiral (6/7) ||| Full
 | 
				
			||||||
 | 
					        ircLayout = GridRatio (4/3) False ||| emptyBSP
 | 
				
			||||||
 | 
					        -- Pdfs are restricted to tabs
 | 
				
			||||||
 | 
					        vimLayout = Mirror (mastered (1/100) (4/5) Accordion)
 | 
				
			||||||
 | 
					        pdfLayout =  readLayout ||| tiled ||| tabLayout
 | 
				
			||||||
 | 
					        readLayout = renamed [Replace "2/3"] (dwmStyle shrinkText myTabConfig (mastered (1/100) (2/3) Accordion))
 | 
				
			||||||
 | 
					        bspLayout = renamed [Replace "master bsp"] (dwmStyle shrinkText myTabConfig (mastered (1/100) (2/3) (Mirror emptyBSP)))
 | 
				
			||||||
 | 
					        -- Documents are by default tabs, but have looser restrictions
 | 
				
			||||||
 | 
					        documentLayout = tabLayout ||| Full ||| tiled ||| Mirror tiled
 | 
				
			||||||
 | 
					        -- Web is either tabbed, full, or tiled
 | 
				
			||||||
 | 
					        webLayout = readLayout ||| tabLayout ||| Full ||| tiled
 | 
				
			||||||
 | 
					        tiled = Tall nmaster delta ratio
 | 
				
			||||||
 | 
					        -- I need to restrict the type or type inferencer can't deduce type classes
 | 
				
			||||||
 | 
					        tabLayout :: ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) Simplest Window
 | 
				
			||||||
 | 
					        tabLayout = tabbed shrinkText myTabConfig
 | 
				
			||||||
 | 
					        mailLayout = readLayout ||| tabLayout
 | 
				
			||||||
 | 
					        delta = 3/100
 | 
				
			||||||
 | 
					        ratio = 1/2
 | 
				
			||||||
 | 
					        nmaster = 1
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/XMonad/Config/MasseR/ExtraConfig.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/XMonad/Config/MasseR/ExtraConfig.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					{-# LANGUAGE DeriveGeneric #-}
 | 
				
			||||||
 | 
					module XMonad.Config.MasseR.ExtraConfig where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import GHC.Generics (Generic)
 | 
				
			||||||
 | 
					import Data.Text (Text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data Applications = Applications { browser :: FilePath, launcher :: FilePath, prompt :: FilePath, screenshot :: FilePath, urxvt :: FilePath } deriving (Show, Generic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data TopicRule = TopicRule { topicName :: Text
 | 
				
			||||||
 | 
					                           , topicHome :: Maybe Text
 | 
				
			||||||
 | 
					                           , topicAction :: Maybe Text }
 | 
				
			||||||
 | 
					                           deriving (Show, Generic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data ExtraConfig = ExtraConfig { applications :: Applications, topics :: [ TopicRule ] } deriving (Show, Generic)
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/XMonad/Configurable.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/XMonad/Configurable.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					module XMonad.Configurable (Configurable, EndoM(..), configure) where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Control.Monad ((<=<))
 | 
				
			||||||
 | 
					import Control.Monad.Reader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					newtype EndoM m a = EndoM { appEndoM :: a -> m a }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance Monad m => Semigroup (EndoM m a) where
 | 
				
			||||||
 | 
					  EndoM f <> EndoM g = EndoM (f <=< g)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance Monad m => Monoid (EndoM m a) where
 | 
				
			||||||
 | 
					  mempty = EndoM pure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Configurable a = EndoM (Reader a) a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					configure :: Configurable a -> a
 | 
				
			||||||
 | 
					configure (EndoM f) = fix (\self -> runReader (f self) self)
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/XMonad/CustomPrompt.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/XMonad/CustomPrompt.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					module XMonad.CustomPrompt (xdg_open, browser) where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import qualified XMonad.Prompt.AppLauncher as AL
 | 
				
			||||||
 | 
					import XMonad.Prompt
 | 
				
			||||||
 | 
					import XMonad (X)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					launchApp ::  AL.Application -> X ()
 | 
				
			||||||
 | 
					launchApp = AL.launchApp def
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					xdg_open :: X ()
 | 
				
			||||||
 | 
					xdg_open = launchApp "xdg-open"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					browser :: X ()
 | 
				
			||||||
 | 
					browser = launchApp "qutebrowser"
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/XMonad/Customizations.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/XMonad/Customizations.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					{-# Language FlexibleContexts #-}
 | 
				
			||||||
 | 
					module Customizations (customizations) where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Configurable
 | 
				
			||||||
 | 
					import XMonad
 | 
				
			||||||
 | 
					import XMonad.Util.EZConfig (additionalKeys)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Customizations.Types
 | 
				
			||||||
 | 
					import qualified Customizations.Topics as Topics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Control.Lens
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					customizations :: LayoutClass l Window => XConfig l -> XConfig l
 | 
				
			||||||
 | 
					customizations start = xconfig $ configure (mconcat [topics, Topics.customize, initial])
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    initial = EndoM $ \_ -> pure (Customize start def)
 | 
				
			||||||
 | 
					    topics :: LayoutClass l Window => Configurable (Customize l)
 | 
				
			||||||
 | 
					    topics = EndoM $ \super -> do
 | 
				
			||||||
 | 
					      _self <- ask
 | 
				
			||||||
 | 
					      pure (over _xconfig _ super)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										57
									
								
								src/XMonad/Password.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/XMonad/Password.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					module XMonad.Password (passGeneratePrompt, passPrompt) where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           Control.Monad.Trans   (liftIO)
 | 
				
			||||||
 | 
					import           Data.Function         (on)
 | 
				
			||||||
 | 
					import           Data.List             (foldl', scanl', sort, sortBy)
 | 
				
			||||||
 | 
					import           System.Directory      (getHomeDirectory)
 | 
				
			||||||
 | 
					import           System.FilePath.Posix (dropExtension, takeExtension, (</>))
 | 
				
			||||||
 | 
					import           System.Posix.Env      (getEnv)
 | 
				
			||||||
 | 
					import           XMonad.Core
 | 
				
			||||||
 | 
					import           XMonad.Prompt
 | 
				
			||||||
 | 
					import           XMonad.Util.Run       (runProcessWithInput)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data Pass = Pass { passLabel :: String }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Rosetta code levenshtein
 | 
				
			||||||
 | 
					levenshtein :: String -> String -> Int
 | 
				
			||||||
 | 
					levenshtein s1 s2 = last $ foldl' transform [0..length s1] s2
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    transform [] _ = []
 | 
				
			||||||
 | 
					    transform ns@(n:ns1) c = scanl' calc (n+1) $ zip3 s1 ns ns1
 | 
				
			||||||
 | 
					      where
 | 
				
			||||||
 | 
					        calc z (c1, x, y) = minimum [y+1, z+1, x + (fromEnum (c1 /= c) * 2)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance XPrompt Pass where
 | 
				
			||||||
 | 
					  showXPrompt p = passLabel p <> ": "
 | 
				
			||||||
 | 
					  commandToComplete _ = id
 | 
				
			||||||
 | 
					  nextCompletion _ = getNextCompletion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					passGeneratePrompt :: XPConfig -> X ()
 | 
				
			||||||
 | 
					passGeneratePrompt _ = return () -- Not implemented
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					passPrompt :: XPConfig -> X ()
 | 
				
			||||||
 | 
					passPrompt = mkPassPrompt "Select password" selectPassword
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mkPassPrompt :: String -> (String -> X ()) -> XPConfig -> X ()
 | 
				
			||||||
 | 
					mkPassPrompt label f conf = do
 | 
				
			||||||
 | 
					  -- I'm just sorting here, but could use some kind of fuzzy matching instead, but it requires a bit more effort
 | 
				
			||||||
 | 
					  passwords <- sort <$> liftIO getPasswords
 | 
				
			||||||
 | 
					  -- Other change, use infixof instead of prefixof
 | 
				
			||||||
 | 
					  mkXPrompt (Pass label) conf (\input -> pure (sortBy (compare `on` (levenshtein input)) . filter (consumes input) $ passwords)) f
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    consumes [] _ = True -- everything consumed
 | 
				
			||||||
 | 
					    consumes (_:_) [] = False -- all not consumed
 | 
				
			||||||
 | 
					    consumes (a:xs) (a':ys) | a == a' = consumes xs ys
 | 
				
			||||||
 | 
					                            | otherwise = consumes (a:xs) ys
 | 
				
			||||||
 | 
					    getStore = do
 | 
				
			||||||
 | 
					      let storeDefault = (</> ".password-store")
 | 
				
			||||||
 | 
					      maybe (storeDefault <$> getHomeDirectory) pure =<< getEnv "PASSWORD_STORE_DIR"
 | 
				
			||||||
 | 
					    getPasswords = do
 | 
				
			||||||
 | 
					      passwordStoreDir <- getStore
 | 
				
			||||||
 | 
					      files <- runProcessWithInput "find" [ passwordStoreDir, "-type", "f", "-name", "*.gpg", "-printf", "%P\n"] []
 | 
				
			||||||
 | 
					      return . map (\path -> if path `hasExtension` ".gpg" then dropExtension path else path) . lines $ files
 | 
				
			||||||
 | 
					    hasExtension path ext = takeExtension path == ext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					selectPassword :: String -> X ()
 | 
				
			||||||
 | 
					selectPassword pass = spawn $ "pass --clip " ++ pass
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/XMonad/Projects.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/XMonad/Projects.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					module Projects where
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/XMonad/RestartFile.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/XMonad/RestartFile.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					module RestartFile (restartFile, resumeArgsFromFile, getArgs, withArgs) where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import XMonad.Core
 | 
				
			||||||
 | 
					import XMonad.Operations
 | 
				
			||||||
 | 
					import qualified XMonad.StackSet as W
 | 
				
			||||||
 | 
					import Graphics.X11.Xlib.Event
 | 
				
			||||||
 | 
					import Control.Monad.Reader (asks)
 | 
				
			||||||
 | 
					import Control.Monad.State (gets)
 | 
				
			||||||
 | 
					import Data.Maybe
 | 
				
			||||||
 | 
					import Data.List (intercalate)
 | 
				
			||||||
 | 
					import qualified Data.Map.Strict as M
 | 
				
			||||||
 | 
					import System.Environment (getArgs, withArgs)
 | 
				
			||||||
 | 
					import Control.Monad
 | 
				
			||||||
 | 
					import Control.Exception
 | 
				
			||||||
 | 
					import System.Posix.Process (executeFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stateFile = "xmonadargs.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					restartFile :: String -> Bool -> X ()
 | 
				
			||||||
 | 
					restartFile prog resume = do
 | 
				
			||||||
 | 
					    io $ appendFile "/home/masse/xmonad.log" $ "trying to restart"
 | 
				
			||||||
 | 
					    broadcastMessage ReleaseResources
 | 
				
			||||||
 | 
					    io . flush =<< asks display
 | 
				
			||||||
 | 
					    let wsData = show . W.mapLayout show . windowset
 | 
				
			||||||
 | 
					        maybeShow (t, Right (PersistentExtension ext)) = Just (t, show ext)
 | 
				
			||||||
 | 
					        maybeShow (t, Left str) = Just (t, str)
 | 
				
			||||||
 | 
					        maybeShow _ = Nothing
 | 
				
			||||||
 | 
					        extState = return . show . mapMaybe maybeShow . M.toList . extensibleState
 | 
				
			||||||
 | 
					    args <- if resume then return ["--resume"] else return []
 | 
				
			||||||
 | 
					    when resume $ do
 | 
				
			||||||
 | 
					      argsstr <- gets (\s ->  intercalate "\n" ("--resume":wsData s:extState s))
 | 
				
			||||||
 | 
					      catchIO $ writeFile stateFile argsstr
 | 
				
			||||||
 | 
					      return ()
 | 
				
			||||||
 | 
					    catchIO (executeFile prog True args Nothing)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					catchAny :: IO a -> (SomeException -> IO a) -> IO a
 | 
				
			||||||
 | 
					catchAny = Control.Exception.catch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resumeArgsFromFile :: IO [String]
 | 
				
			||||||
 | 
					resumeArgsFromFile = do
 | 
				
			||||||
 | 
					  let readLines = liftM lines . readFile $ stateFile
 | 
				
			||||||
 | 
					  args <- getArgs
 | 
				
			||||||
 | 
					  if ["--resume"] == args then
 | 
				
			||||||
 | 
					    catchAny readLines $ \e -> do
 | 
				
			||||||
 | 
					      appendFile "/home/masse/xmonad.log" $ "got error" ++ show e
 | 
				
			||||||
 | 
					      return args
 | 
				
			||||||
 | 
					  else return args
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/XMonad/Screen.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/XMonad/Screen.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					module Screen (screenWidth, nextScreen, prevScreen) where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Graphics.X11.Xinerama (xineramaQueryScreens, XineramaScreenInfo(..))
 | 
				
			||||||
 | 
					import Graphics.X11.Xlib (openDisplay, closeDisplay)
 | 
				
			||||||
 | 
					import qualified XMonad.Actions.CycleWS as CycleWS
 | 
				
			||||||
 | 
					import XMonad (X())
 | 
				
			||||||
 | 
					import Control.Monad.Trans (liftIO)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					screenWidth :: Int -> IO Int
 | 
				
			||||||
 | 
					screenWidth idx = do
 | 
				
			||||||
 | 
					  dsp <- openDisplay "" -- I don't know what the string does :/
 | 
				
			||||||
 | 
					  info <- xineramaQueryScreens dsp
 | 
				
			||||||
 | 
					  case info of
 | 
				
			||||||
 | 
					       Nothing -> return 0
 | 
				
			||||||
 | 
					       Just [] -> return 0
 | 
				
			||||||
 | 
					       Just screens -> if idx >= 0 && idx < length screens
 | 
				
			||||||
 | 
					                          then (return . fromIntegral . xsi_width) (screens !! idx)
 | 
				
			||||||
 | 
					                          else return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					swapScreenDir :: IO Bool
 | 
				
			||||||
 | 
					swapScreenDir = do
 | 
				
			||||||
 | 
					  dsp <- openDisplay ""
 | 
				
			||||||
 | 
					  info <- xineramaQueryScreens dsp
 | 
				
			||||||
 | 
					  closeDisplay dsp
 | 
				
			||||||
 | 
					  case info of
 | 
				
			||||||
 | 
					       Nothing -> return False
 | 
				
			||||||
 | 
					       Just [] -> return False
 | 
				
			||||||
 | 
					       Just (s:_) -> return (xsi_width s > 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					nextScreen :: X ()
 | 
				
			||||||
 | 
					nextScreen = do
 | 
				
			||||||
 | 
					  swap <- liftIO $ swapScreenDir -- Not too fond of querying the x each time we swap screens, but oh well
 | 
				
			||||||
 | 
					  if swap then CycleWS.prevScreen else CycleWS.nextScreen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					prevScreen :: X ()
 | 
				
			||||||
 | 
					prevScreen = do
 | 
				
			||||||
 | 
					  swap <- liftIO $ swapScreenDir -- Not too fond of querying the x each time we swap screens, but oh well
 | 
				
			||||||
 | 
					  if swap then CycleWS.nextScreen else CycleWS.prevScreen
 | 
				
			||||||
							
								
								
									
										59
									
								
								src/XMonad/TopicSpace.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/XMonad/TopicSpace.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					{-# Language RecordWildCards #-}
 | 
				
			||||||
 | 
					module XMonad.TopicSpace (topicKeys', addTopic, TopicAction(..)) where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import XMonad.Actions.TopicSpace
 | 
				
			||||||
 | 
					import XMonad
 | 
				
			||||||
 | 
					import qualified Data.Map as M
 | 
				
			||||||
 | 
					import XMonad.Actions.GridSelect
 | 
				
			||||||
 | 
					import XMonad.Actions.DynamicWorkspaces
 | 
				
			||||||
 | 
					import XMonad.TopicUtils
 | 
				
			||||||
 | 
					import XMonad.Util.EZConfig (mkNamedKeymap)
 | 
				
			||||||
 | 
					import XMonad.Util.NamedActions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import XMonad.Config.MasseR.ExtraConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import qualified Data.Text as T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import XMonad.Configurable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data TopicAction = TopicAction { name :: String
 | 
				
			||||||
 | 
					                               , action :: X ()
 | 
				
			||||||
 | 
					                               , home :: Maybe FilePath }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					addTopic :: TopicAction -> Configurable TopicConfig
 | 
				
			||||||
 | 
					addTopic TopicAction{..} = EndoM $ \super -> let
 | 
				
			||||||
 | 
					  newDirs = topicDirs super <> maybe mempty (M.singleton name) home
 | 
				
			||||||
 | 
					  newActions = topicActions super <> M.singleton name action
 | 
				
			||||||
 | 
					  in pure super { topicDirs = newDirs
 | 
				
			||||||
 | 
					                , topicActions = newActions }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					myTopicConfig :: ExtraConfig -> TopicConfig
 | 
				
			||||||
 | 
					myTopicConfig extraConfig =
 | 
				
			||||||
 | 
					  let dirs = M.fromList [ (T.unpack n, T.unpack d) | TopicRule n (Just d) _ <- topics extraConfig ]
 | 
				
			||||||
 | 
					      actions = M.fromList [ (T.unpack n, spawn (T.unpack a)) | TopicRule n _ (Just a) <- topics extraConfig ]
 | 
				
			||||||
 | 
					  in def {
 | 
				
			||||||
 | 
					    topicDirs = dirs
 | 
				
			||||||
 | 
					  , defaultTopicAction = const (realTopicDir dirs >>= spawnShellIn)
 | 
				
			||||||
 | 
					  , defaultTopic = "irc"
 | 
				
			||||||
 | 
					  , topicActions = actions
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					topicKeys' :: ExtraConfig -> XConfig l -> [(String, NamedAction)]
 | 
				
			||||||
 | 
					topicKeys' extraConfig conf = [ ("M-y", addName "Change topic" $ visualSelect (myTopicConfig extraConfig))
 | 
				
			||||||
 | 
					                              , ("M-S-g", addName "Move window to topic" $ gridselectMove def)
 | 
				
			||||||
 | 
					                              , ("M-u", addName "Select window" $ gotoSelected' def{gs_colorizer = fromClassName})
 | 
				
			||||||
 | 
					                              , ("M-<Return>", addName "Open project action" $ currentTopicAction' (myTopicConfig extraConfig))
 | 
				
			||||||
 | 
					                              , ("M-w", modificationSubmaps' conf)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					spawnShellIn :: Dir -> X ()
 | 
				
			||||||
 | 
					spawnShellIn dir = safeRunInTerm dir Nothing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					modificationSubmaps' :: XConfig l -> NamedAction
 | 
				
			||||||
 | 
					modificationSubmaps' conf =
 | 
				
			||||||
 | 
					    submapName $ mkNamedKeymap conf [ ("a", addName "Add a new workspace" $ addWorkspacePrompt def)
 | 
				
			||||||
 | 
					                                    , ("w", addName "Copy project" copyTopic)
 | 
				
			||||||
 | 
					                                    , ("d", addName "Remove empty workspace" removeEmptyWorkspace)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										90
									
								
								src/XMonad/TopicUtils.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/XMonad/TopicUtils.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					module XMonad.TopicUtils where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Data.Maybe (fromMaybe, listToMaybe, mapMaybe)
 | 
				
			||||||
 | 
					import Data.List (isPrefixOf, sort, nub)
 | 
				
			||||||
 | 
					import XMonad.Actions.TopicSpace
 | 
				
			||||||
 | 
					import XMonad
 | 
				
			||||||
 | 
					import qualified Data.Map as M
 | 
				
			||||||
 | 
					import XMonad.Actions.GridSelect hiding (gridselectWorkspace)
 | 
				
			||||||
 | 
					import XMonad.Util.Run (safeSpawn)
 | 
				
			||||||
 | 
					import qualified XMonad.StackSet as W
 | 
				
			||||||
 | 
					import XMonad.Util.Dmenu (dmenu)
 | 
				
			||||||
 | 
					import XMonad.Actions.DynamicWorkspaces
 | 
				
			||||||
 | 
					import XMonad.Util.NamedWindows (getName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					realTopicDir :: M.Map String FilePath -> X String
 | 
				
			||||||
 | 
					realTopicDir tg = do
 | 
				
			||||||
 | 
					  topic <- realTopic
 | 
				
			||||||
 | 
					  return . fromMaybe "" . M.lookup topic $ tg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					safeRunInTerm :: Dir -> Maybe String -> X ()
 | 
				
			||||||
 | 
					safeRunInTerm dir Nothing = safeSpawn "urxvt" ["-cd", dir]
 | 
				
			||||||
 | 
					safeRunInTerm dir (Just command) = safeSpawn "urxvt" ["-cd", dir, "-e", command]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inactiveTags :: X [WorkspaceId]
 | 
				
			||||||
 | 
					inactiveTags = map W.tag . inactive' <$> gets windowset
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        inactive' s = W.hidden s ++ map W.workspace (filter (\w -> (W.tag . W.workspace . W.current) s /= (W.tag . W.workspace) w) (W.visible s))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gridselectMove :: GSConfig WorkspaceId -> X ()
 | 
				
			||||||
 | 
					gridselectMove conf = do
 | 
				
			||||||
 | 
					    topics <- inactiveTags
 | 
				
			||||||
 | 
					    gridselect conf [(x,x) | x <- topics] >>= maybe (return ()) (windows . W.shift)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dmenuMove :: X ()
 | 
				
			||||||
 | 
					dmenuMove = do
 | 
				
			||||||
 | 
					  topics <- inactiveTags
 | 
				
			||||||
 | 
					  dmenu topics >>= \t -> windows (W.shift t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gsConfig :: GSConfig Window
 | 
				
			||||||
 | 
					gsConfig = def{gs_navigate = navNSearch, gs_colorizer = fromClassName}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Copied from gridselect and modified so that it doesn't contain current and visible
 | 
				
			||||||
 | 
					-- - Doesn't contain current and visible
 | 
				
			||||||
 | 
					-- - Takes a topicspace viewfunc
 | 
				
			||||||
 | 
					gridselectWorkspace :: GSConfig WorkspaceId -> (WorkspaceId -> X ()) -> X ()
 | 
				
			||||||
 | 
					gridselectWorkspace conf viewFunc = withWindowSet $ \ws -> do
 | 
				
			||||||
 | 
					  let wss = map W.tag . W.hidden $ ws
 | 
				
			||||||
 | 
					  gridselect conf (zip wss wss) >>= flip whenJust viewFunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gotoSelected' :: GSConfig Window -> X ()
 | 
				
			||||||
 | 
					gotoSelected' gsconf = do
 | 
				
			||||||
 | 
					    w <- gridselectCurrentWindows gsconf
 | 
				
			||||||
 | 
					    maybe (return ()) (windows . W.focusWindow) w
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gridselectCurrentWindows :: GSConfig Window -> X (Maybe Window)
 | 
				
			||||||
 | 
					gridselectCurrentWindows gsconf = windowMap >>= gridselect gsconf
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        getName' = fmap show . getName
 | 
				
			||||||
 | 
					        kvPair w = flip (,) w `fmap` getName' w
 | 
				
			||||||
 | 
					        windowMap = do
 | 
				
			||||||
 | 
					            ws <- gets (nub . W.integrate' . W.stack . W.workspace . W.current . windowset)
 | 
				
			||||||
 | 
					            mapM kvPair ws
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					visualSelect :: TopicConfig -> X ()
 | 
				
			||||||
 | 
					visualSelect cfg = gridselectWorkspace def{gs_navigate = navNSearch, gs_colorizer = stringColorizer} (switchTopic cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					realTopic :: X String
 | 
				
			||||||
 | 
					realTopic = gets (real . W.tag . W.workspace . W.current . windowset)
 | 
				
			||||||
 | 
					  where real = takeWhile (/= ':')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					currentTopicAction' :: TopicConfig -> X ()
 | 
				
			||||||
 | 
					currentTopicAction' tg = do
 | 
				
			||||||
 | 
					  topic <- realTopic
 | 
				
			||||||
 | 
					  topicAction tg topic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					copyTopic :: X ()
 | 
				
			||||||
 | 
					copyTopic = do
 | 
				
			||||||
 | 
					  currentTopic <- realTopic
 | 
				
			||||||
 | 
					  lastN <- gets (listToMaybe . reverse . sort . mapMaybe (subset currentTopic . W.tag) . W.workspaces . windowset)
 | 
				
			||||||
 | 
					  addWorkspace (currentTopic ++ ":" ++ (show $ maybe 2 (+1) lastN))
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    subset :: String -> String -> Maybe Int
 | 
				
			||||||
 | 
					    subset topic other = if topic `isPrefixOf` other then (readM $ tail' $ snd $ break (== ':') other) else Nothing
 | 
				
			||||||
 | 
					    readM a = case reads a of
 | 
				
			||||||
 | 
					               [(x,_)] -> Just x
 | 
				
			||||||
 | 
					               _ -> Nothing
 | 
				
			||||||
 | 
					    tail' [] = []
 | 
				
			||||||
 | 
					    tail' xs = tail xs
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/XMonad/TreeSelectUtils.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/XMonad/TreeSelectUtils.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					module TreeSelectUtils where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import XMonad.Actions.TreeSelect
 | 
				
			||||||
 | 
					import Data.Tree
 | 
				
			||||||
 | 
					import Data.List (sort, groupBy)
 | 
				
			||||||
 | 
					import Data.Function (on)
 | 
				
			||||||
 | 
					import qualified XMonad.StackSet as W
 | 
				
			||||||
 | 
					import XMonad.Core
 | 
				
			||||||
 | 
					import Control.Monad.State
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- fromWorkspace :: [String] -> Forest String
 | 
				
			||||||
 | 
					fromWorkspace = map go . group . sort
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        group = groupBy ((==) `on` (takeWhile (/= '.')))
 | 
				
			||||||
 | 
					        go (root:xs) = Node root [Node x [] | x <- xs]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					treeselectWorkspaces' conf f = withWindowSet $ \w -> do
 | 
				
			||||||
 | 
					    let ws = map W.tag . W.hidden $ w
 | 
				
			||||||
 | 
					    treeselectWorkspace conf (fromWorkspace ws) f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/XMonad/XMobar.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/XMonad/XMobar.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					module XMonad.XMobar (zenburnPP) where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- import XMonad.Util.Loggers
 | 
				
			||||||
 | 
					import XMonad.Hooks.DynamicLog (
 | 
				
			||||||
 | 
					    PP(..)
 | 
				
			||||||
 | 
					  , xmobarColor
 | 
				
			||||||
 | 
					  , shorten
 | 
				
			||||||
 | 
					  , xmobarPP
 | 
				
			||||||
 | 
					  , dzenStrip)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					myUrgencyHintFgColor :: String
 | 
				
			||||||
 | 
					myUrgencyHintFgColor = "#333333"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					myUrgencyHintBgColor :: String
 | 
				
			||||||
 | 
					myUrgencyHintBgColor = "#F18C96"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Xmobar pretty printer. Color scheme zenburn
 | 
				
			||||||
 | 
					zenburnPP :: PP
 | 
				
			||||||
 | 
					zenburnPP = xmobarPP {
 | 
				
			||||||
 | 
					      ppTitle = xmobarColor "#DCA3A3" "" . shorten 70
 | 
				
			||||||
 | 
					    , ppCurrent = xmobarColor "#CEFFAC" ""
 | 
				
			||||||
 | 
					    , ppHidden = const ""
 | 
				
			||||||
 | 
					    , ppSep = " | "
 | 
				
			||||||
 | 
					    , ppLayout = id
 | 
				
			||||||
 | 
					    , ppUrgent = xmobarColor myUrgencyHintFgColor myUrgencyHintBgColor . dzenStrip
 | 
				
			||||||
 | 
					    , ppOrder = \(ws:_layout:_title:_) -> [ws]
 | 
				
			||||||
 | 
					    , ppExtras = []
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- xmobar :: IO (X ())
 | 
				
			||||||
 | 
					-- xmobar = do
 | 
				
			||||||
 | 
					--   xmproc <- spawnPipe "xmobar ~/.xmonad/xmobar"
 | 
				
			||||||
 | 
					--   return $ dynamicLogWithPP $ zenburnPP xmproc
 | 
				
			||||||
							
								
								
									
										38
									
								
								xmonad-masser.cabal
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								xmonad-masser.cabal
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					-- Initial xmonad-masser.cabal generated by cabal init.  For further
 | 
				
			||||||
 | 
					-- documentation, see http://haskell.org/cabal/users-guide/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					name:                xmonad-masser
 | 
				
			||||||
 | 
					version:             0.1.0.0
 | 
				
			||||||
 | 
					-- synopsis:
 | 
				
			||||||
 | 
					-- description:
 | 
				
			||||||
 | 
					license:             BSD3
 | 
				
			||||||
 | 
					license-file:        LICENSE
 | 
				
			||||||
 | 
					author:              Mats Rauhala
 | 
				
			||||||
 | 
					maintainer:          mats.rauhala@iki.fi
 | 
				
			||||||
 | 
					-- copyright:
 | 
				
			||||||
 | 
					-- category:
 | 
				
			||||||
 | 
					build-type:          Simple
 | 
				
			||||||
 | 
					extra-source-files:  ChangeLog.md
 | 
				
			||||||
 | 
					cabal-version:       >=1.10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					library
 | 
				
			||||||
 | 
					  exposed-modules:    XMonad.Config.MasseR
 | 
				
			||||||
 | 
					                    , XMonad.Config.MasseR.ExtraConfig
 | 
				
			||||||
 | 
					  other-modules:      XMonad.Configurable
 | 
				
			||||||
 | 
					                    , XMonad.CustomPrompt
 | 
				
			||||||
 | 
					                    , XMonad.Password
 | 
				
			||||||
 | 
					                    , XMonad.TopicUtils
 | 
				
			||||||
 | 
					                    , XMonad.TopicSpace
 | 
				
			||||||
 | 
					                    , XMonad.XMobar
 | 
				
			||||||
 | 
					  -- other-extensions:
 | 
				
			||||||
 | 
					  build-depends:       base >=4.11 && <4.12
 | 
				
			||||||
 | 
					                     , xmonad
 | 
				
			||||||
 | 
					                     , xmonad-contrib
 | 
				
			||||||
 | 
					                     , mtl
 | 
				
			||||||
 | 
					                     , directory
 | 
				
			||||||
 | 
					                     , filepath
 | 
				
			||||||
 | 
					                     , unix
 | 
				
			||||||
 | 
					                     , containers
 | 
				
			||||||
 | 
					                     , text
 | 
				
			||||||
 | 
					  hs-source-dirs:      src
 | 
				
			||||||
 | 
					  default-language:    Haskell2010
 | 
				
			||||||
		Reference in New Issue
	
	Block a user