### Gtk.Window with Pycairo Drawing Demo Source: https://github.com/gnome/pygobject/blob/main/docs/guide/cairo_integration.md This example demonstrates drawing various shapes using pycairo within a Gtk.ApplicationWindow. It showcases different line join styles and dash patterns. Ensure pycairo is installed for this to function. ```python #!/usr/bin/env python3 """Based on cairo-demo/X11/cairo-demo.c.""" import cairo import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk SIZE = 30 class Application(Gtk.Application): def do_activate(self): window = Gtk.ApplicationWindow( application=self, default_width=450, default_height=600 ) drawing_area = Gtk.DrawingArea() drawing_area.set_draw_func(self.draw) window.set_child(drawing_area) window.present() def triangle(self, ctx): ctx.move_to(SIZE, 0) ctx.rel_line_to(SIZE, 2 * SIZE) ctx.rel_line_to(-2 * SIZE, 0) ctx.close_path() def square(self, ctx): ctx.move_to(0, 0) ctx.rel_line_to(2 * SIZE, 0) ctx.rel_line_to(0, 2 * SIZE) ctx.rel_line_to(-2 * SIZE, 0) ctx.close_path() def bowtie(self, ctx): ctx.move_to(0, 0) ctx.rel_line_to(2 * SIZE, 2 * SIZE) ctx.rel_line_to(-2 * SIZE, 0) ctx.rel_line_to(2 * SIZE, -2 * SIZE) ctx.close_path() def inf(self, ctx): ctx.move_to(0, SIZE) ctx.rel_curve_to(0, SIZE, SIZE, SIZE, 2 * SIZE, 0) ctx.rel_curve_to(SIZE, -SIZE, 2 * SIZE, -SIZE, 2 * SIZE, 0) ctx.rel_curve_to(0, SIZE, -SIZE, SIZE, -2 * SIZE, 0) ctx.rel_curve_to(-SIZE, -SIZE, -2 * SIZE, -SIZE, -2 * SIZE, 0) ctx.close_path() def draw_shapes(self, ctx, x, y, fill): ctx.save() ctx.new_path() ctx.translate(x + SIZE, y + SIZE) self.bowtie(ctx) if fill: ctx.fill() else: ctx.stroke() ctx.new_path() ctx.translate(3 * SIZE, 0) self.square(ctx) if fill: ctx.fill() else: ctx.stroke() ctx.new_path() ctx.translate(3 * SIZE, 0) self.triangle(ctx) if fill: ctx.fill() else: ctx.stroke() ctx.new_path() ctx.translate(3 * SIZE, 0) self.inf(ctx) if fill: ctx.fill() else: ctx.stroke() ctx.restore() def fill_shapes(self, ctx, x, y): self.draw_shapes(ctx, x, y, True) def stroke_shapes(self, ctx, x, y): self.draw_shapes(ctx, x, y, False) def draw(self, da, ctx, width, height): ctx.set_source_rgb(0, 0, 0) ctx.set_line_width(SIZE / 4) ctx.set_tolerance(0.1) ctx.set_line_join(cairo.LINE_JOIN_ROUND) ctx.set_dash([SIZE / 4.0, SIZE / 4.0], 0) self.stroke_shapes(ctx, 0, 0) ctx.set_dash([], 0) self.stroke_shapes(ctx, 0, 3 * SIZE) ctx.set_line_join(cairo.LINE_JOIN_BEVEL) self.stroke_shapes(ctx, 0, 6 * SIZE) ctx.set_line_join(cairo.LINE_JOIN_MITER) self.stroke_shapes(ctx, 0, 9 * SIZE) self.fill_shapes(ctx, 0, 12 * SIZE) ctx.set_line_join(cairo.LINE_JOIN_BEVEL) self.fill_shapes(ctx, 0, 15 * SIZE) ctx.set_source_rgb(1, 0, 0) self.stroke_shapes(ctx, 0, 15 * SIZE) app = Application() app.run() ``` -------------------------------- ### Gtk.CenterBox Example Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/layout-widgets.md Demonstrates creating a Gtk.CenterBox with widgets placed at the start, center, and end. Requires Gtk 4.0. ```python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk class CenterBoxWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, default_width=400, title="CenterBox Example") box = Gtk.CenterBox( start_widget=Gtk.Button(label="Start"), center_widget=Gtk.Label(label="Center"), end_widget=Gtk.Button(label="End"), ) self.set_child(box) def on_activate(app): # Create window win = CenterBoxWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### Set Up Python Virtual Environment and Install Dependencies Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md Create a Python virtual environment and install necessary build tools like Meson-python, Meson, Ninja, and testing libraries. This is required for editable installs. ```console python3 -m venv .venv source .venv/bin/activate python3 -m pip install meson-python meson ninja pycairo pytest pre-commit ``` -------------------------------- ### Install PyGObject on openSUSE (System Package) Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md Install PyGObject and GTK4 from openSUSE repositories using zypper. This is the standard installation method for openSUSE. ```bash sudo zypper install python3-gobject python3-gobject-Gdk typelib-1_0-Gtk-4_0 libgtk-4-1 ``` ```bash python3 hello.py ``` -------------------------------- ### Gtk.HeaderBar Example Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/layout-widgets.md Shows how to use Gtk.HeaderBar as a window titlebar, packing buttons at the start and end. Requires Gtk 4.0. ```python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk class HeaderBarWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, default_width=400, title="HeaderBar Example") header_bar = Gtk.HeaderBar() self.set_titlebar(header_bar) button = Gtk.Button(label="Button") header_bar.pack_start(button) icon_button = Gtk.Button(icon_name="open-menu-symbolic") header_bar.pack_end(icon_button) def on_activate(app): # Create window win = HeaderBarWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### Asynchronous Web Page Download with Callbacks Source: https://github.com/gnome/pygobject/blob/main/docs/guide/asynchronous.md This example shows how to download a web page asynchronously using Gio.File.load_contents_async and handle the result with a callback. It includes UI elements for starting and canceling the download. ```python import time import gi gi.require_version("Gtk", "4.0") from gi.repository import Gio, GLib, Gtk class DownloadWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__( *args, **kwargs, default_width=500, default_height=400, title="Async I/O Example", ) self.cancellable = Gio.Cancellable() self.cancel_button = Gtk.Button(label="Cancel") self.cancel_button.connect("clicked", self.on_cancel_clicked) self.cancel_button.set_sensitive(False) self.start_button = Gtk.Button(label="Load") self.start_button.connect("clicked", self.on_start_clicked) textview = Gtk.TextView(vexpand=True) self.textbuffer = textview.get_buffer() scrolled = Gtk.ScrolledWindow() scrolled.set_child(textview) box = Gtk.Box( orientation=Gtk.Orientation.VERTICAL, spacing=6, margin_start=12, margin_end=12, margin_top=12, margin_bottom=12, ) box.append(self.start_button) box.append(self.cancel_button) box.append(scrolled) self.set_child(box) def append_text(self, text): iter_ = self.textbuffer.get_end_iter() self.textbuffer.insert(iter_, f"[{time.time()}] {text}\n") def on_start_clicked(self, button): button.set_sensitive(False) self.cancel_button.set_sensitive(True) self.append_text("Start clicked...") file_ = Gio.File.new_for_uri("https://pygobject.gnome.org/") file_.load_contents_async(self.cancellable, self.on_ready_callback, None) def on_cancel_clicked(self, button): self.append_text("Cancel clicked...") self.cancellable.cancel() def on_ready_callback(self, source_object, result, user_data): try: _success, content, _etag = source_object.load_contents_finish(result) except GLib.GError as e: self.append_text(f"Error: {e.message}") else: content_text = content[:100].decode("utf-8") self.append_text(f"Got content: {content_text}...") finally: self.cancellable.reset() self.cancel_button.set_sensitive(False) self.start_button.set_sensitive(True) class Application(Gtk.Application): def do_activate(self): window = DownloadWindow(application=self) window.present() def main(): app = Application() app.run() if __name__ == "__main__": main() ``` -------------------------------- ### Create a GTK 4 Application with PyGObject Source: https://github.com/gnome/pygobject/blob/main/docs/index.md This example demonstrates how to create a basic GTK 4 application using PyGObject. Ensure you have GTK 4 and PyGObject installed. ```python import gi gi.require_version("Gtk", "4.0") from gi.repository import GLib, Gtk class MyApplication(Gtk.Application): def __init__(self): super().__init__(application_id="com.example.MyGtkApplication") GLib.set_application_name("My Gtk Application") def do_activate(self): window = Gtk.ApplicationWindow(application=self, title="Hello World") window.present() app = MyApplication() app.run() ``` -------------------------------- ### Extended GTK 'Hello World' Example Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/introduction.md A more complex example demonstrating subclassing Gtk.ApplicationWindow to create a custom window with a button that closes the window on click. This is the PyGObject version of the classic 'Hello World'. ```python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk class MyWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title="Hello World") self.button = Gtk.Button(label="Click Here") self.button.connect("clicked", self.on_button_clicked) self.set_child(self.button) def on_button_clicked(self, _widget): self.close() def on_activate(app): # Create window win = MyWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### Install Project with PDM Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md Use this command to install project dependencies when using PDM. Ensure PDM version 2.13 or newer is installed. ```console pdm install ``` -------------------------------- ### Gtk.Switch Example Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/controls/switch.md Demonstrates creating and connecting to a Gtk.Switch widget. Use the `notify::active` signal for state changes. ```Python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk class SwitcherWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title="Switch Demo") hbox = Gtk.Box(spacing=6, homogeneous=True, margin_top=24, margin_bottom=24) self.set_child(hbox) switch = Gtk.Switch(active=False, halign=Gtk.Align.CENTER) switch.connect("notify::active", self.on_switch_activated) hbox.append(switch) switch = Gtk.Switch(active=True, halign=Gtk.Align.CENTER) switch.connect("notify::active", self.on_switch_activated) hbox.append(switch) def on_switch_activated(self, switch, _gparam): state = "on" if switch.props.active else "off" print("Switch was turned", state) def on_activate(app): win = SwitcherWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### Python Class Docstring with Example Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/style_guide.md Example of a Python class docstring, including __init__ argument documentation and a reST code block for usage examples. ```python class Bacon(CookedFood): """Bacon is a breakfast food. :param CookingType cooking_type: Enum for the type of cooking to use. :param float cooking_time: Amount of time used to cook the Bacon in minutes. Use Bacon in combination with other breakfast foods for a complete breakfast. For example, combine Bacon with other items in a list to make a breakfast: .. code-block:: python breakfast = [Bacon(), Spam(), Spam(), Eggs()] """ def __init__(self, cooking_type=CookingType.BAKE, cooking_time=15.0): super(Bacon, self).__init__(cooking_type, cooking_time) ``` -------------------------------- ### Install openSUSE Dependencies Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md Installs required packages for compiling Python and pip installing pygobject on openSUSE systems. ```bash sudo zypper install -y python3-wheel gobject-introspection-devel \ python3-cairo-devel openssl zlib git sudo zypper install --type pattern devel_basis ``` -------------------------------- ### PyGObject Build Setup Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/profiling.md General vpath build setup for PyGObject using jhbuild shell. Ensure Python 3.3 is specified. ```bash mkdir _build cd _build export PYTHON=`which python3.3` jhbuild shell ../configure --prefix=$JHBUILD_PREFIX --libdir=$JHBUILD_LIBDIR --with-python=$PYTHON make ``` -------------------------------- ### Install PyGObject on openSUSE (Pip) Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md Install PyGObject and its dependencies from PyPI using pip on openSUSE. Ensure all necessary build tools and libraries are installed via zypper. ```bash sudo zypper install cairo-devel pkg-config python3-devel gcc gobject-introspection-devel ``` ```bash pip3 install pycairo ``` ```bash pip3 install PyGObject ``` ```bash python3 hello.py ``` -------------------------------- ### GTK+ Text View Window Setup Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/textview.md Sets up the main GTK+ window and initializes the text view with wrapping options and event handlers. ```python radio_wrapchar, radio_wrapnone, Gtk.PositionType.RIGHT, 1, 1 ) radio_wrapword = Gtk.CheckButton(label="Word Wrapping", group=radio_wrapnone) grid.attach_next_to( radio_wrapword, radio_wrapchar, Gtk.PositionType.RIGHT, 1, 1 ) radio_wrapnone.connect("toggled", self.on_wrap_toggled, Gtk.WrapMode.NONE) radio_wrapchar.connect("toggled", self.on_wrap_toggled, Gtk.WrapMode.CHAR) radio_wrapword.connect("toggled", self.on_wrap_toggled, Gtk.WrapMode.WORD) def on_button_clicked(self, _widget, tag): bounds = self.textbuffer.get_selection_bounds() if len(bounds) != 0: start, end = bounds self.textbuffer.apply_tag(tag, start, end) def on_clear_clicked(self, _widget): start = self.textbuffer.get_start_iter() end = self.textbuffer.get_end_iter() self.textbuffer.remove_all_tags(start, end) def on_wrap_toggled(self, _widget, mode): self.textview.props.wrap_mode = mode def on_justify_toggled(self, _widget, justification): self.textview.props.justification = justification def on_search_clicked(self, _widget): self.search_dialog = SearchDialog(self) self.search_dialog.button.connect("clicked", self.on_find_clicked) self.search_dialog.present() def on_find_clicked(self, _button): cursor_mark = self.textbuffer.get_insert() start = self.textbuffer.get_iter_at_mark(cursor_mark) if start.get_offset() == self.textbuffer.get_char_count(): start = self.textbuffer.get_start_iter() self.search_and_mark(self.search_dialog.entry.get_text(), start) def search_and_mark(self, text, start): end = self.textbuffer.get_end_iter() match = start.forward_search(text, 0, end) if match is not None: match_start, match_end = match self.textbuffer.apply_tag(self.tag_found, match_start, match_end) self.search_and_mark(text, match_end) ``` -------------------------------- ### Install PyGObject with Editable Install (Default Build) Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md Install PyGObject in editable mode, allowing for dynamic rebuilds. The `--no-build-isolation` flag is crucial for this. The `.[dev]` extra installs development dependencies. ```console pip install --no-build-isolation --config-settings=setup-args="-Dtests=true" -e '.[dev]' ``` -------------------------------- ### Async Download Window with Feedback Source: https://github.com/gnome/pygobject/blob/main/docs/guide/asynchronous.md A complete GTK 4 application demonstrating asynchronous file download with UI feedback. It uses asyncio for background tasks and provides buttons to start and cancel the download. Ensure you have PyGObject and GTK 4 installed. ```python import asyncio import time import gi gi.require_version("Gtk", "4.0") from gi.repository import Gio, GLib, Gtk from gi.events import GLibEventLoopPolicy class DownloadWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__( *args, **kwargs, default_width=500, default_height=400, title="Async I/O Example", ) self.background_task = None self.cancel_button = Gtk.Button(label="Cancel") self.cancel_button.connect("clicked", self.on_cancel_clicked) self.cancel_button.set_sensitive(False) self.start_button = Gtk.Button(label="Load") self.start_button.connect("clicked", self.on_start_clicked) textview = Gtk.TextView(vexpand=True) self.textbuffer = textview.get_buffer() scrolled = Gtk.ScrolledWindow() scrolled.set_child(textview) box = Gtk.Box( orientation=Gtk.Orientation.VERTICAL, spacing=6, margin_start=12, margin_end=12, margin_top=12, margin_bottom=12, ) box.append(self.start_button) box.append(self.cancel_button) box.append(scrolled) self.set_child(box) def append_text(self, text): iter_ = self.textbuffer.get_end_iter() self.textbuffer.insert(iter_, f"[{time.time()}] {text}\n") def on_start_clicked(self, button): button.set_sensitive(False) self.cancel_button.set_sensitive(True) self.append_text("Start clicked...") self.background_task = asyncio.create_task(self.download()) def on_cancel_clicked(self, button): self.append_text("Cancel clicked...") self.background_task.cancel() async def download(self): file_ = Gio.File.new_for_uri("https://pygobject.gnome.org/") try: _success, content, _etag = await file_.load_contents_async() except GLib.GError as e: self.append_text(f"Error: {e.message}") else: content_text = content[:100].decode("utf-8") self.append_text(f"Got content: {content_text}...") finally: self.cancel_button.set_sensitive(False) self.start_button.set_sensitive(True) class Application(Gtk.Application): def do_activate(self): window = DownloadWindow(application=self) window.present() def main(): asyncio.set_event_loop_policy(GLibEventLoopPolicy()) app = Application() app.run() if __name__ == "__main__": main() ``` -------------------------------- ### Install Pre-commit Hooks Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/style_guide.md Install pre-commit hooks to ensure consistent code style before committing changes. ```bash pre-commit install ``` -------------------------------- ### Install PyGObject from PyPI Source: https://github.com/gnome/pygobject/blob/main/README.rst Use pip to install the latest version of PyGObject. A C compiler is required as PyGObject is distributed as a source distribution. ```bash pip install PyGObject ``` -------------------------------- ### Define MyWindow Class Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/introduction.md Start by defining your custom window class inheriting from Gtk.ApplicationWindow. ```python class MyWindow(Gtk.ApplicationWindow): ``` -------------------------------- ### Gtk.SpinButton Example Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/controls/spinbutton.md Demonstrates the creation and basic usage of a Gtk.SpinButton, including connecting to value changes and binding properties like 'numeric' and 'update_policy'. ```Python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk class SpinButtonWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title="SpinButton Demo") hbox = Gtk.Box(spacing=6) self.set_child(hbox) adjustment = Gtk.Adjustment(upper=100, step_increment=1, page_increment=10) self.spinbutton = Gtk.SpinButton(adjustment=adjustment) self.spinbutton.connect("value-changed", self.on_value_changed) hbox.append(self.spinbutton) check_numeric = Gtk.CheckButton(label="Numeric") check_numeric.bind_property("active", self.spinbutton, "numeric", 0) hbox.append(check_numeric) check_ifvalid = Gtk.CheckButton(label="If Valid") check_ifvalid.connect("toggled", self.on_ifvalid_toggled) hbox.append(check_ifvalid) def on_value_changed(self, _scroll): print(self.spinbutton.get_value_as_int()) def on_ifvalid_toggled(self, button): if button.get_active(): policy = Gtk.SpinButtonUpdatePolicy.IF_VALID else: policy = Gtk.SpinButtonUpdatePolicy.ALWAYS self.spinbutton.props.update_policy = policy def on_activate(app): win = SpinButtonWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### Install PyGObject on Arch Linux (Pip) Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md Install PyGObject and its dependencies from PyPI using pip on Arch Linux. Build dependencies must be installed via pacman first. ```bash sudo pacman -S python cairo pkgconf gobject-introspection gtk4 ``` ```bash pip3 install pycairo ``` ```bash pip3 install PyGObject ``` ```bash python3 hello.py ``` -------------------------------- ### PyGTK 2 Hello Message Box Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/introspection_porting.md Example of creating a 'Hello World' message dialog using PyGTK 2. ```console $ python -c 'import gtk; gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, "Hello World").run()' ``` -------------------------------- ### Install PyGObject on Fedora (System Package) Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md Install PyGObject and GTK4 from system repositories on Fedora using dnf. This is the recommended method for Fedora users. ```bash sudo dnf install python3-gobject gtk4 ``` ```bash python3 hello.py ``` -------------------------------- ### Gtk.Grid Example with attach and attach_next_to Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/layout-widgets.md Demonstrates arranging widgets in a Gtk.Grid using both attach() and attach_next_to() methods. Requires Gtk 4.0. ```python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk class GridWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title="Grid Example") button1 = Gtk.Button(label="Button 1") button2 = Gtk.Button(label="Button 2") button3 = Gtk.Button(label="Button 3") button4 = Gtk.Button(label="Button 4") button5 = Gtk.Button(label="Button 5") button6 = Gtk.Button(label="Button 6") grid = Gtk.Grid() grid.attach(button1, 0, 0, 1, 1) grid.attach(button2, 1, 0, 2, 1) grid.attach_next_to(button3, button1, Gtk.PositionType.BOTTOM, 1, 2) grid.attach_next_to(button4, button3, Gtk.PositionType.RIGHT, 2, 1) grid.attach(button5, 1, 2, 1, 1) grid.attach_next_to(button6, button5, Gtk.PositionType.RIGHT, 1, 1) self.set_child(grid) def on_activate(app): # Create window win = GridWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### Import GTK and Gio Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/application.md Import necessary modules from gi.repository for GTK 4.0 and GLib. This is a standard setup for GTK applications. ```python import sys import gi gi.require_version("Gtk", "4.0") from gi.repository import GLib, Gio, Gtk ``` -------------------------------- ### Gtk.ListBox Example Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/layout-widgets.md Demonstrates the creation and population of a Gtk.ListBox with custom rows, including sorting and filtering functionality. Connects to the 'row-activated' signal. ```Python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk class ListBoxRowWithData(Gtk.ListBoxRow): def __init__(self, data): super().__init__() self.data = data self.set_child(Gtk.Label(label=data)) class ListBoxWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, default_width=400, title="ListBox Demo") # Main box of out window box_outer = Gtk.Box( orientation=Gtk.Orientation.VERTICAL, spacing=24, margin_start=24, margin_end=24, margin_top=24, margin_bottom=24, ) self.set_child(box_outer) # Let's create our first ListBox listbox = Gtk.ListBox( selection_mode=Gtk.SelectionMode.NONE, show_separators=True, ) box_outer.append(listbox) # Let's create our first ListBoxRow row = Gtk.ListBoxRow() hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=24) row.set_child(hbox) # We set the Box as the ListBoxRow child vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox.append(vbox) label1 = Gtk.Label(label="Automatic Date & Time", xalign=0) label2 = Gtk.Label(label="Requires internet access", xalign=0) vbox.append(label1) vbox.append(label2) switch = Gtk.Switch( hexpand=True, # Lets make the Switch expand to the window width halign=Gtk.Align.END, # Horizontally aligned to the end valign=Gtk.Align.CENTER, # Vertically aligned to the center ) hbox.append(switch) listbox.append(row) # Add the row to the list # Our second row. We will omit the ListBoxRow and directly append a Box hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=24) label = Gtk.Label(label="Enable Automatic Update", xalign=0) check = Gtk.CheckButton(hexpand=True, halign=Gtk.Align.END) hbox.append(label) hbox.append(check) listbox.append(hbox) # Add the second row to the list # Let's create a second ListBox listbox_2 = Gtk.ListBox() box_outer.append(listbox_2) items = ["This", "is", "a", "sorted", "ListBox", "Fail"] # Populate the list for item in items: listbox_2.append(ListBoxRowWithData(item)) # Set sorting and filter functions listbox_2.set_sort_func(self.sort_func) listbox_2.set_filter_func(self.filter_func) # Connect to "row-activated" signal listbox_2.connect("row-activated", self.on_row_activated) def sort_func(self, row_1, row_2): return row_1.data.lower() > row_2.data.lower() def filter_func(self, row): return row.data != "Fail" def on_row_activated(self, _listbox, row): pass def on_activate(app): # Create window win = ListBoxWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### Install PyGObject with Debug Symbols Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md Install PyGObject in editable mode with C libraries compiled in debug mode. This is achieved by setting the `buildtype` to `debug` via setup arguments. ```console pip install --no-build-isolation --config-settings=setup-args="-Dbuildtype=debug" --config-settings=setup-args="-Dtests=true" -e '.[dev]' ``` -------------------------------- ### Set Up Build Directory with Meson Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md Initialize the build environment using Meson. This command is typically needed only once to set up the build configuration. ```console meson setup _build ``` -------------------------------- ### Get Selection Bounds Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/textview.md Retrieve the start and end iterators for the currently selected text within a Gtk.TextBuffer. Returns `True` if there is a selection, and the iterators defining its bounds. ```python success, start_iter, end_iter = buffer.get_selection_bounds() ``` -------------------------------- ### Initialize Pixi Environment and Add PyGObject Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md Initialize a new Pixi project in the current directory, then add PyGObject and GTK4 as dependencies. This is suitable for managing project-specific environments. ```bash pixi init . ``` ```bash pixi add pygobject gtk4 ``` -------------------------------- ### Create and Populate a Gtk.FlowBox Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/layout-widgets.md Demonstrates how to create a Gtk.FlowBox, set its properties, and append child widgets. This example shows how to create color swatches as buttons and add them to the FlowBox. ```Python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk, Gdk class FlowBoxWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title="FlowBox Demo") self.set_default_size(300, 250) header = Gtk.HeaderBar() self.set_titlebar(header) scrolled = Gtk.ScrolledWindow() scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.set_child(scrolled) flowbox = Gtk.FlowBox( valign=Gtk.Align.START, max_children_per_line=30, selection_mode=Gtk.SelectionMode.NONE, ) scrolled.set_child(flowbox) self.create_flowbox(flowbox) def draw_button_color(self, area, cr, width, height, rgba): cr.set_source_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha) cr.rectangle(0, 0, width, height) cr.fill() def color_swatch_new(self, str_color): rgba = Gdk.RGBA() rgba.parse(str_color) button = Gtk.Button(tooltip_text=str_color) area = Gtk.DrawingArea() area.set_size_request(24, 24) area.set_draw_func(self.draw_button_color, rgba) button.set_child(area) return button def create_flowbox(self, flowbox): colors = [ "AliceBlue", "AntiqueWhite", "AntiqueWhite1", "AntiqueWhite2", "AntiqueWhite3", "AntiqueWhite4", "aqua", "aquamarine", "aquamarine1", "aquamarine2", "aquamarine3", "aquamarine4", "azure", "azure1", "azure2", "azure3", "azure4", "beige", "bisque", "bisque1", "bisque2", "bisque3", "bisque4", "black", "BlanchedAlmond", "blue", "blue1", "blue2", "blue3", "blue4", "BlueViolet", "brown", "brown1", "brown2", "brown3", "brown4", "burlywood", "burlywood1", "burlywood2", "burlywood3", "burlywood4", "CadetBlue", "CadetBlue1", "CadetBlue2", "CadetBlue3", "CadetBlue4", "chartreuse", "chartreuse1", "chartreuse2", "chartreuse3", "chartreuse4", "chocolate", "chocolate1", "chocolate2", "chocolate3", "chocolate4", "coral", "coral1", "coral2", "coral3", "coral4", ] for color in colors: button = self.color_swatch_new(color) flowbox.append(button) def on_activate(app): # Create window win = FlowBoxWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### Gtk.Spinner with Timeout Function Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/display-widgets/spinner.md This example demonstrates using Gtk.Spinner with a timeout function for timed animations. The GLib.timeout_add function schedules a callback to run at regular intervals, allowing for controlled start and stop of the spinner. Ensure the timeout is removed when the window is destroyed to prevent issues. ```python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk, GLib class SpinnerAnimation(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title="Spinner Demo") main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.set_child(main_box) self.spinner = Gtk.Spinner() main_box.append(self.spinner) self.label = Gtk.Label() main_box.append(self.label) self.entry = Gtk.Entry(text="10") main_box.append(self.entry) self.button_start = Gtk.Button(label="Start timer") self.button_start.connect("clicked", self.on_button_start_clicked) main_box.append(self.button_start) self.button_stop = Gtk.Button(label="Stop timer", sensitive=False) self.button_stop.connect("clicked", self.on_button_stop_clicked) main_box.append(self.button_stop) self.timeout_id = None self.connect("unrealize", self.on_window_destroy) def on_button_start_clicked(self, _widget): """Handles 'clicked' event of button_start.""" self.start_timer() def on_button_stop_clicked(self, _widget): """Handles 'clicked' event of button_stop.""" self.stop_timer("Stopped from button") def on_window_destroy(self, _widget): """Handles unrealize event of main window.""" # Ensure the timeout function is stopped if self.timeout_id: GLib.source_remove(self.timeout_id) self.timeout_id = None def on_timeout(self): """A timeout function. Return True to stop it. This is not a precise timer since next timeout is recalculated based on the current time. """ self.counter -= 1 if self.counter <= 0: self.stop_timer("Reached time out") return False self.label.props.label = f"Remaining: {int(self.counter / 4)!s}" return True def start_timer(self): """Start the timer.""" self.button_start.props.sensitive = False self.button_stop.props.sensitive = True # time out will check every 250 milliseconds (1/4 of a second) self.counter = 4 * int(self.entry.props.text) self.label.props.label = f"Remaining: {int(self.counter / 4)!s}" self.spinner.start() self.timeout_id = GLib.timeout_add(250, self.on_timeout) def stop_timer(self, label_text): """Stop the timer.""" if self.timeout_id: GLib.source_remove(self.timeout_id) self.timeout_id = None self.spinner.stop() self.button_start.props.sensitive = True self.button_stop.props.sensitive = False self.label.props.label = label_text def on_activate(app): win = SpinnerAnimation(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### List Block Devices using GUdev Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/introspection_porting.md Demonstrates how to use the GUdev library to query and list all block devices connected to the system. This example requires the gudev library and shows signal integration. ```python from gi.repository import GUdev c = GUdev.Client() for dev in c.query_by_subsystem("block"): print dev.get_device_file() ``` -------------------------------- ### Import and Print Gtk Module Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/introspection_porting.md Demonstrates how to import the Gtk module from gi.repository and print its representation. This is a basic check to ensure GTK typelibs are installed and accessible. ```console python -c 'from gi.repository import Gtk; print Gtk' ``` -------------------------------- ### Install PyGObject on Fedora (Pip) Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md Install PyGObject and its dependencies from PyPI using pip on Fedora. Ensure build dependencies are installed before proceeding with pip installs. ```bash sudo dnf install gcc gobject-introspection-devel cairo-gobject-devel pkg-config python3-devel gtk4 ``` ```bash pip3 install pycairo ``` ```bash pip3 install PyGObject ``` ```bash python3 hello.py ``` -------------------------------- ### Initialize Gtk.ApplicationWindow with Actions Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/application.md This class sets up a Gtk.ApplicationWindow, including defining and connecting stateful actions for toggling maximization and changing a label's text. It also configures the window's menubar visibility and default size. ```python class AppWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.set_default_size(200, 200) # By default the title bar will be hide, let's show it self.props.show_menubar = True # This will be in the windows group and have the 'win' prefix max_action = Gio.SimpleAction.new_stateful( "maximize", None, GLib.Variant.new_boolean(False) ) max_action.connect("change-state", self.on_maximize_toggle) self.add_action(max_action) # Keep it in sync with the actual state self.connect( "notify::maximized", lambda obj, _pspec: max_action.set_state( GLib.Variant.new_boolean(obj.props.maximized) ), ) lbl_variant = GLib.Variant.new_string("String 1") lbl_action = Gio.SimpleAction.new_stateful( "change_label", lbl_variant.get_type(), lbl_variant ) lbl_action.connect("change-state", self.on_change_label_state) self.add_action(lbl_action) self.label = Gtk.Label(label=lbl_variant.get_string()) self.set_child(self.label) def on_change_label_state(self, action, value): action.set_state(value) self.label.set_text(value.get_string()) def on_maximize_toggle(self, action, value): action.set_state(value) if value.get_boolean(): self.maximize() else: self.unmaximize() ``` -------------------------------- ### Install Fedora Dependencies Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md Installs required packages for compiling Python and pip installing pygobject on Fedora systems. ```bash sudo dnf install -y python3-wheel sudo dnf install -y gcc zlib-devel bzip2 bzip2-devel readline-devel \ sqlite sqlite-devel openssl-devel tk-devel git python3-cairo-devel \ cairo-gobject-devel gobject-introspection-devel ``` -------------------------------- ### PyGI GTK 3 Hello Message Box Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/introspection_porting.md Example of creating a 'Hello World' message dialog using PyGI GTK 3, demonstrating the import and naming conventions. ```console $ python -c 'from gi.repository import Gtk; Gtk.MessageDialog(None, 0, Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE, "Hello World").run()' ``` -------------------------------- ### Install Arch Linux Dependencies Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md Installs necessary packages for compiling Python and pip installing pygobject on Arch Linux. ```bash sudo pacman -S --noconfirm python-wheel sudo pacman -S --noconfirm base-devel openssl zlib git gobject-introspection ``` -------------------------------- ### Build PyGObject with Meson Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/packagingguide.md Commands to set up, compile, test, and install PyGObject using Meson. Ensure the prefix and buildtype are set appropriately for your environment. ```bash meson setup --prefix /usr --buildtype=plain _build -Dc_args=... -Dc_link_args=... meson compile -C _build Meson test -C _build DESTDIR=/path/to/staging/root meson install -C _build ``` -------------------------------- ### Install Ubuntu/Debian Dependencies Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md Installs necessary packages for compiling Python and pip installing pygobject on Ubuntu or Debian-based systems. ```bash sudo apt-get install -y python3-venv python3-wheel python3-dev sudo apt-get install -y gobject-introspection libgirepository-2.0-dev \ gir1.2-girepository-3.0 build-essential libbz2-dev libreadline-dev \ libssl-dev zlib1g-dev libsqlite3-dev wget curl llvm libncurses-dev \ xz-utils tk-dev libcairo2-dev ``` -------------------------------- ### Create and Use Gtk Buttons Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/controls/buttons.md Demonstrates creating buttons with labels and mnemonics, and connecting to their 'clicked' signal. Use this for standard button actions. ```python import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk class ButtonWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title="Button Demo") hbox = Gtk.Box(spacing=6) self.set_child(hbox) button = Gtk.Button.new_with_label("Click Me") button.connect("clicked", self.on_click_me_clicked) hbox.append(button) button = Gtk.Button.new_with_mnemonic("_Open") button.connect("clicked", self.on_open_clicked) hbox.append(button) button = Gtk.Button.new_with_mnemonic("_Close") button.connect("clicked", self.on_close_clicked) hbox.append(button) def on_click_me_clicked(self, _button): print("[Click me] button was clicked") def on_open_clicked(self, _button): print("[Open] button was clicked") def on_close_clicked(self, _button): print("Closing application") self.close() def on_activate(app): win = ButtonWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ``` -------------------------------- ### Initialize Gtk.Application with Options and Actions Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/application.md This class defines the main Gtk.Application, setting an application ID and flags. It adds command-line options, connects actions for 'about' and 'quit', and loads the application menu from XML. ```python class Application(Gtk.Application): def __init__(self, *args, **kwargs): super().__init__( *args, application_id="org.example.App", flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE, **kwargs, ) self.window = None self.add_main_option( "test", ord("t"), GLib.OptionFlags.NONE, GLib.OptionArg.NONE, "Command line test", None, ) def do_startup(self): Gtk.Application.do_startup(self) action = Gio.SimpleAction.new("about", None) action.connect("activate", self.on_about) self.add_action(action) action = Gio.SimpleAction.new("quit", None) action.connect("activate", self.on_quit) self.add_action(action) builder = Gtk.Builder.new_from_string(MENU_XML, -1) self.set_menubar(builder.get_object("menubar")) def do_activate(self): # We only allow a single window and raise any existing ones if not self.window: # Windows are associated with the application # when the last one is closed the application shuts down self.window = AppWindow(application=self, title="Main Window") self.window.present() def do_command_line(self, command_line): options = command_line.get_options_dict() # convert GVariantDict -> GVariant -> dict options = options.end().unpack() if "test" in options: # This is printed on the main instance pass self.activate() return 0 ``` -------------------------------- ### Install PyGObject on Ubuntu/Debian (Pip) Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md Install PyGObject and its dependencies from PyPI using pip on Ubuntu/Debian. This method requires installing build dependencies first. ```bash sudo apt install libgirepository-2.0-dev gcc libcairo2-dev pkg-config python3-dev gir1.2-gtk-4.0 ``` ```bash pip3 install pycairo ``` ```bash pip3 install PyGObject ``` ```bash python3 hello.py ``` -------------------------------- ### Gtk Notebook Example Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/layout-widgets.md Demonstrates the creation of a Gtk.Notebook widget with two pages, each having a different tab label. The first page uses a plain text label, and the second uses an icon. ```default import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk class NotebookWindow(Gtk.Window): def __init__(self, **kargs): super().__init__(**kargs, title="Simple Notebook Example") notebook = Gtk.Notebook() self.set_child(notebook) page1 = Gtk.Box() page1.append(Gtk.Label(label="Default Page!")) notebook.append_page(page1, Gtk.Label(label="Plain Title")) page2 = Gtk.Box() page2.append(Gtk.Label(label="A page with an image for a Title.")) notebook.append_page(page2, Gtk.Image(icon_name="help-about")) def on_activate(app): # Create window win = NotebookWindow(application=app) win.present() app = Gtk.Application(application_id="com.example.App") app.connect("activate", on_activate) app.run(None) ```