# 通知設計書 25-CM_UPDATE_TITLE

## 概要

本ドキュメントは、Windows TerminalにおけるCM_UPDATE_TITLEウィンドウメッセージ通知の設計を記述する。ターミナルのタイトルが変更された際に、レンダラーからウィンドウプロシージャに対してウィンドウタイトルの更新を要求するカスタムWindowsメッセージである。

### 本通知の処理概要

CM_UPDATE_TITLEは、ターミナルのタイトル文字列が変更された際にPostMessageWを使用してウィンドウメッセージキューに投入されるカスタムメッセージである。コンソールホスト（conhost）とWindows Terminal（Cascadia）の両方で使用されるが、メッセージIDの定義は異なる。

**業務上の目的・背景**：ターミナルのタイトルはシェルやアプリケーションによって頻繁に変更される（カレントディレクトリ、実行中のコマンド名等）。タイトルの更新はレンダリングスレッドで検知されるが、ウィンドウタイトルの変更（SetWindowTextW）はメインGUIスレッドで行う必要がある。このクロススレッド通信を実現するためにカスタムウィンドウメッセージが使用される。

**通知の送信タイミング**：レンダラーがタイトル変更を検知した際にPostMessageWで送信される。GDIエンジンでは`_DoUpdateTitle`メソッド内、AtlasエンジンではStartPaint処理内で送信される。

**通知の受信者**：対象のコンソールウィンドウ（HWND）のウィンドウプロシージャが受信する。conhostではWindow::ConsoleWindowProc、Windows TerminalではBaseWindow::MessageHandler。

**通知内容の概要**：タイトル更新要求のシグナルのみ。実際のタイトル文字列は別途クエリされる。

**期待されるアクション**：ウィンドウプロシージャがSetWindowTextWを呼び出してウィンドウタイトルバーのテキストを更新する。

## 通知種別

ウィンドウメッセージ通知（カスタムWindowsメッセージ: WM_USER+N）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（PostMessageW） |
| 優先度 | 低 |
| リトライ | 無 |

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

レンダラーが保持するターゲットウィンドウハンドル（HWND）に対して直接PostMessageWで送信する。conhostでは`_hwndTargetWindow`、AtlasEngineでは`_api.s->target->hwnd`、Windows Terminalでは`_window.get()`が使用される。

## 通知テンプレート

### conhost側（GDI/Atlas）

| 項目 | 内容 |
|-----|------|
| メッセージID | CM_UPDATE_TITLE (WM_USER + 5) |
| wParam | 0 |
| lParam | nullptr (0) |

### Windows Terminal側（BaseWindow）

| 項目 | 内容 |
|-----|------|
| メッセージID | CM_UPDATE_TITLE (WM_USER + 0) |
| wParam | 0 |
| lParam | nullptr (0) |

### 本文テンプレート

```
PostMessageW(hwnd, CM_UPDATE_TITLE, 0, 0)
```

### 添付ファイル

該当なし

## テンプレート変数

該当なし（メッセージパラメータは固定値。タイトル文字列は受信側で別途取得）

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 内部処理 | GdiEngine::_DoUpdateTitle | PostMessageWが成功すること | GDIレンダラーがタイトル変更を検知した際 |
| 内部処理 | AtlasEngine::StartPaint | _api.invalidatedTitleがtrueかつHWNDが有効 | Atlasレンダラーがタイトル変更を検知した際 |
| 内部処理 | BaseWindow::UpdateTitle | _windowが有効 | Windows TerminalのXAMLベースウィンドウでのタイトル更新 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| HWNDが無効 | ウィンドウハンドルがnullの場合 |
| AtlasEngine: タイトル未変更 | _api.invalidatedTitleがfalseの場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[タイトル変更検知] --> B{レンダラー種別}
    B -->|GDI| C[GdiEngine::_DoUpdateTitle]
    B -->|Atlas| D[AtlasEngine::StartPaint]
    B -->|BaseWindow| E[BaseWindow::UpdateTitle]
    C --> F[PostMessageW CM_UPDATE_TITLE]
    D --> G{invalidatedTitle?}
    G -->|Yes| F
    G -->|No| H[スキップ]
    E --> I[_titleを更新]
    I --> F
    F --> J[ウィンドウプロシージャで受信]
    J --> K[SetWindowTextW呼び出し]
    K --> L[タイトルバー更新完了]
    H --> L
