dwmパッチを読解してグループ分けする

はじめに

久しぶりの投稿でまたdwmの話題。 dwmって何な人はこの辺をどうぞ。(宣伝)
タイル型ウィンドウマネージャー dwm を導入 - fuhaのゲームとかLinuxとか色々

勉強のために公開されているパッチを色々調べたので、 せっかくなので資料として残したいと思う。 使用中も不使用もとりあえず調べたものは列挙していくので、 一部不正確かもしれない点は注意。

ついでに現在使用中のパッチを公開する。

GitHub

GitHub - fuha-htrshooter/dwm: 自分カスタマイズdwm

※4/6更新:一部パッチが取得できない状態だったので修正。

おすすめ

全部使用中。

  • awesomebar 【ステータス表示変更】
    タイトルバーに、現在開いている全てのウィンドウを一覧表示する。 また、ウィンドウをクリックで選択可能にする。
    インストール時にまず入れるパッチの一つ。

    • しかし、マルチモニタでの使用時にバグ?があったので追加パッチを自作した。
      ->awesomebar-multimons
    • あと最近公開された最新版20200907は、頻出操作の C-h(ウィンドウ境界を左に移動)を上書きするので、 キーコンフィグ変更推奨。
  • extrabar 【ステータス表示変更】
    画面下部に追加のステータスバーを表示する。 ステータスバーの途中にセミコロンを入れるとそれ以降が追加部分に表示される。
    awesomebarを使う場合、メインのステータスバーが狭いと見辛くなってしまうため、 このパッチと組み合わせると領域が広くとれて丁度いい。

  • statusallmons 【ステータス表示変更】
    マルチモニター使用時、通常選択中のモニターしかステータスバーは更新されないが、 その制限を撤廃して全モニター一斉に更新するようにする。
    なお、extrabarには適用されないので自分で追加変更した。

  • gridmode 【レイアウト追加】
    全ての画面を同じサイズにして、2x2、3x3、4x4といった格子状のレイアウトにする。 数が合わない場合、右下が空き領域になる。
    全画面を一覧できるので、WindowsにおけるWin+Tabのように 必要な画面を探す時に使える。

自作

  • awesomebar-multimons 【ステータス表示変更】
    拙作1。 awesomebarをマルチモニターで使う時用の追加パッチ。

    • 非選択モニターのウィンドウが選択スタイルのままだった所、 非選択スタイルにするよう修正
    • 選択モニターがウィンドウ無しの場合非選択スタイルのままだった所、 選択スタイルにするよう修正
  • statusmonbutton 【動作変更】
    拙作2。 ステータスバーの区切り文字を認識し、領域毎に別コマンドを実行できるようにする。
    押したい場所がextrabar領域だったので、extrabarパッチに依存。 音量表示部分を左右クリックで音量調整するために使っている。

    参考:statuscmd

レイアウト追加系

■基本知識
dwmは基本的に各ウィンドウのサイズを個別に操作しない(できない)。
なので、好きなウィンドウ構成にするにはレイアウトパッチを入れるのがよい。

dwmのウィンドウ管理の基礎として「マスター領域&スタック領域」という考え方がある。
ウィンドウは基本的にそのどちらかに割り当てられる。
- マスターはメインの作業領域、デフォルトだと左半分。
- スタックはそれ以外のウィンドウ、デフォルトだと右半分。
(※ただし例外もある)
  • columns
    適用したが未使用。
    メイン領域に複数ウィンドウを置いた時、デフォルトだと横に割る所を縦に割るようになる。
    しかし、スタックを含めると最低でも3分割となるので、 ウルトラワイドモニタ等でないと今一つ?

  • deck
    適用したが未使用。
    スタック領域を一枚レイアウトにする。
    山札(deck)のようにスタックトップだけが見えるようになるからこの名前らしい。

  • rmaster
    マスターとスタックを左右逆にする関数を追加する。 なので厳密にはレイアウト追加ではない。

  • leftstack
    マスターとスタックの左右を逆にするパッチその2。
    こちらはデフォルトのtileレイアウトを上書きするため不可逆だが、 差分2行と圧倒的にパッチ内容が少ない。

  • bottomstack
    マスターを上、スタックを下にしたレイアウトを追加する。
    デフォルトを90度横向きにした感じ。

  • centeredmaster
    マスターを中央、スタックを左右に置く。
    columns同様横に広いウィンドウを使っている人向け。

  • fibonacci
    全画面を渦巻き状にレイアウトする。
    サイズ比率はフィボナッチ数を一辺にした正方形となる。
    ...どこに使うんだこれ。

  • tatami
    スタック領域のレイアウトを畳敷きにする。
    非常に複雑な式で計算されている、どこに使うんだこれ2。

  • nmaster
    マスターを分割可能にする。メインリポジトリに取り込まれておりパッチ不要っぽい?

フォーカス変更系

ウィンドウを追加する時の追加位置および追加後のフォーカス遷移を変える。

  • (デフォルト)
    フォーカス位置に限らず、新しいウィンドウが常に一番上のマスターになる。

  • attachbelow
    使用中

    • 現在フォーカスしているウィンドウ(以下現在位置)の直後にウィンドウを 追加する
    • 現在位置がマスターの末尾である場合、 追加されたウィンドウはマスターに残り、他はスタックに入る
    • 現在位置がマスターかつ末尾以外の場合、 追加されたウィンドウの分マスター末尾のウィンドウが スタックに押し出される。
  • attachabove
    現在位置の上にウィンドウを追加する。
    元々はこれが大本で、他のパッチはこのパッチの派生らしい。

  • attachtop
    現在位置にかかわらずスタックの一番上に新規ウィンドウを積む。
    デフォルトに近いがマスターは動かしたくない人向け。

  • attachbottom
    現在位置にかかわらずスタックの一番下に新規ウィンドウを積む。
    他のウィンドウ順序を一切変えたくない人向け。

  • attachdirection
    上記全てを合体して切り替えできるようにしたもの。
    各パッチの実装は同じ。

ステータス表示変更

  • alpha
    ステータスバーを半透明にする。

  • dualstatus
    extrabarと同様に追加バーを表示するパッチだが、 個別に表示切り替えができるなど機能的な違いあり。

