使いやすいGNU/Linuxのデスクトップ

仕事もプライベートもGNU/Linuxのデスクトップを使っている。とても自由で使いやすい。長年使ってきて、知見も溜まってきたので紹介したい。他のOSでも使える部分もあると思う。

## 目的別にワークスペース[^1]を切り替える
[^1]: 仮想デスクトップと言ったりもする

ノートPCなので、基本的にPCの起動・停止はしないし、アプリも起動したままになる。並行したタスクをやっているといろんな情報が入り混じってカオスになって混乱するので、目的別にワークスペースを切り替えている。どのワークスペースにも、ブラウザ(Firefox)とターミナル(Tilix)、エディタ(Emacs)を配置して、それに加えて各タスクに必要なアプリを起動している。例えばこんな感じ：

- Workspace 1: プライベート  
  Firefox(Profile: default), Emacs, ターミナル
- Workspace 2: 仕事(事務)  
  Firefox(Profile: 事務用), Emacs, ターミナル
- Workspace 3: 仕事A  
  Firefox(Profile: 仕事A用), Emacs, ターミナル
- Workspace 4: 仕事B  
  Firefox(Profile: 仕事B用), Emacs, ターミナル, AndroidStudio
- Workspace 5: 仕事C  
  Firefox(Profile: 仕事C用), Emacs, ターミナル, Firefox2つめ

ここでターミナルは各ワークスペースで別のプロセスとして立ち上げている。
Emacsは一つのインスタンスから`(make-frame)`で複数ウィンドウを立ち上げて、それぞれのワークスペースに配置している。
Firefoxはワークスペースごとに異なるプロファイルで起動(`firefox -P <プロファイル名>`)している。プロファイルを分けることで、目的に応じて様々なサービス(SlackとかGithubとかAWSとか)のアカウントを別々に管理できる。
Firefoxは<kbd><kbd>Alt</kbd>+<kbd>n(数字)</kbd></kbd>でn番目のタブを開くことができる。あと<kbd><kbd>Alt</kbd>+<kbd>9</kbd></kbd>で一番右のタブを開くのも便利でよく使う。一番左のタブにコミュニケーションツール(Slackなど)、その隣にissue管理、...などとルールを決めている。プロファイルも分けているので、例えばコミュニケーションツールを開くなら<kbd><kbd>Alt</kbd>+<kbd>1</kbd></kbd>など操作が統一されるし、複数のタブから探す必要なく直線的に操作できる。ワークスペースごとにそのタスク用のfirefoxが配置されているので、チャットはSlackかDiscordかとか、レポジトリはGithubかgitlabか混乱することもなく統一的なキー操作でタブ移動ができる。

ちなみにワークスペースの移動は<kbd><kbd>Alt</kbd>+<kbd>Fn(数字)</kbd></kbd>に設定している。

## フォーカスを切り替える
フォーカスの切り替えは<kbd>Alt</kbd>+<kbd>Tab</kbd>でもできるが、「順番に切り替えて選ぶ」という操作はストレスフルなので、ショートカットで一発で切り替えたい。下記のように設定している。

|キー|フォーカスがあたるアプリ|
|:-----------|:-----------|
| <kbd><kbd>Super</kbd>+<kbd>f</kbd></kbd> (※1) | Firefox             |
| <kbd><kbd>Super</kbd>+<kbd>e</kbd></kbd>       | Emacs               |
| <kbd><kbd>Super</kbd>+<kbd>s</kbd></kbd>       | ターミナル          |
| <kbd><kbd>Super</kbd>+<kbd>o</kbd></kbd>       | 上記以外の何か(※2) |
(※1) <kbd><kbd>Super</kbd></kbd>は`alt`の隣のwindowsのロゴが書かれているキー。左手親指の側面で押してる。やや訓練がいるけどすぐ慣れる
(※2) AndroidStudioだったりChromeだったり、その時々によって異なる。Webアプリの開発の時はFirefoxをもう一つ別ウィンドウで立ち上げたりもする。この時でも1つ目のfirefoxと2つ目を区別したい

重要な点として、ここで切り替えたいのは現在のワークスペース上の特定のウィンドウである。単純にアプリ名などでは判断できないため、設定では実現できないので、シェルスクリプトを書いた。

A. ワークスペースごとの`window id`を保存するスクリプト
B. 引数で指定されたアプリを1.で生成したファイルから`window id`を特定してフォーカスを切り替えるスクリプト
C. 現在のワークスペース上のアプリから、1.で生成したファイルに存在しない`window id`を見つけて、フォーカスを切り替えるスクリプト

PC起動後に、初期状態を作るスクリプト(各ワークスペースのFirefox,Emacs,ターミナルを起動)を実行してからAの保存スクリプトを呼んで、以降、BやCのスクリプトをショートカットからキックしている。

