It took 3 months to prepare this release and here we go!
This update mainly focuses on rethinking and refactoring some parts of Ignis, but it include many new features & fixes too!
Breaking Changes
Options
Options Service is removed, introducing the new OptionManager
& Options
API instead!
Now all options for all services of Ignis will be in one place, and one class to manage them all.
Migration guide:
- Notification Service:
dnd
,popup_timeout
,max_popups_count
are removed, use corresponding options inignis.options.Options
. E.g., replacenotifications.dnd
withoptions.notifications.dnd
- Recorder Service:
bitrate
,default_file_location
,default_filename
properties are removed. All the same like with Notification Service. - Applications Service: public API hasn't changed
- Wallpaper Service:
wallpaper
property is removed. Useoptions.wallpaper.wallpaper_path
.
If you use Options Service to define your custom options, move to the new OptionsManager
API.
More info is available in the documentation.
Asyncio
asyncio
integration! Some functions are asynchronous now. Use await
or asyncio.create_task()
to call them.
DBusProxy
new_async()
get_dbus_property_async()
set_dbus_property_async()
BluetoothDevice
connect_to()
disconnect_from()
WifiAccessPoint
commit_changes_async()
connect_to()
connect_to_graphical()
disconnect_from()
forget()
EthernetDevice
connect_to()
disconnect_from()
VpnConnection
connect_to()
disconnect_from()
WifiDevice
scan()
Utils.exec_sh_async()
Utils.read_file_async()
Utils.write_file_async()
Widget.FileDialog.open_dialog()
Plus, methods of some services are synchronous and have their explicit async versions now.
Affected methods:
-
MprisPlayer
next()
previous()
pause()
play()
play_pause()
stop()
seek()
-
SystemTrayItem
activate()
secondary_activate()
context_menu()
scroll()
-
SystemdUnit
start()
stop()
restart()
This also affects some property setters:
BacklightDevice.brightness
setter is now synchronous, you can use its asynchronous version which is available as usual method: set_brightness_async()
.
Same for BacklightService.brightness
and MprisPlayer.position
.
Explicit GObject Property type
#157 replaces GObject.Property
with the new IgnisProperty
class.
The main difference with IgnisProperty
is that it can determine the property type automatically based on the return type of the getter
.
This greatly reduces code repetition, as it is sufficient to specify only the return type for the getter function.
Since properties have explicit types, their value can only be of the that defined type because it is now controlled on the GObject/C side, which doesn't support dynamic types.
It means you can't set None
as a value for a property which type is bool/int/str/float
or GObject/GType.
If you use .bind()
, you have to add an additional check if the new value is None
.
Otherwise, an exception like this will be raised:
TypeError: could not convert None to type 'gdouble' when setting property 'IgnisScale.value'
Hyprland Service moved to GObject-based objects
#171 brings objects inherited from IgnisGObject
for Hyprland Service, replacing usual python dictionaries.
This approach allows to bind properties and other GObject features.
New classes:
HyprlandWorkspace
HyprlandWindow
HyprlandKeyboard
Migration Guide:
- Since these objects are not dictionaries anymore, you have to get properties like usual class attributes:
# Old
hyprland.active_workspace["id"]
# New
hyprland.active_workspace.id
HyprlandService.kb_layout
is removed, useHyprlandService.main_keyboard.active_keymap
instead.HyprlandService.switch_kb_layout()
is removed, useHyprlandService.main_keyboard.switch_layout()
instead (to restore the old functionality pass"next"
as an argument to it).HyprlandService.workspaces
will not be notified on the active workspace change anymore.
If you want to restore the old functionality, usebind_many()
:
# Old
hyprland.bind(
"workspaces",
transform=lambda value: [WorkspaceButton(i) for i in value],
)
# New
hyprland.bind_many(
["workspaces", "active_workspace"],
transform=lambda workspaces, *_: [
WorkspaceButton(i) for i in workspaces
],
)
Niri Service moved to GObject-based objects
#181 introduces GObject-based objects for Niri Service.
A few notes:
- Since these objects are not dictionaries anymore, you have to get properties like usual class attributes
NiriService.kb_layout
is removed, useNiriService.keyboard_layouts.current_name
instead.NiriService.active_workspaces
has been dropped, to avoid introducing a separate data structure (list) that needs to be kept up to date. Active workspaces can still be extracted fromNiriService.workspaces
(eachNiriWorkspace
object exposes theis_active
property).NiriService.send_command
now performs json serialization of thecmd
argument and adds a trailing newline ("\n") to the resulting string, thus eliminating the need to pre-process any argument passed to this method.
See updated docs for more info.
Other Breaking Changes
- #103:
Binding.target_property
removed, useBinding.target_properties
(list) instead - #146: logs are stored at
$XDG_STATE_HOME/ignis/ignis.log
(~/.local/state/ignis/ignis.log
) instead of~/.ignis/ignis.log
- The minimal required version of PyGObject is now 3.50.0
- Now
Utils.FileMonitor.flags
usesGio.FileMonitorFlags
, notstr
- chore!: rename
DBusProxy.proxy
->gproxy
for clarity - refactor!: overhaul
DBusProxy
initialization & add support for async initialization (#142) - chore!: remove
Utils.download_image()
as unnecessary - feat!: wrap gvc instead of using git submodule (#109)
New Features
- feat!: allow binding multiple properties (IgnisGObject.bind_many()) (#103)
- feat: add Widget.Stack (Widget.StackPage, Widget.StackSwitcher) (#107)
- feat: Support installation using pip (#92)
- feat: allow skipping gvc build using meson options
- feat: allow skipping dependency check using meson options
- feat(
Widget.Window
): adddynamic_input_region
property - feat: add
Utils.get_monitors()
- feat(
IgnisApp
): addreload_on_monitors_change
property (closes #87) - feat: allow gtk css priority to be overridden (#116)
- feat: support Grass Sass compiler as a fallback (#123)
- feat(
Widget.EventBox
): allow custom scroll flags (#129) - feat: allow custom command format for
Application.launch()
- feat: add
Application.launch_uwsm()
(#134) - feat(
Application
): addis_terminal
property - feat(
Application
): allow running terminal applications using a separate format (closes #141) - feat(
DBusProxy
): make__get_dbus_property
and__set_dbus_property
public - feat(
DBusProxy
): addget_dbus_property_async()
&set_dbus_property_async()
- feat!: follow XDG base directories (#144)
- feat: add
Utils.snake_to_pascal()
&Utils.pascal_to_snake()
Wifi
: Allow get and change PSK (#131)- feat: log python warnings
- feat!: asyncio integration (#152)
- feat: log exceptions from asynchronous functions
- feat: add
ConnectionManager
&DBusConnectionManager
(#159) - feat(
Utils
): add functions for file operations (#149) - feat(
NiriService
): addwindows
property (#164) - feat: add
Utils.get_app_icon_name()
(#167) - feat(
HyprlandService
): addget_workspace_by_id()
method - feat: add
DataGObject
- feat(
DBusProxy
): addcall()
&call_async()
methods - feat(
DBusProxy
): support calling D-Bus methods asynchronously using pythonic way - feat!(
DBusMenu
): move to async - feat(
HyprlandService
): sync workspace on "renameworkspace" event (#172) - feat(
FetchService
): add k10temp cpu temperature support (#187) - feat: add
ignis.is_editable_install
variable - feat(
HyprlandService
): addwindows
property (#210) - feat(
HyprlandService
): addget_windows_on_workspace()
method - feat(
OptionsManager
): Add support for hot-reloading when the file is modified externally (#198) - feat: store compiled css file in a random temporary directory (#211)
- feat(
OptionsManager
): implementTrackedList
(#215) - feat: support modifying
options.applications.pinned_apps
(#216) - feat(
HyprlandService
): addmonitors
property (#219)
Fixes
- fix(nix): add
gnome-bluetooth
toGI_TYPELIB_PATH
(#97) - fix(
NetworkService
): exceptKeyError
on.pop()
- fix(
Vpn
): notifyactive-vpn-id
&is-connected
when adding/removing an active connection - fix(
Widget.Box
): notify child onappend()
,remove()
, andprepend()
- fix(
Widget.Window
): change input region after realize if surface is None - fix(
SystemTrayService
): do not add an item if itsbus_name
is already present inself._items
(closes #118) - fix(
SystemTrayService
): add icon theme of item to search path (#120) - fix: use triple double quotes (
"""
) in__commit__.py
- fix: escape commit message for correct string syntax in
__commit__.py
- fix(nix): do not use
substituteInPlace
for/bin/sass
(#130) - fix(
Wifi
): do not add access points with the same bssid - refactor(
Widget.PopoverMenu
): improve menu generation logic (#136) - fix(
SystemTrayService
): initialize item proxy asynchronously (closes #140) - fix: use
GLib.Error
instead ofGLib.GError
- fix(
SystemTrayItem
): move to asynchronous property synchronization (#147) - Wi-Fi AP Connection Fixes (#131)
- fix(
MprisPlayer
): close player gracefully - fix(
SystemTrayItem
): remove item gracefully - fix(audio/
Stream
): remove stream gracefully - fix(
MprisPlayer
): correctly compare the new art url with the previous one - fix(
RevealerWindow
): do not setRevealer
as the child in therevealer
setter (#162) - fix: add
AsyncCompletedProcess
toUtils
class - fix(
MprisPlayer
): do not sync position if playback status is"Paused"
(#160) - fix(audio/
Stream
): return fallback value instead of returningNone
for properties - fix(
Widget.Box
): remove child on unparent (#182) - fix!(
Widget.Window
): remove setter for namespace property - fix(nix): include build commit hash using
self.rev
(#196) - fix: print correct version information when installed in editable mode
- fix: resolve compatibility issues with PyGObject 3.52.0 (girepository 2.0) (#202)
- fix(
ApplicationsService
): launch applications asynchronously (#204) - fix(
NotificationsService
): follow freedesktop notifications icons specification - docs: add
Display applications icons on Hyprland workspaces buttons
to code snippets
Misc
- github: static.yaml: do not install pygobject & setuptools (#99)
- pyproject.toml: set
requires-python = ">=3.11"
- docs: add
Troubleshooting
page - github(build_docs.yaml): upload documentation artifact
- github(workflows): refactor documentation build & deploy
- .gitignore: add .artifacts
- misc: update project description
- docs: add Code Snippets to examples (#132)
- docs: add
Using Classes
page to user guide - github: add nix issue template
- github: simplify & improve issue templates
- docs: divide utils into categories
- docs: pin sphinx version to 8.1.0 (#154)
- chore: remove
requests
from dependencies lists as unnecessary - refactor: group utils into files by category
- docs: add missing
Utils
to the paths of some classes - refactor(
NiriService
): use match/case statement for event type checking - refactor: define GObject signals arg types in functions arguments (#173)
- nix: update flake.lock
- refactor(
MprisPlayer
): move to asynchronous property synchronization (#158) - chore(
SystemTrayItem
): initialize DBusMenu asynchronously - refactor(
SystemTrayItem
): implement & move to asynchronous constructor - chore(
SystemTrayItem
): rename self.__dbus -> self._proxy for clarity - refactor(
MprisPlayer
): implement & move to asynchronous constructor - refactor: add & use
is_sphinx_build
var instead of checking"sphinx"
insys.modules
- github: suggest using Github Discussions for questions
- github: remove Other issue template as unnecessary
- refactor: prepend only current dir or only build dir to gir repository at a time
- pin pygobject-stubs version to 2.12.0
- docs(
PopoverMenu
): add a note about pointing - docs: explicitly define constructor arguments (#207)
- docs: document members of
Variable
- docs: use custom directives for signals and properties (#177)
- docs: correct typo for
ListBoxRow
- usechild
property instead oflabel
- github(workflows): remove
create_release.yaml
as unnecessary
PRs
- fix(nix): add
gnome-bluetooth
toGI_TYPELIB_PATH
by @AstrickHarren in #97 - feat(github/workflows): static.yaml: do not install pygobject & setuptools by @linkfrg in #99
- Rewrite Options by @linkfrg in #98
- feat!: allow binding multiple properties (
IgnisGObject.bind_many()
) by @PacificViking in #103 - feat!: wrap gvc instead of using git submodule by @linkfrg in #109
- feat: add
Widget.Stack
(Widget.StackPage
,Widget.StackSwitcher
) by @linkfrg in #107 - feat: Support installation using pip by @linkfrg in #92
- fix(tray): add icon theme of item to search path by @TanR314 in #120
- feat: allow gtk css priority to be overridden by @Anomalocaridid in #116
- feat: support Grass Sass compiler as a fallback by @theridane in #123
- fix: nix build by @pschmitt in #130
- feat: allow custom scroll flags for
Widget.EventBox
by @linkfrg in #129 - docs: add Code Snippets to examples by @linkfrg in #132
- feat(applications): add
Application.launch_uwsm()
by @linkfrg in #134 - refactor(
Widget.PopoverMenu
): improve menu generation logic by @linkfrg in #136 - refactor!: overhaul
DBusProxy
initialization & add support for async initialization by @linkfrg in #142 - feat: follow XDG base directories by @linkfrg in #144
- Revert #144 by @linkfrg in #145
- feat!: follow XDG base directories by @linkfrg in #146
- fix(
SystemTrayItem
): move to asynchronous property synchronization by @linkfrg in #147 - feat(utils): add functions for file operations by @linkfrg in #149
- refactor!(
MprisPlayer
): move to asynchronous property synchronization by @linkfrg in #150 - Revert "refactor!(
MprisPlayer
): move to asynchronous property synchronization" by @linkfrg in #151 - Wi-Fi AP Connection Fixes & Allow get and change PSK by @linkfrg in #131
- docs: pin sphinx version to 8.1.0 by @linkfrg in #154
- feat!: asyncio integration by @linkfrg in #152
- refactor(
MprisPlayer
): move to asynchronous property synchronization by @linkfrg in #158 - feat: add
ConnectionManager
&DBusConnectionManager
by @linkfrg in #159 - feat(
NiriService
): addwindows
property by @linkfrg in #164 - fix(
RevealerWindow
): do not setRevealer
as the child in therevealer
setter by @linkfrg in #162 - fix(
NiriService
): sync windows on"WindowsChanged"
and"WindowClosed"
by @linkfrg in #168 - feat: add
Utils.get_app_icon_name()
by @linkfrg in #167 - feat!: explicitly set type for GObject properties by @linkfrg in #157
- feat!(
HyprlandService
): move to GObject-based objects by @linkfrg in #171 - fix(
MprisPlayer
): do not sync position if playback status is"Paused"
by @linkfrg in #160 - refactor: define GObject signals arg types in functions arguments by @linkfrg in #173
- fix(
HyprlandService
): check for presence of attribute when syncing object properties by @linkfrg in #176 - fix(
Widget.Box
): remove child on unparent by @linkfrg in #182 - feat!: add explicit async versions of D-Bus methods for services by @linkfrg in #184
- feat(
HyprlandService
): sync workspaces on"renameworkspace"
event by @linkfrg in #172 - feat: add k10temp cpu temperature support to fetch service by @Anomalocaridid in #187
- fix(
Utils.exec_sh_async
): use asyncio for creating subprocess instead of Gio by @linkfrg in #189 - fix(nix): include build commit hash using
self.rev
by @linkfrg in #196 - fix: resolve compatibility issues with PyGObject 3.52.0 (girepository 2.0) by @linkfrg in #202
- fix(
ApplicationsService
): launch applications asynchronously by @linkfrg in #204 - feat(
OptionsManager
): Add support for hot-reloading when the file is modified externally by @linkfrg in #198 - docs: explicitly define constructor arguments by @linkfrg in #207
- docs: use custom directives for signals and properties by @linkfrg in #177
- feat(
HyprlandService
): addwindows
property by @linkfrg in #210 - feat: store compiled css file in a random temporary directory by @ratson in #211
- feat(
OptionsManager
): implementTrackedList
by @linkfrg in #215 - feat: support modifying
options.applications.pinned_apps
by @linkfrg in #216 - feat!(NiriService): move to GObject-based objects by @regenman in #181
- feat(
HyprlandService
): addmonitors
property by @linkfrg in #219
New Contributors
- @AstrickHarren made their first contribution in #97
- @PacificViking made their first contribution in #103
- @TanR314 made their first contribution in #120
- @Anomalocaridid made their first contribution in #116
- @theridane made their first contribution in #123
- @pschmitt made their first contribution in #130
Full Changelog: v0.4...v0.5