Skip to content

3.48.0 gtk4.issue94804.20260925 - #193405

Draft
richyo-codes wants to merge 154 commits into
flutter:masterfrom
richyo-codes:3.48.0-gtk4.issue94804.20260925
Draft

richyo-codes wants to merge 154 commits into
flutter:masterfrom
richyo-codes:3.48.0-gtk4.issue94804.20260925

Conversation

@richyo-codes

@richyo-codes richyo-codes commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

This PR adds GTK4 as an opt-in variant of Flutter's native Linux desktop embedder while retaining the existing GTK3 implementation as the default.

This draft implementation as informed the following RFC for key design decisions to be made. This PR implementation reflects the decisions I believe (currently) to be most pragmatic. Comments / feedback are appreciated.
https://github.com/richyo-codes/rfc/blob/rfc/gtk4-linux-embedder/rfc/430.0000-gtk4-linux-embedder.md

The engine provides GTK3 and GTK4 embedder variants in parallel, allowing applications to adopt GTK4 without requiring existing Linux applications, runners, and plugins to migrate immediately.

The work covers the native Linux embedder, including rendering and presentation, input, text input, display integration, native windowing, accessibility, build configuration, and Flutter tooling.

Fixes #94804.

Related to #159460. GTK4 no longer uses GTK3's ATK accessibility architecture, and this PR maps Flutter semantics into GTK4's native accessibility interfaces. It does not implement the direct AT-SPI-over-D-Bus backend proposed by #159460 for the GTK3 embedder.

Linux GTK4 embedder

This PR adds a GTK4 implementation alongside Flutter's existing GTK3 Linux embedder.

The implementation:

  • keeps GTK3 as the default;
  • separates GTK3- and GTK4-specific platform code while sharing common Linux embedder infrastructure where practical;
  • adds GTK4 application, view, display, rendering, text-input, platform, and accessibility integration;
  • supports the native Linux windowing paths needed by secondary windows and popups;
  • retains compatibility paths for systems where optional GTK4 or graphics capabilities are unavailable.

Rendering and presentation

GTK4 introduces a different native presentation model from GTK3. This PR adds the view and compositor integration needed to present Flutter-rendered content through GTK4, with presentation paths selected according to the window system and available GTK/GDK, GL/EGL, and graphics-driver capabilities.

The implementation covers optional DMA-BUF texture integration, synchronization between Flutter's rendering context and GTK/GDK's presentation context, and Wayland-specific presentation paths. Accelerated paths are capability-gated, with compatibility fallbacks where the required functionality is unavailable.

DMA-BUF texture presentation

Newer GTK4 runtimes provide GDK APIs for constructing textures from DMA-BUF buffers and querying supported formats and modifiers.

The GTK runtime capability layer exposes these APIs only when the complete required capability set is available. This keeps DMA-BUF support optional without raising Flutter's GTK baseline solely to access the newer GDK interfaces.

GL/EGL synchronization

Where GPU resources are shared between Flutter's rendering context and GTK/GDK's presentation context, the implementation handles synchronization between producer and consumer contexts.

Synchronization features are capability-checked, with conservative fallback behavior when the required EGL functionality is unavailable.

Wayland presentation

GTK4-specific Wayland presentation paths can use EGL/native-surface integration where applicable.

Compatibility presentation paths remain available so GTK4 applications do not require one particular Wayland, EGL, Mesa, or proprietary-driver configuration.

Runtime GTK4 capability bindings

A GTK4 runtime capability layer separates Flutter's build-time GTK baseline from optional functionality provided by newer installed GTK runtimes. This supports newer accessibility and graphics/presentation APIs without making the newest GTK release an unconditional build or runtime requirement.

Depending directly on those symbols at link time would make Flutter's minimum GTK requirement equal to the newest API used by the embedder. Instead, this PR adds typed runtime bindings and capability checks for optional GTK/GDK functionality.

The runtime layer:

  • resolves optional APIs from the GTK/GDK libraries already loaded into the process;
  • associates APIs with the GTK versions that introduced them;
  • provides typed ABI declarations where the build-time headers do not contain newer interfaces;
  • verifies that the required capability set is available before using it;
  • fails closed or uses a compatibility path when optional functionality is unavailable.

