nandi/vflutter_ffipublic Fork 0
7fdf712
Commits
Clone
git clone https://git.rickub.com/nandi/vflutter_ffi.git
git clone ssh://git@rickub.com/nandi/vflutter_ffi.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Add Flutter example app with Linux runner

Adds the example/ app that exercises the vflutter_ffi plugin, including
the Linux desktop runner and a widget test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-09-18T22:03:06Z Browse files
7fdf712 parent: ad0ccda
added example/.gitignore +48 -0
new file mode 100644
@@ -0,0 +1,48 @@
1+# Miscellaneous
2+*.class
3+*.log
4+*.pyc
5+*.swp
6+.DS_Store
7+.atom/
8+.build/
9+.buildlog/
10+.history
11+.svn/
12+.swiftpm/
13+migrate_working_dir/
14+
15+# IntelliJ related
16+*.iml
17+*.ipr
18+*.iws
19+.idea/
20+
21+# The .vscode folder contains launch configuration and tasks you configure in
22+# VS Code which you may wish to be included in version control, so this line
23+# is commented out by default.
24+#.vscode/
25+
26+# Flutter/Dart/Pub related
27+**/doc/api/
28+**/ios/Flutter/.last_build_id
29+.dart_tool/
30+.flutter-plugins-dependencies
31+.pub-cache/
32+.pub/
33+/build/
34+/coverage/
35+
36+# Symbolication related
37+app.*.symbols
38+
39+# Obfuscation related
40+app.*.map.json
41+
42+# Android Studio will place build artifacts here
43+/android/app/debug
44+/android/app/profile
45+/android/app/release
46+
47+# Widget Preview related
48+.widget_preview/
new file mode 100644
@@ -0,0 +1,48 @@
1+# Miscellaneous
2+*.class
3+*.log
4+*.pyc
5+*.swp
6+.DS_Store
7+.atom/
8+.build/
9+.buildlog/
10+.history
11+.svn/
12+.swiftpm/
13+migrate_working_dir/
14+
15+# IntelliJ related
16+*.iml
17+*.ipr
18+*.iws
19+.idea/
20+
21+# The .vscode folder contains launch configuration and tasks you configure in
22+# VS Code which you may wish to be included in version control, so this line
23+# is commented out by default.
24+#.vscode/
25+
26+# Flutter/Dart/Pub related
27+**/doc/api/
28+**/ios/Flutter/.last_build_id
29+.dart_tool/
30+.flutter-plugins-dependencies
31+.pub-cache/
32+.pub/
33+/build/
34+/coverage/
35+
36+# Symbolication related
37+app.*.symbols
38+
39+# Obfuscation related
40+app.*.map.json
41+
42+# Android Studio will place build artifacts here
43+/android/app/debug
44+/android/app/profile
45+/android/app/release
46+
47+# Widget Preview related
48+.widget_preview/
added example/.metadata +30 -0
new file mode 100644
@@ -0,0 +1,30 @@
1+# This file tracks properties of this Flutter project.
2+# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+#
4+# This file should be version controlled and should not be manually edited.
5+
6+version:
7+ revision: "9584c6713b324636289d067944a46fd6b49df14b"
8+ channel: "stable"
9+
10+project_type: app
11+
12+# Tracks metadata for the flutter migrate command
13+migration:
14+ platforms:
15+ - platform: root
16+ create_revision: 9584c6713b324636289d067944a46fd6b49df14b
17+ base_revision: 9584c6713b324636289d067944a46fd6b49df14b
18+ - platform: linux
19+ create_revision: 9584c6713b324636289d067944a46fd6b49df14b
20+ base_revision: 9584c6713b324636289d067944a46fd6b49df14b
21+
22+ # User provided section
23+
24+ # List of Local paths (relative to this file) that should be
25+ # ignored by the migrate tool.
26+ #
27+ # Files that are not part of the templates will be ignored by default.
28+ unmanaged_files:
29+ - 'lib/main.dart'
30+ - 'ios/Runner.xcodeproj/project.pbxproj'
new file mode 100644
@@ -0,0 +1,30 @@
1+# This file tracks properties of this Flutter project.
2+# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+#
4+# This file should be version controlled and should not be manually edited.
5+
6+version:
7+ revision: "9584c6713b324636289d067944a46fd6b49df14b"
8+ channel: "stable"
9+
10+project_type: app
11+
12+# Tracks metadata for the flutter migrate command
13+migration:
14+ platforms:
15+ - platform: root
16+ create_revision: 9584c6713b324636289d067944a46fd6b49df14b
17+ base_revision: 9584c6713b324636289d067944a46fd6b49df14b
18+ - platform: linux
19+ create_revision: 9584c6713b324636289d067944a46fd6b49df14b
20+ base_revision: 9584c6713b324636289d067944a46fd6b49df14b
21+
22+ # User provided section
23+
24+ # List of Local paths (relative to this file) that should be
25+ # ignored by the migrate tool.
26+ #
27+ # Files that are not part of the templates will be ignored by default.
28+ unmanaged_files:
29+ - 'lib/main.dart'
30+ - 'ios/Runner.xcodeproj/project.pbxproj'
added example/README.md +17 -0
new file mode 100644
@@ -0,0 +1,17 @@
1+# vflutter_ffi_example
2+
3+A new Flutter project.
4+
5+## Getting Started
6+
7+This project is a starting point for a Flutter application.
8+
9+A few resources to get you started if this is your first Flutter project:
10+
11+- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
12+- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
13+- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
14+
15+For help getting started with Flutter development, view the
16+[online documentation](https://docs.flutter.dev/), which offers tutorials,
17+samples, guidance on mobile development, and a full API reference.
new file mode 100644
@@ -0,0 +1,17 @@
1+# vflutter_ffi_example
2+
3+A new Flutter project.
4+
5+## Getting Started
6+
7+This project is a starting point for a Flutter application.
8+
9+A few resources to get you started if this is your first Flutter project:
10+
11+- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
12+- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
13+- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
14+
15+For help getting started with Flutter development, view the
16+[online documentation](https://docs.flutter.dev/), which offers tutorials,
17+samples, guidance on mobile development, and a full API reference.
added example/analysis_options.yaml +33 -0
new file mode 100644
@@ -0,0 +1,33 @@
1+# This file configures the analyzer, which statically analyzes Dart code to
2+# check for errors, warnings, and lints.
3+#
4+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6+# invoked from the command line by running `flutter analyze`.
7+
8+# The following line activates a set of recommended lints for Flutter apps,
9+# packages, and plugins designed to encourage good coding practices.
10+include: package:flutter_lints/flutter.yaml
11+
12+analyzer:
13+ exclude:
14+ - build/**
15+ - linux/**
16+
17+linter:
18+ # The lint rules applied to this project can be customized in the
19+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
20+ # included above or to enable additional rules. A list of all available lints
21+ # and their documentation is published at https://dart.dev/lints.
22+ #
23+ # Instead of disabling a lint rule for the entire project in the
24+ # section below, it can also be suppressed for a single line of code
25+ # or a specific dart file by using the `// ignore: name_of_lint` and
26+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
27+ # producing the lint.
28+ rules:
29+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
30+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
31+
32+# Additional information about this file can be found at
33+# https://dart.dev/guides/language/analysis-options
new file mode 100644
@@ -0,0 +1,33 @@
1+# This file configures the analyzer, which statically analyzes Dart code to
2+# check for errors, warnings, and lints.
3+#
4+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6+# invoked from the command line by running `flutter analyze`.
7+
8+# The following line activates a set of recommended lints for Flutter apps,
9+# packages, and plugins designed to encourage good coding practices.
10+include: package:flutter_lints/flutter.yaml
11+
12+analyzer:
13+ exclude:
14+ - build/**
15+ - linux/**
16+
17+linter:
18+ # The lint rules applied to this project can be customized in the
19+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
20+ # included above or to enable additional rules. A list of all available lints
21+ # and their documentation is published at https://dart.dev/lints.
22+ #
23+ # Instead of disabling a lint rule for the entire project in the
24+ # section below, it can also be suppressed for a single line of code
25+ # or a specific dart file by using the `// ignore: name_of_lint` and
26+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
27+ # producing the lint.
28+ rules:
29+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
30+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
31+
32+# Additional information about this file can be found at
33+# https://dart.dev/guides/language/analysis-options
added example/lib/main.dart +121 -0
new file mode 100644
@@ -0,0 +1,121 @@
1+import 'package:flutter/material.dart';
2+import 'package:vflutter_ffi/vflutter_ffi.dart' as v;
3+
4+void main() => runApp(const ExampleApp());
5+
6+class ExampleApp extends StatelessWidget {
7+ const ExampleApp({super.key});
8+
9+ @override
10+ Widget build(BuildContext context) => MaterialApp(
11+ title: 'vflutter_ffi',
12+ theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),
13+ home: const HomePage(),
14+ );
15+}
16+
17+class HomePage extends StatefulWidget {
18+ const HomePage({super.key});
19+
20+ @override
21+ State<HomePage> createState() => _HomePageState();
22+}
23+
24+class _HomePageState extends State<HomePage> {
25+ final _controller = TextEditingController(text: 'Flutter');
26+
27+ // Synchronous results are cheap enough to compute in build(); the async one
28+ // is not, so it is held here and refreshed on demand.
29+ String _async = '(not run)';
30+ String _stress = '(not run)';
31+
32+ @override
33+ void dispose() {
34+ _controller.dispose();
35+ super.dispose();
36+ }
37+
38+ Future<void> _runAsync() async {
39+ final r = await v.greetAsync(_controller.text);
40+ setState(() => _async = r);
41+ }
42+
43+ /// 20k round trips on the UI isolate. Fast enough not to jank, and proves
44+ /// the V side frees its temporaries under load.
45+ void _runStress() {
46+ final sw = Stopwatch()..start();
47+ for (var i = 0; i < 20000; i++) {
48+ v.greet('stress$i');
49+ }
50+ sw.stop();
51+ setState(() => _stress = '20k calls in ${sw.elapsedMilliseconds} ms');
52+ }
53+
54+ @override
55+ Widget build(BuildContext context) {
56+ return Scaffold(
57+ appBar: AppBar(title: const Text('V → Flutter over dart:ffi')),
58+ body: Center(
59+ child: ConstrainedBox(
60+ constraints: const BoxConstraints(maxWidth: 520),
61+ child: ListView(
62+ padding: const EdgeInsets.all(24),
63+ shrinkWrap: true,
64+ children: [
65+ _Row(label: 'v.add(20, 22)', value: '${v.add(20, 42 - 20)}'),
66+ const Divider(height: 32),
67+ TextField(
68+ controller: _controller,
69+ decoration: const InputDecoration(
70+ labelText: 'name',
71+ border: OutlineInputBorder(),
72+ ),
73+ onChanged: (_) => setState(() {}),
74+ ),
75+ const SizedBox(height: 16),
76+ _Row(label: 'v.greet(name)', value: v.greet(_controller.text)),
77+ const Divider(height: 32),
78+ _Row(label: 'v.greetAsync(name)', value: _async),
79+ const SizedBox(height: 8),
80+ FilledButton.tonal(
81+ onPressed: _runAsync,
82+ child: const Text('run on background isolate'),
83+ ),
84+ const Divider(height: 32),
85+ _Row(label: 'ownership stress', value: _stress),
86+ const SizedBox(height: 8),
87+ FilledButton.tonal(
88+ onPressed: _runStress,
89+ child: const Text('run 20k round trips'),
90+ ),
91+ ],
92+ ),
93+ ),
94+ ),
95+ );
96+ }
97+}
98+
99+class _Row extends StatelessWidget {
100+ const _Row({required this.label, required this.value});
101+
102+ final String label;
103+ final String value;
104+
105+ @override
106+ Widget build(BuildContext context) {
107+ final theme = Theme.of(context);
108+ return Column(
109+ crossAxisAlignment: CrossAxisAlignment.start,
110+ children: [
111+ Text(label, style: theme.textTheme.labelMedium),
112+ const SizedBox(height: 4),
113+ SelectableText(
114+ value,
115+ style: theme.textTheme.titleMedium
116+ ?.copyWith(fontFamily: 'monospace', color: theme.colorScheme.primary),
117+ ),
118+ ],
119+ );
120+ }
121+}
new file mode 100644
@@ -0,0 +1,121 @@
1+import 'package:flutter/material.dart';
2+import 'package:vflutter_ffi/vflutter_ffi.dart' as v;
3+
4+void main() => runApp(const ExampleApp());
5+
6+class ExampleApp extends StatelessWidget {
7+ const ExampleApp({super.key});
8+
9+ @override
10+ Widget build(BuildContext context) => MaterialApp(
11+ title: 'vflutter_ffi',
12+ theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),
13+ home: const HomePage(),
14+ );
15+}
16+
17+class HomePage extends StatefulWidget {
18+ const HomePage({super.key});
19+
20+ @override
21+ State<HomePage> createState() => _HomePageState();
22+}
23+
24+class _HomePageState extends State<HomePage> {
25+ final _controller = TextEditingController(text: 'Flutter');
26+
27+ // Synchronous results are cheap enough to compute in build(); the async one
28+ // is not, so it is held here and refreshed on demand.
29+ String _async = '(not run)';
30+ String _stress = '(not run)';
31+
32+ @override
33+ void dispose() {
34+ _controller.dispose();
35+ super.dispose();
36+ }
37+
38+ Future<void> _runAsync() async {
39+ final r = await v.greetAsync(_controller.text);
40+ setState(() => _async = r);
41+ }
42+
43+ /// 20k round trips on the UI isolate. Fast enough not to jank, and proves
44+ /// the V side frees its temporaries under load.
45+ void _runStress() {
46+ final sw = Stopwatch()..start();
47+ for (var i = 0; i < 20000; i++) {
48+ v.greet('stress$i');
49+ }
50+ sw.stop();
51+ setState(() => _stress = '20k calls in ${sw.elapsedMilliseconds} ms');
52+ }
53+
54+ @override
55+ Widget build(BuildContext context) {
56+ return Scaffold(
57+ appBar: AppBar(title: const Text('V → Flutter over dart:ffi')),
58+ body: Center(
59+ child: ConstrainedBox(
60+ constraints: const BoxConstraints(maxWidth: 520),
61+ child: ListView(
62+ padding: const EdgeInsets.all(24),
63+ shrinkWrap: true,
64+ children: [
65+ _Row(label: 'v.add(20, 22)', value: '${v.add(20, 42 - 20)}'),
66+ const Divider(height: 32),
67+ TextField(
68+ controller: _controller,
69+ decoration: const InputDecoration(
70+ labelText: 'name',
71+ border: OutlineInputBorder(),
72+ ),
73+ onChanged: (_) => setState(() {}),
74+ ),
75+ const SizedBox(height: 16),
76+ _Row(label: 'v.greet(name)', value: v.greet(_controller.text)),
77+ const Divider(height: 32),
78+ _Row(label: 'v.greetAsync(name)', value: _async),
79+ const SizedBox(height: 8),
80+ FilledButton.tonal(
81+ onPressed: _runAsync,
82+ child: const Text('run on background isolate'),
83+ ),
84+ const Divider(height: 32),
85+ _Row(label: 'ownership stress', value: _stress),
86+ const SizedBox(height: 8),
87+ FilledButton.tonal(
88+ onPressed: _runStress,
89+ child: const Text('run 20k round trips'),
90+ ),
91+ ],
92+ ),
93+ ),
94+ ),
95+ );
96+ }
97+}
98+
99+class _Row extends StatelessWidget {
100+ const _Row({required this.label, required this.value});
101+
102+ final String label;
103+ final String value;
104+
105+ @override
106+ Widget build(BuildContext context) {
107+ final theme = Theme.of(context);
108+ return Column(
109+ crossAxisAlignment: CrossAxisAlignment.start,
110+ children: [
111+ Text(label, style: theme.textTheme.labelMedium),
112+ const SizedBox(height: 4),
113+ SelectableText(
114+ value,
115+ style: theme.textTheme.titleMedium
116+ ?.copyWith(fontFamily: 'monospace', color: theme.colorScheme.primary),
117+ ),
118+ ],
119+ );
120+ }
121+}
added example/linux/.gitignore +1 -0
new file mode 100644
@@ -0,0 +1 @@
1+flutter/ephemeral
new file mode 100644
@@ -0,0 +1 @@
1+flutter/ephemeral
added example/linux/CMakeLists.txt +128 -0
new file mode 100644
@@ -0,0 +1,128 @@
1+# Project-level configuration.
2+cmake_minimum_required(VERSION 3.13)
3+project(runner LANGUAGES CXX)
4+
5+# The name of the executable created for the application. Change this to change
6+# the on-disk name of your application.
7+set(BINARY_NAME "vflutter_ffi_example")
8+# The unique GTK application identifier for this application. See:
9+# https://wiki.gnome.org/HowDoI/ChooseApplicationID
10+set(APPLICATION_ID "com.example.vflutter_ffi_example")
11+
12+# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
13+# versions of CMake.
14+cmake_policy(SET CMP0063 NEW)
15+
16+# Load bundled libraries from the lib/ directory relative to the binary.
17+set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
18+
19+# Root filesystem for cross-building.
20+if(FLUTTER_TARGET_PLATFORM_SYSROOT)
21+ set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
22+ set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
23+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
24+ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
25+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
26+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
27+endif()
28+
29+# Define build configuration options.
30+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
31+ set(CMAKE_BUILD_TYPE "Debug" CACHE
32+ STRING "Flutter build mode" FORCE)
33+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
34+ "Debug" "Profile" "Release")
35+endif()
36+
37+# Compilation settings that should be applied to most targets.
38+#
39+# Be cautious about adding new options here, as plugins use this function by
40+# default. In most cases, you should add new options to specific targets instead
41+# of modifying this function.
42+function(APPLY_STANDARD_SETTINGS TARGET)
43+ target_compile_features(${TARGET} PUBLIC cxx_std_14)
44+ target_compile_options(${TARGET} PRIVATE -Wall -Werror)
45+ target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
46+ target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
47+endfunction()
48+
49+# Flutter library and tool build rules.
50+set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
51+add_subdirectory(${FLUTTER_MANAGED_DIR})
52+
53+# System-level dependencies.
54+find_package(PkgConfig REQUIRED)
55+pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
56+
57+# Application build; see runner/CMakeLists.txt.
58+add_subdirectory("runner")
59+
60+# Run the Flutter tool portions of the build. This must not be removed.
61+add_dependencies(${BINARY_NAME} flutter_assemble)
62+
63+# Only the install-generated bundle's copy of the executable will launch
64+# correctly, since the resources must in the right relative locations. To avoid
65+# people trying to run the unbundled copy, put it in a subdirectory instead of
66+# the default top-level location.
67+set_target_properties(${BINARY_NAME}
68+ PROPERTIES
69+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
70+)
71+
72+
73+# Generated plugin build rules, which manage building the plugins and adding
74+# them to the application.
75+include(flutter/generated_plugins.cmake)
76+
77+
78+# === Installation ===
79+# By default, "installing" just makes a relocatable bundle in the build
80+# directory.
81+set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
82+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
83+ set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
84+endif()
85+
86+# Start with a clean build bundle directory every time.
87+install(CODE "
88+ file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
89+ " COMPONENT Runtime)
90+
91+set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
92+set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
93+
94+install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
95+ COMPONENT Runtime)
96+
97+install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
98+ COMPONENT Runtime)
99+
100+install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
101+ COMPONENT Runtime)
102+
103+foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
104+ install(FILES "${bundled_library}"
105+ DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
106+ COMPONENT Runtime)
107+endforeach(bundled_library)
108+
109+# Copy the native assets provided by the build.dart from all packages.
110+set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
111+install(DIRECTORY "${NATIVE_ASSETS_DIR}"
112+ DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
113+ COMPONENT Runtime)
114+
115+# Fully re-copy the assets directory on each build to avoid having stale files
116+# from a previous install.
117+set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
118+install(CODE "
119+ file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
120+ " COMPONENT Runtime)
121+install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
122+ DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
123+
124+# Install the AOT library on non-Debug builds only.
125+if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
126+ install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
127+ COMPONENT Runtime)
128+endif()
new file mode 100644
@@ -0,0 +1,128 @@
1+# Project-level configuration.
2+cmake_minimum_required(VERSION 3.13)
3+project(runner LANGUAGES CXX)
4+
5+# The name of the executable created for the application. Change this to change
6+# the on-disk name of your application.
7+set(BINARY_NAME "vflutter_ffi_example")
8+# The unique GTK application identifier for this application. See:
9+# https://wiki.gnome.org/HowDoI/ChooseApplicationID
10+set(APPLICATION_ID "com.example.vflutter_ffi_example")
11+
12+# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
13+# versions of CMake.
14+cmake_policy(SET CMP0063 NEW)
15+
16+# Load bundled libraries from the lib/ directory relative to the binary.
17+set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
18+
19+# Root filesystem for cross-building.
20+if(FLUTTER_TARGET_PLATFORM_SYSROOT)
21+ set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
22+ set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
23+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
24+ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
25+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
26+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
27+endif()
28+
29+# Define build configuration options.
30+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
31+ set(CMAKE_BUILD_TYPE "Debug" CACHE
32+ STRING "Flutter build mode" FORCE)
33+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
34+ "Debug" "Profile" "Release")
35+endif()
36+
37+# Compilation settings that should be applied to most targets.
38+#
39+# Be cautious about adding new options here, as plugins use this function by
40+# default. In most cases, you should add new options to specific targets instead
41+# of modifying this function.
42+function(APPLY_STANDARD_SETTINGS TARGET)
43+ target_compile_features(${TARGET} PUBLIC cxx_std_14)
44+ target_compile_options(${TARGET} PRIVATE -Wall -Werror)
45+ target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
46+ target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
47+endfunction()
48+
49+# Flutter library and tool build rules.
50+set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
51+add_subdirectory(${FLUTTER_MANAGED_DIR})
52+
53+# System-level dependencies.
54+find_package(PkgConfig REQUIRED)
55+pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
56+
57+# Application build; see runner/CMakeLists.txt.
58+add_subdirectory("runner")
59+
60+# Run the Flutter tool portions of the build. This must not be removed.
61+add_dependencies(${BINARY_NAME} flutter_assemble)
62+
63+# Only the install-generated bundle's copy of the executable will launch
64+# correctly, since the resources must in the right relative locations. To avoid
65+# people trying to run the unbundled copy, put it in a subdirectory instead of
66+# the default top-level location.
67+set_target_properties(${BINARY_NAME}
68+ PROPERTIES
69+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
70+)
71+
72+
73+# Generated plugin build rules, which manage building the plugins and adding
74+# them to the application.
75+include(flutter/generated_plugins.cmake)
76+
77+
78+# === Installation ===
79+# By default, "installing" just makes a relocatable bundle in the build
80+# directory.
81+set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
82+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
83+ set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
84+endif()
85+
86+# Start with a clean build bundle directory every time.
87+install(CODE "
88+ file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
89+ " COMPONENT Runtime)
90+
91+set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
92+set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
93+
94+install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
95+ COMPONENT Runtime)
96+
97+install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
98+ COMPONENT Runtime)
99+
100+install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
101+ COMPONENT Runtime)
102+
103+foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
104+ install(FILES "${bundled_library}"
105+ DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
106+ COMPONENT Runtime)
107+endforeach(bundled_library)
108+
109+# Copy the native assets provided by the build.dart from all packages.
110+set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
111+install(DIRECTORY "${NATIVE_ASSETS_DIR}"
112+ DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
113+ COMPONENT Runtime)
114+
115+# Fully re-copy the assets directory on each build to avoid having stale files
116+# from a previous install.
117+set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
118+install(CODE "
119+ file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
120+ " COMPONENT Runtime)
121+install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
122+ DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
123+
124+# Install the AOT library on non-Debug builds only.
125+if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
126+ install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
127+ COMPONENT Runtime)
128+endif()
added example/linux/flutter/CMakeLists.txt +88 -0
new file mode 100644
@@ -0,0 +1,88 @@
1+# This file controls Flutter-level build steps. It should not be edited.
2+cmake_minimum_required(VERSION 3.10)
3+
4+set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5+
6+# Configuration provided via flutter tool.
7+include(${EPHEMERAL_DIR}/generated_config.cmake)
8+
9+# TODO: Move the rest of this into files in ephemeral. See
10+# https://github.com/flutter/flutter/issues/57146.
11+
12+# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
13+# which isn't available in 3.10.
14+function(list_prepend LIST_NAME PREFIX)
15+ set(NEW_LIST "")
16+ foreach(element ${${LIST_NAME}})
17+ list(APPEND NEW_LIST "${PREFIX}${element}")
18+ endforeach(element)
19+ set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
20+endfunction()
21+
22+# === Flutter Library ===
23+# System-level dependencies.
24+find_package(PkgConfig REQUIRED)
25+pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
26+pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
27+pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
28+
29+set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
30+
31+# Published to parent scope for install step.
32+set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
33+set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
34+set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
35+set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
36+
37+list(APPEND FLUTTER_LIBRARY_HEADERS
38+ "fl_basic_message_channel.h"
39+ "fl_binary_codec.h"
40+ "fl_binary_messenger.h"
41+ "fl_dart_project.h"
42+ "fl_engine.h"
43+ "fl_json_message_codec.h"
44+ "fl_json_method_codec.h"
45+ "fl_message_codec.h"
46+ "fl_method_call.h"
47+ "fl_method_channel.h"
48+ "fl_method_codec.h"
49+ "fl_method_response.h"
50+ "fl_plugin_registrar.h"
51+ "fl_plugin_registry.h"
52+ "fl_standard_message_codec.h"
53+ "fl_standard_method_codec.h"
54+ "fl_string_codec.h"
55+ "fl_value.h"
56+ "fl_view.h"
57+ "flutter_linux.h"
58+)
59+list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
60+add_library(flutter INTERFACE)
61+target_include_directories(flutter INTERFACE
62+ "${EPHEMERAL_DIR}"
63+)
64+target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
65+target_link_libraries(flutter INTERFACE
66+ PkgConfig::GTK
67+ PkgConfig::GLIB
68+ PkgConfig::GIO
69+)
70+add_dependencies(flutter flutter_assemble)
71+
72+# === Flutter tool backend ===
73+# _phony_ is a non-existent file to force this command to run every time,
74+# since currently there's no way to get a full input/output list from the
75+# flutter tool.
76+add_custom_command(
77+ OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
78+ ${CMAKE_CURRENT_BINARY_DIR}/_phony_
79+ COMMAND ${CMAKE_COMMAND} -E env
80+ ${FLUTTER_TOOL_ENVIRONMENT}
81+ "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
82+ ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
83+ VERBATIM
84+)
85+add_custom_target(flutter_assemble DEPENDS
86+ "${FLUTTER_LIBRARY}"
87+ ${FLUTTER_LIBRARY_HEADERS}
88+)
new file mode 100644
@@ -0,0 +1,88 @@
1+# This file controls Flutter-level build steps. It should not be edited.
2+cmake_minimum_required(VERSION 3.10)
3+
4+set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5+
6+# Configuration provided via flutter tool.
7+include(${EPHEMERAL_DIR}/generated_config.cmake)
8+
9+# TODO: Move the rest of this into files in ephemeral. See
10+# https://github.com/flutter/flutter/issues/57146.
11+
12+# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
13+# which isn't available in 3.10.
14+function(list_prepend LIST_NAME PREFIX)
15+ set(NEW_LIST "")
16+ foreach(element ${${LIST_NAME}})
17+ list(APPEND NEW_LIST "${PREFIX}${element}")
18+ endforeach(element)
19+ set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
20+endfunction()
21+
22+# === Flutter Library ===
23+# System-level dependencies.
24+find_package(PkgConfig REQUIRED)
25+pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
26+pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
27+pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
28+
29+set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
30+
31+# Published to parent scope for install step.
32+set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
33+set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
34+set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
35+set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
36+
37+list(APPEND FLUTTER_LIBRARY_HEADERS
38+ "fl_basic_message_channel.h"
39+ "fl_binary_codec.h"
40+ "fl_binary_messenger.h"
41+ "fl_dart_project.h"
42+ "fl_engine.h"
43+ "fl_json_message_codec.h"
44+ "fl_json_method_codec.h"
45+ "fl_message_codec.h"
46+ "fl_method_call.h"
47+ "fl_method_channel.h"
48+ "fl_method_codec.h"
49+ "fl_method_response.h"
50+ "fl_plugin_registrar.h"
51+ "fl_plugin_registry.h"
52+ "fl_standard_message_codec.h"
53+ "fl_standard_method_codec.h"
54+ "fl_string_codec.h"
55+ "fl_value.h"
56+ "fl_view.h"
57+ "flutter_linux.h"
58+)
59+list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
60+add_library(flutter INTERFACE)
61+target_include_directories(flutter INTERFACE
62+ "${EPHEMERAL_DIR}"
63+)
64+target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
65+target_link_libraries(flutter INTERFACE
66+ PkgConfig::GTK
67+ PkgConfig::GLIB
68+ PkgConfig::GIO
69+)
70+add_dependencies(flutter flutter_assemble)
71+
72+# === Flutter tool backend ===
73+# _phony_ is a non-existent file to force this command to run every time,
74+# since currently there's no way to get a full input/output list from the
75+# flutter tool.
76+add_custom_command(
77+ OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
78+ ${CMAKE_CURRENT_BINARY_DIR}/_phony_
79+ COMMAND ${CMAKE_COMMAND} -E env
80+ ${FLUTTER_TOOL_ENVIRONMENT}
81+ "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
82+ ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
83+ VERBATIM
84+)
85+add_custom_target(flutter_assemble DEPENDS
86+ "${FLUTTER_LIBRARY}"
87+ ${FLUTTER_LIBRARY_HEADERS}
88+)
added example/linux/flutter/generated_plugin_registrant.cc +11 -0
new file mode 100644
@@ -0,0 +1,11 @@
1+//
2+// Generated file. Do not edit.
3+//
4+
5+// clang-format off
6+
7+#include "generated_plugin_registrant.h"
8+
9+
10+void fl_register_plugins(FlPluginRegistry* registry) {
11+}
new file mode 100644
@@ -0,0 +1,11 @@
1+//
2+// Generated file. Do not edit.
3+//
4+
5+// clang-format off
6+
7+#include "generated_plugin_registrant.h"
8+
9+
10+void fl_register_plugins(FlPluginRegistry* registry) {
11+}
added example/linux/flutter/generated_plugin_registrant.h +15 -0
new file mode 100644
@@ -0,0 +1,15 @@
1+//
2+// Generated file. Do not edit.
3+//
4+
5+// clang-format off
6+
7+#ifndef GENERATED_PLUGIN_REGISTRANT_
8+#define GENERATED_PLUGIN_REGISTRANT_
9+
10+#include <flutter_linux/flutter_linux.h>
11+
12+// Registers Flutter plugins.
13+void fl_register_plugins(FlPluginRegistry* registry);
14+
15+#endif // GENERATED_PLUGIN_REGISTRANT_
new file mode 100644
@@ -0,0 +1,15 @@
1+//
2+// Generated file. Do not edit.
3+//
4+
5+// clang-format off
6+
7+#ifndef GENERATED_PLUGIN_REGISTRANT_
8+#define GENERATED_PLUGIN_REGISTRANT_
9+
10+#include <flutter_linux/flutter_linux.h>
11+
12+// Registers Flutter plugins.
13+void fl_register_plugins(FlPluginRegistry* registry);
14+
15+#endif // GENERATED_PLUGIN_REGISTRANT_
added example/linux/flutter/generated_plugins.cmake +24 -0
new file mode 100644
@@ -0,0 +1,24 @@
1+#
2+# Generated file, do not edit.
3+#
4+
5+list(APPEND FLUTTER_PLUGIN_LIST
6+)
7+
8+list(APPEND FLUTTER_FFI_PLUGIN_LIST
9+ vflutter_ffi
10+)
11+
12+set(PLUGIN_BUNDLED_LIBRARIES)
13+
14+foreach(plugin ${FLUTTER_PLUGIN_LIST})
15+ add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
16+ target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
17+ list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
18+ list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
19+endforeach(plugin)
20+
21+foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
22+ add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
23+ list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
24+endforeach(ffi_plugin)
new file mode 100644
@@ -0,0 +1,24 @@
1+#
2+# Generated file, do not edit.
3+#
4+
5+list(APPEND FLUTTER_PLUGIN_LIST
6+)
7+
8+list(APPEND FLUTTER_FFI_PLUGIN_LIST
9+ vflutter_ffi
10+)
11+
12+set(PLUGIN_BUNDLED_LIBRARIES)
13+
14+foreach(plugin ${FLUTTER_PLUGIN_LIST})
15+ add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
16+ target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
17+ list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
18+ list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
19+endforeach(plugin)
20+
21+foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
22+ add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
23+ list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
24+endforeach(ffi_plugin)
added example/linux/runner/CMakeLists.txt +26 -0
new file mode 100644
@@ -0,0 +1,26 @@
1+cmake_minimum_required(VERSION 3.13)
2+project(runner LANGUAGES CXX)
3+
4+# Define the application target. To change its name, change BINARY_NAME in the
5+# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
6+# work.
7+#
8+# Any new source files that you add to the application should be added here.
9+add_executable(${BINARY_NAME}
10+ "main.cc"
11+ "my_application.cc"
12+ "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
13+)
14+
15+# Apply the standard set of build settings. This can be removed for applications
16+# that need different build settings.
17+apply_standard_settings(${BINARY_NAME})
18+
19+# Add preprocessor definitions for the application ID.
20+add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
21+
22+# Add dependency libraries. Add any application-specific dependencies here.
23+target_link_libraries(${BINARY_NAME} PRIVATE flutter)
24+target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
25+
26+target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
new file mode 100644
@@ -0,0 +1,26 @@
1+cmake_minimum_required(VERSION 3.13)
2+project(runner LANGUAGES CXX)
3+
4+# Define the application target. To change its name, change BINARY_NAME in the
5+# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
6+# work.
7+#
8+# Any new source files that you add to the application should be added here.
9+add_executable(${BINARY_NAME}
10+ "main.cc"
11+ "my_application.cc"
12+ "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
13+)
14+
15+# Apply the standard set of build settings. This can be removed for applications
16+# that need different build settings.
17+apply_standard_settings(${BINARY_NAME})
18+
19+# Add preprocessor definitions for the application ID.
20+add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
21+
22+# Add dependency libraries. Add any application-specific dependencies here.
23+target_link_libraries(${BINARY_NAME} PRIVATE flutter)
24+target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
25+
26+target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
added example/linux/runner/main.cc +6 -0
new file mode 100644
@@ -0,0 +1,6 @@
1+#include "my_application.h"
2+
3+int main(int argc, char** argv) {
4+ g_autoptr(MyApplication) app = my_application_new();
5+ return g_application_run(G_APPLICATION(app), argc, argv);
6+}
new file mode 100644
@@ -0,0 +1,6 @@
1+#include "my_application.h"
2+
3+int main(int argc, char** argv) {
4+ g_autoptr(MyApplication) app = my_application_new();
5+ return g_application_run(G_APPLICATION(app), argc, argv);
6+}
added example/linux/runner/my_application.cc +148 -0
new file mode 100644
@@ -0,0 +1,148 @@
1+#include "my_application.h"
2+
3+#include <flutter_linux/flutter_linux.h>
4+#ifdef GDK_WINDOWING_X11
5+#include <gdk/gdkx.h>
6+#endif
7+
8+#include "flutter/generated_plugin_registrant.h"
9+
10+struct _MyApplication {
11+ GtkApplication parent_instance;
12+ char** dart_entrypoint_arguments;
13+};
14+
15+G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
16+
17+// Called when first Flutter frame received.
18+static void first_frame_cb(MyApplication* self, FlView* view) {
19+ gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view)));
20+}
21+
22+// Implements GApplication::activate.
23+static void my_application_activate(GApplication* application) {
24+ MyApplication* self = MY_APPLICATION(application);
25+ GtkWindow* window =
26+ GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
27+
28+ // Use a header bar when running in GNOME as this is the common style used
29+ // by applications and is the setup most users will be using (e.g. Ubuntu
30+ // desktop).
31+ // If running on X and not using GNOME then just use a traditional title bar
32+ // in case the window manager does more exotic layout, e.g. tiling.
33+ // If running on Wayland assume the header bar will work (may need changing
34+ // if future cases occur).
35+ gboolean use_header_bar = TRUE;
36+#ifdef GDK_WINDOWING_X11
37+ GdkScreen* screen = gtk_window_get_screen(window);
38+ if (GDK_IS_X11_SCREEN(screen)) {
39+ const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
40+ if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
41+ use_header_bar = FALSE;
42+ }
43+ }
44+#endif
45+ if (use_header_bar) {
46+ GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
47+ gtk_widget_show(GTK_WIDGET(header_bar));
48+ gtk_header_bar_set_title(header_bar, "vflutter_ffi_example");
49+ gtk_header_bar_set_show_close_button(header_bar, TRUE);
50+ gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
51+ } else {
52+ gtk_window_set_title(window, "vflutter_ffi_example");
53+ }
54+
55+ gtk_window_set_default_size(window, 1280, 720);
56+
57+ g_autoptr(FlDartProject) project = fl_dart_project_new();
58+ fl_dart_project_set_dart_entrypoint_arguments(
59+ project, self->dart_entrypoint_arguments);
60+
61+ FlView* view = fl_view_new(project);
62+ GdkRGBA background_color;
63+ // Background defaults to black, override it here if necessary, e.g. #00000000
64+ // for transparent.
65+ gdk_rgba_parse(&background_color, "#000000");
66+ fl_view_set_background_color(view, &background_color);
67+ gtk_widget_show(GTK_WIDGET(view));
68+ gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
69+
70+ // Show the window when Flutter renders.
71+ // Requires the view to be realized so we can start rendering.
72+ g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb),
73+ self);
74+ gtk_widget_realize(GTK_WIDGET(view));
75+
76+ fl_register_plugins(FL_PLUGIN_REGISTRY(view));
77+
78+ gtk_widget_grab_focus(GTK_WIDGET(view));
79+}
80+
81+// Implements GApplication::local_command_line.
82+static gboolean my_application_local_command_line(GApplication* application,
83+ gchar*** arguments,
84+ int* exit_status) {
85+ MyApplication* self = MY_APPLICATION(application);
86+ // Strip out the first argument as it is the binary name.
87+ self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
88+
89+ g_autoptr(GError) error = nullptr;
90+ if (!g_application_register(application, nullptr, &error)) {
91+ g_warning("Failed to register: %s", error->message);
92+ *exit_status = 1;
93+ return TRUE;
94+ }
95+
96+ g_application_activate(application);
97+ *exit_status = 0;
98+
99+ return TRUE;
100+}
101+
102+// Implements GApplication::startup.
103+static void my_application_startup(GApplication* application) {
104+ // MyApplication* self = MY_APPLICATION(object);
105+
106+ // Perform any actions required at application startup.
107+
108+ G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
109+}
110+
111+// Implements GApplication::shutdown.
112+static void my_application_shutdown(GApplication* application) {
113+ // MyApplication* self = MY_APPLICATION(object);
114+
115+ // Perform any actions required at application shutdown.
116+
117+ G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
118+}
119+
120+// Implements GObject::dispose.
121+static void my_application_dispose(GObject* object) {
122+ MyApplication* self = MY_APPLICATION(object);
123+ g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
124+ G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
125+}
126+
127+static void my_application_class_init(MyApplicationClass* klass) {
128+ G_APPLICATION_CLASS(klass)->activate = my_application_activate;
129+ G_APPLICATION_CLASS(klass)->local_command_line =
130+ my_application_local_command_line;
131+ G_APPLICATION_CLASS(klass)->startup = my_application_startup;
132+ G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
133+ G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
134+}
135+
136+static void my_application_init(MyApplication* self) {}
137+
138+MyApplication* my_application_new() {
139+ // Set the program name to the application ID, which helps various systems
140+ // like GTK and desktop environments map this running application to its
141+ // corresponding .desktop file. This ensures better integration by allowing
142+ // the application to be recognized beyond its binary name.
143+ g_set_prgname(APPLICATION_ID);
144+
145+ return MY_APPLICATION(g_object_new(my_application_get_type(),
146+ "application-id", APPLICATION_ID, "flags",
147+ G_APPLICATION_NON_UNIQUE, nullptr));
148+}
new file mode 100644
@@ -0,0 +1,148 @@
1+#include "my_application.h"
2+
3+#include <flutter_linux/flutter_linux.h>
4+#ifdef GDK_WINDOWING_X11
5+#include <gdk/gdkx.h>
6+#endif
7+
8+#include "flutter/generated_plugin_registrant.h"
9+
10+struct _MyApplication {
11+ GtkApplication parent_instance;
12+ char** dart_entrypoint_arguments;
13+};
14+
15+G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
16+
17+// Called when first Flutter frame received.
18+static void first_frame_cb(MyApplication* self, FlView* view) {
19+ gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view)));
20+}
21+
22+// Implements GApplication::activate.
23+static void my_application_activate(GApplication* application) {
24+ MyApplication* self = MY_APPLICATION(application);
25+ GtkWindow* window =
26+ GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
27+
28+ // Use a header bar when running in GNOME as this is the common style used
29+ // by applications and is the setup most users will be using (e.g. Ubuntu
30+ // desktop).
31+ // If running on X and not using GNOME then just use a traditional title bar
32+ // in case the window manager does more exotic layout, e.g. tiling.
33+ // If running on Wayland assume the header bar will work (may need changing
34+ // if future cases occur).
35+ gboolean use_header_bar = TRUE;
36+#ifdef GDK_WINDOWING_X11
37+ GdkScreen* screen = gtk_window_get_screen(window);
38+ if (GDK_IS_X11_SCREEN(screen)) {
39+ const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
40+ if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
41+ use_header_bar = FALSE;
42+ }
43+ }
44+#endif
45+ if (use_header_bar) {
46+ GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
47+ gtk_widget_show(GTK_WIDGET(header_bar));
48+ gtk_header_bar_set_title(header_bar, "vflutter_ffi_example");
49+ gtk_header_bar_set_show_close_button(header_bar, TRUE);
50+ gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
51+ } else {
52+ gtk_window_set_title(window, "vflutter_ffi_example");
53+ }
54+
55+ gtk_window_set_default_size(window, 1280, 720);
56+
57+ g_autoptr(FlDartProject) project = fl_dart_project_new();
58+ fl_dart_project_set_dart_entrypoint_arguments(
59+ project, self->dart_entrypoint_arguments);
60+
61+ FlView* view = fl_view_new(project);
62+ GdkRGBA background_color;
63+ // Background defaults to black, override it here if necessary, e.g. #00000000
64+ // for transparent.
65+ gdk_rgba_parse(&background_color, "#000000");
66+ fl_view_set_background_color(view, &background_color);
67+ gtk_widget_show(GTK_WIDGET(view));
68+ gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
69+
70+ // Show the window when Flutter renders.
71+ // Requires the view to be realized so we can start rendering.
72+ g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb),
73+ self);
74+ gtk_widget_realize(GTK_WIDGET(view));
75+
76+ fl_register_plugins(FL_PLUGIN_REGISTRY(view));
77+
78+ gtk_widget_grab_focus(GTK_WIDGET(view));
79+}
80+
81+// Implements GApplication::local_command_line.
82+static gboolean my_application_local_command_line(GApplication* application,
83+ gchar*** arguments,
84+ int* exit_status) {
85+ MyApplication* self = MY_APPLICATION(application);
86+ // Strip out the first argument as it is the binary name.
87+ self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
88+
89+ g_autoptr(GError) error = nullptr;
90+ if (!g_application_register(application, nullptr, &error)) {
91+ g_warning("Failed to register: %s", error->message);
92+ *exit_status = 1;
93+ return TRUE;
94+ }
95+
96+ g_application_activate(application);
97+ *exit_status = 0;
98+
99+ return TRUE;
100+}
101+
102+// Implements GApplication::startup.
103+static void my_application_startup(GApplication* application) {
104+ // MyApplication* self = MY_APPLICATION(object);
105+
106+ // Perform any actions required at application startup.
107+
108+ G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
109+}
110+
111+// Implements GApplication::shutdown.
112+static void my_application_shutdown(GApplication* application) {
113+ // MyApplication* self = MY_APPLICATION(object);
114+
115+ // Perform any actions required at application shutdown.
116+
117+ G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
118+}
119+
120+// Implements GObject::dispose.
121+static void my_application_dispose(GObject* object) {
122+ MyApplication* self = MY_APPLICATION(object);
123+ g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
124+ G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
125+}
126+
127+static void my_application_class_init(MyApplicationClass* klass) {
128+ G_APPLICATION_CLASS(klass)->activate = my_application_activate;
129+ G_APPLICATION_CLASS(klass)->local_command_line =
130+ my_application_local_command_line;
131+ G_APPLICATION_CLASS(klass)->startup = my_application_startup;
132+ G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
133+ G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
134+}
135+
136+static void my_application_init(MyApplication* self) {}
137+
138+MyApplication* my_application_new() {
139+ // Set the program name to the application ID, which helps various systems
140+ // like GTK and desktop environments map this running application to its
141+ // corresponding .desktop file. This ensures better integration by allowing
142+ // the application to be recognized beyond its binary name.
143+ g_set_prgname(APPLICATION_ID);
144+
145+ return MY_APPLICATION(g_object_new(my_application_get_type(),
146+ "application-id", APPLICATION_ID, "flags",
147+ G_APPLICATION_NON_UNIQUE, nullptr));
148+}
added example/linux/runner/my_application.h +21 -0
new file mode 100644
@@ -0,0 +1,21 @@
1+#ifndef FLUTTER_MY_APPLICATION_H_
2+#define FLUTTER_MY_APPLICATION_H_
3+
4+#include <gtk/gtk.h>
5+
6+G_DECLARE_FINAL_TYPE(MyApplication,
7+ my_application,
8+ MY,
9+ APPLICATION,
10+ GtkApplication)
11+
12+/**
13+ * my_application_new:
14+ *
15+ * Creates a new Flutter-based application.
16+ *
17+ * Returns: a new #MyApplication.
18+ */
19+MyApplication* my_application_new();
20+
21+#endif // FLUTTER_MY_APPLICATION_H_
new file mode 100644
@@ -0,0 +1,21 @@
1+#ifndef FLUTTER_MY_APPLICATION_H_
2+#define FLUTTER_MY_APPLICATION_H_
3+
4+#include <gtk/gtk.h>
5+
6+G_DECLARE_FINAL_TYPE(MyApplication,
7+ my_application,
8+ MY,
9+ APPLICATION,
10+ GtkApplication)
11+
12+/**
13+ * my_application_new:
14+ *
15+ * Creates a new Flutter-based application.
16+ *
17+ * Returns: a new #MyApplication.
18+ */
19+MyApplication* my_application_new();
20+
21+#endif // FLUTTER_MY_APPLICATION_H_
added example/pubspec.lock +228 -0
new file mode 100644
@@ -0,0 +1,228 @@
1+# Generated by pub
2+# See https://dart.dev/tools/pub/glossary#lockfile
3+packages:
4+ async:
5+ dependency: transitive
6+ description:
7+ name: async
8+ sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
9+ url: "https://pub.dev"
10+ source: hosted
11+ version: "2.13.1"
12+ boolean_selector:
13+ dependency: transitive
14+ description:
15+ name: boolean_selector
16+ sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
17+ url: "https://pub.dev"
18+ source: hosted
19+ version: "2.1.2"
20+ characters:
21+ dependency: transitive
22+ description:
23+ name: characters
24+ sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
25+ url: "https://pub.dev"
26+ source: hosted
27+ version: "1.4.1"
28+ clock:
29+ dependency: transitive
30+ description:
31+ name: clock
32+ sha256: e51d50bca3217c9a9fa2b41a30e4a38971133f5f9ec7a3d57bae095007f1d28e
33+ url: "https://pub.dev"
34+ source: hosted
35+ version: "1.1.3"
36+ collection:
37+ dependency: transitive
38+ description:
39+ name: collection
40+ sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
41+ url: "https://pub.dev"
42+ source: hosted
43+ version: "1.19.1"
44+ cupertino_icons:
45+ dependency: "direct main"
46+ description:
47+ name: cupertino_icons
48+ sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd"
49+ url: "https://pub.dev"
50+ source: hosted
51+ version: "1.0.9"
52+ fake_async:
53+ dependency: transitive
54+ description:
55+ name: fake_async
56+ sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
57+ url: "https://pub.dev"
58+ source: hosted
59+ version: "1.3.3"
60+ ffi:
61+ dependency: "direct main"
62+ description:
63+ name: ffi
64+ sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"
65+ url: "https://pub.dev"
66+ source: hosted
67+ version: "2.2.0"
68+ flutter:
69+ dependency: "direct main"
70+ description: flutter
71+ source: sdk
72+ version: "0.0.0"
73+ flutter_lints:
74+ dependency: "direct dev"
75+ description:
76+ name: flutter_lints
77+ sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
78+ url: "https://pub.dev"
79+ source: hosted
80+ version: "6.0.0"
81+ flutter_test:
82+ dependency: "direct dev"
83+ description: flutter
84+ source: sdk
85+ version: "0.0.0"
86+ leak_tracker:
87+ dependency: transitive
88+ description:
89+ name: leak_tracker
90+ sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
91+ url: "https://pub.dev"
92+ source: hosted
93+ version: "11.0.2"
94+ leak_tracker_flutter_testing:
95+ dependency: transitive
96+ description:
97+ name: leak_tracker_flutter_testing
98+ sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
99+ url: "https://pub.dev"
100+ source: hosted
101+ version: "3.0.10"
102+ leak_tracker_testing:
103+ dependency: transitive
104+ description:
105+ name: leak_tracker_testing
106+ sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
107+ url: "https://pub.dev"
108+ source: hosted
109+ version: "3.0.2"
110+ lints:
111+ dependency: transitive
112+ description:
113+ name: lints
114+ sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
115+ url: "https://pub.dev"
116+ source: hosted
117+ version: "6.1.0"
118+ matcher:
119+ dependency: transitive
120+ description:
121+ name: matcher
122+ sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd"
123+ url: "https://pub.dev"
124+ source: hosted
125+ version: "0.12.20"
126+ material_color_utilities:
127+ dependency: transitive
128+ description:
129+ name: material_color_utilities
130+ sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
131+ url: "https://pub.dev"
132+ source: hosted
133+ version: "0.13.0"
134+ meta:
135+ dependency: transitive
136+ description:
137+ name: meta
138+ sha256: c82594181e3312f3d0695fc95aaaf7758d75b8d4ae2bbecf223b9fd5109a059d
139+ url: "https://pub.dev"
140+ source: hosted
141+ version: "1.18.3"
142+ path:
143+ dependency: transitive
144+ description:
145+ name: path
146+ sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
147+ url: "https://pub.dev"
148+ source: hosted
149+ version: "1.9.1"
150+ sky_engine:
151+ dependency: transitive
152+ description: flutter
153+ source: sdk
154+ version: "0.0.0"
155+ source_span:
156+ dependency: transitive
157+ description:
158+ name: source_span
159+ sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
160+ url: "https://pub.dev"
161+ source: hosted
162+ version: "1.10.2"
163+ stack_trace:
164+ dependency: transitive
165+ description:
166+ name: stack_trace
167+ sha256: "277654b3034d17ac6f9f1cb5595db011b1d5d41e8806866db28e0abaa101c490"
168+ url: "https://pub.dev"
169+ source: hosted
170+ version: "1.12.2"
171+ stream_channel:
172+ dependency: transitive
173+ description:
174+ name: stream_channel
175+ sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
176+ url: "https://pub.dev"
177+ source: hosted
178+ version: "2.1.4"
179+ string_scanner:
180+ dependency: transitive
181+ description:
182+ name: string_scanner
183+ sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
184+ url: "https://pub.dev"
185+ source: hosted
186+ version: "1.4.1"
187+ term_glyph:
188+ dependency: transitive
189+ description:
190+ name: term_glyph
191+ sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
192+ url: "https://pub.dev"
193+ source: hosted
194+ version: "1.2.2"
195+ test_api:
196+ dependency: transitive
197+ description:
198+ name: test_api
199+ sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11"
200+ url: "https://pub.dev"
201+ source: hosted
202+ version: "0.7.12"
203+ vector_math:
204+ dependency: transitive
205+ description:
206+ name: vector_math
207+ sha256: "1d774bbdf6b72a0b12122fc1560c9c2d2a67db5a4a4cc2bd8a5c990ab20e3188"
208+ url: "https://pub.dev"
209+ source: hosted
210+ version: "2.4.0"
211+ vflutter_ffi:
212+ dependency: "direct main"
213+ description:
214+ path: ".."
215+ relative: true
216+ source: path
217+ version: "0.1.0"
218+ vm_service:
219+ dependency: transitive
220+ description:
221+ name: vm_service
222+ sha256: "5f37239c4851efcef929cea7824e76df7f2f0970aef85d66bbc430afa40e72f0"
223+ url: "https://pub.dev"
224+ source: hosted
225+ version: "15.3.0"
226+sdks:
227+ dart: ">=3.13.3 <4.0.0"
228+ flutter: ">=3.18.0-18.0.pre.54"
new file mode 100644
@@ -0,0 +1,228 @@
1+# Generated by pub
2+# See https://dart.dev/tools/pub/glossary#lockfile
3+packages:
4+ async:
5+ dependency: transitive
6+ description:
7+ name: async
8+ sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
9+ url: "https://pub.dev"
10+ source: hosted
11+ version: "2.13.1"
12+ boolean_selector:
13+ dependency: transitive
14+ description:
15+ name: boolean_selector
16+ sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
17+ url: "https://pub.dev"
18+ source: hosted
19+ version: "2.1.2"
20+ characters:
21+ dependency: transitive
22+ description:
23+ name: characters
24+ sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
25+ url: "https://pub.dev"
26+ source: hosted
27+ version: "1.4.1"
28+ clock:
29+ dependency: transitive
30+ description:
31+ name: clock
32+ sha256: e51d50bca3217c9a9fa2b41a30e4a38971133f5f9ec7a3d57bae095007f1d28e
33+ url: "https://pub.dev"
34+ source: hosted
35+ version: "1.1.3"
36+ collection:
37+ dependency: transitive
38+ description:
39+ name: collection
40+ sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
41+ url: "https://pub.dev"
42+ source: hosted
43+ version: "1.19.1"
44+ cupertino_icons:
45+ dependency: "direct main"
46+ description:
47+ name: cupertino_icons
48+ sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd"
49+ url: "https://pub.dev"
50+ source: hosted
51+ version: "1.0.9"
52+ fake_async:
53+ dependency: transitive
54+ description:
55+ name: fake_async
56+ sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
57+ url: "https://pub.dev"
58+ source: hosted
59+ version: "1.3.3"
60+ ffi:
61+ dependency: "direct main"
62+ description:
63+ name: ffi
64+ sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"
65+ url: "https://pub.dev"
66+ source: hosted
67+ version: "2.2.0"
68+ flutter:
69+ dependency: "direct main"
70+ description: flutter
71+ source: sdk
72+ version: "0.0.0"
73+ flutter_lints:
74+ dependency: "direct dev"
75+ description:
76+ name: flutter_lints
77+ sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
78+ url: "https://pub.dev"
79+ source: hosted
80+ version: "6.0.0"
81+ flutter_test:
82+ dependency: "direct dev"
83+ description: flutter
84+ source: sdk
85+ version: "0.0.0"
86+ leak_tracker:
87+ dependency: transitive
88+ description:
89+ name: leak_tracker
90+ sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
91+ url: "https://pub.dev"
92+ source: hosted
93+ version: "11.0.2"
94+ leak_tracker_flutter_testing:
95+ dependency: transitive
96+ description:
97+ name: leak_tracker_flutter_testing
98+ sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
99+ url: "https://pub.dev"
100+ source: hosted
101+ version: "3.0.10"
102+ leak_tracker_testing:
103+ dependency: transitive
104+ description:
105+ name: leak_tracker_testing
106+ sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
107+ url: "https://pub.dev"
108+ source: hosted
109+ version: "3.0.2"
110+ lints:
111+ dependency: transitive
112+ description:
113+ name: lints
114+ sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
115+ url: "https://pub.dev"
116+ source: hosted
117+ version: "6.1.0"
118+ matcher:
119+ dependency: transitive
120+ description:
121+ name: matcher
122+ sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd"
123+ url: "https://pub.dev"
124+ source: hosted
125+ version: "0.12.20"
126+ material_color_utilities:
127+ dependency: transitive
128+ description:
129+ name: material_color_utilities
130+ sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
131+ url: "https://pub.dev"
132+ source: hosted
133+ version: "0.13.0"
134+ meta:
135+ dependency: transitive
136+ description:
137+ name: meta
138+ sha256: c82594181e3312f3d0695fc95aaaf7758d75b8d4ae2bbecf223b9fd5109a059d
139+ url: "https://pub.dev"
140+ source: hosted
141+ version: "1.18.3"
142+ path:
143+ dependency: transitive
144+ description:
145+ name: path
146+ sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
147+ url: "https://pub.dev"
148+ source: hosted
149+ version: "1.9.1"
150+ sky_engine:
151+ dependency: transitive
152+ description: flutter
153+ source: sdk
154+ version: "0.0.0"
155+ source_span:
156+ dependency: transitive
157+ description:
158+ name: source_span
159+ sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
160+ url: "https://pub.dev"
161+ source: hosted
162+ version: "1.10.2"
163+ stack_trace:
164+ dependency: transitive
165+ description:
166+ name: stack_trace
167+ sha256: "277654b3034d17ac6f9f1cb5595db011b1d5d41e8806866db28e0abaa101c490"
168+ url: "https://pub.dev"
169+ source: hosted
170+ version: "1.12.2"
171+ stream_channel:
172+ dependency: transitive
173+ description:
174+ name: stream_channel
175+ sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
176+ url: "https://pub.dev"
177+ source: hosted
178+ version: "2.1.4"
179+ string_scanner:
180+ dependency: transitive
181+ description:
182+ name: string_scanner
183+ sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
184+ url: "https://pub.dev"
185+ source: hosted
186+ version: "1.4.1"
187+ term_glyph:
188+ dependency: transitive
189+ description:
190+ name: term_glyph
191+ sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
192+ url: "https://pub.dev"
193+ source: hosted
194+ version: "1.2.2"
195+ test_api:
196+ dependency: transitive
197+ description:
198+ name: test_api
199+ sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11"
200+ url: "https://pub.dev"
201+ source: hosted
202+ version: "0.7.12"
203+ vector_math:
204+ dependency: transitive
205+ description:
206+ name: vector_math
207+ sha256: "1d774bbdf6b72a0b12122fc1560c9c2d2a67db5a4a4cc2bd8a5c990ab20e3188"
208+ url: "https://pub.dev"
209+ source: hosted
210+ version: "2.4.0"
211+ vflutter_ffi:
212+ dependency: "direct main"
213+ description:
214+ path: ".."
215+ relative: true
216+ source: path
217+ version: "0.1.0"
218+ vm_service:
219+ dependency: transitive
220+ description:
221+ name: vm_service
222+ sha256: "5f37239c4851efcef929cea7824e76df7f2f0970aef85d66bbc430afa40e72f0"
223+ url: "https://pub.dev"
224+ source: hosted
225+ version: "15.3.0"
226+sdks:
227+ dart: ">=3.13.3 <4.0.0"
228+ flutter: ">=3.18.0-18.0.pre.54"
added example/pubspec.yaml +96 -0
new file mode 100644
@@ -0,0 +1,96 @@
1+name: vflutter_ffi_example
2+description: "A new Flutter project."
3+# The following line prevents the package from being accidentally published to
4+# pub.dev using `flutter pub publish`. This is preferred for private packages.
5+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
6+
7+# The following defines the version and build number for your application.
8+# A version number is three numbers separated by dots, like 1.2.43
9+# followed by an optional build number separated by a +.
10+# Both the version and the builder number may be overridden in flutter
11+# build by specifying --build-name and --build-number, respectively.
12+# In Android, build-name is used as versionName while build-number used as versionCode.
13+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
14+# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
15+# Read more about iOS versioning at
16+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
17+# In Windows, build-name is used as the major, minor, and patch parts
18+# of the product and file versions while build-number is used as the build suffix.
19+version: 1.0.0+1
20+
21+environment:
22+ sdk: ^3.13.3
23+
24+# Dependencies specify other packages that your package needs in order to work.
25+# To automatically upgrade your package dependencies to the latest versions
26+# consider running `flutter pub upgrade --major-versions`. Alternatively,
27+# dependencies can be manually updated by changing the version numbers below to
28+# the latest version available on pub.dev. To see which dependencies have newer
29+# versions available, run `flutter pub outdated`.
30+dependencies:
31+ flutter:
32+ sdk: flutter
33+
34+ # The following adds the Cupertino Icons font to your application.
35+ # Use with the CupertinoIcons class for iOS style icons.
36+ cupertino_icons: ^1.0.8
37+
38+ # The plugin under test, from the repo root.
39+ vflutter_ffi:
40+ path: ../
41+
42+ # Used directly by lib/memory_check.dart.
43+ ffi: ^2.1.0
44+
45+dev_dependencies:
46+ flutter_test:
47+ sdk: flutter
48+
49+ # The "flutter_lints" package below contains a set of recommended lints to
50+ # encourage good coding practices. The lint set provided by the package is
51+ # activated in the `analysis_options.yaml` file located at the root of your
52+ # package. See that file for information about deactivating specific lint
53+ # rules and activating additional ones.
54+ flutter_lints: ^6.0.0
55+
56+# For information on the generic Dart part of this file, see the
57+# following page: https://dart.dev/tools/pub/pubspec
58+
59+# The following section is specific to Flutter packages.
60+flutter:
61+
62+ # The following line ensures that the Material Icons font is
63+ # included with your application, so that you can use the icons in
64+ # the material Icons class.
65+ uses-material-design: true
66+
67+ # To add assets to your application, add an assets section, like this:
68+ # assets:
69+ # - images/a_dot_burr.jpeg
70+ # - images/a_dot_ham.jpeg
71+
72+ # An image asset can refer to one or more resolution-specific "variants", see
73+ # https://flutter.dev/to/resolution-aware-images
74+
75+ # For details regarding adding assets from package dependencies, see
76+ # https://flutter.dev/to/asset-from-package
77+
78+ # To add custom fonts to your application, add a fonts section here,
79+ # in this "flutter" section. Each entry in this list should have a
80+ # "family" key with the font family name, and a "fonts" key with a
81+ # list giving the asset and other descriptors for the font. For
82+ # example:
83+ # fonts:
84+ # - family: Schyler
85+ # fonts:
86+ # - asset: fonts/Schyler-Regular.ttf
87+ # - asset: fonts/Schyler-Italic.ttf
88+ # style: italic
89+ # - family: Trajan Pro
90+ # fonts:
91+ # - asset: fonts/TrajanPro.ttf
92+ # - asset: fonts/TrajanPro_Bold.ttf
93+ # weight: 700
94+ #
95+ # For details regarding fonts from package dependencies,
96+ # see https://flutter.dev/to/font-from-package
new file mode 100644
@@ -0,0 +1,96 @@
1+name: vflutter_ffi_example
2+description: "A new Flutter project."
3+# The following line prevents the package from being accidentally published to
4+# pub.dev using `flutter pub publish`. This is preferred for private packages.
5+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
6+
7+# The following defines the version and build number for your application.
8+# A version number is three numbers separated by dots, like 1.2.43
9+# followed by an optional build number separated by a +.
10+# Both the version and the builder number may be overridden in flutter
11+# build by specifying --build-name and --build-number, respectively.
12+# In Android, build-name is used as versionName while build-number used as versionCode.
13+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
14+# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
15+# Read more about iOS versioning at
16+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
17+# In Windows, build-name is used as the major, minor, and patch parts
18+# of the product and file versions while build-number is used as the build suffix.
19+version: 1.0.0+1
20+
21+environment:
22+ sdk: ^3.13.3
23+
24+# Dependencies specify other packages that your package needs in order to work.
25+# To automatically upgrade your package dependencies to the latest versions
26+# consider running `flutter pub upgrade --major-versions`. Alternatively,
27+# dependencies can be manually updated by changing the version numbers below to
28+# the latest version available on pub.dev. To see which dependencies have newer
29+# versions available, run `flutter pub outdated`.
30+dependencies:
31+ flutter:
32+ sdk: flutter
33+
34+ # The following adds the Cupertino Icons font to your application.
35+ # Use with the CupertinoIcons class for iOS style icons.
36+ cupertino_icons: ^1.0.8
37+
38+ # The plugin under test, from the repo root.
39+ vflutter_ffi:
40+ path: ../
41+
42+ # Used directly by lib/memory_check.dart.
43+ ffi: ^2.1.0
44+
45+dev_dependencies:
46+ flutter_test:
47+ sdk: flutter
48+
49+ # The "flutter_lints" package below contains a set of recommended lints to
50+ # encourage good coding practices. The lint set provided by the package is
51+ # activated in the `analysis_options.yaml` file located at the root of your
52+ # package. See that file for information about deactivating specific lint
53+ # rules and activating additional ones.
54+ flutter_lints: ^6.0.0
55+
56+# For information on the generic Dart part of this file, see the
57+# following page: https://dart.dev/tools/pub/pubspec
58+
59+# The following section is specific to Flutter packages.
60+flutter:
61+
62+ # The following line ensures that the Material Icons font is
63+ # included with your application, so that you can use the icons in
64+ # the material Icons class.
65+ uses-material-design: true
66+
67+ # To add assets to your application, add an assets section, like this:
68+ # assets:
69+ # - images/a_dot_burr.jpeg
70+ # - images/a_dot_ham.jpeg
71+
72+ # An image asset can refer to one or more resolution-specific "variants", see
73+ # https://flutter.dev/to/resolution-aware-images
74+
75+ # For details regarding adding assets from package dependencies, see
76+ # https://flutter.dev/to/asset-from-package
77+
78+ # To add custom fonts to your application, add a fonts section here,
79+ # in this "flutter" section. Each entry in this list should have a
80+ # "family" key with the font family name, and a "fonts" key with a
81+ # list giving the asset and other descriptors for the font. For
82+ # example:
83+ # fonts:
84+ # - family: Schyler
85+ # fonts:
86+ # - asset: fonts/Schyler-Regular.ttf
87+ # - asset: fonts/Schyler-Italic.ttf
88+ # style: italic
89+ # - family: Trajan Pro
90+ # fonts:
91+ # - asset: fonts/TrajanPro.ttf
92+ # - asset: fonts/TrajanPro_Bold.ttf
93+ # weight: 700
94+ #
95+ # For details regarding fonts from package dependencies,
96+ # see https://flutter.dev/to/font-from-package
added example/test/widget_test.dart +36 -0
new file mode 100644
@@ -0,0 +1,36 @@
1+// Smoke test for the V bridge behind the UI. Runs on the host, so it loads
2+// the same libvflutter.so the desktop app does.
3+
4+import 'package:flutter_test/flutter_test.dart';
5+
6+import 'package:vflutter_ffi_example/main.dart';
7+
8+void main() {
9+ testWidgets('renders results computed in V', (WidgetTester tester) async {
10+ await tester.pumpWidget(const ExampleApp());
11+
12+ // vf_add across the C ABI.
13+ expect(find.text('42'), findsOneWidget);
14+
15+ // vf_greet round-trips a string and frees the V allocation.
16+ expect(find.text('Hello, Flutter, from V!'), findsOneWidget);
17+ });
18+
19+ testWidgets('background isolate returns the same answer',
20+ (WidgetTester tester) async {
21+ await tester.pumpWidget(const ExampleApp());
22+
23+ expect(find.text('(not run)'), findsNWidgets(2));
24+
25+ // greetAsync spawns a real isolate, which the default fake-async clock
26+ // never lets complete — runAsync is required for the await to resolve.
27+ await tester.runAsync(() async {
28+ await tester.tap(find.text('run on background isolate'));
29+ await Future<void>.delayed(const Duration(seconds: 2));
30+ });
31+ await tester.pump();
32+
33+ // Once on the sync row, once on the async row.
34+ expect(find.text('Hello, Flutter, from V!'), findsNWidgets(2));
35+ });
36+}
new file mode 100644
@@ -0,0 +1,36 @@
1+// Smoke test for the V bridge behind the UI. Runs on the host, so it loads
2+// the same libvflutter.so the desktop app does.
3+
4+import 'package:flutter_test/flutter_test.dart';
5+
6+import 'package:vflutter_ffi_example/main.dart';
7+
8+void main() {
9+ testWidgets('renders results computed in V', (WidgetTester tester) async {
10+ await tester.pumpWidget(const ExampleApp());
11+
12+ // vf_add across the C ABI.
13+ expect(find.text('42'), findsOneWidget);
14+
15+ // vf_greet round-trips a string and frees the V allocation.
16+ expect(find.text('Hello, Flutter, from V!'), findsOneWidget);
17+ });
18+
19+ testWidgets('background isolate returns the same answer',
20+ (WidgetTester tester) async {
21+ await tester.pumpWidget(const ExampleApp());
22+
23+ expect(find.text('(not run)'), findsNWidgets(2));
24+
25+ // greetAsync spawns a real isolate, which the default fake-async clock
26+ // never lets complete — runAsync is required for the await to resolve.
27+ await tester.runAsync(() async {
28+ await tester.tap(find.text('run on background isolate'));
29+ await Future<void>.delayed(const Duration(seconds: 2));
30+ });
31+ await tester.pump();
32+
33+ // Once on the sync row, once on the async row.
34+ expect(find.text('Hello, Flutter, from V!'), findsNWidgets(2));
35+ });
36+}