Post Page Advertisement [Top]

0.17.0newstopwindowswallowing

xmonadの0.17.0へおしゃれにバージョンアップ

.com/img/a/

2021年10月27日、約3年ぶりにxmonadの新しいバージョン0.17.0がリリースされました!!


これにともなって、「The Xmonad Logo Contest」が開催中。 締切は、2022年1月31日で、その後投票があるみたいです。賞金も100ドル出るみたいですよー! 詳しくは上のリンクを辿ってください。 僕は絵心とかないけれど、新しい、楽しいxmonadのロゴが沢山出てくるといいなーと思ってウオッチ中。まだ、誰も応募してません。


archlinuxでxmonad0.17を使う

さて、2021年11月5日現在、archlinuxの公式パッケージはまだxmonad0.15のままですが、 AURのxmonad-gitとxmonad-contrib-gitをインストールすれば、0.17にバージョンアップできます。 もう早速、xmonadを新しくしちゃいましょう!!


$ yay -S xmonad-git xmonad-contrib-git


現時点では、aurでのパッケージのバージョン名がまだ0.15や0.16ですが、gitのリポジトリはすでに0.17なので0.17がインストールされます。 公式のxmonadパッケージxonad-contribパッケージとはコンフリクトするので、 今まで公式パッケージを使っている場合、指示に従って公式側を消し、git側に入れ替えましょう。


さてここで、AURのxmonad-gitとxmonad-contrib-gitを初めて使う場合、注意が必要です。


haskellライブラリアップグレードの際、AURのxmonad-git等の再インストールを忘れない

archlinuxのパッケージでxmonadを使っている場合、haskell関連のプログラムファイルは動的ライブラリになっています。 ですから、普段からxmonadを使っている人たちは、haskellの関連するライブラリが更新されると、 xmonad.hs自体も再コンパイルするのが習慣になっていると思います。 そして、これは、公式リポジトリのxmonadパッケージは、 関連ライブラリのアップグレードとともに、 xmonad自身も再コンパイルした新しいパッケージが公式リポジトリにリリースされているので、 xmonad.hsだけを自分で再コンパイルすればよいようになっています。 しかし、公式リポジトリのxmonadではなく、 AURのxmonad-gitを使う場合、新しい関連ライブラリのもとでビルドされた新しいxmonadはアップデートで自動的に降ってこないので、 xmonadの再コンパイルを自分でしなければならなくたります。


だからといって、なにか難しいことをしないといけないわけではなく、 単に、yay等で、もう一度、xmonad-git、xmonad-contrib-gitを上書きインストールするだけです。 まぁ、コンパイルにちょっとだけ時間がかかる(数分)ので、のんびりやりましょう。


もちろん、その後に、xmonad.hsを「M-q」で再コンパイルするのも忘れずに!!


非推奨を無視してコンパイルする

バージョンアップによって関数等の書き方が変わり、もともとの書き方が「Deprecated(非推奨)」に指定されているものがあります。 そこで、今まで使っていたxmonad.hsのコードの中に非推奨のものが含まれるとエラーとなって、リコンパイルができないことがあります。 この場合、エラーメッセージで新しく推奨される書き方の指示がされるので、 そのとおりに、訂正すればコンパイルが通るようになります。


しかし、とりあえず、非推奨でもそのまま使いたい場合には、GHCへ次のオプションを渡すことで、非推奨を無視してコンパイルすることが出来ます。 xmonad.hsの一番はじめの行に以下の一行を加えてみましょう。


