| 作成者 | BlinkGTK-Readium プロジェクト (consumer/embedder 視点、#121) |
| 対象バージョン | BlinkGTK 1.2.1 (Chromium 152.0.7977.64) |
| 位置づけ | consumer (組み込み側) が実運用で得た知見を含む利用者マニュアル |
API セマンティクスの正は、公開ヘッダ
blink_gtk/blink_gtk.h と上流のレビューに従う。
BlinkGTK は、Chromium の Blink レンダリングエンジンを GTK4
ウィジェットとして
アプリケーションに組み込むためのライブラリである。WebKitGTK
と同様の設計思想の
C API(BlinkWebView)を提供する。GTK4
アプリケーションは、ウェブコンテンツの
表示・ナビゲーション・JavaScript 連携・カスタム URI
スキーム配信などを利用できる。
Chromium 本体をビルドする必要はない。 prebuilt
パッケージ(共有ライブラリ +
ヘッダ + pkg-config)へリンクするだけでよい。本マニュアルは EPUB
ビューワ(BlinkGTK-Readium)として
BlinkGTK を実運用している embedder の視点で書かれている。
階層は上から下へ次のとおり。
BlinkWebView を 1
つの子ウィジェットとして置く。GtkWidget のサブクラス(GObject)。embedder が直接触るのは 2 層目までであり、Chromium
のプロセスモデルは背後に隠れる。
ただし後述の「実運用の落とし穴」(サンドボックス、プロファイル、RUNPATH)は
このマルチプロセス構造に由来するため、存在だけは意識しておくとトラブル時に早い。
#include <blink_gtk/blink_gtk.h>pkg-config --cflags --libs blinkgtk-0.1include するのは
blink_gtk.hだけです。v1.2.0-build5 以前は、GObject 化以前 (2025 年) の内部ヘッダ
blink_web_view.h
も同梱されていました。blink_gtk.hと同時に include すると同名 typedef が
別の型を指すため、確定的にコンパイルエラーになります。error: conflicting types for 'BlinkWebView'; have 'struct BlinkWebView'使えないヘッダを置いておく理由がないため、それ以降は同梱していません。
blink_gtk.hに無い機能が要る場合は Issue でご相談ください。アプリケーションが include するのは
blink_gtk/blink_gtk.hのみとすること。v1.2.0-build6 以降は除外済みです (2026-09-03 に、当時公開されていた
devel パッケージをすべて展開して確認)。現在配られている
ヘッダはblink_gtk.h/blinkgtk_export.h/blinkgtk_version.hの 3 つです。
全ての BlinkGTK 公開 API は GTK
メインスレッドからのみ呼び出せる
(ヘッダ冒頭の Thread Safety Policy を参照)。コールバック
(JavaScript 結果、cookie、print 等)も常に GTK
メインスレッドで呼ばれる。
ワーカースレッドからは g_idle_add()
でメインスレッドへディスパッチする。
embedder のプロセスは次のフェーズを一方向に進む。
| フェーズ | 主な API | 備考 |
|---|---|---|
| (0) init 前設定 | blink_gtk_set_resources_path() 等 |
blink_gtk_init()
より前に呼ぶ必要がある |
| (1) 初期化 | blink_gtk_init() |
全 GTK/GLib 呼び出しより前・メインスレッドで 1 回 |
| (2) WebView 生成 | blink_web_view_new() /
_new_with_gpu_mode() / _new_container() |
GtkWidget として返る |
| (3) ロード前登録 | blink_web_view_register_custom_scheme_full()、register_message_handler()、g_signal_connect(load-changed) |
load_uri() より前に済ませる |
| (4) 配置・表示 | gtk_window_set_child()、gtk_window_present() |
通常の GTK4 ウィジェットとして扱う |
| (5) ロード | blink_web_view_load_uri() |
以後 load-changed シグナルで進行を受ける |
| (6) メインループ | blink_gtk_run_main_loop() /
blink_gtk_quit_main_loop() |
GTK ではなく Chromium の RunLoop |
| (7) 終了 | blink_gtk_shutdown() |
run_main_loop()
復帰後(明示呼び出しを推奨。下記参照) |
blink_gtk_shutdown()の要否とタイミング(上流#123レビューでの正式見解)
呼び方 評価 run_main_loop()復帰後に呼ぶ推奨。teardown 順序が決定的になる(下記の最小完全例はこの形) ウィンドウ close ハンドラ等 RunLoop 実行中に呼ぶ 安全。デッドロックせず遅延 shutdown に切り替わり、 run_main_loop()復帰後に実処理が走る呼ばない 動作はする( atexitの安全網が働く)が、teardown が atexit 任せで順序が非決定的。非推奨未呼出でも壊れないのは、
ContentMainRunner::Run成功後にatexitハンドラが登録されており、
AtExitManager 生存中に自動 teardown されるため(Issue#102-C)。歴史的に未呼出の embedder が
動いていた理由もこれ。ただし順序が決定的になる明示呼び出しを推奨する。
以下は blink_gtk_init()
の前に呼ぶことがヘッダで明示されている。
void blink_gtk_set_devtools_locale(const char* locale); /* NULL=システムロケール追従 */
const char* blink_gtk_get_devtools_locale(void);
void blink_gtk_set_icu_data_path(const char* path); /* icudtl.dat の絶対パス */
void blink_gtk_set_resources_path(const char* path); /* pak/snapshot 群のルート */通常はパッケージインストール先
<prefix>/lib/chromium/ が自動検出されるため
指定不要。非標準配置(自アプリへの同梱等)のときだけ
set_resources_path() を
指定する。set_icu_data_path() と同時指定時は
resources_path が優先される。
gboolean blink_gtk_init(int* argc, char*** argv);argc/argv を渡すと Chromium
系コマンドラインフラグ(--no-sandbox 等)が
ここで解釈される。戻り値 FALSE
は初期化失敗。メインスレッドで、他のあらゆる
GTK/GLib 呼び出しより前に 1 回だけ呼ぶ。
GtkWidget* blink_web_view_new(void);
GtkWidget* blink_web_view_new_with_gpu_mode(BlinkGpuMode mode);
GtkWidget* blink_web_view_new_container(void);
BlinkGpuMode blink_web_view_get_gpu_mode(BlinkWebView* web_view);typedef enum {
BLINK_GPU_MODE_SOFTWARE = 0, /* CPU 描画のみ(既定・GPU 不要) */
BLINK_GPU_MODE_SWIFTSHADER = 1, /* SwiftShader による GL エミュレーション */
BLINK_GPU_MODE_EGL = 2, /* ネイティブ EGL ハードウェア GPU */
} BlinkGpuMode;GtkWidget*。型安全アクセスには
BLINK_WEB_VIEW() / BLINK_IS_WEB_VIEW()new_container() は GtkOverlay +
GtkPicture を自動構築して返す簡易系。BlinkWebView* は
g_object_get_data(overlay, "blinkgtk-webview")
で取る。BLINK_GPU_MODE_SOFTWARE
を推奨(当方の常用も software。BLINKGTK_GPU_MODE と第 5 章(描画)参照)。load_uri()
を呼ぶ前に、コンテンツ側から発生するイベントの受け口を揃える。
/* カスタム URI スキーム(バイナリ対応版。Issue #103) */
void blink_web_view_register_custom_scheme_full(
BlinkWebView* web_view, const char* scheme,
BlinkCustomSchemeBytesCallback callback, gpointer user_data);
/* JS→C メッセージ(window.blinkgtk.postMessage) */
void blink_web_view_register_message_handler(
BlinkWebView* web_view, const char* name,
BlinkMessageCallback callback, gpointer user_data);ロードイベントは GObject シグナル "load-changed"
で受ける。
typedef enum {
BLINK_LOAD_STARTED = 0,
BLINK_LOAD_COMMITTED = 1,
BLINK_LOAD_FINISHED = 2,
BLINK_LOAD_REDIRECTED = 3 /* 予約。現行ランタイムは発火しない */
} BlinkLoadEvent;consumer 知見: BLINK_LOAD_REDIRECTED
は将来予約であり現行では発火しない。
また enum の整数値は v1.0.10 iter14 で「実際に emit
される値」に合わせて明示化
された経緯がある(それ以前は ev == BLINK_LOAD_FINISHED
が黙って偽になる版が
存在した)。古いパッケージと混ぜないこと。
BlinkWebView は普通の GTK4 ウィジェットとして
gtk_window_set_child() で置き、
gtk_window_present() 後に
blink_web_view_load_uri() を呼ぶ。
void blink_web_view_load_uri(BlinkWebView* web_view, const char* uri);
void blink_web_view_load_html(BlinkWebView* web_view, const char* html, const char* base_uri);int blink_gtk_run_main_loop(void); /* 0=成功。復帰までブロック */
void blink_gtk_quit_main_loop(void);g_application_run() ではなく Chromium の
base::RunLoop を回す。GTK と
Chromium
のライフサイクル衝突を避け、シャットダウン順序を制御するための設計で
ある。GLib の g_timeout_add() / g_idle_add()
はこのループ下でも発火する
(当方は録画・診断タイマを GLib timeout で常用)。終了させたい箇所
(ウィンドウの close-request 等)から
blink_gtk_quit_main_loop() を呼ぶ。
void blink_gtk_shutdown(void);run_main_loop() 復帰後、プロセス終了直前に呼ぶ。
実運用 embedder(BlinkGTK-Readium の readium-launcher)の実フローを 1
本に
簡約したコンパイル可能な例。カスタムスキーム app://
でローカルディレクトリを
配信し、ロード完了をシグナルで受ける。
/* minimal-embedder.c — BlinkGTK 最小 embedder(GTK4) */
#include <blink_gtk/blink_gtk.h>
#include <gtk/gtk.h>
#include <string.h>
/* app://host/<path> をカレントディレクトリから配信(バイナリ可)。NULL=404 */
static GBytes* scheme_cb(BlinkWebView* wv, const char* uri,
char** out_mime, gpointer ud) {
(void)wv; (void)ud;
const char* p = strstr(uri, "://");
if (!p) return NULL;
const char* slash = strchr(p + 3, '/'); /* host の後の '/' */
const char* rel = slash ? slash + 1 : "index.html";
if (*rel == '\0') rel = "index.html";
if (strstr(rel, "..")) return NULL; /* path traversal 防御 */
char* contents = NULL; gsize len = 0;
if (!g_file_get_contents(rel, &contents, &len, NULL)) return NULL;
if (out_mime && g_str_has_suffix(rel, ".html"))
*out_mime = g_strdup("text/html"); /* NULL なら URI から推測 */
return g_bytes_new_take(contents, len);
}
static void on_load_changed(BlinkWebView* wv, BlinkLoadEvent ev, gpointer ud) {
(void)ud;
if (ev == BLINK_LOAD_FINISHED)
g_print("loaded: %s (title=%s)\n",
blink_web_view_get_uri(wv), blink_web_view_get_title(wv));
}
static gboolean on_close(GtkWindow* w, gpointer ud) {
(void)w; (void)ud;
blink_gtk_quit_main_loop();
return FALSE;
}
int main(int argc, char* argv[]) {
/* (0) 非標準配置なら blink_gtk_set_resources_path() をここで。 */
/* (1) 初期化(全 GTK/GLib 呼び出しより前) */
if (!blink_gtk_init(&argc, &argv)) return 1;
/* (2) ウィンドウ + WebView(software 描画を推奨) */
GtkWidget* window = gtk_window_new();
gtk_window_set_default_size(GTK_WINDOW(window), 1024, 768);
GtkWidget* webview = blink_web_view_new_with_gpu_mode(BLINK_GPU_MODE_SOFTWARE);
/* (3) ロード前登録 */
blink_web_view_register_custom_scheme_full(
BLINK_WEB_VIEW(webview), "app", scheme_cb, NULL);
g_signal_connect(webview, "load-changed", G_CALLBACK(on_load_changed), NULL);
g_signal_connect(window, "close-request", G_CALLBACK(on_close), NULL);
/* (4)〜(5) 配置・表示・ロード */
gtk_window_set_child(GTK_WINDOW(window), webview);
gtk_window_present(GTK_WINDOW(window));
blink_web_view_load_uri(BLINK_WEB_VIEW(webview),
argc > 1 ? argv[1] : "app://local/index.html");
/* (6)〜(7) メインループ → 終了 */
int rc = blink_gtk_run_main_loop();
blink_gtk_shutdown();
return rc;
}ビルドと起動:
export PKG_CONFIG_PATH="$BLINKGTK_PKG/lib/pkgconfig:$PKG_CONFIG_PATH"
cc -O2 -Wall -o minimal-embedder minimal-embedder.c \
-Wl,-rpath,'$ORIGIN' \
$(pkg-config --cflags --libs blinkgtk-0.1)
# 実行はランタイム(.so + chromium リソース)と同じディレクトリに置くのが確実
cp minimal-embedder "$BLINKGTK_PKG/lib/chromium/"
"$BLINKGTK_PKG/lib/chromium/minimal-embedder" --no-sandbox --no-zygote-Wl,-rpath,'$ORIGIN' と「lib/chromium
に置いて起動」の理由は次節。
ゼロ知識の新規 embedder が 1 往復で動かせるよう、当方が実際に踏んだものを率直に挙げる。
libblinkgtk.so は同一パッケージの Chromium
リソース(v8_context_snapshot.bin
等)と厳密に対でなければならない。.pc 由来の絶対 rpath
だけでビルドしたバイナリを、別のパッケージの
lib/chromium/
にコピーして起動しないでください。ビルド時パッケージの .so を
読み込んでしまいます。V8 snapshot mismatch で renderer
が即死します
(当方 2026-07-07 実証)。対策は次のどちらか。
-Wl,-rpath,'$ORIGIN'
を先頭に焼き込み、バイナリを使用したいlib/chromium/ に置いて起動する(設置先の .so
群が常に優先され、LD_LIBRARY_PATH=<pkg>/lib/chromium
を明示する。配布されたサンプルバイナリは RUNPATH
がビルド時パスに焼き込まれていることが
あるため、パッケージを移動・差し替えて使う場合は自前ビルドが安全である。
~/.blink_gtk/ を全インスタンスで共有当方の実測では、--user-data-dir
を渡してもプロファイルは分離されず、
~/.blink_gtk/ が同一ユーザーの全 BlinkGTK
プロセスで共有される。さらに
ディスクへの永続化(localStorage 等)は SIGTERM
などの正常終了経路でのみ
行われ、SIGKILL や _exit()
では失われる。テストで状態を汚した場合は
~/.blink_gtk/
配下の該当データを手で消す運用になる。複数アプリの同時運用や
プロファイル分離が要件なら、この挙動を前提に設計すること。
--no-sandbox --no-zygote が必要な環境があるChromium サンドボックスが構成できない環境(コンテナ、user namespace
制限、
一部の開発環境)では、blink_gtk_init() に渡す argv に
--no-sandbox --no-zygote
を含めないと子プロセスが起動できない。当方の実運用起動スクリプトは常時この
2 フラグ付きで起動している。環境変数での同等指定は第 9 章
BLINKGTK_NO_SANDBOX
を参照。セキュリティ上の含意(サンドボックス無効化)は理解の上で使うこと。
EGL(ハードウェア GPU)経路は実験的であり、当方は評価の結果「当面
software で
運用」に決定している(縦書き EPUB
本文の描画・スクリーンショット採取とも
software で安定)。また前述のとおりモードはプロセス単位なので、WebView
ごとの
切り替えはできない。
blink_web_view_capture_screenshot() 系は renderer
側で再描画したフレームを
保存するため、コンポジタ表示段の不具合(表示だけ白紙になる等)は写らないことが
ある。表示系の検証を capture PNG
だけで合格判定しないこと(当方はこれで
False Pass を経験し、GTK 合成結果を直接読む検査を併用している)。
const char* blink_gtk_get_version(void); /* 例 "1.2.1" */
const char* blink_gtk_get_chromium_version(void); /* 例 "152.0.7977.64" */
/* build 番号 (Since 1.2.2)。build 番号は「同じ版を作り直した回数」です。
* 同じ版でも build が違えば挙動が違うことがあります。 */
const char* blink_gtk_get_build(void); /* 例 "2"。不明なら NULL */
const char* blink_gtk_get_version_full(void); /* 例 "1.2.1-build3"。必ず非 NULL */コンパイル時マクロ(BLINKGTK_VERSION /
CHROMIUM_VERSION)ではなく、実行時に
リンクされている .so から取得する(consumer
の再ビルドなしで表示が追従する)。
ログ・バグ報告には必ずこの実行時値を記録することを勧める。
load_uri / 履歴 /
load-changed・load-failed の詳細register_custom_scheme_full()、バイナリ配信、fetch()
との関係capture_screenshot 系BLINKGTK_GPU_MODE
ほか公開サポート env の正リストと実用例(章題は #121 合意目次の第 1 弾時点の予定。確定は上流レビューに従う)
初稿は下記により起草した。その後 2026-09-03 と 2026-09-08
に、それぞれ
当時の最新の配布物で再確認し、ヘッダ同梱の記述と版数の例を実体に合わせた。
include/blinkgtk-0.1/blink_gtk/blink_gtk.h。関数シグネチャはdocs/04-user-guides/api-reference/c-api-reference-ja.mdapp/native/readium-launcher.c(実
embedder)および同ビルド/起動スクリプト