BlinkGTK Python (PyGObject) チュートリアル

Python言語バインディング対応


目次

  1. はじめに
  2. PyGObjectのセットアップ
  3. 最小限のブラウザ
  4. シグナル処理
  5. プロパティ監視
  6. ナビゲーション機能
  7. 実践的な使い方
  8. トラブルシューティング

はじめに

BlinkGTKはGObject Introspectionに対応しているため、PythonからPyGObjectを使って利用できます。

BlinkGTKの特徴

前提条件


PyGObjectのセットアップ

必要なパッケージのインストール

# Fedora/RHEL系
sudo dnf install python3-gobject gtk4 gobject-introspection-devel

# Ubuntu/Debian系
sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-4.0

# Arch Linux
sudo pacman -S python-gobject gtk4

BlinkGTKのインストール

開発版(ローカルビルド)の使用

# BlinkGTKをビルド(C++/Chromiumビルドが必要)
cd $BLINKGTK_ROOT
# ビルド手順はBUILD.mdを参照

# GIR/typelibファイルを生成
./scripts/generate_gir.sh

# Pythonから使用する際は、GI_TYPELIB_PATHを設定
export GI_TYPELIB_PATH=$BLINKGTK_ROOT/gir:$GI_TYPELIB_PATH

システムワイドインストール(将来)

# 将来的にはpkg-configで自動検出される予定
sudo cp gir/BlinkGTK-0.1.typelib /usr/lib64/girepository-1.0/

インポートの確認

import gi
gi.require_version('Gtk', '4.0')
gi.require_version('BlinkGTK', '0.1')

from gi.repository import Gtk, BlinkGTK

print(f"GTK version: {Gtk.get_major_version()}.{Gtk.get_minor_version()}")
print(f"BlinkGTK loaded successfully!")

最小限のブラウザ

基本的な使い方

#!/usr/bin/env python3
import gi
import sys
import os

# ローカルビルドのtypelibを使用する場合
typelib_dir = os.path.join(os.path.dirname(__file__), '../../gir')
if os.path.exists(typelib_dir):
    gi.require_foreign('cairo')
    from gi.repository import GLib
    GLib.setenv('GI_TYPELIB_PATH', typelib_dir, True)

gi.require_version('Gtk', '4.0')
gi.require_version('BlinkGTK', '0.1')

from gi.repository import Gtk, BlinkGTK

class MinimalBrowser(Gtk.ApplicationWindow):
    """最小限のBlinkGTKブラウザ"""

    def __init__(self, app):
        super().__init__(application=app, title="BlinkGTK Minimal Browser")
        self.set_default_size(1024, 768)

        # BlinkWebView作成
        self.webview = BlinkGTK.WebView.new()
        self.set_child(self.webview)

        # URLをロード
        self.webview.load_uri("https://www.example.com")

def on_activate(app):
    window = MinimalBrowser(app)
    window.present()

def main():
    app = Gtk.Application(application_id='org.example.MinimalBrowser')
    app.connect('activate', on_activate)
    return app.run(sys.argv)

if __name__ == '__main__':
    sys.exit(main())

コードの解説

1. GI_TYPELIB_PATHの設定

typelib_dir = os.path.join(os.path.dirname(__file__), '../../gir')
if os.path.exists(typelib_dir):
    gi.require_foreign('cairo')
    from gi.repository import GLib
    GLib.setenv('GI_TYPELIB_PATH', typelib_dir, True)

2. バージョン指定

gi.require_version('Gtk', '4.0')
gi.require_version('BlinkGTK', '0.1')

3. BlinkWebViewの作成

self.webview = BlinkGTK.WebView.new()

シグナル処理

基本的なシグナル

BlinkWebViewは以下のシグナルを発行します:

シグナル名 引数 説明
load-changed BlinkLoadEvent ページロード状態の変化
load-failed BlinkLoadEvent, uri, error ロード失敗
title-changed なし ページタイトルの変更

シグナルの接続

class BrowserWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(application=app)

        self.webview = BlinkGTK.WebView.new()
        self.set_child(self.webview)

        # シグナル接続
        self.webview.connect("load-changed", self.on_load_changed)
        self.webview.connect("load-failed", self.on_load_failed)
        self.webview.connect("title-changed", self.on_title_changed)

        self.webview.load_uri("https://www.example.com")

    def on_load_changed(self, webview, load_event):
        """ロード状態変更ハンドラ"""
        # BlinkLoadEvent: 0=STARTED, 1=REDIRECTED, 2=COMMITTED, 3=FINISHED
        event_names = ["STARTED", "REDIRECTED", "COMMITTED", "FINISHED"]
        print(f"Load state: {event_names[load_event]}")

        if load_event == 3:  # FINISHED
            uri = self.webview.get_uri()
            title = self.webview.get_title()
            print(f"Page loaded: {title} ({uri})")

    def on_load_failed(self, webview, load_event, failing_uri, error):
        """ロード失敗ハンドラ"""
        print(f"Load failed: {failing_uri}")
        print(f"Error: {error.message if error else 'Unknown'}")
        return True  # シグナルを処理したことを示す

    def on_title_changed(self, webview):
        """タイトル変更ハンドラ"""
        title = self.webview.get_title()
        self.set_title(f"{title} - Browser")

BlinkLoadEventの詳細

# BlinkLoadEvent 列挙型
BLINK_LOAD_STARTED    = 0  # ロード開始
BLINK_LOAD_REDIRECTED = 1  # リダイレクト
BLINK_LOAD_COMMITTED  = 2  # ナビゲーション確定
BLINK_LOAD_FINISHED   = 3  # ロード完了

def on_load_changed(self, webview, load_event):
    if load_event == 0:
        print("ロード開始")
    elif load_event == 1:
        print("リダイレクト中")
    elif load_event == 2:
        print("ナビゲーション確定")
    elif load_event == 3:
        print("ロード完了")

プロパティ監視

notify::プロパティ名シグナル

GObjectのプロパティ変更は notify::プロパティ名 シグナルで監視できます。

