-
-
Notifications
You must be signed in to change notification settings - Fork 785
Initial libadwaita support for GTK4 backend #3925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
19750dd
e3d49d3
17b21f5
1586cda
994dc7b
b4cd3a8
b42ee97
b797f46
e0a7069
cc62359
4517f72
184d3ad
5351fcc
7435bde
8247559
22aa62d
2c79b13
4c65a01
be5918f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| The GTK4 backend now integrates with libadwaita for ActivityIndicator, Window, and App. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,7 +42,7 @@ $ python -m pip install toga-gtk | |
|
|
||
| ### GTK 4 support (experimental) | ||
|
|
||
| The experimental GTK 4 backend requires the use of GTK 4.8 or newer. This requirement is met by Debian 12, Ubuntu 24.04, and Fedora 41. Most testing occurs with GTK 4.14, as this is the version that ships with Ubuntu 24.04. | ||
| The experimental GTK 4 backend requires the use of GTK 4.10 or newer. This requirement is met by Debian 13, Ubuntu 24.04, and Fedora 41. Most testing occurs with GTK 4.14, as this is the version that ships with Ubuntu 24.04. | ||
|
|
||
| If you want to use the experimental GTK 4 backend, run: | ||
|
|
||
|
|
@@ -55,6 +55,14 @@ and set the `TOGA_GTK` environment variable: | |
| $ export TOGA_GTK=4 | ||
| ``` | ||
|
|
||
| The experimental GTK 4 backend also aims to provides support for integrating with desktop environment-specific libraries. At present, `libadwaita` is the only supported library of this kind. This functionality requires libadwaita 1.5 or newer. To enable libadwaita integration support, set: | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. libadwaita 1.5 changed the way dialog things are handled, and also the application "about" dialogs. The relevant APIs are deprecated in libadwaita 1.6. All major distros ship libadwaita 1.5+. Most major distros ship libadwaita 1.6+. |
||
| ```console | ||
| $ export TOGA_GTKLIB=Adw | ||
| ``` | ||
| Most testing occurs with libadwaita 1.5, as this is the version that ships with Ubuntu 24.04. | ||
|
|
||
| Integration with libhelium of tauOS and Granite of elementaryOS is planned. | ||
|
|
||
| ## Implementation details | ||
|
|
||
| The `toga-gtk` backend uses the [GTK3 API](https://docs.gtk.org/gtk3/). The experimental GTK 4 `toga-gtk` backend uses the [GTK4 API](https://docs.gtk.org/gtk4/). | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,14 @@ | |
| gi.require_version("Gdk", gtk_version) | ||
| gi.require_version("Gtk", gtk_version) | ||
|
|
||
| if ( | ||
| gtk_version == "4.0" and os.getenv("TOGA_GTKLIB") == "Adw" | ||
| ): # pragma: cover-if-libadwaita | ||
| gi.require_version("Adw", "1") | ||
| from gi.repository import Adw # noqa: E402, F401 | ||
| else: # pragma: cover-if-plain-gtk | ||
| Adw = None | ||
|
|
||
| from gi.events import GLibEventLoopPolicy # noqa: E402, F401 | ||
| from gi.repository import ( # noqa: E402, F401 | ||
| Gdk, | ||
|
|
@@ -25,10 +33,19 @@ | |
|
|
||
| GLIB_VERSION: tuple[int, int, int] = ( | ||
| GLib.MAJOR_VERSION, | ||
| GLib.MAJOR_VERSION, | ||
| GLib.MAJOR_VERSION, | ||
| GLib.MINOR_VERSION, | ||
| GLib.MICRO_VERSION, | ||
| ) | ||
|
Comment on lines
34
to
38
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't believe I didn't catch this before... |
||
|
|
||
| if Adw: # pragma: cover-if-libadwaita | ||
| ADW_VERSION: tuple[int, int, int] = ( | ||
| Adw.get_major_version(), | ||
| Adw.get_minor_version(), | ||
| Adw.get_micro_version(), | ||
| ) | ||
| else: # pragma: cover-if-plain-gtk | ||
| ADW_VERSION = None | ||
|
|
||
| if GTK_VERSION < (4, 0, 0): # pragma: no-cover-if-gtk4 | ||
| default_display = Gdk.Screen.get_default() | ||
| else: # pragma: no-cover-if-gtk3 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,35 +1,67 @@ | ||
| from ..libs import GTK_VERSION, Gtk | ||
| from ..libs import ADW_VERSION, GTK_VERSION, Adw, Gtk | ||
| from .base import Widget | ||
|
|
||
|
|
||
| class ActivityIndicator(Widget): | ||
| def create(self): | ||
| self.native = Gtk.Spinner() | ||
|
|
||
| def is_running(self): | ||
| if GTK_VERSION < (4, 0, 0): # pragma: no-cover-if-gtk4 | ||
| return self.native.get_property("active") | ||
| else: # pragma: no-cover-if-gtk3 | ||
| return self.native.get_property("spinning") | ||
|
|
||
| def start(self): | ||
| self.native.start() | ||
|
|
||
| def stop(self): | ||
| self.native.stop() | ||
|
|
||
| def rehint(self): | ||
| if GTK_VERSION < (4, 0, 0): # pragma: no-cover-if-gtk4 | ||
| # print( | ||
| # "REHINT", | ||
| # self, | ||
| # self.native.get_preferred_width(), | ||
| # self.native.get_preferred_height(), | ||
| # ) | ||
| width = self.native.get_preferred_width()[0] | ||
| height = self.native.get_preferred_height()[0] | ||
| else: # pragma: no-cover-if-gtk3 | ||
| size = self.native.get_preferred_size()[0] | ||
| width, height = size.width, size.height | ||
| self.interface.intrinsic.width = width | ||
| self.interface.intrinsic.height = height | ||
| # libadwaita 1.6.0 is not in Ubuntu 24.04 yet; no-cover it. | ||
| if Adw is not None and ADW_VERSION >= (1, 6, 0): # pragma: no cover | ||
|
Comment on lines
+6
to
+7
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this no-cover perhaps makes you nervous? Should we land Adwaita 1.6.0 changes until all majors distros ship it? Right now Ubuntu 24.04 does not. |
||
|
|
||
| def create(self): | ||
| self.native = Adw.Spinner() | ||
| self._hidden = False | ||
| self._running = False | ||
|
|
||
| def set_hidden(self, hidden): | ||
| super().set_hidden(not self._running or hidden) | ||
| self._hidden = hidden | ||
|
|
||
| def start(self): | ||
| self._running = True | ||
| super().set_hidden(self._hidden) | ||
|
|
||
| def stop(self): | ||
| self._running = False | ||
| super().set_hidden(True) | ||
|
|
||
| def is_running(self): | ||
| return self._running | ||
|
|
||
| def rehint(self): | ||
| # libadwaita spinners could take on any size; | ||
| # getting preferred size would not work. Hardcode | ||
| # a reasonable size based on documented limits. | ||
| self.interface.intrinsic.width = 32 | ||
| self.interface.intrinsic.height = 32 | ||
|
|
||
| else: # pragma: cover-if-plain-gtk | ||
|
|
||
| def create(self): | ||
| self.native = Gtk.Spinner() | ||
|
|
||
| def start(self): | ||
| self.native.start() | ||
|
|
||
| def stop(self): | ||
| self.native.stop() | ||
|
|
||
| def is_running(self): | ||
| if GTK_VERSION < (4, 0, 0): # pragma: no-cover-if-gtk4 | ||
| return self.native.get_property("active") | ||
| else: # pragma: no-cover-if-gtk3 | ||
| return self.native.get_property("spinning") | ||
|
|
||
| def rehint(self): | ||
| if GTK_VERSION < (4, 0, 0): # pragma: no-cover-if-gtk4 | ||
| # print( | ||
| # "REHINT", | ||
| # self, | ||
| # self.native.get_preferred_width(), | ||
| # self.native.get_preferred_height(), | ||
| # ) | ||
| width = self.native.get_preferred_width()[0] | ||
| height = self.native.get_preferred_height()[0] | ||
| else: # pragma: no-cover-if-gtk3 | ||
| size = self.native.get_preferred_size()[0] | ||
| width, height = size.width, size.height | ||
| self.interface.intrinsic.width = width | ||
| self.interface.intrinsic.height = height | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,7 @@ | |
|
|
||
| import toga | ||
| from toga_gtk.keys import gtk_accel, toga_key | ||
| from toga_gtk.libs import GTK_VERSION, IS_WAYLAND, Gdk, Gtk | ||
| from toga_gtk.libs import GTK_VERSION, IS_WAYLAND, Adw, Gdk, Gtk | ||
|
|
||
| from .dialogs import DialogsMixin | ||
| from .probe import BaseProbe | ||
|
|
@@ -27,7 +27,10 @@ class AppProbe(BaseProbe, DialogsMixin): | |
| def __init__(self, app): | ||
| super().__init__() | ||
| self.app = app | ||
| assert isinstance(self.app._impl.native, Gtk.Application) | ||
| if Adw is None: | ||
| assert isinstance(self.app._impl.native, Gtk.Application) | ||
| else: | ||
| assert isinstance(self.app._impl.native, Adw.Application) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically, Adw.Application subclasses Gtk.Application... however, I used this stronger assertion because without Adw.Application, window bottom corners doesn't round at all. Same with Adw.Window |
||
| assert IS_WAYLAND is (os.environ.get("WAYLAND_DISPLAY", "") != "") | ||
|
|
||
| @property | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI -- the Qt things worked before because Qt overrode all the variables in the include section.