# 通知設計書 42-TransparencyChanged

## 概要

本ドキュメントは、Windows Terminal における TransparencyChanged イベントの設計仕様を記述する。このイベントは、ターミナルウィンドウの透過度（Opacity）が変更された際に発火し、UI層に透過度の更新を通知する。

### 本通知の処理概要

TransparencyChangedイベントは、ターミナルの背景透過度が変更されたことをUI層に伝えるためのイベントである。透過度の変更はユーザーのAdjustOpacityアクション、フォーカス/アンフォーカス切り替え時のApplyAppearance、またはAdjustOpacity API呼び出しによって発生する。ControlCore内で新しい透過度が計算・適用された後、TransparencyChangedEventArgsに新しいOpacity値を格納してイベントが発火される。

**業務上の目的・背景**：Windows Terminalはウィンドウ背景の透過度をリアルタイムに調整する機能を提供している。ユーザーがCtrl+Shift+マウスホイール等で透過度を変更した際、UIのブラシ（Acrylic/SolidColor）を適切に更新する必要がある。この通知により、TermControlがバックグラウンドの描画方式を即座に切り替えることができる。

**通知の送信タイミング**：透過度が実際に変更された時（新旧の値が異なる場合のみ）に発火する。具体的には、_setOpacity()内で新しいOpacityが現在値と異なる場合、およびApplyAppearance()でフォーカス/アンフォーカスの外観が適用される際に発火する。

**通知の受信者**：TermControlの_coreTransparencyChangedハンドラがControlCoreからのイベントを受信する。TermControlは_changeBackgroundOpacity()を呼び出して背景ブラシの透過度を更新する。

**通知内容の概要**：TransparencyChangedEventArgsオブジェクトにOpacity（float型、0.0〜1.0）が格納される。

**期待されるアクション**：受信側（TermControl）は背景ブラシのOpacityを更新し、必要に応じてAcrylicブラシとSolidColorブラシの切り替えを行う。

## 通知種別

アプリ内通知（WinRT イベント）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（UIスレッドから発火） |
| 優先度 | 中 |
| リトライ | 無し |

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

ControlCoreがTransparencyChangedイベントを発火し、TermControlがwinrt::auto_revokeで購読している。TermControlの_coreTransparencyChangedが呼び出される。

## 通知テンプレート

### メール通知の場合

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

### 本文テンプレート