動作変更

  • cursorwarp
    使用中。
    ウィンドウ変更時にマウスカーソルをウィンドウ中央まで自動移動させる。 常に移動、モニタ変更時のみ移動、モニタ変更しない時のみ移動の3種類存在。
    モニタ変更時、カーソル位置が分からないので、 とりあえずマウスをガーっと動かすみたいな人、 おすすめ。

  • center
    自動でフローティングウィンドウにするconfig.hルールに、 「センタリング」設定を追加する。
    小さなウィンドウを表示してすぐ消すような用途のソフトで便利?

  • alwayscenter
    上記と違い、フローティング化したタイミングでセンタリングする。
    その後の移動は自由。

  • dwmc
    WMの外からdwm関数を呼べるようになるパッチ。 ステータスバーと同じ、xsetrootを使用してコマンドを送る。
    xsetrootにヘッダを付けることでステータスバーの更新と区別し、 送信内容を先取りしている模様。

  • dwmfifo
    dwmcと似ているが、こちらは一時ファイルを使用してコマンドを送る。
    反映にラグがあるのか、連続送信には要スリープとのこと。

  • ipc
    同じく外部コマンド系で、UNIXソケットを使用するもの。 送るだけでなく中の状態を取得することもできるなど高機能。
    追加行だけで2000行オーバーという中々インパクトのあるパッチだが、 その実態の殆どは別コマンドなので適用難易度はそうでもない、はず。

既に使えないもの

  • historical
    他のリンクと見分けが付かないが、実はこのリンクに全て纏められている。
    そのため、逆に言えばここにあるもの以外は使える(?)はず。

おわりに

色々パッチを当ててみた感想。

  • メソッド追加するだけの簡単なパッチは基本的にconfig.def.hくらいしか干渉箇所がないので、 そこだけ消せば入る場合が多い。(レイアウト追加系とか)

  • フォーカス変更は、デフォルトが一般的なタブ形式に慣れた人には 結構違和感を感じる動作なので、 とりあえず入れてみると印象がかなり変わる。

  • メインリポジトリをちょっと追ってみたが、 ソース変更は基本的に無造作でリファクタリングも全く容赦なく行われている。 こわい。

  • ただ逆に干渉しても変数変わってるだけとかよくあるので諦めないで。

喧伝の通り構造は簡単なので、アイデアさえ決まれば自作もそう難しくはない。
…が、長く使えるかは保証できないって感じなので、正直あまり良い所とは言い辛い。
使い勝手が気にいっているので使い続けるけど。

dwmのステータスバーなどをカスタマイズ

前段

以前のエントリで mockbuildによるdwmのインストールを紹介したが、 非常にビルド時間がかかる上にバージョン管理も何かと面倒になってしまうことから、 結局mockbuildは使わず直接ソースビルドする簡略方式にした。 また、Fedoraのパッケージで提供されているバージョンは最新ver6.2でなくver6.1であり、 公式に公開されているパッチがほとんど使えなかった事も、 ソースビルドに移行する理由の一つだった。

ソースビルドとなると依存関係が心配だったが、流石コード量の少なさが売りのdwm。 どうやらほとんど依存関係がないらしく、 gitから取得して単純にmakeするだけで何事もなく実行ファイルが生成された。 また、ビルドにかかる時間も1秒弱と極めて速い。 恐らく、これが製作者の想定している本来の姿だと思われる。

スクリーンショット

f:id:fuha:20191102193829p:plain

ステータスバーの出力内容

以下の内容をxsetrootで5秒ごとに設定して出力させている。
(待ち時間を含めると出力に2秒ほどかかるため)

#!/bin/bash
# ステータスバー用の文字列を生成するプログラム

# 日時
LOCALTIME=$(/usr/bin/date '+%Y年%m月%d日(%a) %H:%M')
# CPUコア数 (マルチスレッディングによる仮想コアを含む)
CPU_CORENUM=$(/usr/bin/lscpu | /usr/bin/awk '/^CPU:/ {print $2}')
# CPU使用率 (1文字=1コアで、パーセント表記のうち10の位のみ表示。100%の場合"X"とする。)
CPU_USAGE=$(/usr/bin/mpstat -P ALL 1 1 | /usr/bin/tail -n ${CPU_CORENUM} | /usr/bin/awk '{u=10-int($12/10); printf 10<=u?"X":u}')
# メモリ使用量
MEM_INFO=$(/usr/bin/free | /usr/bin/awk '/Mem/ {printf "%.1f/%.1f G",($2-$7)/2^20,$2/2^20}')
# GPU/CPU温度
TEMP_INFO=$(/usr/bin/sensors | /usr/bin/awk '/temp1:/ {printf "GPU:%.1f/",$2}; /Tdie:/ {printf "CPU:%.1f °C",$2}')
# ネットワーク速度 (秒間トラフィック量から自前計測)
NETWORK_IF=enp34s0
NETBUF1=$(/usr/bin/awk '/'${NETWORK_IF}':/ {print $2,$10}' /proc/net/dev)
sleep 1s
NETBUF2=$(/usr/bin/awk '/'${NETWORK_IF}':/ {print $2,$10}' /proc/net/dev)
NET_SPEED=$(echo ${NETBUF1} ${NETBUF2} | /usr/bin/awk '{printf "Tx:%3d/Rx:%3d kB",($4-$2)/2^10,($3-$1)/2^10}')

# 出力実行
echo "| ${NET_SPEED} | ${MEM_INFO} | ${TEMP_INFO} | ${CPU_CORENUM}t:${CPU_USAGE} | ${LOCALTIME} "
  • 必要パッケージ

    使用プログラム インストールコマンド
    /usr/bin/sensors dnf install lm_sensors
    /usr/bin/mpstat dnf install sysstat

dwmに適用したパッチ

全て公式サイトから取得している。

  • awesomebar
    タイトルバーがタスクバーのように全ウィンドウ表示&マウスでフォーカス操作できるようなるパッチ。 グループ化などはできないが一覧性はかなり向上し、全画面モードでもマウスで操作できるようになる。
    https://dwm.suckless.org/patches/awesomebar/
  • float border color
    フローティングウィンドウの枠色を変更するパッチ。 スクリーンショットで画面枠がピンク色になっている箇所が該当。
    実際はフローティングを使うことはほとんど無いのだが、不意になってしまうことが稀にあり混乱するために導入した。 フォーカスを当てないと色が変わらず判別できないことが多少不満ではあるが、効果は割と高い。
    https://dwm.suckless.org/patches/float_border_color/

