# 通知設計書 38-TitleChanged

## 概要

本ドキュメントは、Windows Terminal におけるターミナルタイトル変更通知（TitleChanged）の設計仕様を記述する。TitleChanged は、ターミナルのタイトル（ウィンドウタイトル）が変更された際に発火するイベントであり、シェルやアプリケーションが VT シーケンスでタイトルを設定した場合に、タブのタイトル表示を更新するために使用される。

### 本通知の処理概要

TitleChanged は、Terminal コアがタイトル変更コマンド（OSC 0/2 シーケンス等）を受信した際に発火する通知機構であり、変更後のタイトル文字列を含む TitleChangedEventArgs を伝達する。

**業務上の目的・背景**：ターミナルアプリケーションでは、現在実行中のコマンドやカレントディレクトリに応じてタブのタイトルが動的に変わることが一般的である。シェル（bash, PowerShell 等）は VT エスケープシーケンスを使用してターミナルタイトルを設定する。TitleChanged イベントはこのタイトル変更をアプリケーション層に伝達し、タブヘッダーやウィンドウタイトルの表示を最新の状態に保つために不可欠である。

**通知の送信タイミング**：Terminal コアの SetWindowTitle メソッドが呼ばれた際（_suppressApplicationTitle が false の場合）に _pfnTitleChanged コールバックを経由して発火する。ControlCore の `_terminalTitleChanged` メソッドで TitleChangedEventArgs が生成される。

**通知の受信者**：ControlCore が TitleChanged イベントを発火し、TermControl がバブル（BUBBLED_FORWARDED_TYPED_EVENT）し、TerminalPaneContent の _controlTitleChanged を経由して BasicPaneEvents.TitleChanged が発火される。最終的に Tab がスロットル付きハンドラーで受信し、タブタイトルを更新する。

**通知内容の概要**：変更後のタイトル文字列（Title, hstring型）を含む TitleChangedEventArgs。

**期待されるアクション**：Tab はタイトル更新処理（UpdateTitle）を実行し、タブヘッダーの表示を最新のタイトルに更新する。TerminalPage はウィンドウタイトルの更新を行う場合もある。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（バックグラウンドスレッドから発火、Tab 側でスロットル + UIスレッドディスパッチ） |
| 優先度 | 中（UI表示更新） |
| リトライ | なし |

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

Terminal コアが VT シーケンスのタイトル設定コマンドを処理し、SetWindowTitle メソッド内で _pfnTitleChanged コールバックを呼び出す。ControlCore、TermControl、TerminalPaneContent、Tab の各層でイベントチェーンが構成される。

## 通知テンプレート

### メール通知の場合

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

### 本文テンプレート

該当なし（TitleChangedEventArgs.Title プロパティで新しいタイトルを伝達）

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Title | 変更後のタイトル文字列（hstring） | Terminal コアの _title プロパティ | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| VT シーケンス | OSC 0/2 タイトル設定シーケンス | _suppressApplicationTitle が false の場合 | シェルやアプリケーションからのタイトル設定 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| _suppressApplicationTitle が true | アプリケーションタイトルの抑制設定が有効な場合、SetWindowTitle 内でタイトル変更が無視される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[シェルが VT シーケンスでタイトルを設定] --> B[Terminal::SetWindowTitle]
    B --> C{_suppressApplicationTitle?}
    C -->|true| D[タイトル変更無視]
    C -->|false| E[_title を更新]
    E --> F[_pfnTitleChanged コールバック呼び出し]
    F --> G[ControlCore._terminalTitleChanged]
    G --> H[TitleChangedEventArgs 生成<br/>Title]
    H --> I[TitleChanged.raise イベント発火]
    I --> J[TermControl バブル処理]
    J --> K[TerminalPaneContent._controlTitleChanged]
    K --> L[BasicPaneEvents.TitleChanged.raise]
    L --> M[Tab スロットル付きハンドラー]
    M --> N[UpdateTitle でタブタイトル更新]