```

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

### 参照テーブル一覧

該当なし

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| PostMessageW失敗 | ウィンドウが既に破棄されている等 | GDIEngineではE_FAILを返す。AtlasEngineではLOG_IF_WIN32_BOOL_FALSEでログ記録 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0 |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

明示的なレート制限はないが、レンダラーのフレーム描画サイクルに紐づくため、事実上フレームレートによって制限される。

### 配信時間帯

制限なし

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

- ウィンドウメッセージはプロセス内またはOSメッセージキュー経由で送信される
- タイトル文字列自体はメッセージパラメータに含まれず、受信側で内部データから取得するため、メッセージ傍受による情報漏洩リスクは低い

## 備考

- conhostとWindows Terminal（BaseWindow）でCM_UPDATE_TITLEのメッセージIDが異なる（conhost: WM_USER+5、BaseWindow: WM_USER+0）
- GDIレンダラーではタイトル文字列をメッセージパラメータに含めず、受信側のウィンドウプロシージャがgci.GetTitleAndPrefix()を呼び出して取得する
- BaseWindow側では_titleメンバ変数にタイトルを保存してからPostMessageWを呼び出し、受信側で_title.c_str()を使用する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CustomWindowMessages.h | `src/interactivity/win32/CustomWindowMessages.h` | CM_UPDATE_TITLEの定義（行12: WM_USER + 5） |
| 1-2 | BaseWindow.h | `src/cascadia/WindowsTerminal/BaseWindow.h` | CM_UPDATE_TITLEの定義（行10: WM_USER + 0） |

**読解のコツ**: conhostとWindows Terminalで異なるメッセージIDが使用されていることに注意。同じ名前だが別の値が定義されている。

#### Step 2: 送信側（GDIレンダラー）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | state.cpp | `src/renderer/gdi/state.cpp` | _DoUpdateTitle関数（行576-579）。PostMessageWでCM_UPDATE_TITLEを送信 |

**主要処理フロー**:
- **行578-579**: `PostMessageW(_hwndTargetWindow, CM_UPDATE_TITLE, 0, nullptr)` で送信

#### Step 3: 送信側（Atlasレンダラー）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AtlasEngine.cpp | `src/renderer/atlas/AtlasEngine.cpp` | StartPaint内のタイトル更新処理（行67-71） |

**主要処理フロー**:
- **行67**: `_api.invalidatedTitle` のチェック
- **行69**: `PostMessageW(hwnd, CM_UPDATE_TITLE, 0, 0)` で送信
- **行70**: `_api.invalidatedTitle = false` でフラグリセット

#### Step 4: 送信側（BaseWindow）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BaseWindow.h | `src/cascadia/WindowsTerminal/BaseWindow.h` | UpdateTitle関数（行174-178） |

**主要処理フロー**:
- **行176**: `_title = newTitle` でタイトルを保存
- **行177**: `PostMessageW(_window.get(), CM_UPDATE_TITLE, 0, nullptr)` で送信

#### Step 5: 受信側を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | windowproc.cpp | `src/interactivity/win32/windowproc.cpp` | CM_UPDATE_TITLEハンドラ（行726-733） |
| 5-2 | BaseWindow.h | `src/cascadia/WindowsTerminal/BaseWindow.h` | CM_UPDATE_TITLEハンドラ（行81-85） |

**主要処理フロー**:
- **windowproc.cpp 行729**: `gci.GetTitleAndPrefix()` でタイトル取得
- **windowproc.cpp 行731**: `SetWindowTextW(hWnd, titleAndPrefix.c_str())` でタイトルバー更新
- **BaseWindow.h 行83**: `SetWindowTextW(_window.get(), _title.c_str())` でタイトルバー更新

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

```
[conhost]
GdiEngine::_DoUpdateTitle (state.cpp:576)
    |
    +-- PostMessageW(CM_UPDATE_TITLE = WM_USER+5)
           |
           +-- Window::ConsoleWindowProc (windowproc.cpp:726)
                  |
                  +-- SetWindowTextW(gci.GetTitleAndPrefix())

AtlasEngine::StartPaint (AtlasEngine.cpp:67)
    |
    +-- PostMessageW(CM_UPDATE_TITLE = WM_USER+5)
           |
           +-- (同上)

[Windows Terminal]
BaseWindow::UpdateTitle (BaseWindow.h:174)
    |
    +-- PostMessageW(CM_UPDATE_TITLE = WM_USER+0)
           |
           +-- BaseWindow::MessageHandler (BaseWindow.h:81)
                  |
                  +-- SetWindowTextW(_title.c_str())
```

### データフロー図

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

タイトル文字列変更       PostMessageW                   ウィンドウタイトルバー
(シェル/アプリ)  -----> CM_UPDATE_TITLE           ---->  SetWindowTextW
                        |                                 タイトルテキスト更新
                        v
                  ウィンドウプロシージャ
                  (メインGUIスレッド)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CustomWindowMessages.h | `src/interactivity/win32/CustomWindowMessages.h` | ソース（ヘッダ） | conhost用CM_UPDATE_TITLEメッセージID定義 |
| BaseWindow.h | `src/cascadia/WindowsTerminal/BaseWindow.h` | ソース（ヘッダ） | Windows Terminal用CM_UPDATE_TITLEメッセージID定義と処理 |
| state.cpp | `src/renderer/gdi/state.cpp` | ソース（実装） | GDIレンダラーからの送信 |
| AtlasEngine.cpp | `src/renderer/atlas/AtlasEngine.cpp` | ソース（実装） | Atlasレンダラーからの送信 |
| windowproc.cpp | `src/interactivity/win32/windowproc.cpp` | ソース（実装） | conhost側の受信処理 |
