対象: BlinkGTK を使って自分のアプリを作る方 (C /
Python / Rust など)
最終更新: 2026-07-29
リンクは pkg-config を通してください。これだけで、以降の落とし穴はほぼ避けられます。
cc -o myapp myapp.c $(pkg-config --cflags --libs blinkgtk-0.1)Makefile なら次のとおりです。
CFLAGS += $(shell pkg-config --cflags blinkgtk-0.1)
LDLIBS += $(shell pkg-config --libs blinkgtk-0.1)
うまく動かないときは、まずこの 3 つを確認してください。
| 症状 | 確認すること |
|---|---|
| ビルドできない | pkg-config --cflags --libs blinkgtk-0.1
が値を返すか。devel パッケージは入っているか |
| 起動するが画面が白い | readelf -d ./myapp | grep allocator_shim が 1
行以上出るか (第 2 章) |
Invalid file descriptor to ICU data で落ちる |
リソースの置き場所 (第 3 章) |
以降は、なぜそうなるのかと、pkg-config
を使えない場合の対処です。必要になったときに
読んでください。
BlinkGTK は中に Chromium
を丸ごと抱えています。そのため、リンクと実行時に
普通の GTK ライブラリにはない前提があります。
前提を外すと、ビルドも起動も成功したように見えて、ページだけが表示されません
(白画面または黒画面)。エラーも出ないので原因が分かりにくい、というのがこのガイドの
存在理由です。
同梱サンプル blinkgtk_browser は pkg-config
経由でリンクしているので、この前提を
満たしています。
Chromium は独自のメモリ確保方式 (PartitionAlloc)
を使います。これを効かせるには、
malloc
などの標準関数を横取りする部品をプロセス開始時に読み込む必要があります。
この部品を allocator shim と呼びます。
shim の読み込みが遅れると、Chromium
の内部でメモリ確保の辻褄が合わなくなり、
ページの読み込みが最後まで進みません。
-lblinkgtk だけを書くと、shim は
libblinkgtk.so
経由で間接的に読み込まれます。
間接だとタイミングが遅すぎて、横取りが間に合いません。
shim
は実行ファイルが直接依存している必要があります。blinkgtk-0.1.pc
の Libs に
shim が含まれているので、pkg-config を通せば自動的にそうなります。
確認するにはこうします。
readelf -d ./myapp |
grep allocator_shim
# 1 行以上出れば OK。何も出なければ pkg-config を通っていないshim を直接リンクしないと、Chromium 148 以降ではレンダラの
navigation commit が失敗 し、
起動直後に黒画面になります。ログには次のような兆候が現れます。
HasCommitted=0(ナビゲーションがコミットされない)set_dmabuf_pixels=0(フレームが一度も供給されない)error=6 の連続Chromium 147 では shim が間接ロードでも成立していました。Chromium 148
で PartitionAlloc が
レンダラの commit
経路により深く統合され、早期インターポーズが必須になったと考えられます。
この要件は Chromium 151 でも継続します(151 のビルドで
simple_browser が shim を直接 NEEDED
に持つことを確認済み)。
v1.1.0 以降、BlinkGTK は WebKitGTK と同等に runtime / devel /
gir の 3 分割で
配布されます(バイナリのみ、GitHub Releases)。consumer 開発では runtime
に加えて
devel(+ 必要なら gir)を導入します。
| パッケージ | RPM | DEB | 内容 | consumer での役割 |
|---|---|---|---|---|
| runtime | blinkgtk-bin |
libblinkgtk-0.1-0 |
共有ライブラリ (libblinkgtk-0.1.so.0) + Chromium
ランタイム (private dir /usr/lib64/blinkgtk-0.1/) +
リソース |
アプリの実行に必要 |
| devel | blinkgtk-bin-devel |
libblinkgtk-0.1-dev |
ヘッダ + blinkgtk-0.1.pc + .so
symlink |
アプリのビルドに必要 |
| gir | blinkgtk-bin-gir |
(同 devel) | GObject Introspection typelib | Python / GJS 等からの利用時 |
# Fedora/RHEL (開発時は runtime + devel + gir)
sudo dnf install ./blinkgtk-bin-<VER>-1.fc44.x86_64.rpm \
./blinkgtk-bin-devel-<VER>-1.fc44.x86_64.rpm \
./blinkgtk-bin-gir-<VER>-1.fc44.x86_64.rpm
# Debian/Ubuntu
sudo apt install ./libblinkgtk-0.1-0_<VER>-1_amd64.deb \
./libblinkgtk-0.1-dev_<VER>-1_amd64.debdevel パッケージが blinkgtk-0.1.pc
を提供するため、導入後は下記 3.1 の pkg-config が
そのまま解決します(.pc の Libs: は FHS
配置後も shim 直接リンクを維持します。
Issue #90)。runtime
のみ導入した環境ではアプリの実行はできますが、ビルド
(pkg-config / ヘッダ)はできません。
tarball (FHS) で導入する場合は runtime / devel の 2 つを同一 prefix に展開し、
runtime のld.so.conf.d断片またはLD_LIBRARY_PATHで private dir を解決、
devel の.pcをPKG_CONFIG_PATHに追加します。詳細は
インストールガイド を参照。
正規 SDK の blinkgtk-0.1.pc は、アロケータ shim を
Libs: に含んでいます。したがって
pkg-config 経由でリンクすれば、shim
は自動的に実行ファイルの直接依存になります。
cc your_app.c $(pkg-config --cflags --libs blinkgtk-0.1) -o your_appPython / Rust などの FFI
バインディング経由で利用する場合も、ビルドメタデータが
pkg-config を参照していれば同様に shim が含まれます。
pkg-config
を使わずリンク行をハードコードする場合は、-lblinkgtk の後に
shim を明示的に
追加してください。
BLINKGTK_LIBS = -L$(BLINKGTK_LIBDIR) \
-lblinkgtk \
-lbase_allocator_partition_allocator_src_partition_alloc_allocator_shim
shim ライブラリは BlinkGTK のライブラリディレクトリ(SDK の
lib/chromium/ 等)に同梱
されています。
リンク後、実行ファイルが shim を直接 NEEDED
しているかを確認します。これは描画不具合の
第一手としても有効です。
readelf -d ./your_app | grep NEEDED |
grep allocator_shim
# → 1 行出れば直接 NEEDED 済み。出なければ未リンク(黒画面の原因)。内部サンプルとの差分比較も有効です。
readelf -d ./your_app | grep NEEDED | sort > /tmp/app.needed
readelf -d ./blinkgtk_browser | grep NEEDED |
sort > /tmp/ref.needed
diff /tmp/ref.needed /tmp/app.neededBlinkGTK のライフサイクルは次の順序です。
int main(int argc, char** argv) {
if (!blink_gtk_init(&argc, &argv)) { // 最初に呼ぶ(メインスレッドから)
return 1;
}
// ... ウィンドウ / WebView の構築、load_uri ...
int rc = blink_gtk_run_main_loop(); // メインループ開始
blink_gtk_shutdown(); // 終了処理(必須)
return rc;
}gboolean blink_gtk_init(int* argc, char*** argv) —
最初に、メインスレッドから呼ぶ。int blink_gtk_run_main_loop(void) —
メインループを開始する。void blink_gtk_quit_main_loop(void) —
メインループを終了させる。void blink_gtk_shutdown(void) — 終了時に呼ぶ。終了処理を必ず呼ぶこと。
blink_gtk_shutdown() を呼ばずにプロセスを終えると、Chromium
の
teardown が AtExitManager 破棄後に走り、終了時に NOTREACHED
で異常終了することがあります
(過去 issue
で観測)。安全網として未終了検出時の自動終了処理も登録されますが、consumer
は
明示的に blink_gtk_shutdown() を呼ぶことを推奨します。
WebView は blink_web_view_new() で生成します。返り値は
GtkWidget* で、BLINK_WEB_VIEW()
で BlinkWebView* にキャストできます。
GtkWidget* web_view = blink_web_view_new(); // 自己描画する WebView
blink_web_view_load_uri(BLINK_WEB_VIEW(web_view), "https://example.com");
// 自前のレイアウトに埋め込む(例: GtkOverlay)
GtkWidget* overlay = gtk_overlay_new();
gtk_overlay_set_child(GTK_OVERLAY(overlay), web_view);blink_web_view_new_container()
は非推奨(deprecated)です。 旧コンテナ生成 API は
Chromium 148 以降で描画されません(#90
関連)。blink_web_view_new()(自己描画)を使い、
コンテナが必要なら 自前の GtkOverlay /
GtkBox に載せてください。
同一 WebView に対して blink_web_view_load_uri()
を繰り返し呼ぶことは安全です。内部の
レンダラビューは再利用され、ページ遷移を繰り返してもリソースが累積しません(過去のリーク
は解消済み)。アプリ側で WebView を毎回作り直す必要はありません。
描画バックエンドは 3 モードあります。
| モード | enum | 用途 | 要件 |
|---|---|---|---|
| software | BLINK_GPU_MODE_SOFTWARE(0) |
既定。CPU 描画。最も安定 | GPU 不要 |
| swiftshader | BLINK_GPU_MODE_SWIFTSHADER(1) |
CPU ベース GL エミュレーション | GPU 不要 |
| egl | BLINK_GPU_MODE_EGL(2) |
ネイティブ GPU 描画(WebGL/WebGPU) | GPU / DRM 必須 |
GtkWidget* web_view = blink_web_view_new_with_gpu_mode(BLINK_GPU_MODE_SOFTWARE);環境変数 BLINKGTK_GPU_MODE=software|swiftshader|egl
でも指定できます。まず software で
動作確認することを推奨します。egl は実 GPU と DRM
が必要で、ヘッドレスや GPU 無し環境では
描画されません。
高 DPI 環境(scale=2 等)では、device-scale-factor
の不整合により「描画が左上に小さく
出る」症状が起きることがあります。software モードでは GTK
のスケールに追従して自動処理
されます。egl など experimental
経路でスケール不整合が出る場合は、Chromium のコマンドライン
引数 --force-device-scale-factor=<n> を
blink_gtk_init(&argc, &argv) に渡す
argv に含めることで
スケールを明示できます。WebView
を入れ子のコンテナに深く埋め込む場合は、スケール伝播に注意
してください。
日本語ページを正しく描画するには、システムに CJK フォント(Harano
Aji、Noto CJK 等)が
インストールされている必要があります。フォントが無いと豆腐(□)になります。配布環境に
フォントが無い可能性がある場合は、依存に CJK
フォントパッケージを含めてください。
BlinkWebView は GObject
シグナルでイベントを通知します。利用可能なシグナルは次の 7 つです。
load-changed — ロード状態の変化(引数は
BlinkLoadEvent 列挙型)load-failed — ロード失敗(引数は error_code (int) +
失敗 URI、この順)title-changed —
タイトル変化(追加引数なし — 値は
blink_web_view_get_title() で取得)uri-changed — URI 変化(追加引数なし —
値は blink_web_view_get_uri()
で取得)。blink_web_view_load_uri() 呼び出し時と、URI
が変わるナビゲーションのコミット時に発火しますnew-window-requested —
新規ウィンドウ要求(window.open() /
target="_blank"。通知のみ)message-received — ページ内 JavaScript
からのメッセージ受信(引数は name, data の 2 つ)permission-request —
位置情報・通知等の権限要求(既定は拒否・ハンドラ内で同期応答)各シグナルの正確な発火条件と落とし穴は Signals API リファレンス を参照してください。
あわせて、uri / title /
is-loading / zoom-level
の各プロパティは値の変化時に
notify::
シグナルを発火します(g_signal_connect(view, "notify::uri", ...)
で購読可能)。
g_signal_connect(web_view, "load-changed", G_CALLBACK(on_load_changed), NULL);
g_signal_connect(web_view, "title-changed", G_CALLBACK(on_title_changed), NULL);blink_web_view_inject_user_script(BLINK_WEB_VIEW(web_view), js_source,
TRUE /* inject_at_document_start */);
blink_web_view_inject_user_stylesheet(BLINK_WEB_VIEW(web_view), css_source);inject_at_document_start=TRUE
のスクリプトは、ナビゲーションが commit
された後の
document_start タイミングで実行されます。2 章のアロケータ shim
が未リンクで commit が成立
しないと、'Stored' ログは出ても注入スクリプトが実行されません(過去
issue)。注入が走らない
場合は、まず 2 章のリンク要件を確認してください。
サブタイトル等に表示する BlinkGTK / Chromium
バージョンは、ハードコードせずランタイム
API で取得してください。これにより libblinkgtk.so
の更新に自動追従します。
const char* blinkgtk_ver = blink_gtk_get_version(); /* BlinkGTK バージョン */
const char* chromium_ver = blink_gtk_get_chromium_version(); /* Chromium バージョン */これらの API は公開ヘッダ <blink_gtk/blink_gtk.h>
に宣言されています(extern 宣言は
不要)。返り値は内部の静的文字列のため free しないでください。シンボルを
export する
libblinkgtk.soとリンクする必要があります。
電子書籍端末・キオスク端末向けに、コピー / 保存 / 印刷等を制限できます。
blink_web_view_set_content_policy(BLINK_WEB_VIEW(web_view),
BLINK_CONTENT_POLICY_EBOOK_READER);プリセット:
BLINK_CONTENT_POLICY_ALLOW_ALL(既定)、BLINK_CONTENT_POLICY_EBOOK_READER、
BLINK_CONTENT_POLICY_KIOSK。個別フラグ(NO_COPY
/ NO_SAVE / NO_PRINT /
NO_CONTEXT_MENU / NO_DEVTOOLS
等)のビットマスク組み合わせも可能です。ポリシーは即時
適用され、いつでも変更できます。
Web コンテンツの element.requestFullscreen() /
document.exitFullscreen() を機能させるに
は、フルスクリーンハンドラを登録してトップレベルウィンドウの全画面化に反映します。登録
しない場合、フルスクリーン要素は WebView
の表示領域内で拡大するだけで、ウィンドウ自体は全画面
化されません(電子書籍リーダーの全画面ボタンが「効かない」ように見える主因です)。
static void on_fullscreen(BlinkWebView* view, gboolean enter, gpointer user_data) {
(void)user_data;
GtkRoot* root = gtk_widget_get_root(GTK_WIDGET(view));
if (!root ||
!GTK_IS_WINDOW(root)) return;
if (enter)
gtk_window_fullscreen(GTK_WINDOW(root));
else
gtk_window_unfullscreen(GTK_WINDOW(root));
}
/* WebView 生成後に一度だけ登録 */
blink_web_view_set_fullscreen_handler(BLINK_WEB_VIEW(web_view), on_fullscreen, NULL);補足:
requestFullscreen() は Web
標準の要件によりユーザージェスチャ(実際のクリック /
キー操作)
起点でのみ許可されます。プログラム的な
element.click() 等の合成イベントからは拒否されます
(API can only be initiated by a user gesture)。全画面ボタンは実際のクリックに紐付けてくだ
さい。
blink_web_view_exit_fullscreen(view)
でアプリ側から明示的に解除できます。
blink_web_view_is_fullscreen(view)
で現在の状態を照会できます。
ESC キーでの解除は自動では行われません(HTML
fullscreen は browser 側の ESC 協調が
必要)。トップレベルウィンドウに CAPTURE phase
のキーコントローラを付け、全画面中の ESC で
blink_web_view_exit_fullscreen()
を呼んでください(document.exitFullscreen()
と同じ協調
経路で Blink 側の状態も更新されます)。
static gboolean on_key(GtkEventControllerKey* c, guint keyval, guint kc,
GdkModifierType st, gpointer ud) {
if (keyval == GDK_KEY_Escape && blink_web_view_is_fullscreen(BLINK_WEB_VIEW(ud))) {
blink_web_view_exit_fullscreen(BLINK_WEB_VIEW(ud));
return TRUE; /* consume */
}
return FALSE; /* 非全画面時は伝播 */
}
GtkEventController* kc = gtk_event_controller_key_new();
gtk_event_controller_set_propagation_phase(kc, GTK_PHASE_CAPTURE);
g_signal_connect(kc, "key-pressed", G_CALLBACK(on_key), web_view);
gtk_widget_add_controller(toplevel_window, kc);これらの API は公開ヘッダ
<blink_gtk/blink_gtk.h> に宣言済みです。
libblinkgtk.so および Chromium
の共有ライブラリ群が解決できるよう、rpath または
LD_LIBRARY_PATH を設定してください。pkg-config の
Libs: には -rpath 指定が含まれて
います。
LD_LIBRARY_PATH
を実行時に設定する必要がある構成では、Chromium
ライブラリがロードされる
前にパスを確定させる必要があります。プロセス先頭で
LD_LIBRARY_PATH を設定し直して
自プロセスを re-exec
するパターンが有効です(環境変数設定 → execv
で自分自身を再起動
→ 以降は正しい探索パスでロード)。
Chromium は起動時に icudtl.dat や
content_shell.pak などを読み込みます。
探しに行くのは
実行ファイルと同じディレクトリです。カレントディレクトリでは
ありません。
自分のアプリを別の場所に置くと、これらが見つからず起動に失敗します。
ERROR:base/i18n/icu_util.cc: Invalid file descriptor to ICU data received.
FATAL:base/i18n/icu_util.cc: Check failed: result.
このときは、blink_gtk_init()
を呼ぶ前に置き場所を教えてください。
blink_gtk_set_resources_path("/usr/lib64/blinkgtk-0.1/chromium");
blink_gtk_set_icu_data_path("/usr/lib64/blinkgtk-0.1/chromium");
blink_gtk_init(&argc, &argv);RPM / DEB でインストールした場合、リソースは
/usr/lib64/blinkgtk-0.1/chromium/ にあります。
同梱の blinkgtk_browser
もこの方法を使っています。実際のコードは
examples/blinkgtk_browser.c を見てください。
開発時はサンドボックスを無効化する --no-sandbox を
argv に渡すと取り回しが容易です。
BlinkGTK は単一プロセス構成で動作します。
blink_gtk_init(&argc, &argv) を含む BlinkGTK /
GTK の API は、原則としてメインスレッド(GTK メイン
ループのスレッド)から呼び出してください。別スレッドからの UI
操作は避けてください。
BlinkGTK は Wayland のみをサポートします(X11
は使用しません)。起動時に Ozone プラット
フォームは Wayland に強制されます。
V8 関連の 3
ファイルは同一ビルド由来でバージョンが一致していなければなりません。混在
すると起動時に V8 の致命的エラーで起動不能になります。
libv8.sosnapshot_blob.binv8_context_snapshot.bin異なる Chromium バージョンのビルドツリーからファイルを混ぜないでください。
実行時に次のファイル群が必要です。consumer アプリの配布物に同梱してください。
content_shell.pak(UI /
デフォルトスタイルシート。欠けると CSS が崩れる)icudtl.dat(ICU
データ。日本語の禁則・ルビ処理等に必要)locales/ja.pak,
locales/en-US.pak(ロケールリソース)snapshot_blob.bin,
v8_context_snapshot.bin(V8 スナップショット、8.1
と同一)Chromium
のデータファイルは実行ファイルからの相対位置で解決されます。データファイルを
実行ファイルと異なるディレクトリに置いて起動すると、Invalid file descriptor to ICU data
等のエラーで起動に失敗することがあります。データファイルは実行ファイルと同じディレクトリ
(または規定の相対パス)に配置してください。
描画されない(黒画面 / 白画面)場合、上位の複雑な仮説を立てる前に、以下を順に確認します。
| 確認項目 | コマンド / 兆候 | 異常時の対処 |
|---|---|---|
| allocator shim 直接リンク | readelf -d <app> | grep allocator_shim |
出なければ 3 章でリンク追加 |
| NEEDED 差分 | 内部サンプルと diff |
欠落ライブラリを補う |
| navigation commit | ログの HasCommitted |
0 のままなら shim を疑う |
| フレーム供給 | ログの set_dmabuf_pixels |
0 のままなら shim / commit を疑う |
| 終了時クラッシュ | 終了時 NOTREACHED | blink_gtk_shutdown() を呼ぶ |
| 注入スクリプト非実行 | 'Stored' は出るが走らない | commit を確認(shim) |
| 描画が小さい | scale=2 で左上に縮小 | device-scale-factor / software モード |
| V8 整合 | libv8.so と snapshot の由来 |
同一ビルドに揃える |
| データファイル | content_shell.pak / icudtl.dat の同梱 |
実行ファイル隣に配置 |
第一手は常に NEEDED
差分の確認です。ビルドと起動が成功しても描画されない場合、原因の
多くはリンク不足かデータファイル不足という「足元」にあります。
# 1) shim 直接リンクの確認
readelf -d ./your_app | grep -c allocator_shim # 1 を期待
# 2) 必須ランタイムファイルの存在確認
for f in libblinkgtk.so libv8.so content_shell.pak \
snapshot_blob.bin v8_context_snapshot.bin \
icudtl.dat locales/ja.pak locales/en-US.pak; do
[ -e "$f" ] && echo "OK $f" || echo "MISSING $f"
done
# 3) 起動ログの健全性(描画されない場合)
grep -E "HasCommitted|set_dmabuf_pixels|error=6" your_app.log | taildocs/04-user-guides/api-reference/)