```
該当なし（TransparencyChangedEventArgsとしてOpacity値が伝達される）
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Opacity | 新しい透過度（0.0〜1.0） | ControlCore._runtimeOpacity | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ユーザー操作 | AdjustOpacity アクション | Opacityの値が変化した場合 | Ctrl+Shift+マウスホイール等による透過度調整 |
| 内部処理 | ApplyAppearance(focused) | Opacityの値が変化した場合 | フォーカス/アンフォーカス切り替え時の外観適用 |
| API呼び出し | AdjustOpacity(opacity, relative) | Opacityの値が変化した場合 | 相対/絶対指定による透過度設定 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 新旧Opacityが同一 | _setOpacity()内で `newOpacity == Opacity()` の場合はearly returnする |
| adjustment == 0 | AdjustOpacity()で調整量が0の場合はearly returnする |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[トリガー: AdjustOpacity/ApplyAppearance] --> B[_setOpacity呼び出し]
    B --> C{新旧Opacityが異なるか?}
    C -->|同一| D[送信スキップ]
    C -->|異なる| E[_runtimeOpacity更新]
    E --> F[_runtimeUseAcrylic更新]
    F --> G[レンダラー透過設定更新]
    G --> H[TransparencyChangedEventArgs生成]
    H --> I[TransparencyChanged.raise]
    I --> J[TermControl::_coreTransparencyChanged]
    J --> K[_changeBackgroundOpacity]
    D --> L[終了]
    K --> L
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| CATCH_LOG | _coreTransparencyChangedハンドラ内で例外が発生した場合 | CATCH_LOG()でログ出力し処理続行 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし

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

透過度設定は純粋なUI設定であり、個人情報や機密情報を含まない。0.0〜1.0の範囲にclampされるため、異常値が伝搬されることはない。

## 備考

- ControlCore.idlでは `event Windows.Foundation.TypedEventHandler<Object, TransparencyChangedEventArgs> TransparencyChanged` として「UIスレッドから常に呼び出される」カテゴリに分類されている
- Opacityは `std::clamp(opacity, 0.0f, 1.0f)` で正規化される
- Opacity < 1.0f && UseAcrylic設定有効時にAcrylicが自動的に適用される
- RUNTIME_SETTINGマクロにより、ランタイム上書き値が設定値より優先される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | 104-107行目: TransparencyChangedEventArgs定義（Opacityプロパティ） |
| 1-2 | EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | 161-170行目: TransparencyChangedEventArgs実装。コンストラクタでfloat opacityを受け取る |
| 1-3 | ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | 268-270行目: RUNTIME_SETTINGマクロによるOpacity/FocusedOpacity/UseAcrylicの定義 |

**読解のコツ**: RUNTIME_SETTINGマクロは、ランタイムで設定された値（_runtimeXxx）があればそれを返し、なければ設定ファイルの値を返すプロパティを生成する。`til::coalesce_value`がそのロジックを担う。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | 744-751行目: AdjustOpacity(float)、2434-2442行目: AdjustOpacity(float, bool)の2つのオーバーロード |

**主要処理フロー**:
1. **744-751行目**: `AdjustOpacity(adjustment)` - adjustmentが0でなければ `_setOpacity(Opacity() + adjustment)` を呼ぶ
2. **2434-2442行目**: `AdjustOpacity(opacityAdjust, relative)` - relativeならAdjustOpacity(opacityAdjust)、絶対値なら_setOpacity(opacityAdjust)

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | 761-791行目: _setOpacity実装。clamp、_runtimeOpacity更新、レンダラー更新、イベント発火 |

**主要処理フロー**:
- **763行目**: `std::clamp(opacity, 0.0f, 1.0f)` で正規化
- **765-768行目**: 新旧値比較、同一ならearly return
- **771行目**: `_runtimeOpacity = newOpacity` でランタイム値を更新
- **775行目**: focusedフラグに応じて`_runtimeFocusedOpacity`を更新
- **778行目**: `_runtimeUseAcrylic` を透過度とUseAcrylic設定に基づき決定
- **782-787行目**: レンダラーの透過背景設定を更新
- **789-790行目**: `TransparencyChangedEventArgs`を生成しイベント発火

#### Step 4: ApplyAppearanceからの発火

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | 960-991行目: ApplyAppearance内で_setOpacity呼び出しとTransparencyChanged発火 |

**主要処理フロー**:
- **973行目**: `_setOpacity(newOpacity, focused)` 呼び出し
- **987-988行目**: ApplyAppearance完了後にTransparencyChanged.raiseを明示的に再発火

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | 311行目: イベント購読、2175-2181行目: _coreTransparencyChangedハンドラ |

**主要処理フロー**:
- **2179行目**: `_changeBackgroundOpacity()` を呼び出して背景ブラシを更新

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

```
TermControl::AdjustOpacity() / キーバインド
    |
    +-- ControlCore::AdjustOpacity(float adjustment)
    |       |
    |       +-- ControlCore::_setOpacity(opacity)
    |               |
    |               +-- _runtimeOpacity 更新
    |               +-- _runtimeUseAcrylic 更新
    |               +-- _renderEngine->EnableTransparentBackground()
    |               +-- TransparencyChanged.raise()
    |                       |
    |                       +-- TermControl::_coreTransparencyChanged()
    |                               |
    |                               +-- _changeBackgroundOpacity()
    |
    +-- ControlCore::ApplyAppearance(focused)
            |
            +-- ControlCore::_setOpacity(newOpacity, focused)
            +-- TransparencyChanged.raise()
```

### データフロー図

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

AdjustOpacity       ControlCore::_setOpacity()       TransparencyChangedEventArgs
(float adjustment)  --> clamp(0.0, 1.0)               --> Opacity: float
                    --> _runtimeOpacity更新
                    --> レンダラー透過設定
                    --> TransparencyChanged.raise()   --> TermControl
                                                          _changeBackgroundOpacity()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | IDL | TransparencyChangedEventArgs定義 |
| EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | ソース | TransparencyChangedEventArgs実装 |
| EventArgs.cpp | `src/cascadia/TerminalControl/EventArgs.cpp` | ソース | EventArgs関連ファクトリ |
| ControlCore.idl | `src/cascadia/TerminalControl/ControlCore.idl` | IDL | TransparencyChangedイベント宣言 |
| ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | ソース | TransparencyChangedイベント定義、RUNTIME_SETTING定義 |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | _setOpacity/AdjustOpacity/ApplyAppearance実装 |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | _coreTransparencyChangedハンドラ |
| TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | ソース | ハンドラ宣言 |
