# 通知設計書 10-doom-switch-frame-hook

## 概要

本ドキュメントは、Doom Emacsにおける`doom-switch-frame-hook`機能の設計を記載する。このフックは、フレームのフォーカスが変更された際に登録された関数を実行するための通知メカニズムである。

### 本通知の処理概要

doom-switch-frame-hookは、Emacsフレームのフォーカス状態が変更された際に発火するカスタムフックである。デバウンス機能を備え、過剰な発火を防止しながら、フレームフォーカス変更に応じた処理を実装できる。

**業務上の目的・背景**：マルチモニター環境やウィンドウマネージャとの連携において、フレームのフォーカス変更を検知することは重要である。例えば、フォーカスを得たフレームでのUI更新、自動保存のトリガー、外部プロセスとの同期などが考えられる。doom-switch-frame-hookは、`focus-in-hook`や`after-focus-change-function`のアナログとして機能し、デバウンス機能により安定した動作を提供する。

**通知の送信タイミング**：`after-focus-change-function`がトリガーされた際に、`doom-run-switch-frame-hooks-fn`が呼び出され、最終フォーカス変更から`doom-switch-frame-hook-debounce-delay`秒（デフォルト2.0秒）経過後に`doom-switch-frame-hook`が実行される。

**通知の受信者**：`doom-switch-frame-hook`に登録された関数群。ユーザーコードやパッケージ設定から追加可能。

**通知内容の概要**：フック関数に引数は渡されない。現在のフレームは`(selected-frame)`で取得可能。

**期待されるアクション**：フック関数はフレームフォーカス変更に応じた処理（UIの更新、状態の同期など）を実行する。

## 通知種別

アプリ内通知（フック実行による内部通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（デバウンス付き） |
| 優先度 | 中 |
| リトライ | 無 |

### 送信先決定ロジック

`doom-switch-frame-hook`に登録された全ての関数が順次実行される。複数のフォーカスフレームが存在する可能性がある場合、各フレームに対して実行される。

## 通知テンプレート

### フック実行の場合

| 項目 | 内容 |
|-----|------|
| 対象 | doom-switch-frame-hookに登録された関数 |
| 引数 | なし |

### 本文テンプレート

