# 通知設計書 28-SettingsChanged

## 概要

本ドキュメントは、Windows TerminalにおけるSettingsChangedイベント通知の設計を記述する。設定ファイル（settings.json等）が再読み込みされた際に発火するイベントで、アプリケーション全体に設定変更を伝播するためのWinRT型イベントである。

### 本通知の処理概要

SettingsChangedは、設定ファイルの変更を検知してリロードした後に、その結果（成功/失敗/警告）と新しい設定オブジェクトをアプリケーション内の各コンポーネントに伝達するイベント通知である。

**業務上の目的・背景**：Windows Terminalはユーザーがsettings.jsonファイルを外部エディタで編集することを前提としている。ファイル変更の自動検知と設定の動的リロードにより、アプリケーションの再起動なしに設定変更を反映する。この通知はリロード結果を全ウィンドウ・全コンポーネントに伝播し、テーマ、ホットキー、通知領域アイコン等の更新をトリガーする。

**通知の送信タイミング**：AppLogic::ReloadSettings内で設定ファイルの読み込み完了後に発火する。初回ロード時（エラー発生時）と設定再読み込み時の2つのパスで呼び出される。設定変更の検知にはファイルシステム監視（wil::unique_folder_change_reader_nothrow）が使用され、ThrottledFuncにより頻繁な変更がスロットリングされる。

**通知の受信者**：TerminalWindow、AppHost、WindowEmperorの3つのコンポーネントがイベントをハンドルする。それぞれが独自の更新処理を行う。

**通知内容の概要**：SettingsLoadEventArgs構造体が送信され、以下の情報を含む: Reload（リロードフラグ）、Result（HRESULT）、ExceptionText（例外テキスト）、Warnings（警告リスト）、NewSettings（新しいCascadiaSettingsオブジェクト）。

**期待されるアクション**：各受信コンポーネントが新しい設定を適用する。TerminalWindowはページの設定更新とテーマ変更、AppHostはウィンドウ動作の更新、WindowEmperorはグローバルホットキーと通知アイコンの更新を行う。

## 通知種別

アプリ内通知（WinRT TypedEvent: `TypedEventHandler<Object, SettingsLoadEventArgs>`）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（イベントハンドラの直接呼び出し） |
| 優先度 | 高 |
| リトライ | 無 |

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

WinRTのTypedEventメカニズムにより、イベントにサブスクライブした全てのハンドラに通知される。サブスクリプションは各コンポーネントの初期化時に登録される。

## 通知テンプレート

### イベント引数

| 項目 | 型 | 内容 |
|-----|-----|------|
| Reload | Boolean | リロードかどうか（初回=false、再読み込み=true） |
| Result | UInt64 | HRESULT値（S_OK=成功、S_FALSE=警告あり、その他=エラー） |
| ExceptionText | String | 例外テキスト（エラー時のみ） |
| Warnings | IVectorView<SettingsLoadWarnings> | 設定読み込み警告のリスト |
| NewSettings | CascadiaSettings | 新しい設定オブジェクト |

### 本文テンプレート

