BlinkGTK GObject Signals API リファレンス

バージョン: 1.2.0-build2
最終更新: 2026-07-30
言語: 日本語 |

English


このページについて

BlinkWebView が発する GObject シグナル 7 本のリファレンスです。ページの
ロード状態・URL・タイトルの変化、新規ウィンドウ要求、JS からのメッセージ、
権限要求を受け取れます。

本ページはエンジン実装を実測して書かれています。ハンドラやシグナルの状況は
1.2.0-build2 時点で再確認しました。

旧版 (2026-07-29 以前) からの重大な訂正: 旧版は title-changed /
uri-changed のコールバックに文字列引数があるかのように記載していましたが、
両シグナルに引数はありません。旧版のシグネチャどおりに書くと
user_data が文字列引数の位置に入り、クラッシュやメモリ破壊の原因に
なります。本ページのシグネチャが実装どおりの正です。

シグナル一覧 (実装どおり)

シグナル名 追加引数 発火タイミング 用途
load-changed BlinkLoadEvent ロード状態変化 (下記の表に注意) プログレス表示、UI更新
load-failed error_code (int), failing_uri (この順) コミットされない失敗のみ (下記) エラーハンドリング
title-changed なし — 値は get_title() で取る タイトル変化 ウィンドウタイトル更新
uri-changed なし — 値は get_uri() で取る URL 変化 アドレスバー更新
new-window-requested url window.open() / target="_blank" 新規ウィンドウ要求の通知 (制御は不可、下記)
message-received name, data (2 引数) ページ JS からの postMessage JS→C 連携 (アプリ連携 API)
permission-request BlinkPermissionRequest* ページが権限を要求 位置情報・通知等の許可判断 (既定は拒否・同期応答必須)

GtkWidget 由来のプロパティ通知 notify::uri / notify::title /
notify::is-loading も使えます (WebKitGTK からの移行では notify::uri /
notify::title をそのまま流用するのが最も簡単です)。

まず知っておく 3 つの事実

  1. エンジン発のシグナルは全て GTK メインスレッドで届きます (Chromium の
    UI スレッド = GTK メインループ)。ハンドラから GTK API を直接呼べます。
    一方、load_uri() が同期発火するシグナル (下記) は「API を呼んだ
    スレッド」で走るため、BlinkGTK API はメインスレッドから呼んでください
  2. title-changed / uri-changed に引数はありません。 値はハンドラ内で
    blink_web_view_get_title() / blink_web_view_get_uri() から取ります。
  3. getter が返す文字列は内部の静的バッファで、次に同じ getter を呼ぶと
    上書きされます。保持するなら g_strdup() してください。

基本形

static void on_title_changed(BlinkWebView *view, gpointer user_data) {
    GtkWindow *win = GTK_WINDOW(user_data);
    const char *title = blink_web_view_get_title(view);   /* 引数でなく getter */
    gtk_window_set_title(win, title ? title : "BlinkGTK");
}

static void on_uri_changed(BlinkWebView *view, gpointer user_data) {
    GtkEditable *entry = GTK_EDITABLE(user_data);
    const char *uri = blink_web_view_get_uri(view);
    gtk_editable_set_text(entry, uri ? uri : "");
}

g_signal_connect(view, "title-changed", G_CALLBACK(on_title_changed), win);
g_signal_connect(view, "uri-changed", G_CALLBACK(on_uri_changed), entry);

load-changed

シグネチャ

void user_function(BlinkWebView* web_view,
                   BlinkLoadEvent load_event,
                   gpointer user_data);

BlinkLoadEvent の値 (明示値 — 順序に注意)

typedef enum {
    BLINK_LOAD_STARTED    = 0,
    BLINK_LOAD_COMMITTED  = 1,
    BLINK_LOAD_FINISHED   = 2,
    BLINK_LOAD_REDIRECTED = 3   /* 予約 — 現在のランタイムは発火しません */
} BlinkLoadEvent;

各値の実際の意味