This allows an engine built against an older GTK4 SDK/sysroot to take advantage of newer APIs when running against a newer GTK installation.

Accessibility

GTK4's accessibility architecture differs substantially from GTK3's ATK-based implementation.

The GTK4 embedder maps Flutter's semantics tree into GTK4-native accessibility objects and exposes additional functionality when newer GTK runtime APIs are available.

Native accessibility hierarchy

Newer GTK4 accessibility interfaces provide functionality needed to expose the Flutter semantics hierarchy as a native GTK accessibility tree, including:

  • parent/child relationships;
  • sibling traversal;
  • accessible bounds;
  • focus-related platform state;
  • stable native accessibility objects associated with Flutter semantics nodes.

The implementation updates this hierarchy incrementally as Flutter semantics updates arrive.

This includes:

  • preserving unchanged native accessibility objects;
  • preserving unchanged parent/child relationships;
  • updating changed properties without rebuilding the entire tree;
  • handling reordered and removed children;
  • pruning cached semantics nodes that are no longer reachable.

Keeping native object identity stable is particularly important for assistive technologies navigating the tree while an application updates.

Newer GTK accessibility APIs at runtime

The runtime-binding layer allows the embedder to use newer GTK accessibility capabilities without requiring those APIs to exist in the build-time GTK headers.

This includes functionality introduced in newer GTK4 releases for the native accessible hierarchy and text accessibility.

Where the required runtime interfaces are not available, the implementation uses the compatible subset rather than attempting to call unavailable symbols.

Accessible text

On GTK runtimes providing the newer text accessibility interfaces, Flutter text semantics can expose richer information to assistive technologies, including:

  • accessible text contents;
  • caret position;
  • selection ranges;
  • text ranges;
  • text attributes;
  • character and text extents;
  • coordinate-to-text-offset lookup;
  • notifications when text content changes;
  • notifications when the caret or selection changes.

This functionality is capability-gated at runtime instead of making the newest GTK4 release Flutter's minimum build target.

Accessibility announcements

Where supported by the installed GTK runtime, the runtime layer also allows Flutter semantics announcements to be forwarded through GTK's native accessibility announcement API.

Relationship to direct AT-SPI support

Flutter's GTK3 embedder currently exposes accessibility through ATK, which in turn bridges to AT-SPI.

Issue #159460 proposes replacing that architecture with a toolkit-independent backend that communicates directly with AT-SPI over D-Bus.

This PR does not implement that direct AT-SPI backend.

GTK4 uses GTK4's native accessibility architecture. The semantics-tree maintenance, incremental update handling, text accessibility work, and separation between Flutter semantics and toolkit-specific objects may nevertheless provide useful groundwork for a future direct AT-SPI implementation.

Flutter tooling

Flutter tooling allows the GTK embedder variant to be selected explicitly:

flutter run -d linux --linux-gtk=gtk4
flutter build linux --linux-gtk=gtk4

GTK3 remains the default when no GTK variant is specified.

The GTK selection is exposed through the Flutter tool rather than requiring developers to manually modify generated Linux runner files.

GTK3 and GTK4 builds use separate build state so CMake configuration and generated artifacts from one variant do not contaminate the other.

The option intentionally refers to the GTK variant rather than introducing a broader --linux-embedder abstraction. Both implementations remain variants of Flutter's GTK-based Linux embedder.

Build environment

The GTK4 work accounts for the difference between the Linux environment used to build the engine and the GTK runtime installed on the target system.

Together with runtime capability detection, this allows Flutter to maintain a conservative build-time GTK baseline while using newer GTK functionality when it is available at runtime.

This is particularly important for accessibility, where requiring the latest interfaces at link time would otherwise increase the minimum GTK version for the complete embedder.

Tests

