Dynamic content#

Static text can be boring, so let's add some dynamic elements!

import datetime
from ignis.widgets import Widget
from ignis.utils import Utils

def update_label(clock_label: Widget.Label) -> None:
    text = datetime.datetime.now().strftime("%H:%M:%S")
    clock_label.set_label(text)

def bar(monitor: int) -> Widget.Window:
    clock_label = Widget.Label()

    Utils.Poll(1000, lambda x: update_label(clock_label))

    return Widget.Window(
        namespace=f"some-window-{monitor}",
        monitor=monitor,
        child=Widget.Box(
            vertical=True,
            spacing=10,
            child=[clock_label],
        ),
    )

This code updates label every second with the current time (using built-in Python module datetime).

Signals#

Polling data every second isn't always ideal, as it can negatively impact performance. This is where signals are useful. Signals let us call a callback only when an event occurs (like on_click in Widget.Button).

Let's consider services, which often have both signals and properties.

Here's an example using the MprisService:

from ignis.services.mpris import MprisService

mpris = MprisService.get_default()

mpris.connect("player_added", lambda x, player: print(player.desktop_entry, player.title))
#                                    ^    ^
# Signals always pass the GObject they belong to as the first argument to the callback.
# In this case, MprisPlayer is the second argument of the signal.

Now, open any media player (like a video on YouTube or music on Spotify). Magic! The player name and title will be printed.

Hint

To manually emit (trigger) a signal, use the .emit() method and pass the signal name to it.

Binding#

Next, let's bind a property. Use the .bind() method, passing the property name as the first argument, and optionally a transform function.

from ignis.services.audio import AudioService
from ignis.widgets import Widget

audio = AudioService.get_default()

def bar(monitor: int) -> Widget.Window:
    return Widget.Window(
        namespace=f"some-window-{monitor}",
        monitor=monitor,
        child=Widget.Box(
            child=[
                Widget.Label(label="Current volume: "),
                Widget.Label(
                    label=audio.speaker.bind("volume", lambda value: str(value))  # this function converts the value to a string
                )
            ]
        ),
    )

Try changing the speaker volume using a tool like pavucontrol.

When the property changes, the transform function (if provided) will be called with the new value, and it should return the processed result.

notify signal#

The notify is a special signal that emits when a property changes. To connect to it, use the following syntax: "notify::PROPERTY-NAME".

Danger

Make sure to use - instead of _ in the property name. Otherwise, the signal will not be triggered.

mpris.connect("notify::players", lambda x, y: print(x.players))