該当なし（フック実行）

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| selected-frame | 現在選択中のフレーム | (selected-frame)で取得 | No |
| doom-switch-frame-hook-debounce-delay | デバウンス遅延秒数 | グローバル変数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 関数呼び出し | after-focus-change-function | フォーカス状態変更 | フレームフォーカス変更 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| デバウンス期間内 | 前回のフック実行から2.0秒以内は抑止 |
| frame-focus-state = nil または 'unknown | フォーカス状態が不明または無効時 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[フレームフォーカス変更] --> B[after-focus-change-function発火]
    B --> C[doom-run-switch-frame-hooks-fn]
    C --> D{フォーカス状態変更?}
    D -->|No| E[終了]
    D -->|Yes| F[pre-redisplay-functionsにフック追加]
    F --> G[次の再描画時]
    G --> H[doom--run-switch-frame-hooks-fn]
    H --> I[visible-frame-listをループ]
    I --> J{frame-focus-state有効?}
    J -->|No| K[スキップ]
    J -->|Yes| L{デバウンス期間経過?}
    L -->|No| K
    L -->|Yes| M[with-selected-frame]
    M --> N[run-hooks 'doom-switch-frame-hook]
    N --> O[+last-focusフレームパラメータ更新]
    K --> P{全フレーム処理完了?}
    P -->|No| I
    P -->|Yes| E
    O --> P
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（Emacs Lisp変数のみ使用）

### 変数参照詳細

| 変数名 | 用途 | 取得条件 |
|--------|------|---------|
| doom-switch-frame-hook | フック関数リスト | 常時参照可能 |
| doom-switch-frame-hook-debounce-delay | デバウンス遅延（秒） | 常時参照可能（デフォルト2.0） |
| +last-focus | フレームパラメータ（最終フォーカス時刻） | フレームごとに保存 |
| gc-cons-threshold | GC閾値 | 一時的にmost-positive-fixnumに設定 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| フック関数内エラー | フック関数の実装エラー | unwind-protectで+last-focus更新を保証 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| デバウンス | 同一フレームへの連続フォーカスは2.0秒間抑止 |

### 配信時間帯

制限なし

## セキュリティ考慮事項

- フック関数はローカルで実行され、外部通信はない
- デバウンス機能により、悪意あるフォーカス操作の影響を軽減
- パフォーマンス影響を考慮し、フック関数は軽量に実装すべき

## 備考

- `doom-switch-frame-hook-debounce-delay`でデバウンス遅延をカスタマイズ可能
- 複数フレームが同時にフォーカスを持つエッジケースにも対応
- `pre-redisplay-functions`を使用して次の再描画まで遅延させることで安定性を確保
- `inhibit-redisplay`をtに設定してフック実行中の再描画を抑止

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

フック変数とデバウンス設定を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | doom-ui.el | `lisp/doom-ui.el` | doom-switch-frame-hook定義（96-103行目）を確認 |
| 1-2 | doom-ui.el | `lisp/doom-ui.el` | doom-switch-frame-hook-debounce-delay定義（118-124行目）を確認 |

**読解のコツ**: `defcustom`でカスタムフックを定義。デバウンス遅延はデフォルト2.0秒。

#### Step 2: エントリーポイントを理解する

フック実行関数を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | doom-ui.el | `lisp/doom-ui.el` | doom-run-switch-frame-hooks-fn関数（142-149行目）を確認 |
| 2-2 | doom-ui.el | `lisp/doom-ui.el` | doom--run-switch-frame-hooks-fn関数（126-140行目）を確認 |

**主要処理フロー**:
1. **142行目**: `doom-run-switch-frame-hooks-fn`がafter-focus-change-functionから呼ばれる
2. **145-147行目**: フォーカス状態の変更を検知
3. **148行目**: `pre-redisplay-functions`に実際のフック実行を遅延
4. **126行目**: `doom--run-switch-frame-hooks-fn`が実際のフック実行を行う
5. **129-140行目**: 各フォーカスフレームに対してデバウンスチェックとフック実行

#### Step 3: フック登録処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | doom-ui.el | `lisp/doom-ui.el` | doom-init-ui-h関数内のフック登録（740行目）を確認 |

**主要処理フロー**:
- **740行目**: `add-function :after after-focus-change-function`で`doom-run-switch-frame-hooks-fn`を追加

### プログラム呼び出し階層図

```
[フレームフォーカス変更]
    |
    +-- after-focus-change-function
            |
            +-- doom-run-switch-frame-hooks-fn
                    |
                    +-- [フォーカス状態変更検知]
                    |
                    +-- pre-redisplay-functionsに登録
                            |
                            +-- [次の再描画時]
                                    |
                                    +-- doom--run-switch-frame-hooks-fn
                                            |
                                            +-- [各フォーカスフレームに対して]
                                                    |
                                                    +-- frame-focus-state判定
                                                    |
                                                    +-- デバウンス判定
                                                    |
                                                    +-- run-hooks 'doom-switch-frame-hook
                                                    |
                                                    +-- +last-focus更新
```

### データフロー図

```
[入力]                    [処理]                          [出力]

フォーカス変更 ───────▶ after-focus-change-function
                              │
                              ▼
                    doom-run-switch-frame-hooks-fn
                              │
                              ▼
last-focus-state ───▶ [状態比較]
                              │
                              ▼
                    pre-redisplay-functionsに遅延
                              │
                              ▼
visible-frame-list ──▶ doom--run-switch-frame-hooks-fn
                              │
frame-focus-state ───▶ [フォーカス判定]
                              │
+last-focus ─────────▶ [デバウンス判定]
                              │
                              ▼
doom-switch-frame-hook-debounce-delay
                              │
                              ▼
                    run-hooks 'doom-switch-frame-hook
                              │
                              ▼
                    +last-focus更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| doom-ui.el | `lisp/doom-ui.el` | ソース | doom-switch-frame-hookの定義、デバウンス処理、実行処理 |
