# 通知設計書 52-NOTIFICATION_WM_DPI_CHANGE

## 概要

本ドキュメントは、GodotエンジンにおけるDPI（Dots Per Inch）スケール変更時に発火するNOTIFICATION_WM_DPI_CHANGE通知の設計仕様を定義する。

### 本通知の処理概要

NOTIFICATION_WM_DPI_CHANGEは、ディスプレイのDPIスケールが変更された際にWindowノードおよびその子ノードに対して送信されるシステム通知である。この通知により、高DPIディスプレイへの切り替えや、ディスプレイ設定の変更を検知し、UIスケーリングやフォントサイズの調整などの処理を実行することができる。

**業務上の目的・背景**：現代のディスプレイ環境では、異なるDPIを持つ複数のモニター間でウィンドウを移動したり、システム設定でDPIスケールを変更したりすることが一般的である。アプリケーションがこれらの変更に適切に対応し、鮮明な表示を維持するためにこの通知が必要となる。特にRetinaディスプレイなどの高DPI環境での表示品質を確保するために重要である。

**通知の送信タイミング**：OSからDPI変更イベント（DisplayServer::WINDOW_EVENT_DPI_CHANGE）を受信した際に発火する。具体的には、ウィンドウが異なるDPIのディスプレイに移動した時や、システムのDPI設定が変更された時に送信される。

**通知の受信者**：DPI変更が発生したWindowノードおよび`_propagate_window_notification`を通じて伝播された子ノードが受信する。

**通知内容の概要**：通知値1009を持つ整数通知として送信される。追加のパラメータは含まれないが、受信時にDisplayServerのscreen_get_dpi()やWindow.content_scale_factorなどで現在のDPI情報を取得できる。

**期待されるアクション**：受信者はDPI変更に基づいてフォントサイズの調整、アイコン・画像のスケーリング、UIレイアウトの再計算などを実行することが期待される。

## 通知種別

エンジン内部通知（Object._notification経由）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | なし |

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

DPI変更が発生したWindowノードに対して`_propagate_window_notification`を通じて通知が伝播される。これにより、Window自身およびその子ノードが通知を受信する。

## 通知テンプレート

### 通知定数定義

| 項目 | 内容 |
|-----|------|
| 定数名 | NOTIFICATION_WM_DPI_CHANGE |
| 値 | 1009 |
| 定義場所 | scene/main/node.h |

### 受信処理例

```gdscript
func _notification(what):
    if what == NOTIFICATION_WM_DPI_CHANGE:
        var new_dpi = DisplayServer.screen_get_dpi()
        # DPI変更に応じたスケーリング処理を実行
        _update_ui_scale(new_dpi)
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| screen_dpi | 現在のスクリーンDPI | DisplayServer.screen_get_dpi() | No |
| content_scale_factor | コンテンツスケールファクター | Window.content_scale_factor | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| システムイベント | DisplayServer::WINDOW_EVENT_DPI_CHANGE | DPI変更検知時 | OSからのDPI変更イベント受信 |
| 環境変更 | ディスプレイ間移動 | 異なるDPIのディスプレイへ移動 | マルチモニター環境でのウィンドウ移動 |
| 設定変更 | システムDPI設定変更 | OS設定でDPIスケール変更 | ユーザーによるシステム設定変更 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ウィンドウ非アクティブ | ウィンドウがシーンツリーに存在しない場合 |
| DPI値同一 | 前回と同じDPI値の場合（OS依存） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[OSからDPI変更イベント受信] --> B[DisplayServer::process_events]
    B --> C[Window::_event_callback]
    C --> D{イベント種別判定}
    D -->|DPI_CHANGE| E[_update_viewport_size]
    E --> F[ビューポートDPI更新]
    F --> G[_propagate_window_notification]
    G --> H[NOTIFICATION_WM_DPI_CHANGE伝播]
    H --> I[dpi_changedシグナル発火]
    I --> J[終了]
```

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

### 参照テーブル一覧

該当なし（データベースを使用しない内部通知）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ウィンドウ無効 | Windowノードが無効な状態で呼び出された場合 | 処理をスキップ |
| DPI取得失敗 | DPI情報が取得できない場合 | デフォルト値（96）を使用 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（DPI変更イベントに応じて随時発火）

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

特別な考慮事項なし。内部通知であり、外部からのアクセスは不可。

## 備考

- macOSプラットフォームでのみ実装されている（公式ドキュメントに明記）
- DPI変更時にはビューポートサイズも同時に更新される
- dpi_changedシグナルも同時に発火される
- 高DPIサポートを実装する際の主要なエントリーポイント

---

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

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

### 推奨読解順序

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

通知の定数値とその定義場所を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | node.h | `scene/main/node.h` | NOTIFICATION_WM_DPI_CHANGE = 1009 の定義（484行目） |

**読解のコツ**: Nodeクラスのenum定義を確認し、DPI関連の通知がどのように定義されているか確認する。

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

通知の発火元となるWindowクラスの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | window.cpp | `scene/main/window.cpp` | WINDOW_EVENT_DPI_CHANGEの処理（857-860行目） |

**主要処理フロー**:
1. **857行目**: `case DisplayServer::WINDOW_EVENT_DPI_CHANGE:` - DPI変更イベントの判定
2. **858行目**: `_update_viewport_size()` - ビューポートサイズの更新
3. **859行目**: `_propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE)` - 通知の伝播
4. **860行目**: `emit_signal(SNAME("dpi_changed"))` - シグナルの発火

#### Step 3: 通知伝播処理を理解する

_propagate_window_notificationメソッドの詳細を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | window.cpp | `scene/main/window.cpp` | _propagate_window_notification()メソッドの実装 |

**主要処理フロー**:
- Windowノード自身への通知発火
- 子ノードへの再帰的な通知伝播

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

```
DisplayServer (OS - macOS)
    │
    ├─ Window::_event_callback()
    │      │
    │      └─ WINDOW_EVENT_DPI_CHANGE イベント
    │             │
    │             ├─ _update_viewport_size()
    │             │
    │             ├─ _propagate_window_notification()
    │             │      │
    │             │      └─ notification(NOTIFICATION_WM_DPI_CHANGE)
    │             │             │
    │             │             └─ 子ノードへ再帰的に伝播
    │             │
    │             └─ emit_signal("dpi_changed")
    │
    └─ ユーザー定義処理
```

### データフロー図

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

OS DPI変更       DisplayServer           Window通知
イベント    ───▶ イベント処理   ───▶    発火
                      │
                      ▼
              ビューポートDPI
                  更新処理
                      │
                      ├───▶ NOTIFICATION_WM_DPI_CHANGE
                      │
                      └───▶ dpi_changed シグナル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| node.h | `scene/main/node.h` | ソース | 通知定数の定義 |
| node.cpp | `scene/main/node.cpp` | ソース | Nodeベースクラスの通知処理 |
| window.cpp | `scene/main/window.cpp` | ソース | Window通知の発火処理 |
| window.h | `scene/main/window.h` | ソース | Windowクラス定義 |
| Node.xml | `doc/classes/Node.xml` | ドキュメント | 通知の公式ドキュメント |