This PR adds or extends coverage around the GTK4 Linux embedder, including:

  • GTK4 runtime API capability detection;
  • GTK4 accessibility compatibility;
  • native accessibility-tree behavior;
  • semantics-node storage and incremental updates;
  • text accessibility;
  • GTK4 rendering and texture presentation;
  • EGL/graphics capability handling;
  • GTK variant handling in flutter_tools;
  • native GTK4 windowing behavior.

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Centralize the ATK linkage workaround and include C++ type traits outside
the C linkage block. Keep GTK4 target selection and accessibility behavior
out of this compatibility fix.
Mark the ATK node setter and class callback flags as read-only.
Use inline helpers for native surface lookup, display lookup,
and monitor lookup in the existing GTK3 view. Preserve GTK3
cursor behavior and build dependencies.
Cache owned semantics nodes per view and apply partial updates for
native accessibility backends. Cover storage, replacement, and view
isolation. Use g_memdup2 with an older-GLib compatibility helper so
the introducing commit also compiles with newer GLib headers.
Resolve optional GTK4 APIs from the already-loaded process with typed ABI declarations, version checks, and fail-closed fallbacks for newer accessibility and DMA-BUF APIs.

docs(linux): explain GTK4 runtime API compatibility
Move input callbacks and event wiring without changing their behavior.
Expose the existing view state through the private header.
Move GTK3 scroll decoding into the input adapter and pass normalized
positions and deltas to the scrolling manager. Add explicit missing-position
fallback coverage. GTK4 event adaptation follows in the embedding commit.
Select inline GTK3 or GTK4 helpers through a small dispatcher.
Keep pixel conversion shared and introduce surface geometry and
scale helpers for the following GTK4 embedding integration.
Include the texture ID in external texture callback warnings and retain a useful fallback when the callback does not provide error details.
Build GTK3 and GTK4 embedding libraries in parallel and add GTK4 rendering,
input, and view lifecycle support. Native windowing APIs and accessibility
follow in separate commits.
Add regular and dialog window creation helpers and GTK4 window/popover
monitoring. Extend view monitoring with size changes and first-frame replay
for secondary views. Keep the Dart windowing integration in its later commit.
Feed the native GTK accessibility tree from view semantics updates and
add backend tests, using the runtime API bindings.
Add GTK3, GTK4, and unified project templates; select the engine library through command-line, project, and global configuration; and cover the build configuration in tool tests.
Adapt the Linux window controller and multiple-windows example for GTK3 and GTK4 runner variants, including GTK4 popup controller handling.
Add a runtime validator for the selected GTK and sysroot combination, and expose GTK4 unit-test targets to engine tooling.
Keep GTK4 accessibility and Wayland subsurface operations with the GTK4 view implementation, leaving the shared view lifecycle variant-neutral.
Move GTK4 texture acquisition, readback, and DMA-BUF presentation into a GTK4-only implementation while retaining shared OpenGL composition in the common source.
Wait for the producer context before exposing a direct GdkGLTexture fallback to GTK. Successful DMA-BUF exports continue to use their native fence, and readback retains its existing synchronization.
Replace the GTK4 shared-texture glFinish handoff with EGL fence synchronization, while retaining a conservative fallback for drivers without fence support. Keep DMA-BUF fallback handoffs synchronized and restore the EGL-image test mocks required by the GTK4 test target.
Allocate new producer storage after exporting an EGL image to GDK so later frames cannot overwrite content retained by GTK.
Track semantics revisions and structural changes to skip unchanged node updates and avoid rebuilding the native tree for property-only batches. Preserve existing child relationships while handling reordered and removed children in linear passes.

Validation: both GTK runner libraries and GTK4 unit tests build; all seven focused semantics-store and native accessibility tests pass under Xvfb with GDK_DISABLE=gl.
Resolve Linux framebuffer and windowing conflicts by retaining GTK4 compositor sharing and popover support while adopting upstream input cancellation and optional depth/stencil buffers.
Describe the GTK3-only windowing operations that fail closed on GTK4 and the supported GTK4 alternatives.
Keep the GTK4 branch's explicit shareable constructor parameter when adopting upstream framebuffer tests.
Pool up to three export allocations with reusable command resources and fences. Reacquire foreign ownership after texture leases release and DMA-BUF fences are ready, retaining producer completion waits. Fall back for busy frames without disabling export, and defer final cleanup beyond GTK release callbacks.

Validated with 71 tests on AMD and 71 on software Vulkan, native GTK4 compute/plugin pixel capture, and 12 local baseline/pool benchmark runs.
Preserve GTK-specific native-assets CMake directories while adopting upstream logger injection. Align the compiler-discovery fixture with the explicit CMake directory contract.

