Skip to content

Commit

Permalink
Add minimal support for GTK4
Browse files Browse the repository at this point in the history
Co-authored-by: Muhammad Murad <[email protected]>
  • Loading branch information
danyeaw and MuhammadMuradG committed Jan 18, 2025
1 parent fbedd3f commit 3ae2bcb
Show file tree
Hide file tree
Showing 22 changed files with 798 additions and 393 deletions.
45 changes: 39 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,9 @@ jobs:
- "macOS-x86_64"
- "macOS-arm64"
- "windows"
- "linux-x11"
- "linux-wayland"
- "linux-x11-gtk3"
- "linux-wayland-gtk3"
- "linux-wayland-gtk4"
- "android"
- "iOS"
- "textual-linux"
Expand All @@ -261,7 +262,7 @@ jobs:
# We use a fixed Ubuntu version rather than `-latest` because at some point,
# `-latest` will be updated, but it will be a soft changeover, which would cause
# the system Python version to become inconsistent from run to run.
- backend: "linux-x11"
- backend: "linux-x11-gtk3"
platform: "linux"
runs-on: "ubuntu-24.04"
# The package list should be the same as in unix-prerequisites.rst, and the BeeWare
Expand Down Expand Up @@ -290,7 +291,7 @@ jobs:
setup-python: false # Use the system Python packages
app-user-data-path: "$HOME/.local/share/testbed"

- backend: "linux-wayland"
- backend: "linux-wayland-gtk3"
platform: "linux"
runs-on: "ubuntu-24.04"
# The package list should be the same as in unix-prerequisites.rst, and the BeeWare
Expand All @@ -309,14 +310,45 @@ jobs:
# Start Window Manager
echo "Start window manager..."
# mutter is being run inside a virtual X server because mutter's headless
# mode is not compatible with Gtk
# mode does not provide a Gdk.Display
DISPLAY=:99 MUTTER_DEBUG_DUMMY_MODE_SPECS=2048x1536 \
mutter --nested --wayland --no-x11 --wayland-display toga &
sleep 1
briefcase-run-prefix: "WAYLAND_DISPLAY=toga"
setup-python: false # Use the system Python packages
app-user-data-path: "$HOME/.local/share/testbed"

- backend: "linux-wayland-gtk4"
platform: "linux"
runs-on: "ubuntu-24.04"
env:
XDG_RUNTIME_DIR: "/tmp"
# The package list should be the same as in unix-prerequisites.rst, and the BeeWare
# tutorial, plus mutter to provide a window manager.
pre-command: |
sudo apt update -y
sudo apt install -y --no-install-recommends \
mutter pkg-config python3-dev libgirepository1.0-dev libcairo2-dev \
gir1.2-webkit2-4.1 gir1.2-xapp-1.0 gir1.2-geoclue-2.0 gir1.2-flatpak-1.0 \
gir1.2-gtk-4.0
# Start Virtual X Server
echo "Start X server..."
Xvfb :99 -screen 0 2048x1536x24 &
sleep 1
# Start Window Manager
echo "Start window manager..."
# mutter is being run inside a virtual X server because mutter's headless
# mode does not provide a Gdk.Display
DISPLAY=:99 MUTTER_DEBUG_DUMMY_MODE_SPECS=2048x1536 \
mutter --nested --wayland --no-x11 --wayland-display toga &
sleep 1
briefcase-run-prefix: "WAYLAND_DISPLAY=toga TOGA_GTK=4"
briefcase-test-args: -k 'test_window or test_desktop or test_app and not test_app_icon'
setup-python: false # Use the system Python packages
app-user-data-path: "$HOME/.local/share/testbed"

