# 通知設計書 48-SwapChainChanged

## 概要

本ドキュメントは、Windows Terminal における SwapChainChanged イベントの設計仕様を記述する。このイベントは、レンダリングエンジンのスワップチェインが変更された際に発火し、XAMLのSwapChainPanelに新しいスワップチェインをアタッチするためのトリガーとなる。

### 本通知の処理概要

SwapChainChangedイベントは、Direct3Dレンダリングで使用されるスワップチェイン（DXGI SwapChain）のハンドルが変更されたことをUI層に通知するためのイベントである。AtlasEngine（レンダリングエンジン）がスワップチェインを再作成すると、ControlCoreの_renderEngineSwapChainChangedコルーチンが呼び出される。このコルーチンはソースハンドルを複製（DuplicateHandle）し、UIスレッドにディスパッチした後、SwapChainChangedイベントを発火する。TermControlはこのイベントを受信し、XAMLのSwapChainPanelに新しいスワップチェインをアタッチする。

**業務上の目的・背景**：Windows Terminalのレンダリングは、Direct3D 11をベースとしたAtlasEngineにより行われる。デバイスロスト、DPI変更、ウィンドウリサイズなどの際にスワップチェインの再作成が必要になることがある。スワップチェインが変更された際に、XAMLのSwapChainPanelを新しいスワップチェインに接続し直す必要がある。

**通知の送信タイミング**：AtlasEngineがスワップチェインを作成または再作成した際に発火する。初期化時のInitialize内でも発火する。

**通知の受信者**：TermControlのRenderEngineSwapChainChangedハンドラがControlCoreからのイベントを受信する。

**通知内容の概要**：イベント引数として新しいスワップチェインのハンドル値（uint64_t型にboxed）が渡される。

**期待されるアクション**：TermControlはハンドルをHANDLEに変換し、_AttachDxgiSwapChainToXamlメソッドでSwapChainPanelに新しいスワップチェインをアタッチする。

## 通知種別

アプリ内通知（WinRT イベント / レンダリングエンジンコールバック）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（バックグラウンドスレッドから発火、co_awaitでUIスレッドにディスパッチ） |
| 優先度 | 高 |
| リトライ | 無し |

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

AtlasEngineがスワップチェイン変更時にコールバックを呼び出し、ControlCoreの_renderEngineSwapChainChangedコルーチンが処理する。UIスレッドにディスパッチ後、SwapChainChangedイベントを発火する。TermControlがwinrt::auto_revokeで購読している。

## 通知テンプレート

### メール通知の場合

該当なし（アプリ内イベント通知のため）

### 本文テンプレート

```
該当なし（uint64_t型のスワップチェインハンドルがboxed valueとして伝達される）
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| SwapChainHandle | 新しいスワップチェインのハンドル（uint64_t） | DuplicateHandle(_lastSwapChainHandle) | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| レンダラーコールバック | AtlasEngine スワップチェイン作成/再作成 | スワップチェイン変更時 | デバイスロスト、DPI変更、初期化時等 |
| 初期化 | ControlCore::Initialize内でのスワップチェイン設定 | 初期化時 | AtlasEngine初期化時にスワップチェインが作成される |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| weak_ptr失効 | ControlCoreがすでに破棄されている場合はスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[AtlasEngine: スワップチェイン作成/再作成] --> B[SwapChainChangedCallback呼び出し]
    B --> C[ControlCore::_renderEngineSwapChainChanged コルーチン]
    C --> D[DuplicateHandle: ハンドル複製]
    D --> E[co_await UIスレッドへディスパッチ]
    E --> F{weak_ptr有効?}
    F -->|No| G[スキップ]
    F -->|Yes| H[_lastSwapChainHandle更新]
    H --> I[SwapChainChanged.raise - boxed uint64_t]
    I --> J[TermControl::RenderEngineSwapChainChanged]
    J --> K[_AttachDxgiSwapChainToXaml]
```

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

### 参照テーブル一覧

該当なし（データベースは使用しない）

### 更新テーブル一覧

該当なし（データベースは使用しない）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| DuplicateHandle失敗 | プロセスハンドルの複製に失敗した場合 | THROW_IF_WIN32_BOOL_FALSEで例外スロー |
| weak_ptr失効 | ControlCoreがco_await中に破棄された場合 | nullチェックでスキップ |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし

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

スワップチェインハンドルはプロセス内リソースであり、DuplicateHandleにより安全に複製される。外部プロセスへの漏洩リスクはない。