後段

参考サイト

Tempermonkeyではてなブログの編集画面を定期的にバックアップする。

概要

何度かはてなブログで8割方書いた記事を消し飛ばす失敗をしてしまったため作成。 はてブ自体にも自動保存があるのは後から知ったが、最近PCを刷新した事もあり再起動を連打していたせいか、 失敗が続いてしまったので。

なお、Tempermonkeyでのスクリプト作成の練習としての側面がかなり強いため非常に簡素な作りとなっている。 利用改造再配布全て自由にしてもらって良いが、自己責任でお願いする。

機能

  • 導入すると30分ごとに内容が保存される。
    保存先はHTML5から追加されたローカルストレージ。(参考サイト参照)
  • 編集画面の下にバックアップの一覧と全削除ボタンが追加される。
    • 一覧は最初保存キーの状態で表示しており、キーをクリックするとバックアップ全文を表示する。
    • 全削除ボタンを押すと、本スクリプトが作った全エントリ分のバックアップを削除する。
  • なお、自動での削除機能はないことから編集画面を開いたまま放っておくと(容量限界まで)永久に増え続ける。 用法容量を守って正しくご利用下さい。

スクリーンショット

f:id:fuha:20191020110246p:plain

コード

// ==UserScript==
// @name         はてブ編集中バックアップ
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  はてなブログの編集画面にて、内容を定期的に保存する。
// @author       fuha
// @match        https://blog.hatena.ne.jp/fuha/fuha.hatenablog.com/edit?*
// @import       https://code.jquery.com/jquery-3.4.1.slim.min.js
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 保存間隔 (秒)
    const SAVE_INTERVAL = 1800;
    // 保存キー
    const SAVE_KEY = "Fuha.HatenaBlog.Backup-";

    // 記事内容をHTMLへ直接挿入可能な文字列に変換する
    function escapeTextToHtml(strKiji) {
        if (!strKiji) return "";

        return strKiji.replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
    }

    // 渡された関数を定期実行する関数
    function cronExec(waitSec, callbackFunc) {
        // 経過時間(秒)
        var spanedSec = 0;
        // 1秒間隔で無名関数を実行
        var id = setInterval(function () {
            spanedSec++;
            // 待機時間 <= 経過時間の場合、コールバック関数を実行して経過時間リセット
            if (waitSec <= spanedSec) {
                callbackFunc();
                spanedSec = 0;
            }
        }, 1000);
    }

    // 一覧HTMLを生成
    function getBackupListHtml() {
        // キー一覧取得
        var keyAry = [];
        var keylist = "";
        for (var i = 0; i < window.localStorage.length; i++) {
            var viewKey = window.localStorage.key(i);
            if (viewKey.startsWith(SAVE_KEY)) {
                keyAry.push(viewKey);
            }
        }
        // ソート実行
        keyAry.sort();
        // 一覧HTML生成
        for (i = 0; i < keyAry.length; i++) {
            keylist = keylist + '<dt style="text-decoration:underline" onclick="Fuha_clickTitle(this)">' + keyAry[i] + '</dt>'
                + '<dd style="display:none"><pre>' + escapeTextToHtml(window.localStorage.getItem(keyAry[i])) + '</pre></dd>';
        }
        return keylist;
    }

    // 読み込み後に実行
    $(function(){
        // 保存イベント登録
        cronExec(SAVE_INTERVAL, function() {
            var titleKey = $(".editor-title-input").val();
            var dt = new Date();
            var saveKey = SAVE_KEY + titleKey + "-"
                + dt.getFullYear()
                + (dt.getMonth() < 9 ? "0" : "") + (dt.getMonth() + 1)
                + (dt.getDate() < 10 ? "0" : "") + dt.getDate()
                + "-"
                + (dt.getHours() < 10 ? "0" : "") + dt.getHours()
                + (dt.getMinutes() < 10 ? "0" : "") + dt.getMinutes()
                + (dt.getSeconds() < 10 ? "0" : "") + dt.getSeconds();
            window.localStorage.setItem(saveKey, $(".editor-body-textarea").val());
            $("#fuha-bk-status").text("ステータス:保存実行 " + new Date());
            $("#fuha-bk-list").html(getBackupListHtml());
        });

        // 一覧を生成
        var initDt = new Date();
        var keylist = getBackupListHtml();
        $('<hr><div>■はてブ編集中バックアップ(保存間隔:' + SAVE_INTERVAL + '秒) <button onclick="Fuha_delBk()">全削除</button><br>'
            + '<span id="fuha-bk-status">ステータス:初期表示 ' + initDt + '</span>'
            + '<dl id="fuha-bk-list" style="border:1px black solid;height:200px;overflow:scroll;font-size:x-small">' + keylist + '</dl>'
            + '<script>function Fuha_delBk(){'
            + 'var kA=[];'
            + 'for(var i=0;i<window.localStorage.length;i++){'
            + 'var k=window.localStorage.key(i);'
            + 'if(k.startsWith("' + SAVE_KEY +'")){'
            + 'kA.push(k);'
            + '}}'
            + 'for(i=0;i<kA.length;i++){'
            + 'window.localStorage.removeItem(kA[i]);'
            + '}'
            + '$("#fuha-bk-status").text("ステータス:削除実行 " + new Date());'
            + '$("#fuha-bk-list").html("");'
            + '}'
            + 'function Fuha_clickTitle(e){'
            + 'var at=$(e).next().css("display");'
            + '$(e).next().css("display",(at=="none")?"inline":"none");'
            + '}</script></div>').appendTo("body");
    });
})();

後書き

  1. 以外と時間かかったので見つけた知見とかをまとめ。

    • HTMLにできない文字列をappendToしようとするとエラーで落ちる。
      結構特定に時間かかった。
    • ローカルストレージから要素削除する場合、1回のループで消そうとすると要素変化に対応できず途中で止まってしまう。
      これはエラーにもならないので、同じく特定まで時間かかった。
    • 以上のような複雑なデバッグにはalertよりconsole.logが必要。
  2. 編集時のフォーマットをはてな記法からMarkdownに変更した。
    その関係で見た目が少し変わったと思うが、中の人は一緒なので安心(?)してほしい。