```
SettingsChanged.raise(*this, *ev)
// ev = SettingsLoadEventArgs(reload, result, exceptionText, warnings, settings)
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Reload | 初回ロードか再読み込みか | AppLogic内部フラグ | Yes |
| Result | 読み込み結果HRESULT | _TryLoadSettings()の戻り値 | Yes |
| ExceptionText | エラー時の例外テキスト | _settingsLoadExceptionText | No |
| Warnings | 設定警告リスト | _warnings | No |
| NewSettings | 新しい設定オブジェクト | _settings | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ファイル監視 | settings.jsonの変更検知 | ファイルの読み込み処理完了後 | ThrottledFuncによりスロットリングされる |
| 画面操作 | 設定UIからの保存 | 設定ファイル保存完了後（間接的にファイル監視で検知） | 設定エディタからの変更 |
| API呼び出し | AppLogic::ReloadSettings() | 直接呼び出し | プログラム的な設定リロード |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 初回ロード成功時 | 初回の正常ロードではイベントは発火せず、_RegisterSettingsChangeで変更監視のみ登録される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[設定ファイル変更検知] --> B[ThrottledFunc経由でReloadSettings呼び出し]
    B --> C[_TryLoadSettings実行]
    C --> D{ロード結果}
    D -->|成功| E[SettingsLoadEventArgs作成]
    D -->|エラー| F{初回ロード?}
    F -->|Yes| G[デフォルト設定で続行]
    F -->|No| H[SettingsLoadEventArgs作成（エラー付き）]
    E --> I[SettingsChanged.raise発火]
    H --> I
    I --> J[TerminalWindow::UpdateSettingsHandler]
    I --> K[AppHost::_HandleSettingsChanged]
    I --> L[WindowEmperor::SettingsChangedハンドラ]
    J --> M[TerminalPage設定更新、テーマ更新]
    K --> N[ウィンドウ動作更新]
    L --> O[グローバルホットキー、通知アイコン更新]
```

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

### 参照テーブル一覧

該当なし（設定ファイルJSON参照）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| JSONパースエラー | settings.jsonの構文エラー | エラー情報付きSettingsLoadEventArgsで通知。受信側でエラーダイアログ表示 |
| ファイル読み込みエラー | ファイルアクセス権限不足等 | エラーHRESULTとExceptionTextで通知 |
| 設定検証警告 | 無効な設定値、非推奨設定等 | Result=S_FALSEと警告リストで通知。受信側で警告ダイアログ表示 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（イベント自体のリトライなし。ファイル変更の再検知による自動リトライは可能） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| スロットリング | ThrottledFuncにより、短時間の連続変更がスロットリングされる |

### 配信時間帯

制限なし

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

- settings.jsonには機密情報は含まれない（パスワード等は保存されない）
- イベントはプロセス内で伝播されるため、外部プロセスへの情報漏洩リスクはない
- 設定ファイルの読み込み元はユーザープロファイルディレクトリに限定される

## 備考

- SettingsChangedイベントはAppLogicとTerminalWindowの2層で発火される。AppLogicが最初に発火し、TerminalWindowがそれを受けて自身の処理を行った後、再度SettingsChangedを発火してAppHostに伝播する
- 初回ロード時にエラーが発生した場合、デフォルト設定（CascadiaSettings::LoadDefaults()）にフォールバックする
- _RegisterSettingsChangeでファイルシステム監視を登録し、wil::unique_folder_change_reader_nothrowで変更を監視する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SettingsLoadEventArgs.h | `src/cascadia/TerminalApp/SettingsLoadEventArgs.h` | イベント引数の定義（Reload, Result, ExceptionText, Warnings, NewSettings） |
| 1-2 | TerminalWindow.idl | `src/cascadia/TerminalApp/TerminalWindow.idl` | SettingsLoadEventArgsのIDL定義（行30-39） |
| 1-3 | AppLogic.idl | `src/cascadia/TerminalApp/AppLogic.idl` | SettingsChangedイベントの定義（行35） |

**読解のコツ**: SettingsLoadEventArgsはWINRT_PROPERTYマクロで定義されており、各プロパティのゲッター/セッターが自動生成される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AppLogic.cpp | `src/cascadia/TerminalApp/AppLogic.cpp` | ReloadSettings関数（行390-438） |

**主要処理フロー**:
1. **行395-406**: エラー時の処理パス。SettingsLoadEventArgsを作成してSettingsChanged.raise()
2. **行427-437**: 正常リロード時のパス。警告情報付きSettingsLoadEventArgsを作成してSettingsChanged.raise()

#### Step 3: 受信側（TerminalWindow）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TerminalWindow.cpp | `src/cascadia/TerminalApp/TerminalWindow.cpp` | イベント登録（行211）とUpdateSettingsHandler（行800-828） |