## 備考

- ControlCore.idlではSwapChainChangedは「UIスレッドから常に呼び出される」カテゴリに分類されている
- _renderEngineSwapChainChangedはsafe_void_coroutineとして実装され、非同期的にUIスレッドへディスパッチする
- ソースハンドルはレンダリングエンジンが所有するweak refであるため、DuplicateHandleで強参照に変換する
- SwapChainHandle()プロパティは`_lastSwapChainHandle.get()`の値を返す
- Detach()時にはTriggerTeardown()がこのコルーチンの完了をブロッキング待機するため、_dispatcher参照は安全

---

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

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

### 推奨読解順序

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

SwapChainChangedは独自のEventArgsを持たず、uint64_t型のboxed valueが使用される。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ControlCore.idl | `src/cascadia/TerminalControl/ControlCore.idl` | 208行目: `event ... SwapChainChanged` - Object, Object型イベント |
| 1-2 | ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | 286行目: `til::typed_event<> SwapChainChanged` |
| 1-3 | ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | 397行目: `winrt::handle _lastSwapChainHandle{ nullptr }` - 複製されたスワップチェインハンドル |

**読解のコツ**: `safe_void_coroutine` はC++/WinRTのコルーチン戻り値型で、例外を安全に処理するfire-and-forgetコルーチンである。`winrt::handle` はWinRTのHANDLEラッパーで、スコープ終了時に自動的にCloseHandleを呼ぶ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | 428行目: Initialize内で `_renderEngineSwapChainChanged(handle)` が呼ばれる |

#### Step 3: 核心処理 _renderEngineSwapChainChanged

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | 1950-1978行目: _renderEngineSwapChainChanged コルーチン |

**主要処理フロー**:
- **1960-1962行目**: DuplicateHandleでソースハンドルを複製。THROW_IF_WIN32_BOOL_FALSEで失敗時に例外
- **1964行目**: `get_weak()` で弱参照を取得
- **1968行目**: `co_await wil::resume_foreground(_dispatcher)` でUIスレッドにディスパッチ
- **1970行目**: `weakThis.get()` でControlCoreの有効性チェック
- **1974行目**: `_lastSwapChainHandle = std::move(duplicatedHandle)` で保存
- **1976行目**: `SwapChainChanged.raise(*this, winrt::box_value<uint64_t>(...))` でイベント発火

#### Step 4: TermControl側ハンドラ

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | 304行目: `_revokers.SwapChainChanged = _core.SwapChainChanged(...)` でイベント購読 |
| 4-2 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | 1289-1294行目: RenderEngineSwapChainChanged - ハンドルをunbox_valueし_AttachDxgiSwapChainToXamlへ |

**主要処理フロー**:
- **1292行目**: `HANDLE h = reinterpret_cast<HANDLE>(winrt::unbox_value<uint64_t>(args))` でハンドル取得
- **1293行目**: `_AttachDxgiSwapChainToXaml(h)` でSwapChainPanelにアタッチ

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

```
AtlasEngine (レンダリングスレッド)
    |
    +-- SwapChain 作成/再作成
            |
            +-- SwapChainChangedCallback(handle)
                    |
                    +-- ControlCore::_renderEngineSwapChainChanged(sourceHandle)
                            |
                            +-- DuplicateHandle() [ハンドル複製]
                            +-- co_await wil::resume_foreground() [UIスレッドへ]
                            +-- _lastSwapChainHandle = duplicatedHandle
                            +-- SwapChainChanged.raise(boxed uint64_t)
                                    |
                                    +-- TermControl::RenderEngineSwapChainChanged()
                                            |
                                            +-- unbox_value<uint64_t>()
                                            +-- _AttachDxgiSwapChainToXaml(h)
```

### データフロー図

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

AtlasEngine          ControlCore                     TermControl
SwapChain       -->  DuplicateHandle()               -->  _AttachDxgiSwapChainToXaml()
HANDLE               co_await UIスレッド                    SwapChainPanel更新
                     _lastSwapChainHandle保存
                     SwapChainChanged.raise()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ControlCore.idl | `src/cascadia/TerminalControl/ControlCore.idl` | IDL | SwapChainChangedイベント宣言、SwapChainHandleプロパティ |
| ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | ソース | SwapChainChangedイベント定義、_lastSwapChainHandle |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | _renderEngineSwapChainChangedコルーチン |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | RenderEngineSwapChainChangedハンドラ |
| TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | ソース | ハンドラ宣言 |