参考サイト

Fedoraでサポート期限を切らしてDNF(YUM)でupgradeコマンドが効かなくなった場合の対処法

前書き

2~3日経ってDNFを実行しても更新が来ない場合は大体この状態に陥っている。
既に2回ほど嵌まってしまったため、更新方法をまとめておく。

発生時の状況

・こんな感じで、アップデートを実行しても何もなく終了してしまう。

[root@server]/# dnf upgrade    
Last metadata expiration check: 0:29:47 ago on Thu Dec 27 23:36:46 2018.
Dependencies resolved.
Nothing to do.
Complete!

・"-v"オプションで詳細を表示するとこんな感じ。
 リポジトリを見ようとすると「not found」となっていることが分かる。

[root@server]/# dnf -v upgrade                    
Loaded plugins: builddep, config-manager, copr, debug, debuginfo-install, download, etckeeper, generate_completion_cache, needs-restarting, playground, repoclosure, repograph, repomanage, reposync, system-upgrade
DNF version: 2.7.5
cachedir: /var/cache/dnf
repo: using cache for: updates
updates: using metadata from Fri Nov 30 10:29:19 2018.
repo: using cache for: fedora
not found deltainfo for: Fedora 27 - x86_64
not found updateinfo for: Fedora 27 - x86_64
fedora: using metadata from Sun Nov  5 14:51:47 2017.
(中略)
--> Starting dependency resolution
--> Finished dependency resolution
Dependencies resolved.
Nothing to do.
Complete!

・で、リポジトリの設定ファイルを見てみるとbaseurlの部分がコメントアウトされている。(多分サービス最期の更新の時にDNFが実施するものと思われ)

[root@server]/# cat /etc/yum.repos.d/fedora.repo 
[fedora]
name=Fedora $releasever - $basearch
failovermethod=priority
#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
enabled=1
(後略)

解決方法

DNFコマンドに「system-upgrade」オプションを付けて実行することでシステム更新ができる。なお、こんなタイトルだがサポートが切れていてもいなくても手順は同じ。
(当然だがroot権限で実行のこと)


手順1) キャッシュをクリアし、アップグレードを全て適用する。

# dnf clean all
# dnf --refresh upgrade

手順1.5) ※Fedora27→28のアップデート時のみ


そのままシステム更新を実行しようとするとnss-pemパッケージが依存エラーを起こす。これはアップデートと同時に更新できないだけらしく、事前にinstallしてからアップデートすれば解決できる。

# dnf install nss-pem --releasever=28

手順2) システム更新をダウンロードする。

# dnf system-upgrade download -y --releasever <更新先バージョン>

※自動YESオプション"-y"を指定しない場合、ダウンロード後に
 鍵の更新確認プロンプトが出て一旦止まるので注意

 From       : (鍵のパス)
Is this ok [y/N]: 

手順3) DNFで以下のコマンドを実行すると、再起動後にシステム更新が始まる。

# dnf system-upgrade reboot

実際に試してみるとこんな感じ

#手順1
[root@server]/# dnf clean all                              
42 files removed
[root@server]/# dnf --refresh upgrade                      
Fedora 27 - x86_64 - Updates                                                                                                                                                        18 MB/s |  27 MB     00:01    
Fedora 27 - x86_64                                                                                                                                                                  17 MB/s |  58 MB     00:03    
Last metadata expiration check: 0:00:00 ago on Fri Dec 28 01:02:45 2018.
Dependencies resolved.
Nothing to do.
Complete!

#手順1.5 ※エラー発生も含め記載
[root@server]/# dnf system-upgrade download --releasever 28
Before you continue ensure that your system is fully upgraded by running "dnf --refresh upgrade". Do you want to continue [y/N]: y
RPM Fusion for Fedora 28 - Free - Updates                     299 kB/s | 528 kB     00:01    
RPM Fusion for Fedora 28 - Free                               324 kB/s | 754 kB     00:02    
Last metadata expiration check: 0:00:00 ago on Fri Dec 28 01:29:50 2018.
Error: 
 Problem: nss-pem-1.0.3-6.fc27.i686 has inferior architecture
  - nss-pem-1.0.3-6.fc27.x86_64 does not belong to a distupgrade repository
  - problem with installed package nss-pem-1.0.3-6.fc27.i686
[root@server]# dnf install nss-pem-1.0.3-9.fc28 --releasever=28
Last metadata expiration check: 0:34:03 ago on Fri Dec 28 01:45:25 2018.
Dependencies resolved.
==============================================================================================
 Package                     Arch            Version                   Repository        Size
==============================================================================================
Upgrading:
 nss                         i686            3.41.0-3.fc28             updates          765 k
 nss                         x86_64          3.41.0-3.fc28             updates          693 k
 nss-pem                     x86_64          1.0.3-9.fc28              fedora            80 k
 nss-softokn                 i686            3.41.0-3.fc28             updates          462 k
 nss-softokn                 x86_64          3.41.0-3.fc28             updates          434 k
 nss-softokn-freebl          i686            3.41.0-3.fc28             updates          265 k
 nss-softokn-freebl          x86_64          3.41.0-3.fc28             updates          266 k
 nss-sysinit                 x86_64          3.41.0-3.fc28             updates           66 k
 nss-tools                   x86_64          3.41.0-3.fc28             updates          545 k
 nss-util                    i686            3.41.0-3.fc28             updates          132 k
 nss-util                    x86_64          3.41.0-3.fc28             updates          130 k

Transaction Summary
==============================================================================================
Upgrade  11 Packages