```

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

### 参照テーブル一覧

該当なし（インメモリイベント処理のみ）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 空タイトル | タイトルが空文字列の場合 | _startingTitle（初期タイトル）にフォールバック |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | Tab 側でスロットル制御（200ms、leading + trailing） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし

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

- タイトル文字列にはシェルから送信される任意のテキストが含まれる可能性がある
- タイトル文字列はプロセス内のUI表示のみに使用される

## 備考

- タイトルが空文字列の場合、Terminal コアは _startingTitle にフォールバックする
- TitleChanged イベントは ControlCore.idl で「バックグラウンドスレッドから呼ばれるイベント」グループに属する（行191）
- Tab のハンドラーでは ThrottledFunc を使用し、200ms のスロットル（leading + trailing）で頻繁なタイトル更新を抑制する
- TermControl.h では BUBBLED_FORWARDED_TYPED_EVENT マクロでバブル処理される（行224）
- Terminal コアの SetWindowTitle は書き込みロック取得状態で呼び出されるため、コールバック内で追加のロックは不要

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | TitleChangedEventArgs の IDL 定義（行53-56）。String Title プロパティ |
| 1-2 | EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | C++ 実装（行42-49）。コンストラクタで hstring を受け取る |

**読解のコツ**: TitleChangedEventArgs は Title プロパティ1つのみを持つシンプルな構造。

#### Step 2: Terminal コアでの発火起点

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | TerminalApi.cpp | `src/cascadia/TerminalCore/TerminalApi.cpp` | SetWindowTitle（行84-91）。_suppressApplicationTitle チェック後に _pfnTitleChanged 呼び出し |
| 2-2 | Terminal.hpp | `src/cascadia/TerminalCore/Terminal.hpp` | SetTitleChangedCallback 宣言（行225） |

**主要処理フロー**:
1. **行86-88**: _suppressApplicationTitle が false の場合、タイトルを更新
2. **行90**: `_pfnTitleChanged(_title.value())` でコールバック呼び出し

#### Step 3: ControlCore でのイベント生成

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | コールバック設定（行115-116）と _terminalTitleChanged 実装（行1599-1604） |
| 3-2 | ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | TitleChanged イベント宣言（行276） |

#### Step 4: イベントチェーン

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | BUBBLED_FORWARDED_TYPED_EVENT(TitleChanged, ...) マクロ（行224） |
| 4-2 | TerminalPaneContent.cpp | `src/cascadia/TerminalApp/TerminalPaneContent.cpp` | _controlTitleChanged（行164-167）。TitleChanged.raise で再発火 |
| 4-3 | Tab.cpp | `src/cascadia/TerminalApp/Tab.cpp` | TitleChanged ハンドラー登録（行1047-1065）。ThrottledFunc でスロットル制御 |

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

```
Terminal::SetWindowTitle(title)
    |
    +-- [if !_suppressApplicationTitle]
           _title = title (空の場合は _startingTitle)
           _pfnTitleChanged(_title.value())
                  |
                  +-- ControlCore::_terminalTitleChanged(wstr)
                         |
                         +-- TitleChanged.raise(TitleChangedEventArgs{title})
                                |
                                +-- TermControl::BUBBLED_FORWARDED_TYPED_EVENT
                                       |
                                       +-- TerminalPaneContent::_controlTitleChanged
                                       |       |
                                       |       +-- BasicPaneEvents.TitleChanged.raise
                                       |              |
                                       |              +-- Tab (ThrottledFunc 200ms)
                                       |                     +-- UpdateTitle()
```

### データフロー図

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

VT シーケンス                  Terminal コア -> ControlCore         Tab / UI
(OSC 0/2 タイトル設定)  -->  SetWindowTitle()                -->  UpdateTitle()
                              _pfnTitleChanged                     タブヘッダー更新
                              TitleChangedEventArgs生成
                              バブル処理 -> スロットル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | IDL定義 | TitleChangedEventArgs の WinRT インターフェース定義 |
| EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | ソース | TitleChangedEventArgs の C++ 実装 |
| TerminalApi.cpp | `src/cascadia/TerminalCore/TerminalApi.cpp` | ソース | SetWindowTitle メソッド実装 |
| Terminal.hpp | `src/cascadia/TerminalCore/Terminal.hpp` | ソース | SetTitleChangedCallback 宣言 |
| ControlCore.idl | `src/cascadia/TerminalControl/ControlCore.idl` | IDL定義 | TitleChanged イベント宣言 |
| ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | ソース | TitleChanged の til::typed_event 宣言 |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | コールバック設定と _terminalTitleChanged 実装 |
| TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | ソース | BUBBLED_FORWARDED_TYPED_EVENT マクロ |
| BasicPaneEvents.h | `src/cascadia/TerminalApp/BasicPaneEvents.h` | ソース | BasicPaneEvents の TitleChanged 定義 |
| TerminalPaneContent.cpp | `src/cascadia/TerminalApp/TerminalPaneContent.cpp` | ソース | _controlTitleChanged ハンドラー |
| Tab.cpp | `src/cascadia/TerminalApp/Tab.cpp` | ソース | TitleChanged ハンドラーとスロットル制御 |