**主要処理フロー**:
- **行211**: `AppLogic::Current()->SettingsChanged({ get_weak(), &TerminalWindow::UpdateSettingsHandler })` でイベント登録
- **行800**: `_settings = args.NewSettings()` で新設定を保存
- **行804**: `_root->SetSettings(_settings, true)` でTerminalPageの設定を更新
- **行807**: `SettingsChanged.raise(*this, args)` でさらにAppHostに伝播

#### Step 4: 受信側（AppHost、WindowEmperor）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AppHost.cpp | `src/cascadia/WindowsTerminal/AppHost.cpp` | イベント登録（行264）と_HandleSettingsChanged（行1016-1025） |
| 4-2 | WindowEmperor.cpp | `src/cascadia/WindowsTerminal/WindowEmperor.cpp` | イベント登録とハンドラ（行377-385） |

**主要処理フロー**:
- **AppHost.cpp 行1021-1024**: ウィンドウ動作設定の更新（最小化、自動非表示、タブ表示等）
- **WindowEmperor.cpp 行381-383**: グローバルホットキー再設定、通知アイコン更新、セッション永続化設定

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

```
ファイル変更検知 (wil::unique_folder_change_reader_nothrow)
    |
    +-- ThrottledFunc -> AppLogic::ReloadSettings (AppLogic.cpp:390)
           |
           +-- _TryLoadSettings()
           |
           +-- SettingsChanged.raise() [AppLogic]
                  |
                  +-- TerminalWindow::UpdateSettingsHandler (TerminalWindow.cpp:800)
                  |      |
                  |      +-- TerminalPage::SetSettings()
                  |      |
                  |      +-- SettingsChanged.raise() [TerminalWindow]
                  |             |
                  |             +-- AppHost::_HandleSettingsChanged (AppHost.cpp:1016)
                  |                    |
                  |                    +-- ウィンドウ動作設定更新
                  |
                  +-- WindowEmperor::SettingsChangedハンドラ (WindowEmperor.cpp:377)
                         |
                         +-- グローバルホットキー、通知アイコン更新
```

### データフロー図

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

settings.json変更     AppLogic::ReloadSettings        各コンポーネントの更新
(ファイル監視)  ----> _TryLoadSettings()          ---> TerminalPage設定更新
                      SettingsLoadEventArgs作成         ウィンドウ動作更新
                      SettingsChanged.raise()           ホットキー更新
                           |                             通知アイコン更新
                           v                             テーマ更新
                      [TerminalWindow]
                      [AppHost]
                      [WindowEmperor]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SettingsLoadEventArgs.h | `src/cascadia/TerminalApp/SettingsLoadEventArgs.h` | ソース（ヘッダ） | イベント引数の定義 |
| AppLogic.idl | `src/cascadia/TerminalApp/AppLogic.idl` | IDL | SettingsChangedイベントのIDL定義 |
| AppLogic.cpp | `src/cascadia/TerminalApp/AppLogic.cpp` | ソース（実装） | イベント発火元 |
| AppLogic.h | `src/cascadia/TerminalApp/AppLogic.h` | ソース（ヘッダ） | AppLogicクラス定義 |
| TerminalWindow.cpp | `src/cascadia/TerminalApp/TerminalWindow.cpp` | ソース（実装） | イベント受信・伝播 |
| TerminalWindow.idl | `src/cascadia/TerminalApp/TerminalWindow.idl` | IDL | TerminalWindowのSettingsChangedイベント定義 |
| AppHost.cpp | `src/cascadia/WindowsTerminal/AppHost.cpp` | ソース（実装） | イベント受信処理 |
| WindowEmperor.cpp | `src/cascadia/WindowsTerminal/WindowEmperor.cpp` | ソース（実装） | イベント受信処理 |
| CascadiaSettingsSerialization.cpp | `src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp` | ソース（実装） | 設定ファイルの読み込み/シリアライゼーション |