Total download size: 3.7 M
Is this ok [y/N]: y   
Downloading Packages:
(1/11): nss-softokn-3.41.0-3.fc28.x86_64.rpm                  2.6 MB/s | 434 kB     00:00    
(2/11): nss-3.41.0-3.fc28.x86_64.rpm                          3.5 MB/s | 693 kB     00:00    
(3/11): nss-softokn-freebl-3.41.0-3.fc28.x86_64.rpm           5.2 MB/s | 266 kB     00:00    
(4/11): nss-tools-3.41.0-3.fc28.x86_64.rpm                    6.8 MB/s | 545 kB     00:00    
(5/11): nss-sysinit-3.41.0-3.fc28.x86_64.rpm                  3.3 MB/s |  66 kB     00:00    
(6/11): nss-softokn-3.41.0-3.fc28.i686.rpm                    8.8 MB/s | 462 kB     00:00    
(7/11): nss-softokn-freebl-3.41.0-3.fc28.i686.rpm             7.9 MB/s | 265 kB     00:00    
(8/11): nss-util-3.41.0-3.fc28.x86_64.rpm                     7.6 MB/s | 130 kB     00:00    
(9/11): nss-util-3.41.0-3.fc28.i686.rpm                       5.6 MB/s | 132 kB     00:00    
(10/11): nss-3.41.0-3.fc28.i686.rpm                           747 kB/s | 765 kB     00:01    
(11/11): nss-pem-1.0.3-9.fc28.x86_64.rpm                       55 kB/s |  80 kB     00:01    
----------------------------------------------------------------------------------------------
Total                                                         1.0 MB/s | 3.7 MB     00:03     
warning: /var/cache/dnf/fedora-f21308f6293b3270/packages/nss-pem-1.0.3-9.fc28.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 9db62fb1: NOKEY
Importing GPG key 0x9DB62FB1:
 Userid     : "Fedora 28 (28) <fedora-28@fedoraproject.org>"
 Fingerprint: 128C F232 A937 1991 C8A6 5695 E08E 7E62 9DB6 2FB1
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64
Is this ok [y/N]: y
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction

(中略)

Upgraded:
  nss.i686 3.41.0-3.fc28                         nss.x86_64 3.41.0-3.fc28                    
  nss-pem.x86_64 1.0.3-9.fc28                    nss-softokn.i686 3.41.0-3.fc28              
  nss-softokn.x86_64 3.41.0-3.fc28               nss-softokn-freebl.i686 3.41.0-3.fc28       
  nss-softokn-freebl.x86_64 3.41.0-3.fc28        nss-sysinit.x86_64 3.41.0-3.fc28            
  nss-tools.x86_64 3.41.0-3.fc28                 nss-util.i686 3.41.0-3.fc28                 
  nss-util.x86_64 3.41.0-3.fc28                 

Complete!

#手順2
[root@server]/# dnf system-upgrade download --releasever 28     
Before you continue ensure that your system is fully upgraded by running "dnf --refresh upgrade". Do you want to continue [y/N]: y
Last metadata expiration check: 0:00:00 ago on Fri Dec 28 02:21:50 2018.
Dependencies resolved.
==============================================================================================
 Package                            Arch   Version                             Repository
                                                                                         Size
==============================================================================================
Installing:
 kernel                             x86_64 4.19.10-200.fc28                    updates  102 k
 kernel-core                        x86_64 4.19.10-200.fc28                    updates   24 M
 kernel-devel                       x86_64 4.19.10-200.fc28                    updates   13 M
 kernel-modules                     x86_64 4.19.10-200.fc28                    updates   28 M
 kernel-modules-extra               x86_64 4.19.10-200.fc28                    updates  2.2 M
Upgrading:

(中略)

Transaction Summary
==============================================================================================
Install     162 Packages
Upgrade    3124 Packages
Remove        5 Packages
Downgrade     7 Packages

Total download size: 3.2 G
DNF will only download packages, install gpg keys, and check the transaction.
Is this ok [y/N]: y
Downloading Packages:

(中略)

 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-rpmfusion-free-fedora-28
Is this ok [y/N]: y
Key imported successfully
(中略)
Downgraded:
  hplip.x86_64 3.18.3-1.fc28                 hplip-common.x86_64 3.18.3-1.fc28 hplip-libs.x86_64 3.18.3-1.fc28   
(中略)

Complete!
Download complete! Use 'dnf system-upgrade reboot' to start the upgrade.
To remove cached metadata and transaction use 'dnf system-upgrade clean'
The downloaded packages were saved in cache until the next successful transaction.
You can remove cached packages by executing 'dnf clean packages'.

#手順3
[root@server]/# dnf system-upgrade reboot

#ここで再起動&自動でアップデートが開始され、終了すると通常のログイン画面に到達する。

補遺

手順1.5の内容は環境ごとに異なると思われるが、ver27→29のようにバージョンを飛ばして更新しようとするとエラー内容が増えた。
それに対して、ver27→28→29というように順を追って更新した所、手順1.5のエラー以外は出なかった。
よって、更新は飛ばさずに実施した方が良いと考えられる。

後書き

ちゃんとサポート期限が切れる前にシステム更新しよう。

ディスプレイマネージャーLightDMの導入

概要

ディスプレイマネージャーをそれまで使っていたLXDMから、Ubuntuなどで使われているLightDMに切り替える。
LightDM - Wikipedia


LXDMに特に不満はなかったが、特定のデスクトップ環境に依存しないように作られた軽量ディスプレイマネージャーという事で、依存関係を減らしたい自分は興味を持った。
なお、Xウィンドウサーバ(X.Org)やディスプレイマネージャーとウィンドウマネージャーの関係については、導入にあたってかなり詳しく調べたので後日まとめて記事にする予定。

インストール

1. DNFでインストール

$ dnf install lightdm

2. デフォルトのXsessionがxprofileを読み込んでくれないので、読み込むXsessionを設定ファイルで変更する。
   設定ファイルは/usr/share/lightdm以下にあるが、
   直接設定はせずユーザー設定用のディレクトリ/etc/lightdm/lightdm.xonf.dにファイルを作ることで上書き設定する。
   (lightdm-sessionの内容は後述の「補遺A」参照)

$ vim /etc/lightdm/lightdm.conf.d/50-session-wrapper.conf 
[Seat:*]
session-wrapper=/etc/lightdm/lightdm-session

3. 壁紙の設定ができるので以下のファイルを編集。
   使用する画像は全ユーザーが読める/usr/share/backgrounds以下に配置する。

$ vim /etc/lightdm/lightdm-gtk-greeter.conf
# 〜〜前略〜〜
[greeter]
background=/usr/share/backgrounds/user/5756963.jpg
# 〜〜後略〜〜

4. systemdにて起動設定
   (最後のstopを実行した時点で画面がコンソールに戻る。暫く待って再起動しないようだったら電源ボタンから再起動。)

