├── .gitignore ├── .metadata ├── .vscode ├── c_cpp_properties.json ├── launch.json └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example ├── .gitignore ├── README.md ├── analysis_options.yaml ├── example.png ├── integration_test │ └── plugin_integration_test.dart ├── lib │ ├── main.dart │ ├── set_anchors.dart │ ├── set_exclusive_zone.dart │ ├── set_keyboard.dart │ ├── set_layer.dart │ ├── set_margins.dart │ └── set_monitor.dart ├── linux │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter │ │ ├── CMakeLists.txt │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ └── generated_plugins.cmake │ ├── main.cc │ ├── my_application.cc │ └── my_application.h ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── lib ├── types.dart └── wayland_layer_shell.dart ├── linux ├── CMakeLists.txt ├── include │ └── wayland_layer_shell │ │ └── wayland_layer_shell_plugin.h ├── test │ └── wayland_layer_shell_plugin_test.cc ├── wayland_layer_shell_plugin.cc └── wayland_layer_shell_plugin_private.h └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | build/ 30 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 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: "20eb3ea1318f7461893f84f1ad8e92d1c269853d" 8 | channel: "main" 9 | 10 | project_type: plugin 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 20eb3ea1318f7461893f84f1ad8e92d1c269853d 17 | base_revision: 20eb3ea1318f7461893f84f1ad8e92d1c269853d 18 | - platform: linux 19 | create_revision: 20eb3ea1318f7461893f84f1ad8e92d1c269853d 20 | base_revision: 20eb3ea1318f7461893f84f1ad8e92d1c269853d 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' 31 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**" 7 | ], 8 | "defines": [], 9 | "compilerPath": "/usr/bin/clang", 10 | "cStandard": "c17", 11 | "cppStandard": "c++14", 12 | "intelliSenseMode": "linux-clang-x64", 13 | "compileCommands": "${workspaceFolder}/build/compile_commands.json", 14 | "configurationProvider": "ms-vscode.cmake-tools" 15 | } 16 | ], 17 | "version": 4 18 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch Flutter", 6 | "cwd": "example", 7 | "request": "launch", 8 | "type": "dart", 9 | "env": { 10 | "GDK_BACKEND": "wayland" 11 | } 12 | }, 13 | { 14 | "name": "Debug native", 15 | "type": "cppdbg", 16 | "request": "launch", 17 | "program": "${workspaceFolder}/example/build/linux/x64/debug/bundle/wayland_layer_shell_example", 18 | "cwd": "${workspaceFolder}", 19 | "env": { 20 | "GDK_BACKEND": "wayland" 21 | } 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.sourceDirectory": "${workspaceFolder}/wayland_layer_shell/example/linux", 3 | "cmake.configureOnOpen": true, 4 | "files.associations": { 5 | "cstring": "cpp", 6 | "functional": "cpp", 7 | "chrono": "cpp" 8 | }, 9 | "C_Cpp.errorSquiggles": "disabled" 10 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.1] - 11 dec 2023 4 | Update pubspac.yaml to add platform 5 | 6 | ## [1.0.0] - 10 dec 2023 7 | Initial release -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Metin Ur 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wayland_layer_shell 2 | 3 | This plugin exposes the `zwlr_layer_shell_v1` protocol using the [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell) library, enabling the creation of desktop components such as panels, taskbars, application launchers, etc. with Flutter on Wayland systems. 4 | 5 | ## Supported Compositors 6 | 7 | This plugin exclusively functions on Wayland and is compatible only with Wayland compositors that support the `zwlr_layer_shell_v1` protocol. The Layer Shell protocol is supported on: 8 | 9 | - wlroots-based compositors (such as Sway, Hyprland, etc.) 10 | - KDE Plasma on Wayland 11 | - Mir-based compositors (some may not enable the protocol by default and require `--add-wayland-extension zwlr_layer_shell_v1`) 12 | 13 | Layer Shell is not supported on: 14 | 15 | - Gnome-on-Wayland 16 | - Any X11 desktop 17 | 18 | ## Getting Started 19 | 20 | Add this to your project's pubspec.yaml file: 21 | 22 | ```yaml 23 | dependencies: 24 | wayland_layer_shell: ^1.0.1 25 | ``` 26 | 27 | Using the gtk header bar and displaying the gtk window before initializing the layer surface prevents the initialization of the layer surface, hence some changes are required in Flutter's gtk window initialization code. 28 | 29 | Update the file `linux/runner/my_application.cc` as follows: 30 | 31 | ```diff 32 | ... 33 | 34 | // Implements GApplication::activate. 35 | static void my_application_activate(GApplication* application) { 36 | 37 | ... 38 | 39 | - gboolean use_header_bar = TRUE; 40 | + gboolean use_header_bar = FALSE; 41 | 42 | ... 43 | 44 | gtk_window_set_default_size(window, 1280, 720); 45 | - gtk_widget_show(GTK_WIDGET(window)); 46 | + gtk_widget_realize(GTK_WIDGET(window)); 47 | 48 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 49 | 50 | ... 51 | 52 | ``` 53 | 54 | ## Dependencies 55 | 56 | This plugin relies on the [gtk-layer-shell-0](https://github.com/wmww/gtk-layer-shell/tree/master) library. Ensure that it is available on the platforms where apps using this plugin are installed. The library can be found in the repositories of major distributions: [Distro packages](https://github.com/wmww/gtk-layer-shell?tab=readme-ov-file#distro-packages) 57 | 58 | ## Usage 59 | 60 | For usage check out the example app inside [example](./example) folder. 61 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Symbolication related 35 | app.*.symbols 36 | 37 | # Obfuscation related 38 | app.*.map.json 39 | 40 | # Android Studio will place build artifacts here 41 | /android/app/debug 42 | /android/app/profile 43 | /android/app/release 44 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # wayland_layer_shell_example 2 | 3 | ![example screenshot](./example.png) 4 | 5 | Flutter app similar to [gtk-layer-shell's demo app](https://github.com/wmww/gtk-layer-shell/tree/master/examples/demo) demonstrates how to use the wayland_layer_shell plugin. -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 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 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | rules: 24 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 25 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 26 | 27 | # Additional information about this file can be found at 28 | # https://dart.dev/guides/language/analysis-options 29 | -------------------------------------------------------------------------------- /example/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mr-1311/wayland_layer_shell/3d4cdd24a28ad2eb3bd0213952fd979d53d9425d/example/example.png -------------------------------------------------------------------------------- /example/integration_test/plugin_integration_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter integration test. 2 | // 3 | // Since integration tests run in a full Flutter application, they can interact 4 | // with the host side of a plugin implementation, unlike Dart unit tests. 5 | // 6 | // For more information about Flutter integration tests, please see 7 | // https://docs.flutter.dev/cookbook/testing/integration/introduction 8 | 9 | 10 | import 'package:flutter_test/flutter_test.dart'; 11 | import 'package:integration_test/integration_test.dart'; 12 | 13 | import 'package:wayland_layer_shell/wayland_layer_shell.dart'; 14 | 15 | void main() { 16 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 17 | 18 | testWidgets('getPlatformVersion test', (WidgetTester tester) async { 19 | final WaylandLayerShell plugin = WaylandLayerShell(); 20 | final String? version = await plugin.getPlatformVersion(); 21 | // The version string depends on the host platform running the test, so 22 | // just assert that some non-empty string is returned. 23 | expect(version?.isNotEmpty, true); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:wayland_layer_shell/types.dart'; 3 | import 'dart:async'; 4 | 5 | import 'package:wayland_layer_shell/wayland_layer_shell.dart'; 6 | import 'package:wayland_layer_shell_example/set_exclusive_zone.dart'; 7 | import 'package:wayland_layer_shell_example/set_keyboard.dart'; 8 | import 'package:wayland_layer_shell_example/set_monitor.dart'; 9 | import 'package:wayland_layer_shell_example/set_anchors.dart'; 10 | import 'package:wayland_layer_shell_example/set_layer.dart'; 11 | import 'package:wayland_layer_shell_example/set_margins.dart'; 12 | 13 | Future main() async { 14 | WidgetsFlutterBinding.ensureInitialized(); 15 | final waylandLayerShellPlugin = WaylandLayerShell(); 16 | bool isSupported = await waylandLayerShellPlugin.initialize(650, 600); 17 | if (!isSupported) { 18 | runApp(const MaterialApp(home: Center(child: Text('Not supported')))); 19 | return; 20 | } 21 | await waylandLayerShellPlugin 22 | .setKeyboardMode(ShellKeyboardMode.keyboardModeExclusive); 23 | runApp(const MyApp()); 24 | } 25 | 26 | class MyApp extends StatefulWidget { 27 | const MyApp({super.key}); 28 | 29 | @override 30 | State createState() => _MyAppState(); 31 | } 32 | 33 | class _MyAppState extends State { 34 | @override 35 | Widget build(BuildContext context) { 36 | return MaterialApp( 37 | home: Scaffold( 38 | appBar: AppBar( 39 | title: const Text('Wayland Layer Shell example'), 40 | ), 41 | body: const Center( 42 | child: Column( 43 | mainAxisAlignment: MainAxisAlignment.center, 44 | crossAxisAlignment: CrossAxisAlignment.center, 45 | children: [ 46 | Row( 47 | mainAxisAlignment: MainAxisAlignment.center, 48 | children: [ 49 | SetMonitor(), 50 | SizedBox(width: 40), 51 | SetExclusiveZone(), 52 | ], 53 | ), 54 | SizedBox(height: 20), 55 | SetLayer(), 56 | SizedBox(height: 10), 57 | Row( 58 | mainAxisAlignment: MainAxisAlignment.center, 59 | children: [ 60 | SetKeyboard(), 61 | SizedBox( 62 | width: 120, 63 | child: TextField( 64 | autofocus: true, 65 | decoration: 66 | InputDecoration(labelText: 'Test Keyboard Mode'), 67 | ), 68 | ) 69 | ], 70 | ), 71 | SizedBox(height: 20), 72 | Row( 73 | mainAxisAlignment: MainAxisAlignment.center, 74 | children: [SetAnchors(), SizedBox(width: 40), SetMargins()], 75 | ), 76 | ], 77 | ), 78 | ), 79 | ), 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /example/lib/set_anchors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:wayland_layer_shell/types.dart'; 3 | import 'package:wayland_layer_shell/wayland_layer_shell.dart'; 4 | 5 | class SetAnchors extends StatefulWidget { 6 | const SetAnchors({super.key}); 7 | 8 | @override 9 | State createState() => _SetAnchorsState(); 10 | } 11 | 12 | class _SetAnchorsState extends State { 13 | bool isSelectedTop = false, 14 | isSelectedLeft = false, 15 | isSelectedRight = false, 16 | isSelectedBottom = false; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Center( 21 | child: Column( 22 | children: [ 23 | IconButton.outlined( 24 | onPressed: () => _onPressed(ShellEdge.edgeTop), 25 | isSelected: isSelectedTop, 26 | icon: const Icon(Icons.arrow_upward)), 27 | Row( 28 | mainAxisAlignment: MainAxisAlignment.center, 29 | children: [ 30 | IconButton.outlined( 31 | onPressed: () => _onPressed(ShellEdge.edgeLeft), 32 | isSelected: isSelectedLeft, 33 | icon: const Icon(Icons.arrow_back)), 34 | const SizedBox( 35 | width: 40, 36 | height: 40, 37 | ), 38 | IconButton.outlined( 39 | onPressed: () => _onPressed(ShellEdge.edgeRight), 40 | isSelected: isSelectedRight, 41 | icon: const Icon(Icons.arrow_forward)), 42 | ], 43 | ), 44 | IconButton.outlined( 45 | onPressed: () => _onPressed(ShellEdge.edgeBottom), 46 | isSelected: isSelectedBottom, 47 | icon: const Icon(Icons.arrow_downward)), 48 | ], 49 | ), 50 | ); 51 | } 52 | 53 | _onPressed(ShellEdge edge) async { 54 | final waylandLayerShellPlugin = WaylandLayerShell(); 55 | bool getEdge = await waylandLayerShellPlugin.getAnchor(edge); 56 | await waylandLayerShellPlugin.setAnchor(edge, !getEdge); 57 | setState(() { 58 | switch (edge) { 59 | case ShellEdge.edgeTop: 60 | isSelectedTop = !getEdge; 61 | break; 62 | case ShellEdge.edgeLeft: 63 | isSelectedLeft = !getEdge; 64 | break; 65 | case ShellEdge.edgeRight: 66 | isSelectedRight = !getEdge; 67 | break; 68 | case ShellEdge.edgeBottom: 69 | isSelectedBottom = !getEdge; 70 | break; 71 | default: 72 | break; 73 | } 74 | }); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /example/lib/set_exclusive_zone.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:wayland_layer_shell/wayland_layer_shell.dart'; 3 | 4 | class SetExclusiveZone extends StatefulWidget { 5 | const SetExclusiveZone({super.key}); 6 | 7 | @override 8 | State createState() => _SetExclusiveZoneState(); 9 | } 10 | 11 | class _SetExclusiveZoneState extends State { 12 | bool isExculiveZone = false; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Column( 17 | children: [ 18 | const Text('Exclusive Zone'), 19 | Switch( 20 | value: isExculiveZone, 21 | onChanged: (val) => _onSelectionChanged(val)), 22 | ], 23 | ); 24 | } 25 | 26 | _onSelectionChanged(bool val) async { 27 | WaylandLayerShell waylandLayerShellPlugin = WaylandLayerShell(); 28 | if (val == true) { 29 | await waylandLayerShellPlugin.enableAutoExclusiveZone(); 30 | // exclusive zone can be set to any fixed value too. 31 | // await waylandLayerShellPlugin.setExclusiveZone(200); 32 | } else { 33 | await waylandLayerShellPlugin.setExclusiveZone(0); 34 | } 35 | 36 | print('exculive zone: ${await waylandLayerShellPlugin.getExclusiveZone()}'); 37 | print( 38 | 'isExculiveZoneEnabled : ${await waylandLayerShellPlugin.isAutoExclusiveZoneEnabled()}'); 39 | 40 | setState(() { 41 | isExculiveZone = val; 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /example/lib/set_keyboard.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:wayland_layer_shell/types.dart'; 3 | import 'package:wayland_layer_shell/wayland_layer_shell.dart'; 4 | 5 | class SetKeyboard extends StatefulWidget { 6 | const SetKeyboard({super.key}); 7 | 8 | @override 9 | State createState() => _SetKeyboardState(); 10 | } 11 | 12 | class _SetKeyboardState extends State { 13 | ShellKeyboardMode kbMode = ShellKeyboardMode.keyboardModeNone; 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | setCurrentKeyboardMode(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return Column( 24 | children: [ 25 | Text('Set Keyboard Mode: ${kbMode.name}'), 26 | SegmentedButton( 27 | segments: const >[ 28 | ButtonSegment( 29 | value: ShellKeyboardMode.keyboardModeNone, 30 | label: Text('None'), 31 | ), 32 | ButtonSegment( 33 | value: ShellKeyboardMode.keyboardModeExclusive, 34 | label: Text('Exclusive'), 35 | ), 36 | ButtonSegment( 37 | value: ShellKeyboardMode.keyboardModeOnDemand, 38 | label: Text('OnDemand'), 39 | ), 40 | ], 41 | selected: {kbMode}, 42 | onSelectionChanged: (val) => _onSelectionChanged(val), 43 | ), 44 | ], 45 | ); 46 | } 47 | 48 | void _onSelectionChanged(Set kbMode) async { 49 | WaylandLayerShell waylandLayerShellPlugin = WaylandLayerShell(); 50 | await waylandLayerShellPlugin.setKeyboardMode(kbMode.first); 51 | print('keyboard mode: ${await waylandLayerShellPlugin.getKeyboardMode()}'); 52 | setState(() { 53 | this.kbMode = kbMode.first; 54 | }); 55 | } 56 | 57 | void setCurrentKeyboardMode() async { 58 | WaylandLayerShell waylandLayerShellPlugin = WaylandLayerShell(); 59 | final kbMode = await waylandLayerShellPlugin.getKeyboardMode(); 60 | setState(() { 61 | this.kbMode = kbMode; 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /example/lib/set_layer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:wayland_layer_shell/types.dart'; 3 | import 'package:wayland_layer_shell/wayland_layer_shell.dart'; 4 | 5 | class SetLayer extends StatefulWidget { 6 | const SetLayer({super.key}); 7 | 8 | @override 9 | State createState() => _SetLayerState(); 10 | } 11 | 12 | class _SetLayerState extends State { 13 | ShellLayer layer = ShellLayer.layerTop; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Column( 18 | children: [ 19 | Text('Set Layer: ${layer.name}'), 20 | SegmentedButton( 21 | segments: const >[ 22 | ButtonSegment( 23 | value: ShellLayer.layerBackground, 24 | label: Text('Background'), 25 | ), 26 | ButtonSegment( 27 | value: ShellLayer.layerBottom, 28 | label: Text('Bottom'), 29 | ), 30 | ButtonSegment( 31 | value: ShellLayer.layerTop, 32 | label: Text('Top'), 33 | ), 34 | ButtonSegment( 35 | value: ShellLayer.layerOverlay, 36 | label: Text('Overlay'), 37 | ), 38 | ], 39 | selected: {layer}, 40 | onSelectionChanged: (val) => _onSelectionChanged(val), 41 | ), 42 | ], 43 | ); 44 | } 45 | 46 | _onSelectionChanged(Set layer) async { 47 | WaylandLayerShell waylandLayerShellPlugin = WaylandLayerShell(); 48 | await waylandLayerShellPlugin.setLayer(layer.first); 49 | print('layer: ${await waylandLayerShellPlugin.getLayer()}'); 50 | setState(() { 51 | this.layer = layer.first; 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /example/lib/set_margins.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:wayland_layer_shell/types.dart'; 4 | import 'package:wayland_layer_shell/wayland_layer_shell.dart'; 5 | 6 | class SetMargins extends StatefulWidget { 7 | const SetMargins({super.key}); 8 | 9 | @override 10 | State createState() => _SetMarginsState(); 11 | } 12 | 13 | class _SetMarginsState extends State { 14 | @override 15 | Widget build(BuildContext context) { 16 | return SizedBox( 17 | width: 120, 18 | child: Card( 19 | child: Padding( 20 | padding: const EdgeInsets.all(8.0), 21 | child: Column( 22 | children: [ 23 | const Text('Set Margins'), 24 | TextField( 25 | onSubmitted: (value) => 26 | _onMarginChanged(value, ShellEdge.edgeTop), 27 | keyboardType: TextInputType.number, 28 | inputFormatters: [ 29 | FilteringTextInputFormatter.digitsOnly, 30 | ], 31 | decoration: const InputDecoration(labelText: 'Top'), 32 | ), 33 | TextField( 34 | onSubmitted: (value) => 35 | _onMarginChanged(value, ShellEdge.edgeLeft), 36 | keyboardType: TextInputType.number, 37 | inputFormatters: [ 38 | FilteringTextInputFormatter.digitsOnly, 39 | ], 40 | decoration: const InputDecoration(labelText: 'Left'), 41 | ), 42 | TextField( 43 | onSubmitted: (value) => 44 | _onMarginChanged(value, ShellEdge.edgeRight), 45 | keyboardType: TextInputType.number, 46 | inputFormatters: [ 47 | FilteringTextInputFormatter.digitsOnly, 48 | ], 49 | decoration: const InputDecoration(labelText: 'Right'), 50 | ), 51 | TextField( 52 | onSubmitted: (value) => 53 | _onMarginChanged(value, ShellEdge.edgeBottom), 54 | keyboardType: TextInputType.number, 55 | inputFormatters: [ 56 | FilteringTextInputFormatter.digitsOnly, 57 | ], 58 | decoration: const InputDecoration(labelText: 'Bottom'), 59 | ), 60 | ], 61 | ), 62 | ), 63 | ), 64 | ); 65 | } 66 | 67 | _onMarginChanged(String value, ShellEdge edge) async { 68 | final waylandLayerShellPlugin = WaylandLayerShell(); 69 | waylandLayerShellPlugin.setMargin(edge, int.parse(value)); 70 | int margin = await waylandLayerShellPlugin.getMargin(edge); 71 | print('Margin setted to $edge: $margin'); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /example/lib/set_monitor.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:wayland_layer_shell/types.dart'; 3 | import 'package:wayland_layer_shell/wayland_layer_shell.dart'; 4 | 5 | class SetMonitor extends StatefulWidget { 6 | const SetMonitor({super.key}); 7 | 8 | @override 9 | State createState() => _SetMonitorState(); 10 | } 11 | 12 | class _SetMonitorState extends State { 13 | List items = []; 14 | final _waylandLayerShellPlugin = WaylandLayerShell(); 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | setItems(); 20 | } 21 | 22 | Future setItems() async { 23 | final mons = await _waylandLayerShellPlugin.getMonitorList(); 24 | setState(() { 25 | items = mons; 26 | }); 27 | } 28 | 29 | setMonitor(int id) { 30 | if (id == -1) { 31 | _waylandLayerShellPlugin.setMonitor(null); 32 | return; 33 | } 34 | _waylandLayerShellPlugin.setMonitor(items.firstWhere((m) => m.id == id)); 35 | } 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return Column( 40 | children: [ 41 | const Text('Set Monitor'), 42 | DropdownMenu( 43 | onSelected: (value) => setMonitor(int.parse(value!)), 44 | initialSelection: '-1', 45 | dropdownMenuEntries: items.map>((mon) { 46 | return DropdownMenuEntry( 47 | value: mon.id.toString(), label: mon.toString()); 48 | }).toList() 49 | ..add(const DropdownMenuEntry(value: '-1', label: 'default'))), 50 | ], 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /example/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /example/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project-level configuration. 2 | cmake_minimum_required(VERSION 3.10) 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 "wayland_layer_shell_example") 8 | # The unique GTK application identifier for this application. See: 9 | # https://wiki.gnome.org/HowDoI/ChooseApplicationID 10 | set(APPLICATION_ID "com.example.wayland_layer_shell") 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 "$<$>:-O3>") 46 | target_compile_definitions(${TARGET} PRIVATE "$<$>: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 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 58 | 59 | # Define the application target. To change its name, change BINARY_NAME above, 60 | # not the value here, or `flutter run` will no longer work. 61 | # 62 | # Any new source files that you add to the application should be added here. 63 | add_executable(${BINARY_NAME} 64 | "main.cc" 65 | "my_application.cc" 66 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 67 | ) 68 | 69 | # Apply the standard set of build settings. This can be removed for applications 70 | # that need different build settings. 71 | apply_standard_settings(${BINARY_NAME}) 72 | 73 | # Add dependency libraries. Add any application-specific dependencies here. 74 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 75 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 76 | 77 | # Run the Flutter tool portions of the build. This must not be removed. 78 | add_dependencies(${BINARY_NAME} flutter_assemble) 79 | 80 | # Only the install-generated bundle's copy of the executable will launch 81 | # correctly, since the resources must in the right relative locations. To avoid 82 | # people trying to run the unbundled copy, put it in a subdirectory instead of 83 | # the default top-level location. 84 | set_target_properties(${BINARY_NAME} 85 | PROPERTIES 86 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" 87 | ) 88 | 89 | # Enable the test target. 90 | set(include_wayland_layer_shell_tests TRUE) 91 | 92 | # Generated plugin build rules, which manage building the plugins and adding 93 | # them to the application. 94 | include(flutter/generated_plugins.cmake) 95 | 96 | 97 | # === Installation === 98 | # By default, "installing" just makes a relocatable bundle in the build 99 | # directory. 100 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") 101 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 102 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 103 | endif() 104 | 105 | # Start with a clean build bundle directory every time. 106 | install(CODE " 107 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") 108 | " COMPONENT Runtime) 109 | 110 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 111 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") 112 | 113 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 114 | COMPONENT Runtime) 115 | 116 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 117 | COMPONENT Runtime) 118 | 119 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 120 | COMPONENT Runtime) 121 | 122 | foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) 123 | install(FILES "${bundled_library}" 124 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 125 | COMPONENT Runtime) 126 | endforeach(bundled_library) 127 | 128 | # Copy the native assets provided by the build.dart from all packages. 129 | set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") 130 | install(DIRECTORY "${NATIVE_ASSETS_DIR}" 131 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 132 | COMPONENT Runtime) 133 | 134 | # Fully re-copy the assets directory on each build to avoid having stale files 135 | # from a previous install. 136 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 137 | install(CODE " 138 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 139 | " COMPONENT Runtime) 140 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 141 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 142 | 143 | # Install the AOT library on non-Debug builds only. 144 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") 145 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 146 | COMPONENT Runtime) 147 | endif() 148 | -------------------------------------------------------------------------------- /example/linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 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 | ) 89 | -------------------------------------------------------------------------------- /example/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | 11 | void fl_register_plugins(FlPluginRegistry* registry) { 12 | g_autoptr(FlPluginRegistrar) wayland_layer_shell_registrar = 13 | fl_plugin_registry_get_registrar_for_plugin(registry, "WaylandLayerShellPlugin"); 14 | wayland_layer_shell_plugin_register_with_registrar(wayland_layer_shell_registrar); 15 | } 16 | -------------------------------------------------------------------------------- /example/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 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 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /example/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | wayland_layer_shell 7 | ) 8 | 9 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 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 $) 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) 25 | -------------------------------------------------------------------------------- /example/linux/main.cc: -------------------------------------------------------------------------------- 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 | } 7 | -------------------------------------------------------------------------------- /example/linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | #ifdef GDK_WINDOWING_X11 5 | #include 6 | #endif 7 | 8 | #include "flutter/generated_plugin_registrant.h" 9 | 10 | struct _MyApplication 11 | { 12 | GtkApplication parent_instance; 13 | char **dart_entrypoint_arguments; 14 | }; 15 | 16 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 17 | 18 | // Implements GApplication::activate. 19 | static void my_application_activate(GApplication *application) 20 | { 21 | MyApplication *self = MY_APPLICATION(application); 22 | GtkWindow *window = 23 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 24 | 25 | // Use a header bar when running in GNOME as this is the common style used 26 | // by applications and is the setup most users will be using (e.g. Ubuntu 27 | // desktop). 28 | // If running on X and not using GNOME then just use a traditional title bar 29 | // in case the window manager does more exotic layout, e.g. tiling. 30 | // If running on Wayland assume the header bar will work (may need changing 31 | // if future cases occur). 32 | gboolean use_header_bar = FALSE; 33 | #ifdef GDK_WINDOWING_X11 34 | GdkScreen *screen = gtk_window_get_screen(window); 35 | if (GDK_IS_X11_SCREEN(screen)) 36 | { 37 | const gchar *wm_name = gdk_x11_screen_get_window_manager_name(screen); 38 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) 39 | { 40 | use_header_bar = FALSE; 41 | } 42 | } 43 | #endif 44 | if (use_header_bar) 45 | { 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, "wayland_layer_shell_example"); 49 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 50 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 51 | } 52 | else 53 | { 54 | gtk_window_set_title(window, "wayland_layer_shell_example"); 55 | } 56 | 57 | gtk_window_set_default_size(window, 1280, 720); 58 | gtk_widget_realize(GTK_WIDGET(window)); 59 | 60 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 61 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); 62 | 63 | FlView *view = fl_view_new(project); 64 | gtk_widget_show(GTK_WIDGET(view)); 65 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 66 | 67 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 68 | 69 | gtk_widget_grab_focus(GTK_WIDGET(view)); 70 | } 71 | 72 | // Implements GApplication::local_command_line. 73 | static gboolean my_application_local_command_line(GApplication *application, gchar ***arguments, int *exit_status) 74 | { 75 | MyApplication *self = MY_APPLICATION(application); 76 | // Strip out the first argument as it is the binary name. 77 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); 78 | 79 | g_autoptr(GError) error = nullptr; 80 | if (!g_application_register(application, nullptr, &error)) 81 | { 82 | g_warning("Failed to register: %s", error->message); 83 | *exit_status = 1; 84 | return TRUE; 85 | } 86 | 87 | g_application_activate(application); 88 | *exit_status = 0; 89 | 90 | return TRUE; 91 | } 92 | 93 | // Implements GApplication::startup. 94 | static void my_application_startup(GApplication *application) 95 | { 96 | // MyApplication* self = MY_APPLICATION(object); 97 | 98 | // Perform any actions required at application startup. 99 | 100 | G_APPLICATION_CLASS(my_application_parent_class)->startup(application); 101 | } 102 | 103 | // Implements GApplication::shutdown. 104 | static void my_application_shutdown(GApplication *application) 105 | { 106 | // MyApplication* self = MY_APPLICATION(object); 107 | 108 | // Perform any actions required at application shutdown. 109 | 110 | G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); 111 | } 112 | 113 | // Implements GObject::dispose. 114 | static void my_application_dispose(GObject *object) 115 | { 116 | MyApplication *self = MY_APPLICATION(object); 117 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); 118 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object); 119 | } 120 | 121 | static void my_application_class_init(MyApplicationClass *klass) 122 | { 123 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 124 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; 125 | G_APPLICATION_CLASS(klass)->startup = my_application_startup; 126 | G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; 127 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose; 128 | } 129 | 130 | static void my_application_init(MyApplication *self) {} 131 | 132 | MyApplication *my_application_new() 133 | { 134 | return MY_APPLICATION(g_object_new(my_application_get_type(), 135 | "application-id", APPLICATION_ID, 136 | "flags", G_APPLICATION_NON_UNIQUE, 137 | nullptr)); 138 | } 139 | -------------------------------------------------------------------------------- /example/linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 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: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.18.0" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.6" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | file: 61 | dependency: transitive 62 | description: 63 | name: file 64 | sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "7.0.0" 68 | flutter: 69 | dependency: "direct main" 70 | description: flutter 71 | source: sdk 72 | version: "0.0.0" 73 | flutter_driver: 74 | dependency: transitive 75 | description: flutter 76 | source: sdk 77 | version: "0.0.0" 78 | flutter_lints: 79 | dependency: "direct dev" 80 | description: 81 | name: flutter_lints 82 | sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "3.0.1" 86 | flutter_test: 87 | dependency: "direct dev" 88 | description: flutter 89 | source: sdk 90 | version: "0.0.0" 91 | fuchsia_remote_debug_protocol: 92 | dependency: transitive 93 | description: flutter 94 | source: sdk 95 | version: "0.0.0" 96 | integration_test: 97 | dependency: "direct dev" 98 | description: flutter 99 | source: sdk 100 | version: "0.0.0" 101 | leak_tracker: 102 | dependency: transitive 103 | description: 104 | name: leak_tracker 105 | sha256: "04be76c4a4bb50f14904e64749237e541e7c7bcf7ec0b196907322ab5d2fc739" 106 | url: "https://pub.dev" 107 | source: hosted 108 | version: "9.0.16" 109 | leak_tracker_testing: 110 | dependency: transitive 111 | description: 112 | name: leak_tracker_testing 113 | sha256: b06739349ec2477e943055aea30172c5c7000225f79dad4702e2ec0eda79a6ff 114 | url: "https://pub.dev" 115 | source: hosted 116 | version: "1.0.5" 117 | lints: 118 | dependency: transitive 119 | description: 120 | name: lints 121 | sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 122 | url: "https://pub.dev" 123 | source: hosted 124 | version: "3.0.0" 125 | matcher: 126 | dependency: transitive 127 | description: 128 | name: matcher 129 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" 130 | url: "https://pub.dev" 131 | source: hosted 132 | version: "0.12.16" 133 | material_color_utilities: 134 | dependency: transitive 135 | description: 136 | name: material_color_utilities 137 | sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" 138 | url: "https://pub.dev" 139 | source: hosted 140 | version: "0.8.0" 141 | meta: 142 | dependency: transitive 143 | description: 144 | name: meta 145 | sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 146 | url: "https://pub.dev" 147 | source: hosted 148 | version: "1.11.0" 149 | path: 150 | dependency: transitive 151 | description: 152 | name: path 153 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 154 | url: "https://pub.dev" 155 | source: hosted 156 | version: "1.8.3" 157 | platform: 158 | dependency: transitive 159 | description: 160 | name: platform 161 | sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" 162 | url: "https://pub.dev" 163 | source: hosted 164 | version: "3.1.3" 165 | plugin_platform_interface: 166 | dependency: transitive 167 | description: 168 | name: plugin_platform_interface 169 | sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 170 | url: "https://pub.dev" 171 | source: hosted 172 | version: "2.1.7" 173 | process: 174 | dependency: transitive 175 | description: 176 | name: process 177 | sha256: "266ca5be5820feefc777793d0a583acfc8c40834893c87c00c6c09e2cf58ea42" 178 | url: "https://pub.dev" 179 | source: hosted 180 | version: "5.0.1" 181 | sky_engine: 182 | dependency: transitive 183 | description: flutter 184 | source: sdk 185 | version: "0.0.99" 186 | source_span: 187 | dependency: transitive 188 | description: 189 | name: source_span 190 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 191 | url: "https://pub.dev" 192 | source: hosted 193 | version: "1.10.0" 194 | stack_trace: 195 | dependency: transitive 196 | description: 197 | name: stack_trace 198 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 199 | url: "https://pub.dev" 200 | source: hosted 201 | version: "1.11.1" 202 | stream_channel: 203 | dependency: transitive 204 | description: 205 | name: stream_channel 206 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 207 | url: "https://pub.dev" 208 | source: hosted 209 | version: "2.1.2" 210 | string_scanner: 211 | dependency: transitive 212 | description: 213 | name: string_scanner 214 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 215 | url: "https://pub.dev" 216 | source: hosted 217 | version: "1.2.0" 218 | sync_http: 219 | dependency: transitive 220 | description: 221 | name: sync_http 222 | sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" 223 | url: "https://pub.dev" 224 | source: hosted 225 | version: "0.3.1" 226 | term_glyph: 227 | dependency: transitive 228 | description: 229 | name: term_glyph 230 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 231 | url: "https://pub.dev" 232 | source: hosted 233 | version: "1.2.1" 234 | test_api: 235 | dependency: transitive 236 | description: 237 | name: test_api 238 | sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" 239 | url: "https://pub.dev" 240 | source: hosted 241 | version: "0.6.1" 242 | vector_math: 243 | dependency: transitive 244 | description: 245 | name: vector_math 246 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 247 | url: "https://pub.dev" 248 | source: hosted 249 | version: "2.1.4" 250 | vm_service: 251 | dependency: transitive 252 | description: 253 | name: vm_service 254 | sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 255 | url: "https://pub.dev" 256 | source: hosted 257 | version: "13.0.0" 258 | wayland_layer_shell: 259 | dependency: "direct main" 260 | description: 261 | path: ".." 262 | relative: true 263 | source: path 264 | version: "0.0.1" 265 | web: 266 | dependency: transitive 267 | description: 268 | name: web 269 | sha256: edc8a9573dd8c5a83a183dae1af2b6fd4131377404706ca4e5420474784906fa 270 | url: "https://pub.dev" 271 | source: hosted 272 | version: "0.4.0" 273 | webdriver: 274 | dependency: transitive 275 | description: 276 | name: webdriver 277 | sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" 278 | url: "https://pub.dev" 279 | source: hosted 280 | version: "3.0.3" 281 | sdks: 282 | dart: ">=3.3.0-170.0.dev <4.0.0" 283 | flutter: ">=3.3.0" 284 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: wayland_layer_shell_example 2 | description: "Demonstrates how to use the wayland_layer_shell plugin." 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 | environment: 8 | sdk: '>=3.3.0-170.0.dev <4.0.0' 9 | 10 | # Dependencies specify other packages that your package needs in order to work. 11 | # To automatically upgrade your package dependencies to the latest versions 12 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 13 | # dependencies can be manually updated by changing the version numbers below to 14 | # the latest version available on pub.dev. To see which dependencies have newer 15 | # versions available, run `flutter pub outdated`. 16 | dependencies: 17 | flutter: 18 | sdk: flutter 19 | 20 | wayland_layer_shell: 21 | # When depending on this package from a real application you should use: 22 | # wayland_layer_shell: ^x.y.z 23 | # See https://dart.dev/tools/pub/dependencies#version-constraints 24 | # The example app is bundled with the plugin so we use a path dependency on 25 | # the parent directory to use the current plugin's version. 26 | path: ../ 27 | 28 | # The following adds the Cupertino Icons font to your application. 29 | # Use with the CupertinoIcons class for iOS style icons. 30 | cupertino_icons: ^1.0.6 31 | 32 | dev_dependencies: 33 | integration_test: 34 | sdk: flutter 35 | flutter_test: 36 | sdk: flutter 37 | 38 | # The "flutter_lints" package below contains a set of recommended lints to 39 | # encourage good coding practices. The lint set provided by the package is 40 | # activated in the `analysis_options.yaml` file located at the root of your 41 | # package. See that file for information about deactivating specific lint 42 | # rules and activating additional ones. 43 | flutter_lints: ^3.0.0 44 | 45 | # For information on the generic Dart part of this file, see the 46 | # following page: https://dart.dev/tools/pub/pubspec 47 | 48 | # The following section is specific to Flutter packages. 49 | flutter: 50 | 51 | # The following line ensures that the Material Icons font is 52 | # included with your application, so that you can use the icons in 53 | # the material Icons class. 54 | uses-material-design: true 55 | 56 | # To add assets to your application, add an assets section, like this: 57 | # assets: 58 | # - images/a_dot_burr.jpeg 59 | # - images/a_dot_ham.jpeg 60 | 61 | # An image asset can refer to one or more resolution-specific "variants", see 62 | # https://flutter.dev/assets-and-images/#resolution-aware 63 | 64 | # For details regarding adding assets from package dependencies, see 65 | # https://flutter.dev/assets-and-images/#from-packages 66 | 67 | # To add custom fonts to your application, add a fonts section here, 68 | # in this "flutter" section. Each entry in this list should have a 69 | # "family" key with the font family name, and a "fonts" key with a 70 | # list giving the asset and other descriptors for the font. For 71 | # example: 72 | # fonts: 73 | # - family: Schyler 74 | # fonts: 75 | # - asset: fonts/Schyler-Regular.ttf 76 | # - asset: fonts/Schyler-Italic.ttf 77 | # style: italic 78 | # - family: Trajan Pro 79 | # fonts: 80 | # - asset: fonts/TrajanPro.ttf 81 | # - asset: fonts/TrajanPro_Bold.ttf 82 | # weight: 700 83 | # 84 | # For details regarding fonts from package dependencies, 85 | # see https://flutter.dev/custom-fonts/#from-packages 86 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:wayland_layer_shell_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => widget is Text && 22 | widget.data!.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /lib/types.dart: -------------------------------------------------------------------------------- 1 | enum ShellLayer { 2 | layerBackground, // The background layer. 3 | layerBottom, // The bottom layer. 4 | layerTop, // The top layer. 5 | layerOverlay, // The overlay layer. 6 | layerEntryNumber, // Should not be used except to get the number of entries. (NOTE: may change in 7 | } 8 | 9 | enum ShellEdge { 10 | edgeLeft, // The left edge of the screen. 11 | edgeRight, // The right edge of the screen. 12 | edgeTop, // The top edge of the screen. 13 | edgeBottom, // The bottom edge of the screen. 14 | edgeEntryNumber // Should not be used except to get the number of entries. (NOTE: may change in 15 | } 16 | 17 | enum ShellKeyboardMode { 18 | keyboardModeNone, // This window should not receive keyboard events. 19 | keyboardModeExclusive, // This window should have exclusive focus if it is on the top or overlay layer. 20 | keyboardModeOnDemand, // The user should be able to focus and unfocues this window in an implementation defined way. 21 | keyboardModeEntryNumber, // Should not be used except to get the number of entries. 22 | } 23 | 24 | class Monitor { 25 | final int id; 26 | final String name; 27 | 28 | Monitor(this.id, this.name); 29 | 30 | @override 31 | String toString() { 32 | return '$id: $name'; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/wayland_layer_shell.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:wayland_layer_shell/types.dart'; 3 | 4 | class WaylandLayerShell { 5 | final methodChannel = const MethodChannel('wayland_layer_shell'); 6 | 7 | Future getPlatformVersion() async { 8 | final version = 9 | await methodChannel.invokeMethod('getPlatformVersion'); 10 | return version; 11 | } 12 | 13 | /// Returns: 'true' if the platform is Wayland and Wayland compositor supports the 14 | /// zwlr_layer_shell_v1 protocol. If not supported, returns 'false' and initialize 15 | /// gtk window as normal window 16 | Future isLayerShellSupported() async { 17 | return await methodChannel.invokeMethod('isSupported'); 18 | } 19 | 20 | /// @width: The width of the surface. default is 1280 21 | /// @height: The height of the surface. default is 720 22 | /// 23 | /// Initialize the layer shell protocol. 24 | /// checks if the platform is Wayland and Wayland compositor supports the 25 | /// zwlr_layer_shell_v1 protocol so no need use isLayerShellSupported first. 26 | /// 27 | /// Returns: 'true' if platform is Wayland and Wayland compositor supports 28 | /// the zwlr_layer_shell_v1 protocol, if not supported, returns 'false' and initialize 29 | /// gtk window as normal window 30 | Future initialize([int? width, int? height]) async { 31 | final Map arguments = { 32 | 'width': width ?? 1280, 33 | 'height': height ?? 720, 34 | }; 35 | return await methodChannel.invokeMethod('initialize', arguments); 36 | } 37 | 38 | /// @layer: The [ShellLayer] on which this surface appears. 39 | /// 40 | /// Set the "layer" on which the surface appears (controls if it is over top of or below other surfaces). The layer may 41 | /// be changed on-the-fly in the current version of the layer shell protocol, but on compositors that only support an 42 | /// older version the @window is remapped so the change can take effect. 43 | /// 44 | /// Default is %GTK_LAYER_SHELL_LAYER_TOP 45 | Future setLayer(ShellLayer layer) async { 46 | final Map arguments = { 47 | 'layer': layer.index, 48 | }; 49 | await methodChannel.invokeMethod('setLayer', arguments); 50 | } 51 | 52 | /// Returns: the current layer as [ShellLayer]. 53 | Future getLayer() async { 54 | return ShellLayer 55 | .values[(await methodChannel.invokeMethod('getLayer')) as int]; 56 | } 57 | 58 | /// Returns: the list of all [Monitor]s connected to the computer. 59 | Future> getMonitorList() async { 60 | List monitors = 61 | List.from(await methodChannel.invokeMethod('getMonitorList')); 62 | return monitors.map((e) { 63 | final i = e.indexOf(':'); 64 | return Monitor(int.parse(e.substring(0, i)), e.substring(i + 1)); 65 | }).toList(); 66 | } 67 | 68 | /// @monitor: The [Monitor] that this surface will be placed on. 69 | /// (null to let the compositor decide) 70 | /// 71 | /// Set the monitor this surface will be placed on. 72 | Future setMonitor(Monitor? monitor) async { 73 | final Map arguments = { 74 | 'id': monitor == null ? -1 : monitor.id, 75 | }; 76 | await methodChannel.invokeMethod('setMonitor', arguments); 77 | } 78 | 79 | /// @edge: A [ShellEdge] this layer surface may be anchored to. 80 | /// @anchor_to_edge: Whether or not to anchor this layer surface to @edge. 81 | /// 82 | /// Set whether this layer surface should be anchored to @edge. 83 | /// - If two perpendicular edges are anchored, the surface with be anchored to that corner 84 | /// - If two opposite edges are anchored, the window will be stretched across the screen in that direction 85 | /// 86 | /// Default is %FALSE for each [ShellEdge] 87 | Future setAnchor(ShellEdge edge, bool anchorToEdge) async { 88 | final Map arguments = { 89 | 'edge': edge.index, 90 | 'anchor_to_edge': anchorToEdge 91 | }; 92 | await methodChannel.invokeMethod('setAnchor', arguments); 93 | } 94 | 95 | /// @edge: A [ShellEdge] this layer surface may be anchored to. 96 | /// 97 | /// Returns: if this surface is anchored to the given edge. 98 | Future getAnchor(ShellEdge edge) async { 99 | final Map arguments = { 100 | 'edge': edge.index, 101 | }; 102 | return await methodChannel.invokeMethod('getAnchor', arguments); 103 | } 104 | 105 | /// @edge: The [ShellEdge] for which to set the margin. 106 | /// @marginSize: The margin for @edge to be set. 107 | /// 108 | /// Set the margin for a specific @edge of a @window. Effects both surface's distance from 109 | /// the edge and its exclusive zone size (if auto exclusive zone enabled). 110 | /// 111 | /// Default is 0 for each [ShellEdge] 112 | Future setMargin(ShellEdge edge, int marginSize) async { 113 | final Map arguments = { 114 | 'edge': edge.index, 115 | 'margin_size': marginSize 116 | }; 117 | await methodChannel.invokeMethod('setMargin', arguments); 118 | } 119 | 120 | /// @edge: The [ShellEdge] for which to get the margin. 121 | /// 122 | /// Returns: the size of the margin for the given edge. 123 | Future getMargin(ShellEdge edge) async { 124 | final Map arguments = { 125 | 'edge': edge.index, 126 | }; 127 | return await methodChannel.invokeMethod('getMargin', arguments); 128 | } 129 | 130 | /// @exclusiveZone: The size of the exclusive zone. 131 | /// 132 | /// Set the size of the exclusive zone. 133 | /// 134 | /// Has no effect unless the surface is anchored to an edge. Requests that the compositor 135 | /// does not place other surfaces within the given exclusive zone of the anchored edge. 136 | /// For example, a panel can request to not be covered by maximized windows. See 137 | /// wlr-layer-shell-unstable-v1.xml for details. 138 | /// 139 | /// Default is 0 140 | Future setExclusiveZone(int exclusiveZone) async { 141 | final Map arguments = {'exclusive_zone': exclusiveZone}; 142 | await methodChannel.invokeMethod('setExclusiveZone', arguments); 143 | } 144 | 145 | /// Returns: the window's exclusive zone (which may have been set manually or automatically) 146 | Future getExclusiveZone() async { 147 | return await methodChannel.invokeMethod('getExclusiveZone'); 148 | } 149 | 150 | /// Enable auto exclusive zone 151 | /// 152 | /// When auto exclusive zone is enabled, exclusive zone is automatically set to the 153 | /// size of the @window + relevant margin. To disable auto exclusive zone, just set the 154 | /// exclusive zone to 0 or any other fixed value. 155 | Future enableAutoExclusiveZone() async { 156 | await methodChannel.invokeMethod('enableAutoExclusiveZone'); 157 | } 158 | 159 | /// Returns: if the surface's exclusive zone is set to change based on the window's size 160 | Future isAutoExclusiveZoneEnabled() async { 161 | return await methodChannel.invokeMethod('isAutoExclusiveZoneEnabled'); 162 | } 163 | 164 | /// @mode: The type of keyboard interactivity requested. 165 | /// 166 | /// Sets if/when @window should receive keyboard events from the compositor, see 167 | /// [ShellKeyboardMode] for details. 168 | /// 169 | /// Default is [ShellKeyboardMode.keyboardModeNone] 170 | Future setKeyboardMode(ShellKeyboardMode mode) async { 171 | final Map arguments = {'keyboard_mode': mode.index}; 172 | await methodChannel.invokeMethod('setKeyboardMode', arguments); 173 | } 174 | 175 | /// Returns: current keyboard interactivity mode for window 176 | Future getKeyboardMode() async { 177 | return ShellKeyboardMode 178 | .values[(await methodChannel.invokeMethod('getKeyboardMode')) as int]; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The Flutter tooling requires that developers have CMake 3.10 or later 2 | # installed. You should not increase this version, as doing so will cause 3 | # the plugin to fail to compile for some customers of the plugin. 4 | cmake_minimum_required(VERSION 3.10) 5 | 6 | # Project-level configuration. 7 | set(PROJECT_NAME "wayland_layer_shell") 8 | project(${PROJECT_NAME} LANGUAGES CXX) 9 | 10 | 11 | cmake_policy(SET CMP0079 NEW) 12 | 13 | # This value is used when generating builds using this plugin, so it must 14 | # not be changed. 15 | set(PLUGIN_NAME "wayland_layer_shell_plugin") 16 | 17 | # Any new source files that you add to the plugin should be added here. 18 | list(APPEND PLUGIN_SOURCES 19 | "wayland_layer_shell_plugin.cc" 20 | ) 21 | 22 | # Define the plugin library target. Its name must not be changed (see comment 23 | # on PLUGIN_NAME above). 24 | add_library(${PLUGIN_NAME} SHARED 25 | ${PLUGIN_SOURCES} 26 | ) 27 | 28 | # Apply a standard set of build settings that are configured in the 29 | # application-level CMakeLists.txt. This can be removed for plugins that want 30 | # full control over build settings. 31 | apply_standard_settings(${PLUGIN_NAME}) 32 | 33 | # Symbols are hidden by default to reduce the chance of accidental conflicts 34 | # between plugins. This should not be removed; any symbols that should be 35 | # exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. 36 | set_target_properties(${PLUGIN_NAME} PROPERTIES 37 | CXX_VISIBILITY_PRESET hidden) 38 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 39 | 40 | 41 | pkg_check_modules(GTKLAYERSHELL REQUIRED IMPORTED_TARGET gtk-layer-shell-0) 42 | 43 | # Source include directories and library dependencies. Add any plugin-specific 44 | # dependencies here. 45 | target_include_directories(${PLUGIN_NAME} INTERFACE 46 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 47 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) 48 | target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) 49 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTKLAYERSHELL) 50 | 51 | # List of absolute paths to libraries that should be bundled with the plugin. 52 | # This list could contain prebuilt libraries, or libraries created by an 53 | # external build triggered from this build file. 54 | set(wayland_layer_shell_bundled_libraries 55 | "" 56 | PARENT_SCOPE 57 | ) 58 | 59 | # # === Tests === 60 | # # These unit tests can be run from a terminal after building the example. 61 | 62 | # # Only enable test builds when building the example (which sets this variable) 63 | # # so that plugin clients aren't building the tests. 64 | # if (${include_${PROJECT_NAME}_tests}) 65 | # if(${CMAKE_VERSION} VERSION_LESS "3.11.0") 66 | # message("Unit tests require CMake 3.11.0 or later") 67 | # else() 68 | # set(TEST_RUNNER "${PROJECT_NAME}_test") 69 | # enable_testing() 70 | 71 | # # Add the Google Test dependency. 72 | # include(FetchContent) 73 | # FetchContent_Declare( 74 | # googletest 75 | # URL https://github.com/google/googletest/archive/release-1.11.0.zip 76 | # ) 77 | # # Prevent overriding the parent project's compiler/linker settings 78 | # set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 79 | # # Disable install commands for gtest so it doesn't end up in the bundle. 80 | # set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) 81 | 82 | # FetchContent_MakeAvailable(googletest) 83 | 84 | # # The plugin's exported API is not very useful for unit testing, so build the 85 | # # sources directly into the test binary rather than using the shared library. 86 | # add_executable(${TEST_RUNNER} 87 | # test/wayland_layer_shell_plugin_test.cc 88 | # ${PLUGIN_SOURCES} 89 | # ) 90 | # apply_standard_settings(${TEST_RUNNER}) 91 | # target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") 92 | # target_link_libraries(${TEST_RUNNER} PRIVATE flutter) 93 | # target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::GTK) 94 | # target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) 95 | 96 | # # Enable automatic test discovery. 97 | # include(GoogleTest) 98 | # gtest_discover_tests(${TEST_RUNNER}) 99 | 100 | # endif() # CMake version check 101 | # endif() # include_${PROJECT_NAME}_tests -------------------------------------------------------------------------------- /linux/include/wayland_layer_shell/wayland_layer_shell_plugin.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_PLUGIN_WAYLAND_LAYER_SHELL_PLUGIN_H_ 2 | #define FLUTTER_PLUGIN_WAYLAND_LAYER_SHELL_PLUGIN_H_ 3 | 4 | #include 5 | 6 | G_BEGIN_DECLS 7 | 8 | #ifdef FLUTTER_PLUGIN_IMPL 9 | #define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) 10 | #else 11 | #define FLUTTER_PLUGIN_EXPORT 12 | #endif 13 | 14 | typedef struct _WaylandLayerShellPlugin WaylandLayerShellPlugin; 15 | typedef struct { 16 | GObjectClass parent_class; 17 | } WaylandLayerShellPluginClass; 18 | 19 | FLUTTER_PLUGIN_EXPORT GType wayland_layer_shell_plugin_get_type(); 20 | 21 | FLUTTER_PLUGIN_EXPORT void wayland_layer_shell_plugin_register_with_registrar( 22 | FlPluginRegistrar* registrar); 23 | 24 | G_END_DECLS 25 | 26 | #endif // FLUTTER_PLUGIN_WAYLAND_LAYER_SHELL_PLUGIN_H_ 27 | -------------------------------------------------------------------------------- /linux/test/wayland_layer_shell_plugin_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "include/wayland_layer_shell/wayland_layer_shell_plugin.h" 6 | #include "wayland_layer_shell_plugin_private.h" 7 | 8 | // This demonstrates a simple unit test of the C portion of this plugin's 9 | // implementation. 10 | // 11 | // Once you have built the plugin's example app, you can run these tests 12 | // from the command line. For instance, for a plugin called my_plugin 13 | // built for x64 debug, run: 14 | // $ build/linux/x64/debug/plugins/my_plugin/my_plugin_test 15 | 16 | namespace wayland_layer_shell { 17 | namespace test { 18 | 19 | TEST(WaylandLayerShellPlugin, GetPlatformVersion) { 20 | g_autoptr(FlMethodResponse) response = get_platform_version(); 21 | ASSERT_NE(response, nullptr); 22 | ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); 23 | FlValue* result = fl_method_success_response_get_result( 24 | FL_METHOD_SUCCESS_RESPONSE(response)); 25 | ASSERT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING); 26 | // The full string varies, so just validate that it has the right format. 27 | EXPECT_THAT(fl_value_get_string(result), testing::StartsWith("Linux ")); 28 | } 29 | 30 | } // namespace test 31 | } // namespace wayland_layer_shell 32 | -------------------------------------------------------------------------------- /linux/wayland_layer_shell_plugin.cc: -------------------------------------------------------------------------------- 1 | #include "include/wayland_layer_shell/wayland_layer_shell_plugin.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "wayland_layer_shell_plugin_private.h" 10 | 11 | #include 12 | #include "iostream" 13 | 14 | #define WAYLAND_LAYER_SHELL_PLUGIN(obj) \ 15 | (G_TYPE_CHECK_INSTANCE_CAST((obj), wayland_layer_shell_plugin_get_type(), \ 16 | WaylandLayerShellPlugin)) 17 | 18 | struct _WaylandLayerShellPlugin 19 | { 20 | GObject parent_instance; 21 | FlPluginRegistrar *registrar; 22 | }; 23 | 24 | G_DEFINE_TYPE(WaylandLayerShellPlugin, wayland_layer_shell_plugin, g_object_get_type()) 25 | 26 | GtkWindow *get_window(WaylandLayerShellPlugin *self) 27 | { 28 | FlView *view = fl_plugin_registrar_get_view(self->registrar); 29 | if (view == nullptr) 30 | return nullptr; 31 | 32 | return GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); 33 | } 34 | 35 | static FlMethodResponse *is_supported(WaylandLayerShellPlugin *self) 36 | { 37 | if (gtk_layer_is_supported() == 0) 38 | { 39 | GtkWindow *gtk_window = get_window(self); 40 | gtk_widget_show(GTK_WIDGET(gtk_window)); 41 | } 42 | g_autoptr(FlValue) result = 43 | fl_value_new_bool(gtk_layer_is_supported()); 44 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 45 | } 46 | 47 | static FlMethodResponse *initialize(WaylandLayerShellPlugin *self, FlValue *args) 48 | { 49 | g_autoptr(FlValue) result; 50 | GtkWindow *gtk_window = get_window(self); 51 | if (gtk_layer_is_supported() == 0) 52 | { 53 | result = fl_value_new_bool(false); 54 | } 55 | else 56 | { 57 | int width = fl_value_get_int(fl_value_lookup_string(args, "width")); 58 | int height = fl_value_get_int(fl_value_lookup_string(args, "height")); 59 | gtk_widget_set_size_request(GTK_WIDGET(gtk_window), width, height); 60 | gtk_layer_init_for_window(gtk_window); 61 | result = fl_value_new_bool(true); 62 | } 63 | 64 | gtk_widget_show(GTK_WIDGET(gtk_window)); 65 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 66 | } 67 | 68 | static FlMethodResponse *set_layer(WaylandLayerShellPlugin *self, FlValue *args) 69 | { 70 | int layer = fl_value_get_int(fl_value_lookup_string(args, "layer")); 71 | gtk_layer_set_layer(get_window(self), static_cast(layer)); 72 | g_autoptr(FlValue) result = fl_value_new_bool(true); 73 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 74 | } 75 | 76 | static FlMethodResponse *get_layer(WaylandLayerShellPlugin *self) 77 | { 78 | g_autoptr(FlValue) result = fl_value_new_int(gtk_layer_get_layer(get_window(self))); 79 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 80 | } 81 | 82 | static FlMethodResponse *get_monitor_list(WaylandLayerShellPlugin *self) 83 | { 84 | GdkDisplay *display = gdk_display_get_default(); 85 | g_autoptr(FlValue) result = fl_value_new_list(); 86 | for (int i = 0; i < gdk_display_get_n_monitors(display); i++) 87 | { 88 | GdkMonitor *monitor = gdk_display_get_monitor(display, i); 89 | gchar *val = g_strdup_printf("%i:%s", i, gdk_monitor_get_model(monitor)); 90 | fl_value_append_take(result, fl_value_new_string(val)); 91 | } 92 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 93 | } 94 | 95 | static FlMethodResponse *set_monitor(WaylandLayerShellPlugin *self, FlValue *args) 96 | { 97 | GdkDisplay *display = gdk_display_get_default(); 98 | int id = fl_value_get_int(fl_value_lookup_string(args, "id")); 99 | 100 | if (id == -1) 101 | { 102 | gtk_layer_set_monitor(get_window(self), NULL); 103 | 104 | g_autoptr(FlValue) result = fl_value_new_bool(true); 105 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 106 | } 107 | 108 | GdkMonitor *monitor = gdk_display_get_monitor(display, id); 109 | gtk_layer_set_monitor(get_window(self), monitor); 110 | 111 | g_autoptr(FlValue) result = fl_value_new_bool(true); 112 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 113 | } 114 | 115 | static FlMethodResponse *set_anchor(WaylandLayerShellPlugin *self, FlValue *args) 116 | { 117 | int edge = fl_value_get_int(fl_value_lookup_string(args, "edge")); 118 | gboolean anchor_to_edge = fl_value_get_bool(fl_value_lookup_string(args, "anchor_to_edge")); 119 | 120 | gtk_layer_set_anchor(get_window(self), static_cast(edge), anchor_to_edge); 121 | g_autoptr(FlValue) result = fl_value_new_bool(true); 122 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 123 | } 124 | 125 | static FlMethodResponse *get_anchor(WaylandLayerShellPlugin *self, FlValue *args) 126 | { 127 | int edge = fl_value_get_int(fl_value_lookup_string(args, "edge")); 128 | g_autoptr(FlValue) result = fl_value_new_bool(gtk_layer_get_anchor(get_window(self), static_cast(edge))); 129 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 130 | } 131 | 132 | static FlMethodResponse *set_margin(WaylandLayerShellPlugin *self, FlValue *args) 133 | { 134 | int edge = fl_value_get_int(fl_value_lookup_string(args, "edge")); 135 | int margin_size = fl_value_get_int(fl_value_lookup_string(args, "margin_size")); 136 | 137 | gtk_layer_set_margin(get_window(self), static_cast(edge), margin_size); 138 | g_autoptr(FlValue) result = fl_value_new_bool(true); 139 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 140 | } 141 | 142 | static FlMethodResponse *get_margin(WaylandLayerShellPlugin *self, FlValue *args) 143 | { 144 | int edge = fl_value_get_int(fl_value_lookup_string(args, "edge")); 145 | g_autoptr(FlValue) result = fl_value_new_int(gtk_layer_get_margin(get_window(self), static_cast(edge))); 146 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 147 | } 148 | 149 | static FlMethodResponse *set_exclusive_zone(WaylandLayerShellPlugin *self, FlValue *args) 150 | { 151 | int exclusive_zone = fl_value_get_int(fl_value_lookup_string(args, "exclusive_zone")); 152 | gtk_layer_set_exclusive_zone(get_window(self), exclusive_zone); 153 | g_autoptr(FlValue) result = fl_value_new_bool(true); 154 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 155 | } 156 | 157 | static FlMethodResponse *get_exclusive_zone(WaylandLayerShellPlugin *self) 158 | { 159 | g_autoptr(FlValue) result = fl_value_new_int(gtk_layer_get_exclusive_zone(get_window(self))); 160 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 161 | } 162 | 163 | static FlMethodResponse *enable_auto_exclusive_zone(WaylandLayerShellPlugin *self) 164 | { 165 | gtk_layer_auto_exclusive_zone_enable(get_window(self)); 166 | g_autoptr(FlValue) result = fl_value_new_bool(true); 167 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 168 | } 169 | 170 | static FlMethodResponse *is_auto_exclusive_zone_enabled(WaylandLayerShellPlugin *self) 171 | { 172 | g_autoptr(FlValue) result = fl_value_new_bool(gtk_layer_auto_exclusive_zone_is_enabled(get_window(self))); 173 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 174 | } 175 | 176 | static FlMethodResponse *set_keyboard_mode(WaylandLayerShellPlugin *self, FlValue *args) 177 | { 178 | int keyboard_mode = fl_value_get_int(fl_value_lookup_string(args, "keyboard_mode")); 179 | gtk_layer_set_keyboard_mode(get_window(self), static_cast(keyboard_mode)); 180 | g_autoptr(FlValue) result = fl_value_new_bool(true); 181 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 182 | } 183 | 184 | static FlMethodResponse *get_keyboard_mode(WaylandLayerShellPlugin *self) 185 | { 186 | g_autoptr(FlValue) result = fl_value_new_int(gtk_layer_get_keyboard_mode(get_window(self))); 187 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 188 | } 189 | 190 | // Called when a method call is received from Flutter. 191 | static void wayland_layer_shell_plugin_handle_method_call( 192 | WaylandLayerShellPlugin *self, 193 | FlMethodCall *method_call) 194 | { 195 | g_autoptr(FlMethodResponse) response = nullptr; 196 | 197 | const gchar *method = fl_method_call_get_name(method_call); 198 | FlValue *args = fl_method_call_get_args(method_call); 199 | 200 | if (strcmp(method, "getPlatformVersion") == 0) 201 | { 202 | response = get_platform_version(); 203 | } 204 | else if (strcmp(method, "isSupported") == 0) 205 | { 206 | response = is_supported(self); 207 | } 208 | else if (strcmp(method, "initialize") == 0) 209 | { 210 | response = initialize(self, args); 211 | } 212 | else if (strcmp(method, "setLayer") == 0) 213 | { 214 | response = set_layer(self, args); 215 | } 216 | else if (strcmp(method, "getLayer") == 0) 217 | { 218 | response = get_layer(self); 219 | } 220 | else if (strcmp(method, "getMonitorList") == 0) 221 | { 222 | response = get_monitor_list(self); 223 | } 224 | else if (strcmp(method, "setMonitor") == 0) 225 | { 226 | response = set_monitor(self, args); 227 | } 228 | else if (strcmp(method, "setAnchor") == 0) 229 | { 230 | response = set_anchor(self, args); 231 | } 232 | else if (strcmp(method, "getAnchor") == 0) 233 | { 234 | response = get_anchor(self, args); 235 | } 236 | else if (strcmp(method, "setMargin") == 0) 237 | { 238 | response = set_margin(self, args); 239 | } 240 | else if (strcmp(method, "getMargin") == 0) 241 | { 242 | response = get_margin(self, args); 243 | } 244 | else if (strcmp(method, "setExclusiveZone") == 0) 245 | { 246 | response = set_exclusive_zone(self, args); 247 | } 248 | else if (strcmp(method, "getExclusiveZone") == 0) 249 | { 250 | response = get_exclusive_zone(self); 251 | } 252 | else if (strcmp(method, "enableAutoExclusiveZone") == 0) 253 | { 254 | response = enable_auto_exclusive_zone(self); 255 | } 256 | else if (strcmp(method, "isAutoExclusiveZoneEnabled") == 0) 257 | { 258 | response = is_auto_exclusive_zone_enabled(self); 259 | } 260 | else if (strcmp(method, "setKeyboardMode") == 0) 261 | { 262 | response = set_keyboard_mode(self, args); 263 | } 264 | else if (strcmp(method, "getKeyboardMode") == 0) 265 | { 266 | response = get_keyboard_mode(self); 267 | } 268 | else 269 | { 270 | response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); 271 | } 272 | 273 | fl_method_call_respond(method_call, response, nullptr); 274 | } 275 | 276 | FlMethodResponse *get_platform_version() 277 | { 278 | struct utsname uname_data = {}; 279 | uname(&uname_data); 280 | g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version); 281 | g_autoptr(FlValue) result = fl_value_new_string(version); 282 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 283 | } 284 | 285 | static void wayland_layer_shell_plugin_dispose(GObject *object) 286 | { 287 | G_OBJECT_CLASS(wayland_layer_shell_plugin_parent_class)->dispose(object); 288 | } 289 | 290 | static void wayland_layer_shell_plugin_class_init(WaylandLayerShellPluginClass *klass) 291 | { 292 | G_OBJECT_CLASS(klass)->dispose = wayland_layer_shell_plugin_dispose; 293 | } 294 | 295 | static void wayland_layer_shell_plugin_init(WaylandLayerShellPlugin *self) {} 296 | 297 | static void method_call_cb(FlMethodChannel *channel, FlMethodCall *method_call, 298 | gpointer user_data) 299 | { 300 | WaylandLayerShellPlugin *plugin = WAYLAND_LAYER_SHELL_PLUGIN(user_data); 301 | wayland_layer_shell_plugin_handle_method_call(plugin, method_call); 302 | } 303 | 304 | void wayland_layer_shell_plugin_register_with_registrar(FlPluginRegistrar *registrar) 305 | { 306 | WaylandLayerShellPlugin *plugin = WAYLAND_LAYER_SHELL_PLUGIN( 307 | g_object_new(wayland_layer_shell_plugin_get_type(), nullptr)); 308 | 309 | plugin->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar)); 310 | 311 | g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); 312 | g_autoptr(FlMethodChannel) channel = 313 | fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), 314 | "wayland_layer_shell", 315 | FL_METHOD_CODEC(codec)); 316 | fl_method_channel_set_method_call_handler(channel, method_call_cb, 317 | g_object_ref(plugin), 318 | g_object_unref); 319 | 320 | g_object_unref(plugin); 321 | } 322 | -------------------------------------------------------------------------------- /linux/wayland_layer_shell_plugin_private.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "include/wayland_layer_shell/wayland_layer_shell_plugin.h" 4 | 5 | // This file exposes some plugin internals for unit testing. See 6 | // https://github.com/flutter/flutter/issues/88724 for current limitations 7 | // in the unit-testable API. 8 | 9 | // Handles the getPlatformVersion method call. 10 | FlMethodResponse *get_platform_version(); 11 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: wayland_layer_shell 2 | description: "A flutter plugin to create desktop components for Wayland using the Layer Shell protocol" 3 | version: 1.0.1 4 | homepage: https://github.com/Mr-1311/wayland_layer_shell 5 | repository: https://github.com/Mr-1311/wayland_layer_shell 6 | 7 | platforms: 8 | linux: 9 | 10 | topics: 11 | - window 12 | - linux 13 | - wayland 14 | - layer-shell 15 | 16 | environment: 17 | sdk: '>=3.0.0 <4.0.0' 18 | flutter: '>=3.3.0' 19 | 20 | dependencies: 21 | flutter: 22 | sdk: flutter 23 | plugin_platform_interface: ^2.0.2 24 | 25 | dev_dependencies: 26 | flutter_test: 27 | sdk: flutter 28 | flutter_lints: ^3.0.0 29 | 30 | flutter: 31 | plugin: 32 | platforms: 33 | linux: 34 | pluginClass: WaylandLayerShellPlugin 35 | --------------------------------------------------------------------------------