## ウィンドウのリサイズ・移動
ウィンドウのサイズを変えたい時は、縦横それぞれについて画面サイズにフィットさせるかその半分のサイズにするかの2択で基本的に事足りている。ノートPCの画面サイズなのでそれ以上の分割はあまり必要にならない。それ以外にしたいレアケースではマウスを使って調整している。その単純化によってウィンドウのサイズ変更も移動も<kbd>Super</kbd>+<kbd>矢印キー</kbd>でできる。
例えば<kbd>Super</kbd>+<kbd>→</kbd>を押した場合、下記の処理をするスクリプトをキックしている。

- 現在のウィンドウの"右"に余白が...
  - あるなら移動。ウィンドウの横幅分右に移動。ウィンドウの画面外にはみ出す場合は右端に合わせるように移動する
  - ないならリサイズ
     - ウィンドウの横幅が画面サイズと...
         - 一致しているなら、ウィンドウの横幅を画面サイズの半分にする
         - そうでないなら、ウィンドウの横幅を画面サイズに一致させる
![2020-12-15 09-00-02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12251/409752f2-69da-6a4e-40e7-867fdc059a78.gif)

最大化は<kbd>Super</kbd>+<kbd>Enter</kbd>にしている。たまにシェルで動かしたプログラムの実行が終わったかをチラ見したい時があるので、パネルの上に移動するスクリプトも作ってある。
![2020-12-15 08-42-04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12251/4cde4aaf-4f95-4ba2-8b42-3900eb569d2b.gif "ターミナルを画面下部に移動して、他のアプリに移っても、プロンプトの様子だけ表示できるようにしている様子")

## タブUIのショートカットキー
最近の多くのアプリでタブUIが導入されている(firefox, chrome, AndroidStudio, ターミナルなど)。多くのアプリでタブ関連のショートカットで統一されていることが多いが、そのショートカットが押しにくい問題がある。
アプリごとにショートカットを変えるのは手間なので、X側でキーボードのマッピングを変えて一括でショートカットの変更をしている。

| 実際にキーボードで押すキー   | アプリに渡されるキー  | 動作  |  
|:-----------|:-------------|:-----------------------|
| <kbd><kbd>Super</kbd>+<kbd>[</kbd></kbd> | <kbd><kbd>Ctrl</kbd>+<kbd>PageUp</kbd></kbd>   | ひとつ左のタブに切り替え |
| <kbd><kbd>Super</kbd>+<kbd>]</kbd></kbd> | <kbd><kbd>Ctrl</kbd>+<kbd>PageDown</kbd></kbd> | ひとつ右のタブに切り替え |
| <kbd><kbd>Super</kbd>+<kbd>c</kbd></kbd> | <kbd><kbd>Ctrl</kbd>+<kbd>F4</kbd></kbd>       | タブを閉じる             |

Emacs内の分割された画面の移動などもキー操作を統一するため`(global-set-key (kbd "C-<next>") 'other-window)`という感じに設定している。

# 環境詳細
ディストリビューションはArch Linux、Window Manager(以下WM)はFvwm2を使っている。Fvwmはかなり歴史あるが、未だに開発が続いており現在Fvwm3も開発中である。[ここ]( https://en.wikipedia.org/wiki/FVWM )の情報によるとKnuth先生も使っているらしい。

汎用プログラミング言語で設定を書けるWM(stumpwm,xmonad,qtile,awesomeなど)が良かったけど、それらは基本tilingなのが嫌だった。世の中的にはtiling WMが流行りっぽいけど、レイアウトに関しては手動で十分事足りている。tilingとfloatingを切り替え可能なWM（こういうのをdynamic WMというらしい）もあるけど、floating WMとして使うならやっぱりfloating専用の方が楽。
結局、設定自体はプログラミング言語でなくても、込み入った操作をする時は、`wmctrl`や`xdotool`などをシェルから呼んだり、`pyewmh`というモジュールをpythonから使えばいいという結論になった。
でもでも、`ewmh`も結構微妙でresizeがフレームのサイズを考慮しなかったり、WMによっては`workArea`にパネルアプリのtint2の高さが反映されなかったり、微妙な挙動がWMごとに異なったり一部の機能が未実装だったりする。
で、やっぱり専用の設定記述言語も便利ってなる。Fvwmは`FvwmCommand`というCLIツールでFvwmのコマンドを呼べる。ウィンドウの移動・リサイズ用のスクリプトはウィンドウサイズの取得と条件分岐はpythonでやって、その中から`FvwmCommand`を呼んでいる。

# まとめ
紆余曲折あって今の形になっているけど、これまでの教訓をまとめると

- ショートカットでなんでも全部できるようにしようとすると、複雑になって結局使わない機能が出てくる。
- 日常のルーチンで必要になる操作は限られるので、それらをシンプルにできるようにする
- たまにしか発生しない操作は多少面倒でも構わないが、いざやりたい時に簡単にできるようにしておく
- よりシンプルに操作できるように、コンテキストの判断（ex. 移動できる余白があるかとか）をプログラムに委ねる。