$ systemctl disable lxdm
$ systemctl enabel lightdm
$ systemctl stop lxdm

以上

補遺

A. lightdm-sessionの内容
   補遺Bに記載しているLightDM本家のソースコードから取得できるが、バージョン管理のインストールなど色々面倒なので以下に引用。(GPLv3)

#!/bin/bash
#
# LightDM wrapper to run around X sessions.

echo "Running X session wrapper"

message () {
  # pretty-print messages of arbitrary length; use xmessage if it
  # is available and $DISPLAY is set
  MESSAGE="$PROGNAME: $*"
  echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2
  if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then
    echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file -
  fi
}

errormsg () {
  # exit script with error
  message "$*"
  exit 1
}

# temporary storage of error messages
ERR=$(mktemp --tmpdir config-err-XXXXXX)

source_with_error_check () {
    CONFIG_FILE="$1"
    echo "Loading $CONFIG_FILE"
    BASH_VERSION= . "$CONFIG_FILE" 2>"$ERR"
    if [ -s "$ERR" ]; then
        . /usr/lib/lightdm/config-error-dialog.sh
    fi
    cat "$ERR" >&2
    truncate -s 0 "$ERR"
}

# Load profile
for file in "/etc/profile" "$HOME/.profile" "/etc/xprofile" "$HOME/.xprofile"; do
    if [ -f "$file" ]; then
        source_with_error_check "$file"
    fi
done