class ProgressMonitor(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(application=app)

        self.webview = BlinkGTK.WebView.new()
        self.set_child(self.webview)

        # プロパティ変更通知を接続
        self.webview.connect("notify::estimated-load-progress",
                           self.on_progress_changed)
        self.webview.connect("notify::uri", self.on_uri_changed)
        self.webview.connect("notify::title", self.on_title_changed)

    def on_progress_changed(self, webview, pspec):
        """ロード進捗の変更"""
        progress = self.webview.get_estimated_load_progress()
        print(f"Progress: {progress:.0%}")

    def on_uri_changed(self, webview, pspec):
        """URIの変更"""
        uri = self.webview.get_uri()
        print(f"URI changed: {uri}")

    def on_title_changed(self, webview, pspec):
        """タイトルの変更(プロパティ経由)"""
        title = self.webview.get_title()
        print(f"Title: {title}")

利用可能なプロパティ

プロパティ名 説明
uri str 現在のURI
title str ページタイトル
estimated-load-progress float ロード進捗(0.0~1.0)
is-loading bool ロード中かどうか

ナビゲーション機能

ナビゲーションメソッド

class BrowserWithNavigation(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(application=app)

        # ツールバー
        toolbar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)

        # 戻るボタン
        back_button = Gtk.Button(label="◀")
        back_button.connect("clicked", lambda btn: self.webview.go_back())
        toolbar.append(back_button)

        # 進むボタン
        forward_button = Gtk.Button(label="▶")
        forward_button.connect("clicked", lambda btn: self.webview.go_forward())
        toolbar.append(forward_button)

        # リロードボタン
        reload_button = Gtk.Button(label="↻")
        reload_button.connect("clicked", lambda btn: self.webview.reload())
        toolbar.append(reload_button)

        # URL Entry
        self.url_entry = Gtk.Entry()
        self.url_entry.set_hexpand(True)
        self.url_entry.connect("activate", self.on_url_activate)
        toolbar.append(self.url_entry)

        # メインボックス
        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        main_box.append(toolbar)

        self.webview = BlinkGTK.WebView.new()
        main_box.append(self.webview)

        self.set_child(main_box)

    def on_url_activate(self, entry):
        """URL Enterキーハンドラ"""
        url = entry.get_text()
        self.webview.load_uri(url)

ナビゲーション状態の確認

# 戻る/進むボタンの有効/無効を更新
def update_navigation_buttons(self):
    can_go_back = self.webview.can_go_back()
    can_go_forward = self.webview.can_go_forward()

    self.back_button.set_sensitive(can_go_back)
    self.forward_button.set_sensitive(can_go_forward)

実践的な使い方

UIコンポーネントとの統合

class ModernBrowser(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(application=app, title="Modern Browser")
        self.set_default_size(1200, 900)

        # ヘッダーバー
        header = Gtk.HeaderBar()
        self.set_titlebar(header)

        # プログレスバー
        self.progress_bar = Gtk.ProgressBar()

        # WebView
        self.webview = BlinkGTK.WebView.new()
        self.webview.connect("notify::estimated-load-progress",
                           self.on_progress_changed)

        # レイアウト
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.append(self.progress_bar)
        vbox.append(self.webview)
        self.set_child(vbox)

    def on_progress_changed(self, webview, pspec):
        progress = self.webview.get_estimated_load_progress()
        self.progress_bar.set_fraction(progress)
        self.progress_bar.set_visible(progress < 1.0)

JavaScriptの実行

# JavaScript を実行し、結果を JSON 文字列で受け取ります

def on_result(result, user_data):
    # result は JSON エンコードされた文字列 (エラー時は None)
    print("結果:", result)

self.webview.execute_javascript("document.title", on_result, None)

結果が不要なら callback に None を渡せます。

self.webview.execute_javascript("document.body.style.zoom = '1.5'", None, None)

カスタムプロトコルハンドラ

# カスタムプロトコルハンドラ(将来の機能)
# 例: myapp:// スキーマの処理

トラブルシューティング

問題: ModuleNotFoundError: No module named 'gi'

原因: PyGObjectがインストールされていない

解決方法:

# Fedora
sudo dnf install python3-gobject

# Ubuntu
sudo apt install python3-gi

問題: ValueError: Namespace BlinkGTK not available

原因: BlinkGTKのtypelibが見つからない

解決方法:

# GI_TYPELIB_PATHを設定
import os
from gi.repository import GLib

typelib_dir = "/path/to/BlinkGTK/gir"
GLib.setenv('GI_TYPELIB_PATH', typelib_dir, True)

または、システムワイドにインストール:

sudo cp gir/BlinkGTK-0.1.typelib /usr/lib64/girepository-1.0/

問題: AttributeError: 'WebView' object has no attribute 'load_uri'

原因: 古いBlinkGTKバージョンまたはGIRが正しく生成されていない

解決方法:

# GIRを再生成
cd $BLINKGTK_ROOT
./scripts/generate_gir.sh

# Pythonキャッシュをクリア
rm -rf __pycache__

デバッグログの有効化

import logging

# GObjectのデバッグログ
logging.basicConfig(level=logging.DEBUG)

# 環境変数でGI_TYPELIBのデバッグ
import os
os.environ['G_MESSAGES_DEBUG'] = 'all'

サンプルコード

完全なサンプルコードは以下にあります:

実行方法(C言語版):

cd $BLINKGTK_ROOT
gcc -o blinkgtk_browser examples/blinkgtk_browser.c $(pkg-config --cflags --libs blinkgtk-0.1)
./blinkgtk_browser

まとめ

BlinkGTKをPythonから使用することで、以下のメリットがあります:

次のステップ:


BlinkGTK Project | Copyright 2025 | BSD-3-Clause License