BlinkGTK 描画経路のライブ切替と引き継ぎメタ (BlinkShift)

バージョン: 1.2.1-build3
最終更新: 2026-09-01
言語: 日本語 |

English


このページについて

アプリケーションを再起動せずに描画経路を切り替える API と、切替を跨いで
状態を引き継ぐ Handoff Meta のリファレンスです。

切替そのもの (blink_web_view_switch_render_path()render-path-changed
シグナル) の詳細は signals-api-ja.md にあります。本ページは
引き継ぎメタを中心に、切替と組み合わせて使う形をまとめます。


1. 何のための API か

描画経路には長所と短所があります。CPU 合成は互換性が高く、GPU の dmabuf 直渡しは
帯域とCPU に有利です。読者の環境や場面によって、望ましい経路は変わります。

従来は経路を変えるためにプロセスを起動し直していました。読者から見ると数秒の
中断です。BlinkShift はこれを同一プロセス内の切替にします。

引き継ぎメタは「切替を跨いで何を保つか」を、経路に依存しない中間表現で表します。


2. 単位の約束

幾何は論理 px と明示的な倍率で持ちます。

物理 px = logical × device_scale_factor

物理 px をそのまま渡す形にしないのは、受け取る側が倍率を推測する必要をなくすため
です。倍率の解釈が両側でずれると、表示が半分の大きさになるなどの形で現れます。


3. 構造体

#define BLINK_HANDOFF_META_SCHEMA_VERSION 1

typedef struct _BlinkHandoffMeta {
  int   schema_version;       /* == BLINK_HANDOFF_META_SCHEMA_VERSION */
  int   logical_width;        /* 幾何: 論理 px */
  int   logical_height;
  int   device_scale_factor;  /* 物理 px = logical × これ */
  char* url;                  /* 内容: 現在の URL (所有) */
  int   scroll_x;             /* 論理 px */
  int   scroll_y;
  char* path_id;              /* 出力経路: "software" / "egl" など (所有) */
} BlinkHandoffMeta;

schema_version は前方互換のためにあります。読み込む側は自分が知っている版と
一致するかを確かめてから
内容を使ってください。


4. 関数

関数 役割
blink_web_view_export_handoff_meta() 現在の状態をメタに書き出す。戻り値は呼出側が解放
blink_web_view_import_handoff_meta() メタから状態を復元する
blink_handoff_meta_serialize() メタをテキストにする。戻り値は呼出側が解放
blink_handoff_meta_deserialize() テキストからメタを作る。戻り値は呼出側が解放
blink_handoff_meta_free() メタを解放する
BlinkHandoffMeta* blink_web_view_export_handoff_meta(BlinkWebView* web_view);
void  blink_web_view_import_handoff_meta(BlinkWebView* web_view,
                                         const BlinkHandoffMeta* meta);
char* blink_handoff_meta_serialize(const BlinkHandoffMeta* meta);
BlinkHandoffMeta* blink_handoff_meta_deserialize(const char* text);
void  blink_handoff_meta_free(BlinkHandoffMeta* meta);

export は失敗すると NULL を返します。serialize の戻り値は free()
deserializeexport の戻り値は blink_handoff_meta_free() で解放します。

直列化の形式は INI 互換のテキストで、セッション保存ファイルと同じ読み方が
できます。


5. 引き継ぐもの・引き継がないもの

含むのは経路に依存しない意味状態だけです。

含む 含まない
幾何 (論理 px + 倍率) EGL コンテキスト
URL Wayland サーフェス
スクロール位置 (論理 px) dmabuf のファイル記述子
出力経路の id サーフェス識別子

含まないものは切替のたびに作り直されます。生の資源を持ち回らないので、切替に
失敗しても前の経路へ戻せます。

現時点でメタに載っていないもの

次の状態はエンジンからは意味を判定できないため、メタには載せていません。

エンジンが値の正しさを検証できないものに型を付けると、型があるのに中身を保証
できない形になります。これらはアプリケーション側で保存・復元してください。

版面の幾何 (列ピッチなど) は縦書きメトリクスの API から取得できます。メタに
写しを持たせると、片方だけ古くなったときに気付けません。


6. 使い方

切替の前後でメタを採り、同じ状態に戻っているかを確かめる形です。切替は非同期
なので、完了はシグナルで受け取ります

#include <blink_gtk/blink_gtk.h>
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int   g_seq = 0;
static char* g_before = NULL;

static void on_render_path_changed(BlinkWebView* view,
                                   const char* to,
                                   const char* result,
                                   int gate_ms,
                                   int seq,
                                   gpointer user_data) {
  (void)user_data;
  if (seq != g_seq) {
    return;  /* 別の切替の通知。鍵が違えば触らない */
  }
  if (strcmp(result, "ok") != 0) {
    printf("切替できませんでした (%s)。前の経路のままです\n", result);
    return;
  }
  BlinkHandoffMeta* after = blink_web_view_export_handoff_meta(view);
  if (after != NULL) {
    char* text = blink_handoff_meta_serialize(after);
    printf("経路=%s  %d ms\n", to, gate_ms);
    printf("  前: %s", g_before != NULL ? g_before : "(採れず)\n");
    printf("  後: %s", text != NULL ? text : "(採れず)\n");
    free(text);
    blink_handoff_meta_free(after);
  }
}

static void request_switch(BlinkWebView* view, const char* path_id) {
  BlinkHandoffMeta* before = blink_web_view_export_handoff_meta(view);
  if (before != NULL) {
    free(g_before);
    g_before = blink_handoff_meta_serialize(before);
    blink_handoff_meta_free(before);
  }
  g_seq = blink_web_view_switch_render_path(view, path_id);
  if (g_seq == 0) {
    printf("切替の要求が受け付けられませんでした\n");
  }
}

int main(int argc, char** argv) {
  blink_gtk_init(&argc, &argv);
  GtkWidget* window = gtk_window_new();
  GtkWidget* widget = blink_web_view_new();
  BlinkWebView* view = BLINK_WEB_VIEW(widget);

  g_signal_connect(view, "render-path-changed",
                   G_CALLBACK(on_render_path_changed), NULL);
  gtk_window_set_child(GTK_WINDOW(window), widget);
  gtk_window_set_default_size(GTK_WINDOW(window), 1024, 768);
  blink_web_view_load_uri(view, "https://example.com/");
  gtk_widget_set_visible(window, TRUE);

  request_switch(view, "P2");

  blink_gtk_run_main_loop();
  free(g_before);
  blink_gtk_shutdown();
  return 0;
}

通知を切替と結びつける

blink_web_view_switch_render_path() は受理した切替の通し番号を返します
(1 以上。0 は受理されなかったことを表します)。完了シグナルの seq 引数には
同じ番号が入ります。

切替が続けて起きる場面では、時刻の近さで前後を結びつけると別の切替の記録を
突き合わせてしまいます
。しかも一致したように見えるので、間違いに気付けません。
番号で結んでください。

結果の 3 値

result 意味
ok 新しい経路で安定して描けている
rollback 新しい経路が確認に落ち、前の経路へ戻した。表示は保たれている
fail 前の経路へ戻せなかった。異常として扱う

rollback は失敗ですが、読者の画面は壊れません。


7. 経路の id

id 内容
P1 CPU 合成の直接配送 (既定)
P2 CPU 合成の共有メモリ配送
P3 GPU の dmabuf 配送。出力層だけを差し替えるため、失敗すれば CPU 合成へ戻せる

blink_web_view_get_render_path() は現在の経路 id を返します。値が変わるのは
切替が ok で完了したときだけです。


関連