- backend: "textual-linux"
platform: "linux"
runs-on: "ubuntu-latest"
Expand Down Expand Up @@ -397,7 +429,8 @@ jobs:
timeout-minutes: 15
run: |
${{ matrix.briefcase-run-prefix }} \
briefcase run ${{ matrix.platform }} --log --test ${{ matrix.briefcase-run-args }} -- --ci
briefcase run ${{ matrix.platform }} --log --test ${{ matrix.briefcase-run-args }} \
-- ${{ matrix.briefcase-test-args }} --ci
- name: Upload Logs
uses: actions/[email protected]
Expand Down
1 change: 1 addition & 0 deletions changes/3087.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Toga GTK now supports GTK4 for BeeWare Tutorial 1 by setting `TOGA_GTK=4`.
1 change: 1 addition & 0 deletions cocoa/tests_backend/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class WindowProbe(BaseProbe, DialogsMixin):
supports_unminimize = True
supports_minimize = True
supports_placement = True
supports_as_image = True

def __init__(self, app, window):
super().__init__()
Expand Down
60 changes: 39 additions & 21 deletions gtk/src/toga_gtk/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from .keys import gtk_accel
from .libs import (
GTK_VERSION,
IS_WAYLAND,
TOGA_DEFAULT_STYLES,
Gdk,
Expand Down Expand Up @@ -34,7 +35,7 @@ def __init__(self, interface):
# Stimulate the build of the app
self.native = Gtk.Application(
application_id=self.interface.app_id,
flags=Gio.ApplicationFlags.FLAGS_NONE,
flags=Gio.ApplicationFlags.DEFAULT_FLAGS,
)
self.native_about_dialog = None

Expand All @@ -53,12 +54,22 @@ def gtk_startup(self, data=None):

# Set any custom styles
css_provider = Gtk.CssProvider()
css_provider.load_from_data(TOGA_DEFAULT_STYLES)

context = Gtk.StyleContext()
context.add_provider_for_screen(
Gdk.Screen.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER
)
if GTK_VERSION < (4, 0, 0):
css_provider.load_from_data(TOGA_DEFAULT_STYLES)
context = Gtk.StyleContext()
context.add_provider_for_screen(
Gdk.Screen.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER
)
else:
if Gtk.get_minor_version() >= 12:
css_provider.load_from_string(TOGA_DEFAULT_STYLES)
elif Gtk.get_minor_version() > 8:
css_provider.load_from_data(
TOGA_DEFAULT_STYLES, len(TOGA_DEFAULT_STYLES)
)
else:
css_provider.load_from_data(TOGA_DEFAULT_STYLES.encode("utf-8"))

######################################################################
# Commands and menus
Expand Down Expand Up @@ -173,20 +184,24 @@ def set_main_window(self, window):

def get_screens(self):
display = Gdk.Display.get_default()
if IS_WAYLAND: # pragma: no-cover-if-linux-x
# `get_primary_monitor()` doesn't work on wayland, so return as it is.
return [
ScreenImpl(native=display.get_monitor(i))
for i in range(display.get_n_monitors())
]
else: # pragma: no-cover-if-linux-wayland
primary_screen = ScreenImpl(display.get_primary_monitor())
screen_list = [primary_screen] + [
ScreenImpl(native=display.get_monitor(i))
for i in range(display.get_n_monitors())
if display.get_monitor(i) != primary_screen.native
]
return screen_list
if GTK_VERSION < (4, 0, 0):
if IS_WAYLAND: # pragma: no-cover-if-linux-x
# `get_primary_monitor()` doesn't work on wayland, so return as it is.
return [
ScreenImpl(native=display.get_monitor(i))
for i in range(display.get_n_monitors())
]

else: # pragma: no-cover-if-linux-wayland
primary_screen = ScreenImpl(display.get_primary_monitor())
screen_list = [primary_screen] + [
ScreenImpl(native=display.get_monitor(i))
for i in range(display.get_n_monitors())
if display.get_monitor(i) != primary_screen.native
]
return screen_list
else:
return [ScreenImpl(native=monitor) for monitor in display.get_monitors()]

######################################################################
# App state
Expand All @@ -201,7 +216,10 @@ def get_dark_mode_state(self):
######################################################################

def beep(self):
Gdk.beep()
if GTK_VERSION < (4, 0, 0):
Gdk.beep()
else:
Gdk.Display.get_default().beep()

def _close_about(self, dialog, *args, **kwargs):
self.native_about_dialog.destroy()
Expand Down
Loading

0 comments on commit 3ae2bcb

Please sign in to comment.