実際の発火条件
STARTED blink_web_view_load_uri() / load_html() を呼んだときに同期発火。それ以外では来ません — リンククリック・location.hrefgo_back()/go_forward()/reload()・ページ側起点の遷移では発火しない (WebKitGTK との最大の非互換点)
COMMITTED ナビゲーションのコミット時。ただしフレームの区別なし — iframe のロードや、pushState / fragment 移動 (same-document) でも毎回発火します。「新しいページに入った」の判定には使えません
FINISHED メインフレームの onload 完了。iframe では来ない。pushState / fragment では来ない。履歴の戻る/進むがキャッシュ復元 (BFCache) だった場合も来ない

操作別の発火パターン (実測)

操作 STARTED COMMITTED FINISHED uri-changed
load_uri() (通常遷移) ○ (2 回のことあり、下記)
load_html()
リンククリック / location.href
pushState / fragment (#foo)
go_back() / go_forward() (通常)
同 (BFCache 復元時)
reload() — (URL 不変)
iframe のロード・遷移 ○ (iframe ごと)

FINISHED 時点で保証されること

FINISHED の直前に、エンジンは注入 CSS (アプリ連携 API)
と JS メッセージブリッジ (window.blinkgtk) のセットアップを済ませています。
FINISHED ハンドラの中から execute_javascript() を呼べばブリッジは使えます。

ただし FINISHED は onload であり、ページが動的に組み立てるコンテンツの完成
までは意味しません (描画完成の通知は現在未提供です)。

スピナー (読み込み中表示) の正しい止め方

FINISHED だけで止めると永久スピナーになるケースがあります:

/* FINISHED または load-failed で止め、無音ケースはタイムアウトで拾う */

load-failed

シグネチャ

void user_function(BlinkWebView* web_view,
                   int error_code,
                   const char* failing_uri,
                   gpointer user_data);

引数は (error_code, failing_uri) の順です。 逆順で書いたコールバックは
ポインタを整数として読み、クラッシュや文字化けの原因になります。

いつ発火するか (重要 — 直感と異なります)

発火条件は「コミットされずに終わったナビゲーション + net エラーあり
だけです。帰結:

ケース load-failed 実際に起きること
ユーザー操作・新しい遷移によるキャンセル ○ (最頻) error_code = -3 (ERR_ABORTED)。正常な操作でも頻繁に飛ぶため、無条件にエラーダイアログを出すと乱発します
DNS 失敗・接続不能 (例: -105, -102) — (原則) Chromium がエラーページをコミットするため、COMMITTED + FINISHED が来て既定のエラーページが表示されます
HTTP 404 / 500 正常コミット (net エラーではない)。COMMITTED + FINISHED
画像・CSS・fetch などサブリソースの失敗 ナビゲーションではないため対象外
iframe のナビゲーション中断 failing_uriiframe の URL — メインページの URL と比較するガードを推奨
ダウンロード化 / 204・205 どのシグナルも来ません

error_code の実際の型

値は Chromium の net エラーコードの生の負値です (-3, -105, …)。
ヘッダの BlinkLoadError enum (BLINK_LOAD_ERROR_NETWORK 等) は現在の
ランタイムでは使われません — C では int として扱ってください

定数名 (参考) 意味
-3 net::ERR_ABORTED 中断 (最頻・正常操作でも発生)
-7 net::ERR_TIMED_OUT タイムアウト
-105 net::ERR_NAME_NOT_RESOLVED DNS 解決失敗 (通常はエラーページがコミットされ load-failed は来ない)

完全なリストは Chromium net_error_list.h を参照してください。

実装パターン

static void on_load_failed(BlinkWebView *view, int error_code,
                           const char *failing_uri, gpointer user_data) {
    if (error_code == -3)   /* ERR_ABORTED: 正常操作の副産物。無視が基本 */
        return;
    const char *current = blink_web_view_get_uri(view);
    if (current && failing_uri && strcmp(current, failing_uri) != 0)
        return;             /* iframe など、表示中ページ以外の失敗 */
    g_message("load failed: %d %s", error_code, failing_uri);
}

uri-changed / title-changed

シグネチャ (両方とも追加引数なし)

void user_function(BlinkWebView* web_view, gpointer user_data);

値はハンドラ内で blink_web_view_get_uri() / blink_web_view_get_title()
で取得します。

uri-changed の動作の詳細

観点 動作
発火点 load_uri() 呼び出し時 (同期) ②ナビゲーションのコミット時。redirect の途中経過では来ません
同一遷移で 2 回来ることがある ①は渡された文字列、②は正規化済み URL で重複判定するため、"http://example.com""http://example.com/" のような差で 2 回発火します。履歴スタックを自作する場合はアプリ側でも重複排除してください
①の時点の get_uri() まだコミットされていない URL を返します。遷移が失敗するとこの値は「実際には表示されなかった URL」になります
中断時の巻き戻し ありません。失敗した遷移の URL がアドレスバーに残る形になるため、load-failedget_uri() を読み直して戻すのが確実です
load_html() 発火しません

title-changed の動作の詳細

観点 動作
発火条件 ページの <title> 設定時・document.title の動的変更時 (メインフレームのみ)
<title> の無いページ 発火しません (空文字で来るのではなく無音)
履歴の戻る/進む 履歴側に同じタイトルが記録済みだと発火しないことがあります。タブ UI は notify::title の併用が確実です
値の整形 前後の空白・改行は除去済みで届きます
get_title() の返り値 空になりません — タイトル未設定ページでは URL を整形した文字列が返ります。「タイトル無し」を空文字で判定するコードは動きません

new-window-requested

シグネチャ

void user_function(BlinkWebView* web_view,
                   const char* url,
                   gpointer user_data);

これは「通知」です — 制御はできません

window.open()<a target="_blank"> が起きたことを知らせるシグナルで、
開かせない・別の場所に開く、という制御はできません (戻り値なし)。
現在のエンジンはシングルウィンドウ動作で、シグナル発火の時点で既に同じ
WebView を対象 URL へナビゲートし始めています


message-received

ページ JS の window.blinkgtk.postMessage() を受けるシグナルです。
引数は (name, data) の 2 つ (チャネル名と Base64 データ)。詳細な
セマンティクス (エンコーディング・多重購読・C API 版ハンドラとの関係) は
アプリ連携 API にまとめてあります。


権限要求 (permission-request)

位置情報・通知などの権限要求を受けるシグナルです。

static gboolean on_permission(BlinkWebView *view,
                              BlinkPermissionRequest *req,
                              gpointer user_data) {
    const char *kind = blink_permission_request_get_type_name(req);
    if (g_strcmp0(kind, "notifications") == 0)
        blink_permission_request_allow(req);   /* 通知だけ許可 */
    else
        blink_permission_request_deny(req);
    return TRUE;   /* 処理した */
}

g_signal_connect(view, "permission-request", G_CALLBACK(on_permission), NULL);

仕様

API

const char* blink_permission_request_get_type_name(BlinkPermissionRequest* request);
void        blink_permission_request_allow(BlinkPermissionRequest* request);
void        blink_permission_request_deny(BlinkPermissionRequest* request);

発火順序

実装で保証される順序:

保証されない順序:


ライフサイクルとスレッド


実用パターン: ブラウザ UI の更新

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

typedef struct {
    GtkWidget *window;
    GtkWidget *url_entry;
    GtkWidget *spinner;
    guint      spinner_timeout;
} BrowserUI;

static gboolean stop_spinner_fallback(gpointer data) {
    BrowserUI *ui = data;
    gtk_widget_set_visible(ui->spinner, FALSE);
    ui->spinner_timeout = 0;
    return G_SOURCE_REMOVE;
}

static void on_load_changed(BlinkWebView *view, BlinkLoadEvent ev,
                            gpointer user_data) {
    BrowserUI *ui = user_data;
    if (ev == BLINK_LOAD_STARTED) {
        gtk_widget_set_visible(ui->spinner, TRUE);
        /* 無音ケース (ダウンロード化・204) の保険 */
        if (ui->spinner_timeout)
            g_source_remove(ui->spinner_timeout);
        ui->spinner_timeout =
            g_timeout_add_seconds(30, stop_spinner_fallback, ui);
    } else if (ev == BLINK_LOAD_FINISHED) {
        gtk_widget_set_visible(ui->spinner, FALSE);
        if (ui->spinner_timeout) {
            g_source_remove(ui->spinner_timeout);
            ui->spinner_timeout = 0;
        }
    }
}

static void on_load_failed(BlinkWebView *view, int error_code,
                           const char *failing_uri, gpointer user_data) {
    BrowserUI *ui = user_data;
    gtk_widget_set_visible(ui->spinner, FALSE);
    if (error_code == -3)
        return;   /* ERR_ABORTED は正常操作の副産物 */
    g_message("load failed: %d %s", error_code,
              failing_uri ? failing_uri : "");
}

static void on_uri_changed(BlinkWebView *view, gpointer user_data) {
    BrowserUI *ui = user_data;
    const char *uri = blink_web_view_get_uri(view);
    gtk_editable_set_text(GTK_EDITABLE(ui->url_entry), uri ? uri : "");
}

static void on_title_changed(BlinkWebView *view, gpointer user_data) {
    BrowserUI *ui = user_data;
    const char *title = blink_web_view_get_title(view);
    char *t = g_strdup_printf("%s - MyBrowser",
                              (title && *title) ? title : "(untitled)");
    gtk_window_set_title(GTK_WINDOW(ui->window), t);
    g_free(t);
}

static void setup_signals(BlinkWebView *view, BrowserUI *ui) {
    g_signal_connect(view, "load-changed", G_CALLBACK(on_load_changed), ui);
    g_signal_connect(view, "load-failed", G_CALLBACK(on_load_failed), ui);
    g_signal_connect(view, "uri-changed", G_CALLBACK(on_uri_changed), ui);
    g_signal_connect(view, "title-changed", G_CALLBACK(on_title_changed), ui);
}

WebKitGTK からの移行

WebKitGTK BlinkGTK 注意
load-changed (STARTED) load-changed (STARTED) 非互換: BlinkGTK の STARTED は load_uri()/load_html() を呼んだときだけ。リンククリック等では来ません — スピナー開始は STARTED に依存しない設計に
load-changed (REDIRECTED) BlinkGTK では発火しません
load-changed (COMMITTED / FINISHED) 同名 COMMITTED は iframe / same-document でも多重発火する点が異なります
load-failed load-failed 引数形式が違う (GError ではなく int + uri、順序は error_code が先)。発火条件も狭い (本ページの表を参照)
notify::title / notify::uri そのまま使えます 移行はこれが最も簡単。専用シグナル (title-changed / uri-changed) は引数なしの点だけ注意
create (新規ウィンドウ) new-window-requested 非互換: BlinkGTK は通知のみで、ブロック・別 WebView での open はできません
permission-request permission-request 同期応答必須 (WebKitGTK のような遅延応答は不可)

制限事項まとめ

項目 現状
リダイレクトの検知 不可 (BLINK_LOAD_REDIRECTED は予約値)
ページ側起点ナビの開始検知 不可 (STARTED は API 呼び出し時のみ)
新規ウィンドウ要求の制御 不可 (通知のみ・常に同一 view で開く)
コミットされる失敗 (DNS 等) の load-failed 来ない (既定エラーページが表示される)
描画完成の通知 未提供 (FINISHED は onload まで)
言語バインディングからの permission-request 不可 (生ポインタ引数)

関連

変更履歴

バージョン 変更
v1.1.0 (2026-07-30) エンジン実装の実測に基づき全面改訂。title-changed / uri-changed のシグネチャを訂正 (引数なし — 旧版はクラッシュを招く誤記)。BLINK_LOAD_REDIRECTED が発火しない事実、STARTED が API 呼び出し時のみの事実、load-failed の実発火条件 (コミットされない失敗のみ / -3 が最頻)、操作別発火パターン表、発火順序、無音ケース (ダウンロード・204) とスピナー対策、new-window-requested が通知専用である事実を明記
v1.1.0 (2026-07-29 以前) 旧版