# Load resources
if type xrdb >/dev/null 2>&1; then
    xresourcedir="/etc/X11/Xresources"
    if [ -d "$xresourcedir" ]; then
        for file in $xresourcedir/*; do
            echo "Loading resource: $file"
            xrdb -merge "$file"
        done
    fi
    xresourcefile="$HOME/.Xresources"
    if [ -f "$xresourcefile" ]; then
        echo "Loading resource: $xresourcefile"
        xrdb -merge "$xresourcefile"
    fi
fi

# Load keymaps
if type setxkbmap >/dev/null 2>&1; then
    for file in "/etc/X11/Xkbmap" "$HOME/.Xkbmap"; do
        if [ -f "$file" ]; then
            echo "Loading keymap: $file"
            setxkbmap `cat "$file"`
            XKB_IN_USE=yes
        fi
    done
fi

# Load xmodmap if not using XKB
if type xmodmap >/dev/null 2>&1; then
    if [ -z "$XKB_IN_USE" ]; then
        for file in "/etc/X11/Xmodmap" "$HOME/.Xmodmap"; do
            if [ -f "$file" ]; then
               echo "Loading modmap: $file"
               xmodmap "$file"
            fi
        done
    fi
fi

unset XKB_IN_USE

# Run all system xinitrc shell scripts.
xinitdir="/etc/X11/xinit/xinitrc.d"
if [ -d "$xinitdir" ]; then
    for script in $xinitdir/*; do
        echo "Loading xinit script $script"
        if [ -x "$script" -a ! -d "$script" ]; then
            . "$script"
        fi
    done
fi

# Load Xsession scripts
# OPTIONFILE, USERXSESSION, USERXSESSIONRC and ALTUSERXSESSION are required
# by the scripts to work
xsessionddir="/etc/X11/Xsession.d"
OPTIONFILE=/etc/X11/Xsession.options
USERXSESSION=$HOME/.xsession
USERXSESSIONRC=$HOME/.xsessionrc
ALTUSERXSESSION=$HOME/.Xsession

if [ -d "$xsessionddir" ]; then
    for i in `ls $xsessionddir`; do
        script="$xsessionddir/$i"
        echo "Loading X session script $script"
        if [ -r "$script"  -a -f "$script" ] && expr "$i" : '^[[:alnum:]_-]\+$' > /dev/null; then
            . "$script"
        fi
    done
fi

echo "X session wrapper complete, running session $@"

exec $@

B.ソースコードの取得


lightdmのソースコードを参照するにはBazaarが必要。
Bazaar - Wikipedia

DNFでBazaarをインストールして、2行目でLaunchpadというBazaarのホスティングサービスからソースを取得する。なお、結構な容量(数MB)があるので数分を要する。

dnf install bzr
bzr branch lp:lightdm

コンパイル&インストールは以下のコマンドで実行する。(未実施)

cd lightdm
./autogen.sh
make
make install

感想

壁紙が設定できるようになったのが地味に便利。壁紙出すソフトを探している最中だったのだがその手間が無くなった。


最初Xsessionを変更する設定が効かず非常に迷った。
その関係でXサーバやディスプレイマネージャに必要以上に詳しくなった上ソースコードも取得したのだが、
結果的には一度アンインストールしてファイルから再インストールした所正常動作に戻り、
普通に使えるようになった。


…その辺の顛末を削って必要な作業だけまとめた結果、割と短かい記事に。悔しいので後日調べた内容を別に出す。

dwmをSRPMからコンパイルして設定変更

最近のFedoraというかRHEL系では、SRPM(Source RPM)のコンパイルにmockというビルドコマンドを使用する。
chrootを使って綺麗な環境でビルドを実行してくれるが、「Linux丸ごとの環境をOSバージョンが上がる毎に作る」らしいので、ディスク容量に余裕がある場所へ置いた方が良いと思われる。

自PCのファイル置き場

/home/mockbuild
├── dwm-6.1-6.fc27.src.rpm     HOME直下にオリジナルのSRPM
└── rpmbuild                   rpmbuild以下にSRPMでインストールしたソース
    ├── BUILD
    ├── BUILDROOT
    ├── RPMS
    ├── SOURCES
    ├── SPECS
    └── SRPMS

/var/lib/mock                     mockコマンドが作る環境別ビルド結果
└── fedora-27-x86_64
    ├── result                 mockコマンドで作られたバイナリRPM
    └── root                   mockコマンドが作るビルド用環境



インストール

1. mockコマンドが使用するmockbuildユーザーを作成してログインする。
   以降mockbuildユーザーで実行。

$ sudo useradd -s /bin/zsh mockbuild
$ sudo passwd mockbuild
$ su - mockbuild

2. SRPMをダウンロードしてインストールする。

$ cd /home/mockbuild
$ dnf download --source dwm
dwm-6.1-6.fc27.src.rpm                                      276 kB/s |  42 kB     00:00    
$ rpm -ivh dwm-6.1-6.fc27.src.rpm 
更新中 / インストール中...
   1:dwm-6.1-6.fc27                            ################################# [100%]

3. tarになっているソースを解凍後、makeコマンドでヘッダファイルconfig.hを作成する。

$ cd /home/mockbuild/rpmbuild/SOURCES
$ tar xf dwm-6.1.tar.gz
$ cd dwm-6.1/
$ make config.h
$ ls config.h
config.h

4. ここでソースを変更するが、今回はビルドテストがメインなのでとりあえず標準ターミナルのみ変更

$ cd /home/mockbuild/rpmbuild/SOURCES/dwm-6.1
$ diff config.def.h config.h 
58c58
< static const char *termcmd[]  = { "st", NULL };
---
> static const char *termcmd[]  = { "terminator", NULL };

5. 編集したソースコードをtarに戻した後、rpmbuildでSRPMにする。

$ cd /home/mockbuild/rpmbuild/SOURCES/
$ tar czvf dwm-6.1.tar.gz dwm-6.1/
$ rpmbuild -bs /home/mockbuild/rpmbuild/SPECS/dwm.spec

6. /etc/mock/にビルド対象システムごとの設定ファイルが並んでいるので、default.cfgを作成対象へのリンクにする。
   (mockコマンド実行時に-rオプションで個別指定することも可能)

$ su -
$ cd /etc/mock
$ rm default.cfg
$ sudo ln -s fedora-27-x86_64.cfg default.cfg
$ ll default.cfg
lrwxrwxrwx. 1 root root 20 Dec 10 21:05 default.cfg -> fedora-27-x86_64.cfg

※作成しない状態でmockコマンドを実行すると下のようなエラーが出る

ERROR: Could not find required config file: /etc/mock/default.cfg

7. SRPMができたらmockコマンドによるビルドを実行する。
   dnfにより/var/lib/mock/rootの下にLinux環境が構築される。

$ mock --rebuild /home/mockbuild/rpmbuild/SRPMS/dwm-6.1-6.fc27.src.rpm

8. 最終的にエラーなく終了したらビルド完了。

書き込み完了: /builddir/build/RPMS/dwm-6.1-6.fc27.x86_64.rpm
書き込み完了: /builddir/build/RPMS/dwm-user-6.1-6.fc27.x86_64.rpm
書き込み完了: /builddir/build/RPMS/dwm-debugsource-6.1-6.fc27.x86_64.rpm
書き込み完了: /builddir/build/RPMS/dwm-debuginfo-6.1-6.fc27.x86_64.rpm
実行中(%clean): /bin/sh -e /var/tmp/rpm-tmp.TfhmF3
+ umask 022
+ cd /builddir/build/BUILD
+ cd dwm-6.1
+ /usr/bin/rm -rf /builddir/build/BUILDROOT/dwm-6.1-6.fc27.x86_64
+ exit 0
Finish: rpmbuild dwm-6.1-6.fc27.src.rpm
Finish: build phase for dwm-6.1-6.fc27.src.rpm
INFO: Done(/home/mockbuild/rpmbuild/SRPMS/dwm-6.1-6.fc27.src.rpm) Config(default) 5 minutes 40 seconds
INFO: Results and/or logs in: /var/lib/mock/fedora-27-x86_64/result
Finish: run

9. root権限を持つユーザーに戻って、作られたrpmをインストールする。
   その際、バージョン番号が変わってないと"-i"が効かないので"--reinstall"を使う。

$ cd /var/lib/mock/fedora-27-x86_64/result
$ ls *.rpm
dwm-6.1-6.fc27.src.rpm                 dwm-6.1-6.fc27.x86_64.rpm       dwm-debuginfo-6.1-6.fc27.x86_64.rpm
dwm-debugsource-6.1-6.fc27.x86_64.rpm  dwm-user-6.1-6.fc27.x86_64.rpm
$ sudo dnf reinstall dwm-6.1-6.fc27.x86_64.rpm
Last metadata expiration check: 0:17:41 ago on Thu Dec 14 23:44:56 2017.
Dependencies resolved.
==============================================================================================
 Package          Arch                Version                 Repository                 Size
==============================================================================================
Reinstalling:
 dwm              x86_64              6.1-6.fc27              @commandline               40 k

Transaction Summary
==============================================================================================

Total size: 40 k
Is this ok [y/N]: y
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                      1/1 
  Reinstalling     : dwm-6.1-6.fc27.x86_64                                                1/2 
  Erasing          : dwm-6.1-6.fc27.x86_64                                                2/2 
  Running scriptlet: dwm-6.1-6.fc27.x86_64                                                2/2 
Running as unit: run-r54e7c3a61a1645949b5bf54434e1e68b.service
Running as unit: run-rc7e93a98a31949f4b5551a3f4ba83920.service
  Verifying        : dwm-6.1-6.fc27.x86_64                                                1/2 
  Verifying        : dwm-6.1-6.fc27.x86_64                                                2/2 

Reinstalled:
  dwm.x86_64 6.1-6.fc27                                                                       

Complete!

※2017/12/15修正:rpmコマンドを直接使っていたが、dnfでも同様の作業が可能なことが分かったためdnfを使うよう変更。

以上



補遺

  • 設定内容については参考サイトのArchLinuxのサイトか公式サイトを参照。
  • 設定とは少し違うが、公式サイトにはパッチが多数公開されている。システムトレイの追加や透過率の設定など、他で言うプラグインに近い扱いの機能をカバーしている模様。
  • SRPMコンパイルについて、昔は/usr/src/redhat/の下で実行していたようだが、mockパッケージが導入されてから今の形式になったと思われる。現行はもう/usr/src/redhat/自体がない。
  • findで適当に探した結果、dnfからそのままインストールしたRPMはこのあたりにあると思われる。

/var/cache/PackageKit                                    
├── groups.sqlite       グループとか一覧?                
├── hawkey              リポジトリごとの何か             
├── metadata                                             
│       ├── updates    リポジトリ毎のRPMや鍵            
│       ├── fedora              :                           
│       └──    :                                            
└── 24 ~ 27              バージョンごとのインストール履歴 
         ├── hawkey              :                           
         └── metadata

感想

  • 最終的にビルドはされているが途中で結構警告が出ているのが気になる所。
  • あとzshでdnfコマンドとrpmコマンドで補完が効かない部分がいくつかあったので修正したい。
  • dwm-user-6.1-6.fc27.x86_64.rpmは再コンパイルを支援するライブラリらしいが、依存パッケージが足りずインストールできなかったため保留中。できればパッケージは増やしたくないので自前対応のまま行く可能性もあり。
  • ビルドに使うmockというツールについてだが、全くといっていいほど日本語の情報がない。というか英語の情報すら少ない?ようで、参考サイトに書いた分くらいしか見つからなかった。

タイル型ウィンドウマネージャー dwm を導入

日本タイル型ウィンドウマネージャ推進委員会 Wiki - 日本タイル型ウィンドウマネージャ推進委員会 - OSDN

タイル型ウィンドウマネージャは以下のような方にオススメです。
・ウィンドウの下にウィンドウが隠れてしまうのは我慢がならない
・ウィンドウが重ならないように綺麗に配置している
・マウス操作が煩わしい
・GUI環境でもキーボードのショートカットだけで生きていきたい
・軽快なウィンドウマネージャを使いたい
・Emacsにどっぷりハマってる
・GNU screenにどっぷりハマってる
・ディスプレイの解像度が低いので画面を有効に使いたい
・ディスプレイの解像度が高いが画面を有効活用できていない
・1台のパソコンに複数のディスプレイを接続している(マルチディスプレイ環境)

7個ぐらい当てはまったのでベストマッチであることは明らか。


いくつかある中からdwmを選択。
dwm (ウィンドウマネージャ) - Wikipedia

  • 無駄な装飾が少ない
  • シンプルであるためにC言語で2000行程度までという基準がある
  • 設定画面すら無駄としてすべてヘッダファイルにハードコーディング&再コンパイルという割り切った仕様
  • 他のウィンドウマネージャがスクリプト言語などを覚える必要があるのに対してC言語だけで済む



インストール

1. dnfでインストール

dnf install dwm

2. なんか重い気がしたのでGNOMEをやめてLXDMをインストールして有効化
   (先にGDM(GNOME)を止める必要あり)

dnf install lxdm
systemctl disable gdm
systemctl enable lxdm
systemctl stop gdm

3. 再起動するとログイン画面が変わるので、画面下のデスクトップ選択ドロップダウンから"dwm"を選択

4. 左上に数字が並んでいる何もない画面が出たらdwmが起動している。
   とりあえずShift+Alt+Enterでターミナルが起動する。




上記まででウィンドウマネージャの導入は終わったが、今までデスクトップ環境だったGNOMEからウィンドウマネージャしかなくなったので色々足りなくなる。
とりあえず最低限設定する。

マルチディスプレイの順序を変更する

1. 私はプライマリを右、セカンダリを左に置いているのだが逆になっていた。
   xrandr -qで接続されているディスプレイを確認、xrandr --output~で設定する。

$ xrandr -q
Screen 0: minimum 320 x 200, current 3840 x 1080, maximum 8192 x 8192
VGA-1 connected primary 1920x1080+1920+0 (normal left inverted right x axis y axis) 509mm x 286mm
   1920x1080     60.00*+
   1280x1024     75.02    60.02  
   1152x864      75.00  
   1024x768      75.03    60.00  
   800x600       75.00    60.32  
   640x480       75.00    59.94  
   720x400       70.08  
HDMI-1 connected 1920x1080+0+0 (normal left inverted right x axis y axis) 1600mm x 900mm
   1920x1080     60.00*+  59.94    30.00    24.00    29.97    23.98  
   1920x1080i    60.00    59.94  
   1280x1024     60.02  
   1360x768      60.02  
   1280x768      74.89    59.87  
   1280x720      60.00    59.94  
   1024x768      75.03    70.07    60.00  
   800x600       72.19    75.00    60.32  
   720x480       60.00    59.94  
   720x480i      60.00    59.94  
   640x480       75.00    72.81    60.00    59.94  
DP-1 disconnected (normal left inverted right x axis y axis)
$ xrandr --output VGA-1 --right-of HDMI-1

2. ~/.xprofileに書き込むとXorg起動時に読み込まれるようになる。

$ vim ~/.xprofile
#!/bin/sh
/bin/xrandr --output VGA-1 --right-of HDMI-1
$ chmod -x ~/.xprofile

CapsLockをCtrlにする

1. localectlで設定する。空欄の部分は元々空欄だったのでそれを維持。
   (Xorgでなく/etc/sysconfig/に居るから?)

$ localectl set-x11-keymap jp "" "" "ctrl:nocaps"

※この辺に設定されるらしいが、直接編集はよくないらしい。


/etc/X11/xorg.conf.d/00-keyboard.conf

Section "InputClass"
        Identifier "system-keyboard"
        MatchIsKeyboard "on"
        Option "XkbLayout" "jp"
        Option "XkbOptions" "ctrl:nocaps"
EndSection

日本語入力

1. ibus-daemonを実行することでibusによる日本語入力が可能になるので、~/.xprofileに以下を追記する。
   (-xb:XIMサービス起動&バックグラウンド起動)

/bin/ibus-daemon -xb

※未設定で起動中の場合、とりあえずAlt-pでdmenuを出して"ibus-daemon"を起動すれば入力可能になる。



感想

最初LXDE全部入れてみたが、結局ウィンドウマネージャのdwmとランチャのdmenu以外ほとんど使わなかったので削除。というかパネル(Windowsで言うとタスクバー)を通そうとすると、そちらにコントロールを吸われて画面に出てこなくなる…。
使用感としては中々良好。ウィンドウサイズが自動的に決定されて動かす必要がないというのは感動的。あとカーソル移動が長くなりがちなマルチウィンドウ間の移動も一瞬。

  • 残りの問題
    • 画面から音量が変更できない
    • 画面で時間や通知を確認する方法がない
    • 時間経過で画面ロックやスリープがされない
    • 縦分割時、ウィンドウ高さを手動変更する方法がない(横分割の幅は変更可能)
    • コントロール移動にマウスカーソルがついてこないせいで見失う、特にウィンドウ間移動時