Target version: BlinkGTK 1.2.5 or later
Language: 日本語
| English
BlinkGTK supports GObject Introspection, so you can use it from
Python through PyGObject.
Every complete program in this tutorial was run and checked with
BlinkGTK 1.2.5 (Chromium 156).
blinkgtk-run python3 <file> (why)The code that used to be on this page does not work as written. Change these three points.
| Earlier code | 1.2.5 and later |
|---|---|
| Creating widgets without initializing | Call BlinkGTK.gtk_init(sys.argv[:1]) before creating
any widget |
app.run(sys.argv) |
BlinkGTK.gtk_application_run(app) followed by
BlinkGTK.gtk_shutdown() |
Other namespaces such as BlinkGtk, or
import blink_gtk |
gi.require_version("BlinkGTK", "0.1") and
from gi.repository import BlinkGTK |
With app.run() the window appears, but Chromium's work
never runs and pages never load.
# Fedora
sudo dnf install python3-gobject gtk4 blinkgtk-bin blinkgtk-bin-gir
# Debian / Ubuntu
sudo apt install python3-gi gir1.2-gtk-4.0
# Install BlinkGTK and its introspection data from the downloaded DEB files (there is no APT repository)
sudo apt install ./libblinkgtk-0.1-0_<version>-1_amd64.deb ./gir1.2-blinkgtk-0.1_<version>-1_amd64.debFor the repository setup needed to install the BlinkGTK packages, see the installation guide.
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")
from gi.repository import BlinkGTK, Gtk
print(f"GTK {Gtk.get_major_version()}.{Gtk.get_minor_version()}.{Gtk.get_micro_version()}")
print(f"BlinkGTK {BlinkGTK.gtk_get_version()} (Chromium {BlinkGTK.gtk_get_chromium_version()})")BlinkGTK.gtk_get_version() and
BlinkGTK.gtk_get_chromium_version() can be called before
initialization.
If this prints 1.2.4 or earlier, update BlinkGTK.
Save the following program as minimal.py and run it with
blinkgtk-run python3 minimal.py.
Always run Python programs through
blinkgtk-run. BlinkGTK (Chromium) needs its memory
allocator to be loaded from the very start of the process. C
applications load it at startup, but in Python BlinkGTK is loaded later,
so without blinkgtk-run the program aborts when it opens an
HTTPS page. blinkgtk-run is at
/usr/bin/blinkgtk-run in the RPM and DEB packages, and at
usr/bin/blinkgtk-run where you extracted the tarball. It
uses the LD_PRELOAD environment variable, so programs
started from your program inherit it.
Pass a URL as an argument to open that page.
#!/usr/bin/env python3
"""A minimal BlinkGTK browser"""
import sys
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")
from gi.repository import BlinkGTK, Gtk # noqa: E402
def on_activate(app, url):
window = Gtk.ApplicationWindow(application=app, title="BlinkGTK Minimal Browser")
window.set_default_size(1024, 768)
view = BlinkGTK.WebView.new()
window.set_child(view)
window.present()
view.load_uri(url)
def main():
url = sys.argv[1] if len(sys.argv) > 1 else "https://example.com/"
# 1. Initialize BlinkGTK (once, before creating any GTK widget)
ok, _argv = BlinkGTK.gtk_init(sys.argv[:1])
if not ok:
print("Could not initialize BlinkGTK", file=sys.stderr)
return 1
# 2. Create the application and run it with the BlinkGTK main loop
app = Gtk.Application(application_id="org.example.MinimalBrowser")
app.connect("activate", on_activate, url)
rc = BlinkGTK.gtk_application_run(app) # returns when the last window is closed
# 3. Shut BlinkGTK down
BlinkGTK.gtk_shutdown()
return rc
if __name__ == "__main__":
sys.exit(main())gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")State the library versions explicitly. Put these lines before
from gi.repository import ....
ok, _argv = BlinkGTK.gtk_init(sys.argv[:1])BlinkGTK.WebViewsys.argv[:1]. Your
application's own arguments may otherwise be read as Chromium
optionsview = BlinkGTK.WebView.new()BlinkGTK.WebView.new() (not
BlinkGTK.WebView())rc = BlinkGTK.gtk_application_run(app)
BlinkGTK.gtk_shutdown()BlinkGTK.gtk_application_run() runs both GTK's and
Chromium's work. Do not use app.run()BlinkGTK.gtk_shutdown() afterwardsBlinkGTK.WebView emits the following four load-related
signals.
| Signal | Handler arguments | Description |
|---|---|---|
load-changed |
(view, event: BlinkGTK.LoadEvent) |
The load state changed |
load-failed |
(view, error_code: int, failing_uri: str) |
A load ended without committing (for example, aborted) |
title-changed |
(view) |
The page title changed. Read the value with
view.get_title() |
uri-changed |
(view) |
The URI changed. Read the value with
view.get_uri() |
title-changed and uri-changed do not pass
the new value as an argument.
def on_load_changed(view, event):
if event == BlinkGTK.LoadEvent.FINISHED:
print(f"Load finished: {view.get_title()} ({view.get_uri()})")
def on_load_failed(view, error_code, failing_uri):
if failing_uri != (view.get_uri() or failing_uri):
return # A failure that is not for the page on screen, such as an iframe
if error_code == -3:
return # Aborted. Happens normally with the stop button or a new load
print(f"Load did not commit: {failing_uri} (error code {error_code})")
def on_title_changed(view):
window.set_title(f"{view.get_title()} - Browser")
view.connect("load-changed", on_load_changed)
view.connect("load-failed", on_load_failed)
view.connect("title-changed", on_title_changed)| Value | Meaning |
|---|---|
BlinkGTK.LoadEvent.STARTED |
A load started with load_uri() /
load_html(). Not emitted for links, back, forward or
reload |
BlinkGTK.LoadEvent.COMMITTED |
The document to display was committed |
BlinkGTK.LoadEvent.FINISHED |
The load finished |
BlinkGTK.LoadEvent.REDIRECTED |
Reserved for future use. Not emitted at present |
Compare against the names above, not against numbers.
Because STARTED does not arrive for every navigation, use
notify::is-loading (see Property Monitoring) to tell whether a
load is in progress.
error_code is a Chromium network error code (a negative
value). -3 means aborted; it happens normally with the stop
button, or when another page is opened during a loadload-failed is
not emitted; you get COMMITTED and FINISHED
insteadfailing_uri
with view.get_uri() and skip the others before touching the
UIChanges to GObject properties arrive through
notify::property-name signals.
The handler receives (view, pspec). Read the value as, for
example, view.props.title.
def on_title_notify(view, pspec):
print(f"Title: {view.props.title}")
def on_uri_notify(view, pspec):
print(f"URI: {view.props.uri}")
view.connect("notify::title", on_title_notify)
view.connect("notify::uri", on_uri_notify)| Property | Type | Description |
|---|---|---|
uri |
str |
The current URI |
title |
str |
The page title |
zoom-level |
float |
The zoom factor; 1.0 is 100% (read/write) |
is-loading |
bool |
Whether a load is in progress |
Switch loading indicators (a progress bar, the stop and reload
buttons) with notify::is-loading.
It arrives when a load starts and when it ends, for every kind of
navigation, including links, back, forward and reload. Read the value
with view.is_loading().
It may arrive twice in a row at the start, so decide by the value, not
by the number of notifications.
def on_is_loading_changed(view, pspec):
loading = view.is_loading()
stop_button.set_sensitive(loading)
reload_button.set_sensitive(not loading)
view.connect("notify::is-loading", on_is_loading_changed)The load progress (0.0 to 1.0) is available from
view.get_estimated_load_progress().
It is not a property, so there is no change notification. See the
example under Practical Usage.
| Method | Description |
|---|---|
load_uri(uri) |
Open a URI |
reload() |
Reload |
stop() |
Stop loading |
go_back() / go_forward() |
Go back / forward in history |
can_go_back() / can_go_forward() |
Whether going back / forward is possible |
#!/usr/bin/env python3
"""A browser with back, forward, reload and a URL entry"""
import sys
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")
from gi.repository import BlinkGTK, Gtk # noqa: E402
class BrowserWithNavigation(Gtk.ApplicationWindow):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.set_default_size(1024, 768)
toolbar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
self.back_button = Gtk.Button(label="←", sensitive=False)
self.back_button.connect("clicked", lambda _b: self.webview.go_back())
toolbar.append(self.back_button)
self.forward_button = Gtk.Button(label="→", sensitive=False)
self.forward_button.connect("clicked", lambda _b: self.webview.go_forward())
toolbar.append(self.forward_button)
reload_button = Gtk.Button(label="↻")
reload_button.connect("clicked", lambda _b: self.webview.reload())
toolbar.append(reload_button)
self.url_entry = Gtk.Entry(hexpand=True)
self.url_entry.connect("activate", self.on_url_activate)
toolbar.append(self.url_entry)
self.webview = BlinkGTK.WebView.new()
self.webview.set_vexpand(True)
# Update the buttons when a load starts or ends (arrives for every kind of navigation)
self.webview.connect("notify::is-loading", self.on_is_loading_changed)
self.webview.connect("title-changed", self.on_title_changed)
self.webview.connect("uri-changed", self.on_uri_changed)
main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
main_box.append(toolbar)
main_box.append(self.webview)
self.set_child(main_box)
def on_url_activate(self, entry):
url = entry.get_text().strip()
if url and "://" not in url and not url.startswith(("about:", "data:")):
url = "https://" + url
if url:
self.webview.load_uri(url)
def on_is_loading_changed(self, webview, pspec):
self.update_navigation_buttons()
def on_title_changed(self, webview):
title = webview.get_title()
self.set_title(f"{title} - Browser" if title else "Browser")
def on_uri_changed(self, webview):
self.url_entry.set_text(webview.get_uri() or "")
self.update_navigation_buttons()
def update_navigation_buttons(self):
self.back_button.set_sensitive(self.webview.can_go_back())
self.forward_button.set_sensitive(self.webview.can_go_forward())
def on_activate(app, url):
window = BrowserWithNavigation(application=app)
window.present()
window.webview.load_uri(url)
def main():
url = sys.argv[1] if len(sys.argv) > 1 else "https://example.com/"
ok, _argv = BlinkGTK.gtk_init(sys.argv[:1])
if not ok:
print("Could not initialize BlinkGTK", file=sys.stderr)
return 1
app = Gtk.Application(application_id="org.example.NavigationBrowser")
app.connect("activate", on_activate, url)
rc = BlinkGTK.gtk_application_run(app)
BlinkGTK.gtk_shutdown()
return rc
if __name__ == "__main__":
sys.exit(main())The back and forward buttons are updated on uri-changed
and notify::is-loading, so they are also updated after
navigation through links, back and forward.
#!/usr/bin/env python3
"""A browser with a header bar and a load progress bar"""
import sys
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")
from gi.repository import BlinkGTK, GLib, Gtk # noqa: E402
class ProgressBrowser(Gtk.ApplicationWindow):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.set_default_size(1200, 900)
self.set_titlebar(Gtk.HeaderBar())
self.set_title("Browser")
self.progress_bar = Gtk.ProgressBar(visible=False)
self.timer_id = 0
self.webview = BlinkGTK.WebView.new()
self.webview.set_vexpand(True)
# Receive the start and end of every load with notify::is-loading (also for links, back and reload)
self.webview.connect("notify::is-loading", self.on_is_loading_changed)
self.webview.connect("notify::title", self.on_title_notify)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
vbox.append(self.progress_bar)
vbox.append(self.webview)
self.set_child(vbox)
def on_is_loading_changed(self, webview, pspec):
if webview.is_loading():
self.progress_bar.set_visible(True)
if self.timer_id == 0:
# The progress value has no change notification, so read it every 0.1 s while loading
self.progress_bar.set_fraction(0.0)
self.timer_id = GLib.timeout_add(100, self.update_progress)
else:
self.progress_bar.set_visible(False)
if self.timer_id:
GLib.source_remove(self.timer_id)
self.timer_id = 0
print(f"Load ended: {webview.get_title() or '(no title)'}", flush=True)
def update_progress(self):
self.progress_bar.set_fraction(self.webview.get_estimated_load_progress())
return GLib.SOURCE_CONTINUE
def on_title_notify(self, webview, pspec):
self.set_title(webview.props.title or "Browser")
def on_activate(app, url):
window = ProgressBrowser(application=app)
window.present()
window.webview.load_uri(url)
def main():
url = sys.argv[1] if len(sys.argv) > 1 else "https://example.com/"
ok, _argv = BlinkGTK.gtk_init(sys.argv[:1])
if not ok:
print("Could not initialize BlinkGTK", file=sys.stderr)
return 1
app = Gtk.Application(application_id="org.example.ProgressBrowser")
app.connect("activate", on_activate, url)
rc = BlinkGTK.gtk_application_run(app)
BlinkGTK.gtk_shutdown()
return rc
if __name__ == "__main__":
sys.exit(main())is-loading becomes True, a timer
starts and reads get_estimated_load_progress() every 0.1 s
into the baris-loading returns to False, the
timer stops. It returns to False however the load ends
(finished, failed or aborted)There is currently no method to run JavaScript in the page from
Python and get the result back (the equivalent of WebKitGTK's
evaluate_javascript()).
Exchanging messages between the page and the application is described in
the App Integration
API (a C reference).
PyGObject is not installed.
# Fedora
sudo dnf install python3-gobject
# Debian / Ubuntu
sudo apt install python3-giThe BlinkGTK introspection data (BlinkGTK-0.1.typelib)
cannot be found.
Install blinkgtk-bin-gir on Fedora or
gir1.2-blinkgtk-0.1 on Debian / Ubuntu.
If it is still not found, see the troubleshooting section of the installation guide.
Check that you are not running the application with
app.run(). It must be run with
BlinkGTK.gtk_application_run(app).
Also check that BlinkGTK.gtk_init() is called before any
widget is created.
With BlinkGTK 1.2.4 and earlier, starting from Python fails because
Chromium's child processes cannot start.
Check the version with BlinkGTK.gtk_get_version() and
update to 1.2.5 or later.
Check that you are not using names from earlier material. The following names do not exist.
| Name that does not exist | Use instead |
|---|---|
execute_javascript() |
Not available (About Running JavaScript) |
set_enable_javascript() |
set_javascript_enabled() |
set_auto_load_images() |
set_images_enabled() |
set_enable_local_storage() |
set_local_storage_enabled() |
estimated-load-progress property |
get_estimated_load_progress() method |
Complete programs that were run and checked are in examples.
minimal_browser.py — a minimal browserbrowser_with_signals.py — a browser using the four
signals, buttons, a URL entry and a progress barcomplete_browser.py — a browser that also switches
settingsblinkgtk-run python3 minimal_browser.py https://example.com/The key points for using BlinkGTK from Python:
BlinkGTK.gtk_init() before creating widgetsBlinkGTK.gtk_application_run(), then call
BlinkGTK.gtk_shutdown()title-changed and uri-changed take no
arguments; read the values with get_title() /
get_uri()notify::is-loadingNext steps:
BlinkGTK Project | Copyright 2025 | BSD-3-Clause License