Validation: 195 native-assets, Linux-build, and project tooling tests pass; Dart formatting and whitespace checks pass.
Keep the existing request timing, platform-thread dispatch, and clock continuity behavior behind a GTK-specific module. Keep renderer and engine API ownership in the engine bridge.

Validation: build both Linux test targets; 50 GTK4 and 42 GTK3 engine and timing tests pass.
…sources

Track dispatch, timer, and GTK tick lifetimes in the frame pacer. Release callback recipients and strong widget leases after baton delivery, preserve idle clock continuity independently, and drain pending batons before engine shutdown. Protect callback-driven teardown against reentrancy.

Add real GTK3/GTK4 lifecycle targets without the engine suite's GTK replacements, register the GTK3 target in the standard test runner, and cover final engine release from a tick. Validation: 12 lifecycle tests per toolkit; engine and timing regressions pass on both GTK versions.
Accept FLUTTER_LINUX_FRAME_PACER=gtk or engine for both GTK versions. Preserve GTK pacing by default, omit the custom callback for the engine fallback, reject invalid values before initialization, and log explicit selections.

Document ownership, test commands, and remaining timing limitations. Validation: 12 real lifecycle tests per GTK version plus 55 GTK4 and 46 GTK3 engine, policy, and timing checks pass with fatal critical errors.
Merge upstream master at 00fdaae. Project and manifest tooling tests pass (197 tests); no conflict resolution was required.
Register scoped destruction before validating the backing image so every early return destroys the embedder baton before collection. Transfer cleanup to the render target after wrapping succeeds.

Add ten Vulkan lifecycle and cache tests. Five failure cases fail before the fix; all twenty selected Vulkan embedder tests pass afterward. Verify attachment reuse through sixty cache round trips, eviction, and context lifetime.
Render sixty fixed-size frames with caching enabled and disabled using images from the engine Vulkan device, then resize and shut down. Assert creation, destruction, and collection counts and emit them as test properties.
Expose compositor cache hits, Vulkan target wrapping dimensions, transient attachment reuse, and successful texture allocations in the engine timeline. Document capture and interpretation separately from GTK snapshot export metrics.
Adapt GTK4 tooling to upstream dependency injection and encoded assemble defines. Preserve per-command Linux directory overrides through an injected resolver.

Validation: 543 focused Flutter tool tests, flutter_tools analysis, and engine formatting checks pass.
Use gtk_window_destroy instead of recursively requesting close. Disconnect monitor signals before releasing NativeCallable resources: an active signal keeps the monitor alive, so unref alone cannot prevent callbacks into freed Dart trampolines.

Validated with 99 framework windowing tests and two real GTK4 gallery probe runs: deferred then accepted native close requests, exactly-once destruction, repeated cleanup and child-view removal. Regression harness lives in Track Atlas commit 543444e. GTK3 behavior is unchanged; hardware GPU and window-manager interaction remain separate gates.
Preserve GTK-specific native asset paths while adopting upstream SDK injection. Resolve compositor layer coordinate changes without losing GTK4 presentation or GTK3 GL state handling.

Validate both native builds, 25 GTK3 rendering tests, 14 GTK4 rendering tests, 47 native-assets and assemble tests, Flutter tool analysis, and formatting.
Merge upstream through 6b2bb92. Adapt the SDF gradient precision fix to upstream's vertex shader and compact uniform layout while retaining high-precision gradient calculations.

Validate GTK3, GTK4, and Impeller builds; 104 tool tests, 40 GTK3 tests, 14 GTK4 tests, and 23 Impeller tests; full Flutter tool analysis; shader formatting and whitespace checks.
Restore both gradient shader files to upstream master, removing the precision overrides from 83b8fb7 and their adaptation in the latest master merge.

Validate the Impeller build, 23 SDF unit and gradient rendering tests, shader formatting, and whitespace checks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) a: desktop Running on desktop a: text input Entering text in a text field or keyboard related problems d: docs/ flutter/flutter/docs, for contributors d: examples Sample code and demos e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. platform-linux Building on or for Linux specifically platform-web Web applications specifically team-linux Owned by the Linux platform team team-web Owned by Web platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use gtk4 for linux desktop

2 participants