{-# OPTIONS_GHC -Wno-deprecations #-}


XMonad.Hooks.WindowSwallowingを試す

さて、せっかくなので、xmonad-contribの0.17になって新しく加わったモジュールの一つを紹介します。


XMonad.Hooks.WindowSwallowing というモジュールで、twitterでもはじめに話題になっていていました。 どんな機能なのかというと、、、


ターミナルからchromiumを呼ぼうとおもったとき


.com/img/a/

普段使っているレイアウトTallの場合、 呼び出したターミナルは、右側のペインに移り、ワークスペースの右側は、ウィンドウサイズがそれぞれ小さくなっています。 しかも、呼び出したターミナルはGUIからのエラー出力等を見ない限り、実質的には使わないウィンドウにります。そのくせ、かさばって実は邪魔な存在だったりします。


.com/img/a/

しかし、WindowSwallowingを使うと、


.com/img/a/

呼び出されたGUIが もとにあった、ターミナルを飲み込んで(swallow)くれるのです。 つまりは、必要なくなったターミナルアプリがワークスペースから隠れることで、ワークスペースを広く使うことが出来るのです。


.com/img/a/

隠れたターミナルは、呼び出されたGUIアプリを終了すると、吐き出されるようにワークスペースへ戻ってきます。


.com/img/a/

どうですか?なかなか、かゆいところに手が届くxmonadらしいユーザー目線の機能でしょ??


WindowSwallowingを使う

まずは、モジュールのインポートです。


import XMonad.Hooks.WindowSwallowing


次に、swallowEventHook関数で、イベントフックを作成します。 以下のコードは、kittyとalacrittyとxtermからGUIが呼ばれたときに、飲み込まれるようにするイベントフックを作成する例です。


myHandleEventHook 
  = swallowEventHook ( className =? "Alacritty" 
                  <||> className =? "kitty"
                  <||> className =? "XTerm") (return True)


クラス名の文字列でターミナルを判定します。他のターミナルを設定したいときは、 xpropコマンドを利用して、クラス名を調べ、"kitty"のような文字列部分を書き換えたり、 「または」を意味する「<||>」演算子を追加して、新たな条件を追加して調整しましょう。 また、2つ目の引数で、上記の例では常にTrueを返すアクションを定義して渡していますが、 第一引数と同じように、 条件設定をすることでターミナルを飲み込むGUIを限定することも出来ます。


このmyHandleEventHookの定義ができたら、xmonad関数に渡すXConfig l型のdefの「handleEventHook」にこのmyHandleEventHookを追加しましょう。


...他の設定
  handleEventHook = myHandleEventHook <+> handleEventHook def
...他の設定


注意としては、今の所、レイアウトでスマートボーダーやノーボーダーを利用している場合、 GUI終了時に飲み込まれたターミナルが行方不明になるバグがあるようなので、 うまく行かない場合には、それらのレイアウトを外してみてください。


もともと、スマートボーダー機能と相性が悪いバグがありましたが、既に修正済みです。


0.17.0版のxmonad.hsの例

0.17.0用に書き換えたうちのxmonad.hsです。 特にステータスバー周りは、別途、ステータスバープログラムを立ち上げるコードを自分で書く必要がなくなり、 また、データのやり取りにXのプロパティを利用するようになったので、 色々と刷新されています。


特にxmobarの場合、新しいモジュールの関数を使えば、1関数で、簡単に管理できるようになっています。 但し、実際にやってみると、xmobar側でXのプロパティーで情報のやり取りをする設定をしないと、xmobar自体が立ち上がってくれないかもしれません (うちでは、その設定をしないとうまくいかなかった)。 一方、polybarについては、自作しないといけないところがあるので、その辺を適当にやっています。 新しいモジュールで、自分の好きなステータスバーを管理するための関数等を自作する場合の参考にして下さい。


------------------------------------------------------------------------------
-- shunsk's xmonad.hs file for 0.17.0
-- https://ok-xmonad.blogspot.com
--
-- xmobarかpolybarの設定ファイルは別途必要
-- https://ok-xmonad.blogspot.com/p/blog-page.html
------------------------------------------------------------------------------
import XMonad
import qualified XMonad.StackSet as W
import System.Exit
import XMonad.Layout.Spacing
import XMonad.Layout.Renamed
import XMonad.Layout.NoBorders
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.StatusBar
import XMonad.Hooks.StatusBar.PP
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.WindowSwallowing
import XMonad.Util.EZConfig
import XMonad.Util.NamedScratchpad
import XMonad.Util.WorkspaceCompare
import XMonad.Actions.Navigation2D
import XMonad.Actions.DynamicProjects
import XMonad.Actions.CycleWS
import XMonad.Prompt
---------------------------------------------------------------
-- MAIN
---------------------------------------------------------------
main = xmonad
$ dynamicProjects projects
$ ewmhFullscreen . ewmh
$ scratchpadTask mySPConf
$ withNavigation2DConfig myNavi
$ withSB (mySBConfig "polybar")
$ docks
$ def { terminal = "kitty"
, modMask = mod4Mask
, focusFollowsMouse = False
, workspaces = ["home"]
, borderWidth  = 3
, normalBorderColor = "#cccccc"
, focusedBorderColor = "#00bbff"
, layoutHook = mylayouthook
, handleEventHook = myHandleEventHook
<+> handleEventHook def
, keys = \c -> mkKeymap c (myKeyMap c)
}
---------------------------------------------------------------
-- レイアウト
---------------------------------------------------------------
mylayouthook
= smartBorders $ avoidStruts (mytall ||| mymirror) ||| myfull
where
mytall
= renamed [CutWordsLeft 1]
$ spacingRaw True (Border 10 10 10 10) True (Border 5 5 5 5) True
$ Tall 1 0.03 0.5
mymirror
= Mirror mytall
myfull
= noBorders
$ Full
---------------------------------------------
-- キーバインド関連
---------------------------------------------
myKeyMap :: XConfig Layout -> [(String, X ())]
myKeyMap conf =
[("M-S-<Return>", spawn $ XMonad.terminal conf)
,("M-p", spawn "rofi -show drun")
,("M-S-c", kill)
,("M-<Space>", sendMessage NextLayout)
,("M-n", refresh)
,("M-j", windows W.focusDown)
,("M-k", windows W.focusUp)
,("M-m", windows W.focusMaster)
,("M-S-j", windows W.swapDown)
,("M-S-k", windows W.swapUp)
,("M-<Return>", windows W.swapMaster)
,("M-h", sendMessage Shrink)
,("M-l", sendMessage Expand)
,("M-,", sendMessage $ IncMasterN 1)
,("M-.", sendMessage $ IncMasterN (-1))
,("M-t", withFocused $ windows . W.sink)
,("M-S-q", io (exitWith ExitSuccess))
,("M-q", spawn myRecompileCmd)
-- スクラッチパッド
,("M-o", namedScratchpadAction mySPConf "sp01")
,("M-i", namedScratchpadAction mySPConf "sp02")
-- windowのフォーカス移動
,("M-<R>", windowGo R False)
,("M-<L>", windowGo L False)
,("M-<U>", windowGo U False)
,("M-<D>", windowGo D False)
-- workspaceの移動等
,("M-C-<R>", nonEmptyWS Next)
,("M-C-<L>", nonEmptyWS Prev)
,("M-g", switchProjectPrompt myXPConfig)
,("M-S-g", shiftToProjectPrompt myXPConfig)
]
where
myRecompileCmd =
"xmonad --recompile && xmonad --restart"
-----------------------------------------------------------------
--
-- WindowSwallowing
--
-- require module
-- XMonad.Hooks.WindowSwallowing
--
-- 基本形の例
-- main = xmonad def { handleEventHook
-- = myHandleEventHook
-- <+> handleEventHook def
-- }
--
-- refer to
-- https://hackage.haskell.org/package/xmonad-contrib-0.17.0/docs/XMonad-Hooks-WindowSwallowing.html
-- https://ok-xmonad.blogspot.com/2021/11/xmonad0170.html
-----------------------------------------------------------------}
myHandleEventHook
= swallowEventHook (className =? "kitty"
<||> className =? "Alacritty"
<||> className =? "XTerm") (return True)
-----------------------------------------------------------------
--
-- ステータスバーの設定
--
-- xmonad-contrib 0.17.0で刷新されたX.H.StatusBarを利用して
-- xmobarとpolybarを簡単に使えるようにする設定
--
-- require module
-- XMonad.Hooks.StatusBar
-- XMonad.Hooks.StatusBar.PP
-- XMonad.Hooks.ManageDocks
--
--
-- ++++++++++++++++++++++++++++++++++++++
-- 基本例
-- ++++++++++++++++++++++++++++++++++++++
--
-- main = xmonad
-- $ withSB (mySBConfig "xmobar")
-- $ docks
-- $ def
--
-- これに加えてlayoutに適宜avoidStrutsを加える必要あり
--
-- withSB関数に用意したStatusBarConfigを渡した関数で、
-- XConfig l型の設定データを受け取るのが基本。
-- ステータスバー用に加工されたXConfig l型データを返します。
--
-- ここで自作のmySBConfig関数は、
-- "xmobar"か"polybar"の値を渡すとそれぞれに相応しい設定を行う
-- StatusBarConfigデータを返してくれます。
--
--
-- ++++++++++++++++++++++++++++++++++++++
-- polybar利用の場合
-- ++++++++++++++++++++++++++++++++++++++
--
-- 自分のpolybar起動のコマンドをmySBConfigの定義で
-- myPolybarConfの引数を自分の環境に合わせて必ず書き換える必要あり。
-- この文字列でspawnされます。
--
-- また、polybar側の設定としては、
-- https://github.com/xmonad/xmonad-contrib
-- でリポジトリを確認し、
-- script/xmonadpropread.hsにあるファイルを
-- 自分のローカルディレクトリの適当なところにコピーして
-- 実行権限を与えます。
--
-- https://ok-xmonad.blogspot.com/2021/02/polybarxmonad.html
-- ここで紹介している[module/xmonad]の項目で
-- 「xmonad-log」を使っていますが、
-- この部分をxmonadpropread.hsにします。
-- パスの通っているとこにおいてもうまく行かない場合
-- フルパスで記述してみましょう。
--
-- 例)
-- [module/xmonad]
-- type = custom/script
-- exec = /somewhere/path/xmonadpropread.hs
-- tail = true
--
--
-- ++++++++++++++++++++++++++++++++++++++
-- mydefLogPPについて
-- ++++++++++++++++++++++++++++++++++++++
--
-- ステータスバーに何を表示して何を表示しないかの
-- 共通デフォルト値を設定している。
--
-- 基本、非表示でなく、ウィンドウを一つ以上持っているワークスペースを表示
-- 但し、NSP(スクラッチパッド退避ワークスペース名)は常に表示しない
-- 更に、homeという名前のワークスペースは、常に表示する
--
-- カスタム例としては
-- stickmyfavorit関数のパターンマッチで
-- 常に表示するものを追加する。
--
-- 例)
-- stickmyfavorit "home" = "home"
-- stickmyfavorit "1" = "1"
-- stickmyfavorit "2" = "2"
-- stickmyfavorit "3" = "3"
-- stickmyfavorit _ = ""
--
--
-- ++++++++++++++++++++++++++++++++++++++
-- xmobar用
-- ++++++++++++++++++++++++++++++++++++++
--
-- statusBarProp関数でStatusBarConfig値を作成している。
-- カスタムする場合、第2引数でpure関数に渡す引数PP型を書き換える。
--
-- ここでは、先に紹介したmydefLogPPを元に書き換えを行っているが、
-- 好き勝手やりたい場合、def::PPから自分の好きなようにすればOK
--
-- X.H.StatusBar.PPモジュールでは、
-- xmobar用のエスケープに対応した、関数がたくさん追加されてる。
-- refer to
-- https://hackage.haskell.org/package/xmonad-contrib-0.17.0/docs/XMonad-Hooks-StatusBar-PP.html#v:xmobarColor
--
--
-- ++++++++++++++++++++++++++++++++++++++
-- polybar用
-- ++++++++++++++++++++++++++++++++++++++
--
-- 先に述べたとおり起動コマンドの設定は必須
--
-- statusBarProp関数の作成する、StatusBarConfigデータには、
-- 起動時のPID等を管理して、先起動等の手助けをする機能があるが
-- polybarの場合、
-- カスタムスクリプト等どのようになんのコマンドで起動されるか
-- わからないので、単なるアクションを使って
-- 起動コマンドは明示的に入力してそのとおり起動し、
-- 終了時は「killall polybar」によって、全部終了するようにしてある。
--
-- このあたりの改良を目論む場合は以下を参照
-- https://hackage.haskell.org/package/xmonad-contrib-0.17.0/docs/XMonad-Hooks-StatusBar.html#g:6
--
--カスタムについては、
--polybarPPdefのあたりをdef::PP等から書き換える。
--
--ラッパー関数に関しては、
--polybarColor関数を自作してあるので活用。
--
--polybar上でのエスケープシーケンスについては
--https://github.com/polybar/polybar/wiki/Formatting
--
-------------------------------------------------------------------
-- myPolybarConf の引数を必ず自分の環境にあわせて書き換え
mySBConfig "xmobar" = myXmobarConf
mySBConfig "polybar" = myPolybarConf
"/home/neko/.config/polybar/blocks/launch.sh"
mydefLogPP
= filterOutWsPP
[scratchpadWorkspaceTag]
def {ppHiddenNoWindows = stickmyfavorit}
stickmyfavorit "home" = "home"
stickmyfavorit _ = ""
-- xmobar用
myXmobarConf
= statusBarProp
"xmobar"
(pure $ mydefLogPP
{ ppCurrent
= xmobarColor "#FF9F1C" "#1A1B41" . wrap "[" "]"
, ppTitle
= xmobarColor "#6290C3" "#F1FFE7" . pad . shorten 30
}
)
-- polybar用
myPolybarConf cmd
= def { sbLogHook
= xmonadPropLog
=<< dynamicLogString polybarPPdef
, sbStartupHook = spawn cmd
, sbCleanupHook = spawn "killall polybar"
}
polybarPPdef
= mydefLogPP { ppCurrent
= polybarColor "#FF9F1C" "#1A1B41" . wrap "[" "]"
, ppTitle = const ""
}
polybarColor :: String -> String -> String -> String
polybarColor fore_color back_color contents
= wrap ("%{B" <> back_color <> "} ") " %{B-}"
. wrap ("%{F" <> fore_color <> "} ") " %{F-}"
$ contents
-----------------------------------------------------------------
--
-- ワークスペース移動のカスタム関数
--
-- 非表示でウィンドウを持たないワークスペースをスキップする。
-- スクラッチパッドを使う場合に作られるNSPワークスペースをスキップする。
-- ただし、homeという名のワークスペースはどの状態にあってもスキップしない。
--
-- require module
-- XMonad.Actions.CycleWS
-- XMonad.Util.WorkspaceCompare
-- XMonad.Util.NamedScratchpad
--
--「nonEmptyWS d」アクションをキーにバインドする。
-- dはNextかPrev
--
-- 例)
-- ,("M-C-<R>", nonEmptyWS Next)
-- ,("M-C-<L>", nonEmptyWS Prev)
--
-- カスタム例
-- isFavorit関数に、いつでも表示したいワークスペース名を渡して
-- いつでも表示するワークスペース値を作成し
-- これを、findWorkspace関数の第3引数WSTypeの部分に組み込む
--
-- refer to
-- https://hackage.haskell.org/package/xmonad-contrib-0.17.0/docs/XMonad-Actions-CycleWS.html
--
-------------------------------------------------------------------
nonEmptyWS d
= findWorkspace
getSortByIndexNoSP
d
(hiddenWS :&:Not emptyWS :|: isFavorit "home")
1
>>= \t -> (windows . W.view $ t)
-- NSP(スクラッチパッド退避ワークスペース)をスキップ
getSortByIndexNoSP =
fmap (.filterOutWs [scratchpadWorkspaceTag]) getSortByIndex
-- いつでも表示したいワークスペース名を判別する関数
-- これを使っていつでも訪れたいワークスペースに利用する
isFavorit s =
WSIs $ return (((==) s) . W.tag)
---------------------------------------------------------------
--
-- カーソルでのフォーカス移動
--
-- required module
-- XMonad.Actions.Navigation2D
--
-- 基本形
-- main = xmonad
-- $ withNavigation2DConfig myNavi
-- $ def
--
-- キーバインドは以下の通り
-- ,("M-<R>", windowGo R False)
-- ,("M-<L>", windowGo L False)
-- ,("M-<U>", windowGo U False)
-- ,("M-<D>", windowGo D False)
--
-- refer to
-- https://hackage.haskell.org/package/xmonad-contrib-0.17.0/docs/XMonad-Actions-Navigation2D.html
-- https://ok-xmonad.blogspot.com/2021/03/xmonad_10.html
--
---------------------------------------------------------------
myNavi = def {
defaultTiledNavigation = sideNavigation
}
---------------------------------------------------------------
--
-- scratchpad用の設定
--
-- required module
-- XMonad.Util.NamedScratchpad
--
-- 自作のscratchpadTask関数を使った基本形の例
-- main = xmonad
-- $ scratchpadTask mySPConf
-- $ def
--
-- NS型のリストであるmySPConfで自分好みのスクラッチパッドを定義
--
-- refer to
-- https://hackage.haskell.org/package/xmonad-contrib-0.17.0/docs/XMonad-Util-NamedScratchpad.html
-- https://ok-xmonad.blogspot.com/2021/03/xmonad.html
--
----------------------------------------------------------------
scratchpadTask spdata conf
= conf {manageHook
= namedScratchpadManageHook spdata
<+> manageHook conf
}
mySPConf =
[ NS "sp01"
"kitty -T SCPad"
(title =? "SCPad")
(customFloating $ W.RationalRect 0.5 0.05 0.48 0.5)
, NS "sp02"
"kitty -T ranger ranger"
(title =? "ranger")
(customFloating $ W.RationalRect 0.05 0.1 0.9 0.8)
]
---------------------------------------------------------------
--
-- DynamicProject 用のデータ
--
-- required module
-- XMonad.Actions.DynamicProjects
--
-- 基本形の例
-- main = xmonad
-- $ dynamicProjects projects
-- $ def
--
-- Project型のリストであるprojectsで自分好みのプロジェクトを定義
--
-- refer to
-- https://hackage.haskell.org/package/xmonad-contrib-0.17.0/docs/XMonad-Actions-DynamicProjects.html
-- https://ok-xmonad.blogspot.com/2021/03/xmonad_3.html
--
----------------------------------------------------------------
projects :: [Project]
projects =
[ Project "home" "~/" Nothing
, Project "misc" "~/" Nothing
, Project "config" "~/.config" Nothing
, Project "code" "~/Workspace" (Just $ spawn "kitty ranger")
, Project "web" "~/" (Just $ spawn my_browser)
, Project "rstudio" "~/" (Just $ spawn "rstudio-bin")
, Project "slack" "~/" (Just $ spawn "slack")
-- Archlinux page for application list
, Project
"applist"
"~/"
(Just $ spawn $ my_browser ++ url_applist ++ " --new-window")
-- twitterdeck
, Project
"twitter"
"~/"
(Just $ spawn $ my_browser ++ " --app=" ++ url_twitter ++ " --new-window")
-- for xmonad config
, Project
"xmonad"
"~/.xmonad"
(Just $ do spawn (my_browser ++ "https://xmonad.org/documentation.html --new-window")
spawn "kitty nvim xmonad.hs")
]
where
my_browser = "google-chrome-stable "
url_applist = "https://wiki.archlinux.org/index.php/List_of_applications"
url_twitter = "https://tweetdeck.twitter.com/"
myXPConfig = def
{ font = "xft:M+1 mn:size=14:medium:antialias=true"
, position = CenteredAt 0.5 0.8
, height = 40
}
view raw xmonad.hs hosted with ❤ by GitHub

0 件のコメント:

コメントを投稿

Bottom Ad [Post Page]