Repository: google/flutter-desktop-embedding Branch: main Commit: eb3964990cf1 Files: 157 Total size: 392.6 KB Directory structure: gitextract_q9j640lx/ ├── .clang-format ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── BUG-REPORT.yml │ │ ├── OTHER.yml │ │ └── config.yml │ └── workflows/ │ ├── ci.yml │ └── lock.yaml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── macOS-Security.md └── plugins/ ├── .gitignore ├── README.md ├── menubar/ │ ├── .gitignore │ ├── .metadata │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── example/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── integration_test/ │ │ │ └── plugin_integration_test.dart │ │ ├── lib/ │ │ │ └── main.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 │ │ ├── macos/ │ │ │ ├── .gitignore │ │ │ ├── Podfile │ │ │ ├── Runner/ │ │ │ │ ├── AppDelegate.swift │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ └── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Base.lproj/ │ │ │ │ │ └── MainMenu.xib │ │ │ │ ├── Configs/ │ │ │ │ │ ├── AppInfo.xcconfig │ │ │ │ │ ├── Debug.xcconfig │ │ │ │ │ ├── Release.xcconfig │ │ │ │ │ └── Warnings.xcconfig │ │ │ │ ├── DebugProfile.entitlements │ │ │ │ ├── Info.plist │ │ │ │ ├── MainFlutterWindow.swift │ │ │ │ └── Release.entitlements │ │ │ ├── Runner.xcodeproj/ │ │ │ │ ├── project.pbxproj │ │ │ │ ├── project.xcworkspace/ │ │ │ │ │ └── xcshareddata/ │ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ │ └── xcshareddata/ │ │ │ │ └── xcschemes/ │ │ │ │ └── Runner.xcscheme │ │ │ ├── Runner.xcworkspace/ │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata/ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── RunnerTests/ │ │ │ └── RunnerTests.swift │ │ ├── pubspec.yaml │ │ └── windows/ │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── flutter/ │ │ │ ├── CMakeLists.txt │ │ │ ├── generated_plugin_registrant.cc │ │ │ ├── generated_plugin_registrant.h │ │ │ └── generated_plugins.cmake │ │ └── runner/ │ │ ├── CMakeLists.txt │ │ ├── Runner.rc │ │ ├── flutter_window.cpp │ │ ├── flutter_window.h │ │ ├── main.cpp │ │ ├── resource.h │ │ ├── runner.exe.manifest │ │ ├── utils.cpp │ │ ├── utils.h │ │ ├── win32_window.cpp │ │ └── win32_window.h │ ├── lib/ │ │ ├── menubar.dart │ │ └── src/ │ │ ├── menu_channel.dart │ │ ├── native_menu_item.dart │ │ └── set_application_menu.dart │ ├── linux/ │ │ ├── CMakeLists.txt │ │ ├── include/ │ │ │ └── menubar/ │ │ │ └── menubar_plugin.h │ │ └── menubar_plugin.cc │ ├── macos/ │ │ ├── Classes/ │ │ │ ├── FLEMenubarPlugin.h │ │ │ ├── FLEMenubarPlugin.m │ │ │ └── MenubarPlugin.swift │ │ └── menubar.podspec │ ├── pubspec.yaml │ └── windows/ │ ├── .gitignore │ ├── CMakeLists.txt │ ├── include/ │ │ └── menubar/ │ │ └── menubar_plugin.h │ └── menubar_plugin.cpp └── window_size/ ├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example/ │ ├── .gitignore │ ├── README.md │ ├── integration_test/ │ │ └── plugin_integration_test.dart │ ├── lib/ │ │ └── main.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 │ ├── macos/ │ │ ├── .gitignore │ │ ├── Podfile │ │ ├── Runner/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets/ │ │ │ │ └── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ └── MainMenu.xib │ │ │ ├── Configs/ │ │ │ │ ├── AppInfo.xcconfig │ │ │ │ ├── Debug.xcconfig │ │ │ │ ├── Release.xcconfig │ │ │ │ └── Warnings.xcconfig │ │ │ ├── DebugProfile.entitlements │ │ │ ├── Info.plist │ │ │ ├── MainFlutterWindow.swift │ │ │ └── Release.entitlements │ │ ├── Runner.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ └── xcshareddata/ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── RunnerTests/ │ │ └── RunnerTests.swift │ ├── pubspec.yaml │ └── windows/ │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter/ │ │ ├── CMakeLists.txt │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ └── generated_plugins.cmake │ └── runner/ │ ├── CMakeLists.txt │ ├── Runner.rc │ ├── flutter_window.cpp │ ├── flutter_window.h │ ├── main.cpp │ ├── resource.h │ ├── runner.exe.manifest │ ├── utils.cpp │ ├── utils.h │ ├── win32_window.cpp │ └── win32_window.h ├── lib/ │ ├── src/ │ │ ├── platform_window.dart │ │ ├── screen.dart │ │ ├── window_size_channel.dart │ │ └── window_size_utils.dart │ └── window_size.dart ├── linux/ │ ├── CMakeLists.txt │ ├── include/ │ │ └── window_size/ │ │ └── window_size_plugin.h │ └── window_size_plugin.cc ├── macos/ │ ├── Classes/ │ │ ├── FLEWindowSizePlugin.h │ │ ├── FLEWindowSizePlugin.mm │ │ └── WindowSizePlugin.swift │ └── window_size.podspec ├── pubspec.yaml └── windows/ ├── .gitignore ├── CMakeLists.txt ├── include/ │ └── window_size/ │ └── window_size_plugin.h └── window_size_plugin.cpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ BasedOnStyle: Google --- Language: Cpp ================================================ FILE: .github/ISSUE_TEMPLATE/BUG-REPORT.yml ================================================ name: Bug Report description: Report an issue with one of the plugins in this project body: - type: checkboxes id: confirmation attributes: label: Is this a bug in one of the plugins in this project? description: If not, use [the Flutter issue tracker](https://github.com/flutter/flutter/issues). options: - label: I have read [the README section about feedback](https://github.com/google/flutter-desktop-embedding/blob/master/README.md#feedback). required: true - label: My issue is about one of the plugins in this repository. required: true - type: dropdown id: plugin attributes: label: Which plugin is this bug report about? options: - menubar - window_size validations: required: true - type: textarea id: repro attributes: label: Describe the bug description: "Please provide a clear and concise description of the bug, including steps to reproduce, and, if relevant, screenshots:" validations: required: true - type: textarea id: doctor attributes: label: Flutter doctor description: "Provide the output of `flutter doctor -v`:" render: bash validations: required: true ================================================ FILE: .github/ISSUE_TEMPLATE/OTHER.yml ================================================ name: Other description: Request a feature, or provide other feedback that is not about a bug body: - type: checkboxes id: confirmation attributes: label: Is this request within the scope of this project? description: If not, use [the Flutter issue tracker](https://github.com/flutter/flutter/issues). options: - label: I have read [the README section about feedback](https://github.com/google/flutter-desktop-embedding/blob/master/README.md#feedback). required: true - label: My request is specifically related to this repository, not Flutter's desktop support. required: true - type: dropdown id: plugin attributes: label: Which plugin is this request about? options: - menubar - window_size - A proposal for a new experimental plugin - Other feedback validations: required: true - type: textarea id: request attributes: label: Describe the request validations: required: true ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: [push, pull_request] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: os: [macOS-12, windows-2019, ubuntu-22.04] include: - os: macOS-12 TARGET: macos - os: ubuntu-22.04 TARGET: linux - os: windows-2019 TARGET: windows # Disable fail-fast; we want results from all OSes even if one fails. fail-fast: false steps: - uses: actions/checkout@v2 with: path: fde - uses: actions/checkout@v2 with: path: flutter repository: flutter/flutter ref: master # Shallow clones don't work; see https://github.com/flutter/flutter/issues/18532 fetch-depth: 0 - name: Add Flutter tags # Add tags, which are also necessary for version checks to work. run: git fetch origin +refs/tags/*:refs/tags/* working-directory: ${{ github.workspace }}/flutter - name: Add Flutter to path - Windows if: startsWith(matrix.os, 'windows') run: echo "$env:GITHUB_WORKSPACE\flutter\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Add Flutter to path - macOS/Linux if: startsWith(matrix.os, 'macOS') || startsWith(matrix.os, 'ubuntu') run: echo "$GITHUB_WORKSPACE/flutter/bin" >> $GITHUB_PATH - name: Install Linux dependencies if: startsWith(matrix.os, 'ubuntu') run: | sudo apt-get update sudo apt-get install -y libgtk-3-dev libx11-dev pkg-config cmake ninja-build libblkid-dev liblzma-dev - name: Enable desktop support run: | flutter config --enable-linux-desktop flutter config --enable-macos-desktop flutter config --enable-windows-desktop - name: Doctor # Run doctor, for ease of debugging any issues. run: flutter doctor -v - name: Build menubar debug run: | flutter packages get flutter build -v ${{matrix.TARGET}} --debug working-directory: ${{ github.workspace }}/fde/plugins/menubar/example - name: Build menubar release run: | flutter packages get flutter build -v ${{matrix.TARGET}} --release working-directory: ${{ github.workspace }}/fde/plugins/menubar/example - name: Build window_size debug run: | flutter packages get flutter build -v ${{matrix.TARGET}} --debug working-directory: ${{ github.workspace }}/fde/plugins/window_size/example - name: Build window_size release run: | flutter packages get flutter build -v ${{matrix.TARGET}} --release working-directory: ${{ github.workspace }}/fde/plugins/window_size/example ================================================ FILE: .github/workflows/lock.yaml ================================================ # Configuration for Lock Threads - https://github.com/dessant/lock-threads name: 'Lock Threads' on: schedule: - cron: '0 0 * * *' jobs: lock: runs-on: ubuntu-latest steps: - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 with: github-token: ${{ github.token }} # Number of days of inactivity before a closed issue is locked. issue-lock-inactive-days: '14' ================================================ FILE: .gitignore ================================================ .DS_Store ================================================ FILE: CONTRIBUTING.md ================================================ # How to Contribute We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. ## Contributor License Agreement Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution, this simply gives us permission to use and redistribute your contributions as part of the project. Head over to to see your current agreements on file or to sign a new one. You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. ## Code reviews All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests. ## Project Standards - C++ code should follow [Google's C++ style guide](https://google.github.io/styleguide/cppguide.html). - Objective-C code should follow [Google's Objective-C style guide](http://google.github.io/styleguide/objcguide.html). - For C++ and Objective-C code, please run `clang-format -style=file` on files you have changed if possible. If you don't have `clang-format`, don't worry; a project member can do it prior to submission. - Dart code should follow the [Dart style guide](https://www.dartlang.org/guides/language/effective-dart/style) and use `dartfmt`. ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # Desktop Embedding for Flutter This project was originally created to develop Windows, macOS, and Linux embeddings of [Flutter](https://github.com/flutter/flutter). That work has since become part of Flutter, and all that remains here are experimental, early-stage desktop [plugins](https://flutter.dev/docs/development/packages-and-plugins/developing-packages). If you want to get started with Flutter on desktop, the place to start is now [the Flutter documentation](https://flutter.dev/desktop), rather than this project. You will already need to have followed the instructions there to get an application running on desktop before using any of the plugins here. ## Feedback **Do not file issues about Flutter for desktop here.** Since the embeddings have all moved to the Flutter project, the place for desktop bugs and feature requests is now [the Flutter issue tracker](https://github.com/flutter/flutter/issues). For bug reports and feature requests **related to the plugins in this repository**, please file issues here. ## Repository Structure The `plugins` directory contains all the plugins. See [its README](plugins/README.md) to get started. ## Caveats * This is not an officially supported Google product. ================================================ FILE: analysis_options.yaml ================================================ # Copyright 2017 The Fuchsia Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # Root analysis options shared among all Dart code in the respository. Based # on the Fuchsia standard analysis options, with some changes. linter: # Full list available at http://dart-lang.github.io/linter/lints/options/options.html. rules: - always_declare_return_types - always_put_control_body_on_new_line - always_put_required_named_parameters_first - always_require_non_null_named_parameters - annotate_overrides - avoid_bool_literals_in_conditional_expressions - avoid_catches_without_on_clauses - avoid_catching_errors - avoid_classes_with_only_static_members - avoid_empty_else # Not compatible with VS Code yet. # - avoid_field_initializers_in_const_classes - avoid_function_literals_in_foreach_calls - avoid_init_to_null - avoid_null_checks_in_equality_operators - avoid_positional_boolean_parameters - avoid_private_typedef_functions # TODO: Change relative imports for package imports # - avoid_relative_lib_imports # This puts an unnecessary burden on API clients. # - avoid_renaming_method_parameters - avoid_return_types_on_setters - avoid_returning_null - avoid_returning_this - avoid_single_cascade_in_expression_statements - avoid_setters_without_getters - avoid_slow_async_io - avoid_types_as_parameter_names - avoid_types_on_closure_parameters - avoid_unused_constructor_parameters - await_only_futures - camel_case_types - cancel_subscriptions - cascade_invocations - close_sinks - comment_references - constant_identifier_names - control_flow_in_finally - directives_ordering - empty_catches - empty_constructor_bodies - empty_statements - hash_and_equals - implementation_imports - iterable_contains_unrelated_type - join_return_with_assignment - library_names - library_prefixes - list_remove_unrelated_type - literal_only_boolean_expressions - no_adjacent_strings_in_list - no_duplicate_case_values - non_constant_identifier_names - omit_local_variable_types - one_member_abstracts - only_throw_errors - overridden_fields - package_api_docs - package_names - package_prefixed_library_names - parameter_assignments - prefer_adjacent_string_concatenation - prefer_asserts_in_initializer_lists - prefer_collection_literals - prefer_conditional_assignment # Disabled until bug is fixed # https://github.com/dart-lang/linter/issues/995 # - prefer_const_constructors - prefer_const_constructors_in_immutables - prefer_const_declarations - prefer_const_literals_to_create_immutables - prefer_constructors_over_static_methods - prefer_contains - prefer_equal_for_default_values # Add this when 'short' is better defined. # - prefer_expression_function_bodies - prefer_final_fields - prefer_final_locals # Seems to have false positive with await for. # - prefer_foreach - prefer_function_declarations_over_variables - prefer_generic_function_type_aliases - prefer_initializing_formals - prefer_interpolation_to_compose_strings - prefer_is_empty - prefer_is_not_empty - prefer_iterable_whereType - prefer_single_quotes - prefer_typing_uninitialized_variables - public_member_api_docs - recursive_getters - slash_for_doc_comments - sort_constructors_first - sort_unnamed_constructors_first - test_types_in_equals - throw_in_finally - type_annotate_public_apis - type_init_formals - unawaited_futures - unnecessary_brace_in_string_interps - unnecessary_getters_setters - unnecessary_lambdas - unnecessary_null_aware_assignments - unnecessary_null_in_if_null_operators - unnecessary_overrides - unnecessary_parenthesis - unnecessary_statements - unnecessary_this - unrelated_type_equality_checks - use_rethrow_when_possible - use_setters_to_change_properties - use_string_buffers - use_to_and_as_if_applicable - valid_regexps # Not compatible with VS Code yet. # - void_checks ================================================ FILE: macOS-Security.md ================================================ This content has moved [here](https://docs.flutter.dev/desktop#entitlements-and-the-app-sandbox) ================================================ FILE: plugins/.gitignore ================================================ .dart_tool/ flutter/ Flutter/ .flutter-plugins-dependencies !**/example/**/flutter ================================================ FILE: plugins/README.md ================================================ # Desktop Plugins This directory contains plugins that prototype functionality that will likely either become part of Flutter itself, or become officially supported plugins. ## Using Plugins Since the plugins in this repository are not intended to live here long term, these plugins are not published on pub.dev like normal Flutter plugins. Instead, you should include them directly from this repository: ``` dependencies: ... menubar: git: url: https://github.com/google/flutter-desktop-embedding.git path: plugins/menubar ref: INSERT_HASH_HERE ``` Replace `INSERT_HASH_HERE` with the hash of commit you want to pin to, usually the latest commit to the repository at the time you add the plugin. While omitting the `ref` is possible, it is **strongly** discouraged, as without it any breaking change to the plugin would break your project without warning. ================================================ FILE: plugins/menubar/.gitignore ================================================ .packages .flutter-plugins .flutter-plugins-dependencies pubspec.lock .dart_tool ================================================ FILE: plugins/menubar/.metadata ================================================ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled and should not be manually edited. version: revision: 8489d460a4b08c5bce0ee01430575761d47abbb5 channel: master project_type: plugin ================================================ FILE: plugins/menubar/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: plugins/menubar/README.md ================================================ # menubar This plugin provides access to a native menubar. This is a prototype, and in the long term will either be replaced by functionality within the Flutter framework itself, or a published plugin (likely part of flutter/plugins). Either way, the API will change significantly. ## Supported Platforms - [x] macOS - [x] Windows - [x] Linux ## Caveats ### macOS Currently there is no way to interact with existing top-level menus, only add new ones. E.g., the Window menu cannot be extended from Flutter code. ## Use See [the plugin README](../README.md) for general instructions on using FDE plugins. ================================================ FILE: plugins/menubar/analysis_options.yaml ================================================ include: ../../analysis_options.yaml ================================================ FILE: plugins/menubar/example/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ migrate_working_dir/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Symbolication related app.*.symbols # Obfuscation related app.*.map.json # Android Studio will place build artifacts here /android/app/debug /android/app/profile /android/app/release ================================================ FILE: plugins/menubar/example/README.md ================================================ # menubar_example Demonstrates how to use the menubar plugin. ## Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flutter project: - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) For help getting started with Flutter development, view the [online documentation](https://docs.flutter.dev/), which offers tutorials, samples, guidance on mobile development, and a full API reference. ================================================ FILE: plugins/menubar/example/integration_test/plugin_integration_test.dart ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:menubar/menubar.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('sanity check', (tester) async { expect( setApplicationMenu([ NativeSubmenu(label: 'Test', children: [ NativeMenuItem( label: '1', shortcut: LogicalKeySet( LogicalKeyboardKey.meta, LogicalKeyboardKey.keyA), onSelected: () {}), const NativeMenuDivider(), NativeSubmenu(label: 'Presets', children: [ NativeMenuItem( label: '2', shortcut: LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.shift, LogicalKeyboardKey.keyB), onSelected: null), ]) ]), ]), completes); }); } ================================================ FILE: plugins/menubar/example/lib/main.dart ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:menubar/menubar.dart'; void main() { runApp(const MyApp()); } /// Top level widget for the application. class MyApp extends StatefulWidget { /// Constructs a new app with the given [key]. const MyApp({Key? key}) : super(key: key); @override State createState() => _AppState(); } class _AppState extends State { Color _primaryColor = Colors.blue; int _counter = 0; static _AppState? of(BuildContext context) => context.findAncestorStateOfType<_AppState>(); /// Sets the primary color of the app. void setPrimaryColor(Color color) { setState(() { _primaryColor = color; }); } void incrementCounter() { _setCounter(_counter + 1); } void _decrementCounter() { _setCounter(_counter - 1); } void _setCounter(int value) { setState(() { _counter = value; }); } /// Rebuilds the native menu bar based on the current state. void updateMenubar() { setApplicationMenu([ NativeSubmenu(label: 'Color', children: [ NativeMenuItem( label: 'Reset', shortcut: LogicalKeySet( LogicalKeyboardKey.meta, LogicalKeyboardKey.backspace), onSelected: _primaryColor == Colors.blue ? null : () { setPrimaryColor(Colors.blue); }), const NativeMenuDivider(), NativeSubmenu(label: 'Presets', children: [ NativeMenuItem( label: 'Red', shortcut: LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.shift, LogicalKeyboardKey.keyR), onSelected: _primaryColor == Colors.red ? null : () { setPrimaryColor(Colors.red); }), NativeMenuItem( label: 'Green', shortcut: LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.alt, LogicalKeyboardKey.keyG), onSelected: _primaryColor == Colors.green ? null : () { setPrimaryColor(Colors.green); }), NativeMenuItem( label: 'Purple', shortcut: LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.control, LogicalKeyboardKey.keyP), onSelected: _primaryColor == Colors.deepPurple ? null : () { setPrimaryColor(Colors.deepPurple); }), ]) ]), NativeSubmenu(label: 'Counter', children: [ NativeMenuItem( label: 'Reset', shortcut: LogicalKeySet( LogicalKeyboardKey.meta, LogicalKeyboardKey.digit0), onSelected: _counter == 0 ? null : () { _setCounter(0); }), const NativeMenuDivider(), NativeMenuItem( label: 'Increment', shortcut: LogicalKeySet(LogicalKeyboardKey.f2), onSelected: incrementCounter), NativeMenuItem( label: 'Decrement', shortcut: LogicalKeySet(LogicalKeyboardKey.f1), onSelected: _counter == 0 ? null : _decrementCounter), ]), ]); } @override Widget build(BuildContext context) { // Any time the state changes, the menu needs to be rebuilt. updateMenubar(); final theme = ThemeData(); return MaterialApp( title: 'Flutter Demo', theme: theme.copyWith( colorScheme: theme.colorScheme .copyWith(primary: _primaryColor, secondary: _primaryColor), ), darkTheme: ThemeData.dark(), home: _MyHomePage(title: 'Flutter Demo Home Page', counter: _counter), ); } } class _MyHomePage extends StatelessWidget { const _MyHomePage({required this.title, this.counter = 0}); final String title; final int counter; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(title), ), body: LayoutBuilder( builder: (context, viewportConstraints) { return SingleChildScrollView( child: ConstrainedBox( constraints: BoxConstraints(minHeight: viewportConstraints.maxHeight), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'You have pushed the button this many times:', ), Text( '$counter', style: Theme.of(context).textTheme.headlineMedium, ), ], ), ), ), ); }, ), floatingActionButton: FloatingActionButton( onPressed: _AppState.of(context)!.incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } } ================================================ FILE: plugins/menubar/example/linux/.gitignore ================================================ flutter/ephemeral ================================================ FILE: plugins/menubar/example/linux/CMakeLists.txt ================================================ # Project-level configuration. cmake_minimum_required(VERSION 3.10) project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "menubar_example") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID set(APPLICATION_ID "com.example.menubar") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(SET CMP0063 NEW) # Load bundled libraries from the lib/ directory relative to the binary. set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") # Root filesystem for cross-building. if(FLUTTER_TARGET_PLATFORM_SYSROOT) set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) endif() # Define build configuration options. if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() # Compilation settings that should be applied to most targets. # # Be cautious about adding new options here, as plugins use this function by # default. In most cases, you should add new options to specific targets instead # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_14) target_compile_options(${TARGET} PRIVATE -Wall -Werror) target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") endfunction() # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") # Define the application target. To change its name, change BINARY_NAME above, # not the value here, or `flutter run` will no longer work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} "main.cc" "my_application.cc" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add dependency libraries. Add any application-specific dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) # Only the install-generated bundle's copy of the executable will launch # correctly, since the resources must in the right relative locations. To avoid # people trying to run the unbundled copy, put it in a subdirectory instead of # the default top-level location. set_target_properties(${BINARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" ) # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) # === Installation === # By default, "installing" just makes a relocatable bundle in the build # directory. set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() # Start with a clean build bundle directory every time. install(CODE " file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") " COMPONENT Runtime) set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) install(FILES "${bundled_library}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endforeach(bundled_library) # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() ================================================ FILE: plugins/menubar/example/linux/flutter/CMakeLists.txt ================================================ # This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.10) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. # Serves the same purpose as list(TRANSFORM ... PREPEND ...), # which isn't available in 3.10. function(list_prepend LIST_NAME PREFIX) set(NEW_LIST "") foreach(element ${${LIST_NAME}}) list(APPEND NEW_LIST "${PREFIX}${element}") endforeach(element) set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) endfunction() # === Flutter Library === # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "fl_basic_message_channel.h" "fl_binary_codec.h" "fl_binary_messenger.h" "fl_dart_project.h" "fl_engine.h" "fl_json_message_codec.h" "fl_json_method_codec.h" "fl_message_codec.h" "fl_method_call.h" "fl_method_channel.h" "fl_method_codec.h" "fl_method_response.h" "fl_plugin_registrar.h" "fl_plugin_registry.h" "fl_standard_message_codec.h" "fl_standard_method_codec.h" "fl_string_codec.h" "fl_value.h" "fl_view.h" "flutter_linux.h" ) list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") target_link_libraries(flutter INTERFACE PkgConfig::GTK PkgConfig::GLIB PkgConfig::GIO ) add_dependencies(flutter flutter_assemble) # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/_phony_ COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ) ================================================ FILE: plugins/menubar/example/linux/flutter/generated_plugin_registrant.cc ================================================ // // Generated file. Do not edit. // // clang-format off #include "generated_plugin_registrant.h" #include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) menubar_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MenubarPlugin"); menubar_plugin_register_with_registrar(menubar_registrar); } ================================================ FILE: plugins/menubar/example/linux/flutter/generated_plugin_registrant.h ================================================ // // Generated file. Do not edit. // // clang-format off #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ #include // Registers Flutter plugins. void fl_register_plugins(FlPluginRegistry* registry); #endif // GENERATED_PLUGIN_REGISTRANT_ ================================================ FILE: plugins/menubar/example/linux/flutter/generated_plugins.cmake ================================================ # # Generated file, do not edit. # list(APPEND FLUTTER_PLUGIN_LIST menubar ) list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) endforeach(ffi_plugin) ================================================ FILE: plugins/menubar/example/linux/main.cc ================================================ #include "my_application.h" int main(int argc, char** argv) { g_autoptr(MyApplication) app = my_application_new(); return g_application_run(G_APPLICATION(app), argc, argv); } ================================================ FILE: plugins/menubar/example/linux/my_application.cc ================================================ #include "my_application.h" #include #ifdef GDK_WINDOWING_X11 #include #endif #include "flutter/generated_plugin_registrant.h" struct _MyApplication { GtkApplication parent_instance; char** dart_entrypoint_arguments; }; G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); GtkWindow* window = GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); // Use a header bar when running in GNOME as this is the common style used // by applications and is the setup most users will be using (e.g. Ubuntu // desktop). // If running on X and not using GNOME then just use a traditional title bar // in case the window manager does more exotic layout, e.g. tiling. // If running on Wayland assume the header bar will work (may need changing // if future cases occur). gboolean use_header_bar = TRUE; #ifdef GDK_WINDOWING_X11 GdkScreen* screen = gtk_window_get_screen(window); if (GDK_IS_X11_SCREEN(screen)) { const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); if (g_strcmp0(wm_name, "GNOME Shell") != 0) { use_header_bar = FALSE; } } #endif if (use_header_bar) { GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); gtk_header_bar_set_title(header_bar, "menubar_example"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); } else { gtk_window_set_title(window, "menubar_example"); } gtk_window_set_default_size(window, 1280, 720); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlDartProject) project = fl_dart_project_new(); fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); FlView* view = fl_view_new(project); gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); } // Implements GApplication::local_command_line. static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { MyApplication* self = MY_APPLICATION(application); // Strip out the first argument as it is the binary name. self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); g_autoptr(GError) error = nullptr; if (!g_application_register(application, nullptr, &error)) { g_warning("Failed to register: %s", error->message); *exit_status = 1; return TRUE; } g_application_activate(application); *exit_status = 0; return TRUE; } // Implements GObject::dispose. static void my_application_dispose(GObject* object) { MyApplication* self = MY_APPLICATION(object); g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); G_OBJECT_CLASS(my_application_parent_class)->dispose(object); } static void my_application_class_init(MyApplicationClass* klass) { G_APPLICATION_CLASS(klass)->activate = my_application_activate; G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; G_OBJECT_CLASS(klass)->dispose = my_application_dispose; } static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { return MY_APPLICATION(g_object_new(my_application_get_type(), "application-id", APPLICATION_ID, "flags", G_APPLICATION_NON_UNIQUE, nullptr)); } ================================================ FILE: plugins/menubar/example/linux/my_application.h ================================================ #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ #include G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, GtkApplication) /** * my_application_new: * * Creates a new Flutter-based application. * * Returns: a new #MyApplication. */ MyApplication* my_application_new(); #endif // FLUTTER_MY_APPLICATION_H_ ================================================ FILE: plugins/menubar/example/macos/.gitignore ================================================ # Flutter-related **/Flutter/ephemeral/ **/Pods/ # Xcode-related **/dgph **/xcuserdata/ ================================================ FILE: plugins/menubar/example/macos/Podfile ================================================ platform :osx, '10.14' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' project 'Runner', { 'Debug' => :debug, 'Profile' => :release, 'Release' => :release, } def flutter_root generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) unless File.exist?(generated_xcode_build_settings_path) raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" end File.foreach(generated_xcode_build_settings_path) do |line| matches = line.match(/FLUTTER_ROOT\=(.*)/) return matches[1].strip if matches end raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" end require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) flutter_macos_podfile_setup target 'Runner' do use_frameworks! use_modular_headers! flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) target 'RunnerTests' do inherit! :search_paths end end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_macos_build_settings(target) end end ================================================ FILE: plugins/menubar/example/macos/Runner/AppDelegate.swift ================================================ import Cocoa import FlutterMacOS @NSApplicationMain class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } } ================================================ FILE: plugins/menubar/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "16x16", "idiom" : "mac", "filename" : "app_icon_16.png", "scale" : "1x" }, { "size" : "16x16", "idiom" : "mac", "filename" : "app_icon_32.png", "scale" : "2x" }, { "size" : "32x32", "idiom" : "mac", "filename" : "app_icon_32.png", "scale" : "1x" }, { "size" : "32x32", "idiom" : "mac", "filename" : "app_icon_64.png", "scale" : "2x" }, { "size" : "128x128", "idiom" : "mac", "filename" : "app_icon_128.png", "scale" : "1x" }, { "size" : "128x128", "idiom" : "mac", "filename" : "app_icon_256.png", "scale" : "2x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "app_icon_256.png", "scale" : "1x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "app_icon_512.png", "scale" : "2x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "app_icon_512.png", "scale" : "1x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "app_icon_1024.png", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: plugins/menubar/example/macos/Runner/Base.lproj/MainMenu.xib ================================================ ================================================ FILE: plugins/menubar/example/macos/Runner/Configs/AppInfo.xcconfig ================================================ // Application-level settings for the Runner target. // // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the // future. If not, the values below would default to using the project name when this becomes a // 'flutter create' template. // The application's name. By default this is also the title of the Flutter window. PRODUCT_NAME = menubar_example // The application's bundle identifier PRODUCT_BUNDLE_IDENTIFIER = com.example.menubarExample // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. ================================================ FILE: plugins/menubar/example/macos/Runner/Configs/Debug.xcconfig ================================================ #include "../../Flutter/Flutter-Debug.xcconfig" #include "Warnings.xcconfig" ================================================ FILE: plugins/menubar/example/macos/Runner/Configs/Release.xcconfig ================================================ #include "../../Flutter/Flutter-Release.xcconfig" #include "Warnings.xcconfig" ================================================ FILE: plugins/menubar/example/macos/Runner/Configs/Warnings.xcconfig ================================================ WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings GCC_WARN_UNDECLARED_SELECTOR = YES CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE CLANG_WARN__DUPLICATE_METHOD_MATCH = YES CLANG_WARN_PRAGMA_PACK = YES CLANG_WARN_STRICT_PROTOTYPES = YES CLANG_WARN_COMMA = YES GCC_WARN_STRICT_SELECTOR_MATCH = YES CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES GCC_WARN_SHADOW = YES CLANG_WARN_UNREACHABLE_CODE = YES ================================================ FILE: plugins/menubar/example/macos/Runner/DebugProfile.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.cs.allow-jit com.apple.security.network.server ================================================ FILE: plugins/menubar/example/macos/Runner/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString $(FLUTTER_BUILD_NAME) CFBundleVersion $(FLUTTER_BUILD_NUMBER) LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright $(PRODUCT_COPYRIGHT) NSMainNibFile MainMenu NSPrincipalClass NSApplication ================================================ FILE: plugins/menubar/example/macos/Runner/MainFlutterWindow.swift ================================================ import Cocoa import FlutterMacOS class MainFlutterWindow: NSWindow { override func awakeFromNib() { let flutterViewController = FlutterViewController.init() let windowFrame = self.frame self.contentViewController = flutterViewController self.setFrame(windowFrame, display: true) RegisterGeneratedPlugins(registry: flutterViewController) super.awakeFromNib() } } ================================================ FILE: plugins/menubar/example/macos/Runner/Release.entitlements ================================================ com.apple.security.app-sandbox ================================================ FILE: plugins/menubar/example/macos/Runner.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { isa = PBXAggregateTarget; buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; buildPhases = ( 33CC111E2044C6BF0003C045 /* ShellScript */, ); dependencies = ( ); name = "Flutter Assemble"; productName = FLX; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; B137C041F357630981CDCC22 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC92096444E87FC3AFBFDCD /* Pods_Runner.framework */; }; D8AF70EEAEA7030F1F9BE2C4 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CCBF85A7CBA00ABDCE441EE /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; proxyType = 1; remoteGlobalIDString = 33CC10EC2044A3C60003C045; remoteInfo = Runner; }; 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; proxyType = 1; remoteGlobalIDString = 33CC111A2044C6BA0003C045; remoteInfo = FLX; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 33CC110E2044A8840003C045 /* Bundle Framework */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Bundle Framework"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 2526F1A024602FF74C070566 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 2CCBF85A7CBA00ABDCE441EE /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; 33CC10ED2044A3C60003C045 /* menubar_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = menubar_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 390F3AB92857C7B2493FB6ED /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 4BC92096444E87FC3AFBFDCD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7AF10576CA7900A9BB9385F1 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 8BEFFEA85C2050039B344EBB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; C1E79F42E97B0E8A7F5E4136 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; C953BCFA4E0FE7E0A1B76DD0 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 331C80D2294CF70F00263BE5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D8AF70EEAEA7030F1F9BE2C4 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10EA2044A3C60003C045 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( B137C041F357630981CDCC22 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 27E7A09F7E99E8CC3A7BBFDC /* Pods */ = { isa = PBXGroup; children = ( 2526F1A024602FF74C070566 /* Pods-Runner.debug.xcconfig */, 8BEFFEA85C2050039B344EBB /* Pods-Runner.release.xcconfig */, C1E79F42E97B0E8A7F5E4136 /* Pods-Runner.profile.xcconfig */, C953BCFA4E0FE7E0A1B76DD0 /* Pods-RunnerTests.debug.xcconfig */, 390F3AB92857C7B2493FB6ED /* Pods-RunnerTests.release.xcconfig */, 7AF10576CA7900A9BB9385F1 /* Pods-RunnerTests.profile.xcconfig */, ); name = Pods; path = Pods; sourceTree = ""; }; 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( 331C80D7294CF71000263BE5 /* RunnerTests.swift */, ); path = RunnerTests; sourceTree = ""; }; 33BA886A226E78AF003329D5 /* Configs */ = { isa = PBXGroup; children = ( 33E5194F232828860026EE4D /* AppInfo.xcconfig */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, ); path = Configs; sourceTree = ""; }; 33CC10E42044A3C60003C045 = { isa = PBXGroup; children = ( 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, 27E7A09F7E99E8CC3A7BBFDC /* Pods */, ); sourceTree = ""; }; 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( 33CC10ED2044A3C60003C045 /* menubar_example.app */, 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; }; 33CC11242044D66E0003C045 /* Resources */ = { isa = PBXGroup; children = ( 33CC10F22044A3C60003C045 /* Assets.xcassets */, 33CC10F42044A3C60003C045 /* MainMenu.xib */, 33CC10F72044A3C60003C045 /* Info.plist */, ); name = Resources; path = ..; sourceTree = ""; }; 33CEB47122A05771004F2AC0 /* Flutter */ = { isa = PBXGroup; children = ( 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, ); path = Flutter; sourceTree = ""; }; 33FAB671232836740065AC1E /* Runner */ = { isa = PBXGroup; children = ( 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 33E51913231747F40026EE4D /* DebugProfile.entitlements */, 33E51914231749380026EE4D /* Release.entitlements */, 33CC11242044D66E0003C045 /* Resources */, 33BA886A226E78AF003329D5 /* Configs */, ); path = Runner; sourceTree = ""; }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( 4BC92096444E87FC3AFBFDCD /* Pods_Runner.framework */, 2CCBF85A7CBA00ABDCE441EE /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 331C80D4294CF70F00263BE5 /* RunnerTests */ = { isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( 2BB4DD347B330822959B3AF1 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, ); buildRules = ( ); dependencies = ( 331C80DA294CF71000263BE5 /* PBXTargetDependency */, ); name = RunnerTests; productName = RunnerTests; productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 33CC10EC2044A3C60003C045 /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( 693D02D8BE99AAA5C0A8144C /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, DB05B8D64AE46CC9B8FE9DA8 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( 33CC11202044C79F0003C045 /* PBXTargetDependency */, ); name = Runner; productName = Runner; productReference = 33CC10ED2044A3C60003C045 /* menubar_example.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { CreatedOnToolsVersion = 14.0; TestTargetID = 33CC10EC2044A3C60003C045; }; 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 1100; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.Sandbox = { enabled = 1; }; }; }; 33CC111A2044C6BA0003C045 = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Manual; }; }; }; buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 33CC10E42044A3C60003C045; productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, 331C80D4294CF70F00263BE5 /* RunnerTests */, 33CC111A2044C6BA0003C045 /* Flutter Assemble */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 331C80D3294CF70F00263BE5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 2BB4DD347B330822959B3AF1 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( Flutter/ephemeral/FlutterInputs.xcfilelist, ); inputPaths = ( Flutter/ephemeral/tripwire, ); outputFileListPaths = ( Flutter/ephemeral/FlutterOutputs.xcfilelist, ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; 693D02D8BE99AAA5C0A8144C /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; DB05B8D64AE46CC9B8FE9DA8 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 331C80D1294CF70F00263BE5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10E92044A3C60003C045 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC10EC2044A3C60003C045 /* Runner */; targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; }; 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( 33CC10F52044A3C60003C045 /* Base */, ); name = MainMenu.xib; path = Runner; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = C953BCFA4E0FE7E0A1B76DD0 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.menubarExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/menubar_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/menubar_example"; }; name = Debug; }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 390F3AB92857C7B2493FB6ED /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.menubarExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/menubar_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/menubar_example"; }; name = Release; }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AF10576CA7900A9BB9385F1 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.menubarExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/menubar_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/menubar_example"; }; name = Profile; }; 338D0CE9231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Profile; }; 338D0CEA231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Profile; }; 338D0CEB231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Profile; }; 33CC10F92044A3C60003C045 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 33CC10FA2044A3C60003C045 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; 33CC10FC2044A3C60003C045 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; 33CC10FD2044A3C60003C045 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Release; }; 33CC111C2044C6BA0003C045 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 33CC111D2044C6BA0003C045 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 331C80DB294CF71000263BE5 /* Debug */, 331C80DC294CF71000263BE5 /* Release */, 331C80DD294CF71000263BE5 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC10F92044A3C60003C045 /* Debug */, 33CC10FA2044A3C60003C045 /* Release */, 338D0CE9231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC10FC2044A3C60003C045 /* Debug */, 33CC10FD2044A3C60003C045 /* Release */, 338D0CEA231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC111C2044C6BA0003C045 /* Debug */, 33CC111D2044C6BA0003C045 /* Release */, 338D0CEB231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 33CC10E52044A3C60003C045 /* Project object */; } ================================================ FILE: plugins/menubar/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: plugins/menubar/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme ================================================ ================================================ FILE: plugins/menubar/example/macos/Runner.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: plugins/menubar/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: plugins/menubar/example/macos/RunnerTests/RunnerTests.swift ================================================ import FlutterMacOS import Cocoa import XCTest @testable import menubar // This demonstrates a simple unit test of the Swift portion of this plugin's implementation. // // See https://developer.apple.com/documentation/xctest for more information about using XCTest. class RunnerTests: XCTestCase { } ================================================ FILE: plugins/menubar/example/pubspec.yaml ================================================ name: menubar_example description: Demonstrates how to use the menubar plugin. publish_to: 'none' environment: sdk: '>=2.12.0-0 <3.0.0' flutter: '>=3.0.0' dependencies: flutter: sdk: flutter menubar: # When depending on this package from a real application you should use: # menubar: ^x.y.z # See https://dart.dev/tools/pub/dependencies#version-constraints # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ dev_dependencies: integration_test: sdk: flutter flutter_test: sdk: flutter flutter: uses-material-design: true ================================================ FILE: plugins/menubar/example/windows/.gitignore ================================================ flutter/ephemeral/ # Visual Studio user-specific files. *.suo *.user *.userosscache *.sln.docstates # Visual Studio build-related files. x64/ x86/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ ================================================ FILE: plugins/menubar/example/windows/CMakeLists.txt ================================================ # Project-level configuration. cmake_minimum_required(VERSION 3.14) project(menubar_example LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "menubar_example") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(SET CMP0063 NEW) # Define build configuration option. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" CACHE STRING "" FORCE) else() if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() endif() # Define settings for the Profile build mode. set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") # Use Unicode for all projects. add_definitions(-DUNICODE -D_UNICODE) # Compilation settings that should be applied to most targets. # # Be cautious about adding new options here, as plugins use this function by # default. In most cases, you should add new options to specific targets instead # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") target_compile_options(${TARGET} PRIVATE /EHsc) target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") endfunction() # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # Application build; see runner/CMakeLists.txt. add_subdirectory("runner") # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) # === Installation === # Support files are copied into place next to the executable, so that it can # run in place. This is done instead of making a separate bundle (as on Linux) # so that building and running from within Visual Studio will work. set(BUILD_BUNDLE_DIR "$") # Make the "install" step default, as it's required to run. set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) if(PLUGIN_BUNDLED_LIBRARIES) install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" CONFIGURATIONS Profile;Release COMPONENT Runtime) ================================================ FILE: plugins/menubar/example/windows/flutter/CMakeLists.txt ================================================ # This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "flutter_export.h" "flutter_windows.h" "flutter_messenger.h" "flutter_plugin_registrar.h" "flutter_texture_registrar.h" ) list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") add_dependencies(flutter flutter_assemble) # === Wrapper === list(APPEND CPP_WRAPPER_SOURCES_CORE "core_implementations.cc" "standard_codec.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_PLUGIN "plugin_registrar.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_APP "flutter_engine.cc" "flutter_view_controller.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") # Wrapper sources needed for a plugin. add_library(flutter_wrapper_plugin STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ) apply_standard_settings(flutter_wrapper_plugin) set_target_properties(flutter_wrapper_plugin PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(flutter_wrapper_plugin PROPERTIES CXX_VISIBILITY_PRESET hidden) target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) target_include_directories(flutter_wrapper_plugin PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_plugin flutter_assemble) # Wrapper sources needed for the runner. add_library(flutter_wrapper_app STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_APP} ) apply_standard_settings(flutter_wrapper_app) target_link_libraries(flutter_wrapper_app PUBLIC flutter) target_include_directories(flutter_wrapper_app PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_app flutter_assemble) # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ${PHONY_OUTPUT} COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" windows-x64 $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ) ================================================ FILE: plugins/menubar/example/windows/flutter/generated_plugin_registrant.cc ================================================ // // Generated file. Do not edit. // // clang-format off #include "generated_plugin_registrant.h" #include void RegisterPlugins(flutter::PluginRegistry* registry) { MenubarPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("MenubarPlugin")); } ================================================ FILE: plugins/menubar/example/windows/flutter/generated_plugin_registrant.h ================================================ // // Generated file. Do not edit. // // clang-format off #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ #include // Registers Flutter plugins. void RegisterPlugins(flutter::PluginRegistry* registry); #endif // GENERATED_PLUGIN_REGISTRANT_ ================================================ FILE: plugins/menubar/example/windows/flutter/generated_plugins.cmake ================================================ # # Generated file, do not edit. # list(APPEND FLUTTER_PLUGIN_LIST menubar ) list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) endforeach(ffi_plugin) ================================================ FILE: plugins/menubar/example/windows/runner/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.14) project(runner LANGUAGES CXX) # Define the application target. To change its name, change BINARY_NAME in the # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer # work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" "utils.cpp" "win32_window.cpp" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "Runner.rc" "runner.exe.manifest" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add preprocessor definitions for the build version. target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") # Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) ================================================ FILE: plugins/menubar/example/windows/runner/Runner.rc ================================================ // Microsoft Visual C++ generated resource script. // #pragma code_page(65001) #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_APP_ICON ICON "resources\\app_icon.ico" ///////////////////////////////////////////////////////////////////////////// // // Version // #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else #define VERSION_AS_NUMBER 1,0,0,0 #endif #if defined(FLUTTER_VERSION) #define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION_AS_NUMBER PRODUCTVERSION VERSION_AS_NUMBER FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "com.example" "\0" VALUE "FileDescription", "menubar_example" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "menubar_example" "\0" VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" VALUE "OriginalFilename", "menubar_example.exe" "\0" VALUE "ProductName", "menubar_example" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: plugins/menubar/example/windows/runner/flutter_window.cpp ================================================ #include "flutter_window.h" #include #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(const flutter::DartProject& project) : project_(project) {} FlutterWindow::~FlutterWindow() {} bool FlutterWindow::OnCreate() { if (!Win32Window::OnCreate()) { return false; } RECT frame = GetClientArea(); // The size here must match the window dimensions to avoid unnecessary surface // creation / destruction in the startup path. flutter_controller_ = std::make_unique( frame.right - frame.left, frame.bottom - frame.top, project_); // Ensure that basic setup of the controller was successful. if (!flutter_controller_->engine() || !flutter_controller_->view()) { return false; } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); }); return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } LRESULT FlutterWindow::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { // Give Flutter, including plugins, an opportunity to handle window messages. if (flutter_controller_) { std::optional result = flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, lparam); if (result) { return *result; } } switch (message) { case WM_FONTCHANGE: flutter_controller_->engine()->ReloadSystemFonts(); break; } return Win32Window::MessageHandler(hwnd, message, wparam, lparam); } ================================================ FILE: plugins/menubar/example/windows/runner/flutter_window.h ================================================ #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ #include #include #include #include "win32_window.h" // A window that does nothing but host a Flutter view. class FlutterWindow : public Win32Window { public: // Creates a new FlutterWindow hosting a Flutter view running |project|. explicit FlutterWindow(const flutter::DartProject& project); virtual ~FlutterWindow(); protected: // Win32Window: bool OnCreate() override; void OnDestroy() override; LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override; private: // The project to run. flutter::DartProject project_; // The Flutter instance hosted by this window. std::unique_ptr flutter_controller_; }; #endif // RUNNER_FLUTTER_WINDOW_H_ ================================================ FILE: plugins/menubar/example/windows/runner/main.cpp ================================================ #include #include #include #include "flutter_window.h" #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { // Attach to console when present (e.g., 'flutter run') or create a // new console when running with a debugger. if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { CreateAndAttachConsole(); } // Initialize COM, so that it is available for use in the library and/or // plugins. ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); flutter::DartProject project(L"data"); std::vector command_line_arguments = GetCommandLineArguments(); project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); if (!window.Create(L"menubar_example", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); ::MSG msg; while (::GetMessage(&msg, nullptr, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } ::CoUninitialize(); return EXIT_SUCCESS; } ================================================ FILE: plugins/menubar/example/windows/runner/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by Runner.rc // #define IDI_APP_ICON 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: plugins/menubar/example/windows/runner/runner.exe.manifest ================================================ PerMonitorV2 ================================================ FILE: plugins/menubar/example/windows/runner/utils.cpp ================================================ #include "utils.h" #include #include #include #include #include void CreateAndAttachConsole() { if (::AllocConsole()) { FILE *unused; if (freopen_s(&unused, "CONOUT$", "w", stdout)) { _dup2(_fileno(stdout), 1); } if (freopen_s(&unused, "CONOUT$", "w", stderr)) { _dup2(_fileno(stdout), 2); } std::ios::sync_with_stdio(); FlutterDesktopResyncOutputStreams(); } } std::vector GetCommandLineArguments() { // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. int argc; wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); if (argv == nullptr) { return std::vector(); } std::vector command_line_arguments; // Skip the first argument as it's the binary name. for (int i = 1; i < argc; i++) { command_line_arguments.push_back(Utf8FromUtf16(argv[i])); } ::LocalFree(argv); return command_line_arguments; } std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } int target_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, nullptr, 0, nullptr, nullptr); std::string utf8_string; if (target_length == 0 || target_length > utf8_string.max_size()) { return utf8_string; } utf8_string.resize(target_length); int converted_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, utf8_string.data(), target_length, nullptr, nullptr); if (converted_length == 0) { return std::string(); } return utf8_string; } ================================================ FILE: plugins/menubar/example/windows/runner/utils.h ================================================ #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ #include #include // Creates a console for the process, and redirects stdout and stderr to // it for both the runner and the Flutter library. void CreateAndAttachConsole(); // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string // encoded in UTF-8. Returns an empty std::string on failure. std::string Utf8FromUtf16(const wchar_t* utf16_string); // Gets the command line arguments passed in as a std::vector, // encoded in UTF-8. Returns an empty std::vector on failure. std::vector GetCommandLineArguments(); #endif // RUNNER_UTILS_H_ ================================================ FILE: plugins/menubar/example/windows/runner/win32_window.cpp ================================================ #include "win32_window.h" #include #include #include "resource.h" namespace { /// Window attribute that enables dark mode window decorations. /// /// Redefined in case the developer's machine has a Windows SDK older than /// version 10.0.22000.0. /// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE #define DWMWA_USE_IMMERSIVE_DARK_MODE 20 #endif constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; /// Registry key for app theme preference. /// /// A value of 0 indicates apps should use dark mode. A non-zero or missing /// value indicates apps should use light mode. constexpr const wchar_t kGetPreferredBrightnessRegKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; // The number of Win32Window objects that currently exist. static int g_active_window_count = 0; using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); // Scale helper to convert logical scaler values to physical using passed in // scale factor int Scale(int source, double scale_factor) { return static_cast(source * scale_factor); } // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. // This API is only needed for PerMonitor V1 awareness mode. void EnableFullDpiSupportIfAvailable(HWND hwnd) { HMODULE user32_module = LoadLibraryA("User32.dll"); if (!user32_module) { return; } auto enable_non_client_dpi_scaling = reinterpret_cast( GetProcAddress(user32_module, "EnableNonClientDpiScaling")); if (enable_non_client_dpi_scaling != nullptr) { enable_non_client_dpi_scaling(hwnd); } FreeLibrary(user32_module); } } // namespace // Manages the Win32Window's window class registration. class WindowClassRegistrar { public: ~WindowClassRegistrar() = default; // Returns the singleton registar instance. static WindowClassRegistrar* GetInstance() { if (!instance_) { instance_ = new WindowClassRegistrar(); } return instance_; } // Returns the name of the window class, registering the class if it hasn't // previously been registered. const wchar_t* GetWindowClass(); // Unregisters the window class. Should only be called if there are no // instances of the window. void UnregisterWindowClass(); private: WindowClassRegistrar() = default; static WindowClassRegistrar* instance_; bool class_registered_ = false; }; WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; const wchar_t* WindowClassRegistrar::GetWindowClass() { if (!class_registered_) { WNDCLASS window_class{}; window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); window_class.lpszClassName = kWindowClassName; window_class.style = CS_HREDRAW | CS_VREDRAW; window_class.cbClsExtra = 0; window_class.cbWndExtra = 0; window_class.hInstance = GetModuleHandle(nullptr); window_class.hIcon = LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); window_class.hbrBackground = 0; window_class.lpszMenuName = nullptr; window_class.lpfnWndProc = Win32Window::WndProc; RegisterClass(&window_class); class_registered_ = true; } return kWindowClassName; } void WindowClassRegistrar::UnregisterWindowClass() { UnregisterClass(kWindowClassName, nullptr); class_registered_ = false; } Win32Window::Win32Window() { ++g_active_window_count; } Win32Window::~Win32Window() { --g_active_window_count; Destroy(); } bool Win32Window::Create(const std::wstring& title, const Point& origin, const Size& size) { Destroy(); const wchar_t* window_class = WindowClassRegistrar::GetInstance()->GetWindowClass(); const POINT target_point = {static_cast(origin.x), static_cast(origin.y)}; HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); double scale_factor = dpi / 96.0; HWND window = CreateWindow( window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); if (!window) { return false; } UpdateTheme(window); return OnCreate(); } bool Win32Window::Show() { return ShowWindow(window_handle_, SW_SHOWNORMAL); } // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { if (message == WM_NCCREATE) { auto window_struct = reinterpret_cast(lparam); SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast(window_struct->lpCreateParams)); auto that = static_cast(window_struct->lpCreateParams); EnableFullDpiSupportIfAvailable(window); that->window_handle_ = window; } else if (Win32Window* that = GetThisFromHandle(window)) { return that->MessageHandler(window, message, wparam, lparam); } return DefWindowProc(window, message, wparam, lparam); } LRESULT Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { switch (message) { case WM_DESTROY: window_handle_ = nullptr; Destroy(); if (quit_on_close_) { PostQuitMessage(0); } return 0; case WM_DPICHANGED: { auto newRectSize = reinterpret_cast(lparam); LONG newWidth = newRectSize->right - newRectSize->left; LONG newHeight = newRectSize->bottom - newRectSize->top; SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE); return 0; } case WM_SIZE: { RECT rect = GetClientArea(); if (child_content_ != nullptr) { // Size and position the child window. MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); } return 0; } case WM_ACTIVATE: if (child_content_ != nullptr) { SetFocus(child_content_); } return 0; case WM_DWMCOLORIZATIONCOLORCHANGED: UpdateTheme(hwnd); return 0; } return DefWindowProc(window_handle_, message, wparam, lparam); } void Win32Window::Destroy() { OnDestroy(); if (window_handle_) { DestroyWindow(window_handle_); window_handle_ = nullptr; } if (g_active_window_count == 0) { WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); } } Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { return reinterpret_cast( GetWindowLongPtr(window, GWLP_USERDATA)); } void Win32Window::SetChildContent(HWND content) { child_content_ = content; SetParent(content, window_handle_); RECT frame = GetClientArea(); MoveWindow(content, frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, true); SetFocus(child_content_); } RECT Win32Window::GetClientArea() { RECT frame; GetClientRect(window_handle_, &frame); return frame; } HWND Win32Window::GetHandle() { return window_handle_; } void Win32Window::SetQuitOnClose(bool quit_on_close) { quit_on_close_ = quit_on_close; } bool Win32Window::OnCreate() { // No-op; provided for subclasses. return true; } void Win32Window::OnDestroy() { // No-op; provided for subclasses. } void Win32Window::UpdateTheme(HWND const window) { DWORD light_mode; DWORD light_mode_size = sizeof(light_mode); LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD, nullptr, &light_mode, &light_mode_size); if (result == ERROR_SUCCESS) { BOOL enable_dark_mode = light_mode == 0; DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, &enable_dark_mode, sizeof(enable_dark_mode)); } } ================================================ FILE: plugins/menubar/example/windows/runner/win32_window.h ================================================ #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ #include #include #include #include // A class abstraction for a high DPI-aware Win32 Window. Intended to be // inherited from by classes that wish to specialize with custom // rendering and input handling class Win32Window { public: struct Point { unsigned int x; unsigned int y; Point(unsigned int x, unsigned int y) : x(x), y(y) {} }; struct Size { unsigned int width; unsigned int height; Size(unsigned int width, unsigned int height) : width(width), height(height) {} }; Win32Window(); virtual ~Win32Window(); // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a // consistent size this function will scale the inputted width and height as // as appropriate for the default monitor. The window is invisible until // |Show| is called. Returns true if the window was created successfully. bool Create(const std::wstring& title, const Point& origin, const Size& size); // Show the current window. Returns true if the window was successfully shown. bool Show(); // Release OS resources associated with window. void Destroy(); // Inserts |content| into the window tree. void SetChildContent(HWND content); // Returns the backing Window handle to enable clients to set icon and other // window properties. Returns nullptr if the window has been destroyed. HWND GetHandle(); // If true, closing this window will quit the application. void SetQuitOnClose(bool quit_on_close); // Return a RECT representing the bounds of the current client area. RECT GetClientArea(); protected: // Processes and route salient window messages for mouse handling, // size change and DPI. Delegates handling of these to member overloads that // inheriting classes can handle. virtual LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Called when CreateAndShow is called, allowing subclass window-related // setup. Subclasses should return false if setup fails. virtual bool OnCreate(); // Called when Destroy is called. virtual void OnDestroy(); private: friend class WindowClassRegistrar; // OS callback called by message pump. Handles the WM_NCCREATE message which // is passed when the non-client area is being created and enables automatic // non-client DPI scaling so that the non-client area automatically // responsponds to changes in DPI. All other messages are handled by // MessageHandler. static LRESULT CALLBACK WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Retrieves a class instance pointer for |window| static Win32Window* GetThisFromHandle(HWND const window) noexcept; // Update the window frame's theme to match the system theme. static void UpdateTheme(HWND const window); bool quit_on_close_ = false; // window handle for top level window. HWND window_handle_ = nullptr; // window handle for hosted content. HWND child_content_ = nullptr; }; #endif // RUNNER_WIN32_WINDOW_H_ ================================================ FILE: plugins/menubar/lib/menubar.dart ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. export 'src/native_menu_item.dart'; export 'src/set_application_menu.dart'; ================================================ FILE: plugins/menubar/lib/src/menu_channel.dart ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'dart:async'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'native_menu_item.dart'; /// Whether or not the menu item is a divider, as a boolean. If true, no other /// The name of the plugin's platform channel. const String _kMenuChannelName = 'flutter/menubar'; /// The method name to instruct the native plugin to set the menu. // /// The argument to this method will be an array of map representations /// of menus that should be set as top-level menu items. const String _kMenuSetMethod = 'Menubar.SetMenu'; /// The method name for the Dart-side callback called when a menu item is /// selected. // /// The argument to this method must be the ID of the selected menu item, as /// provided in the kIdKey field in the kMenuSetMethod call. const String _kMenuItemSelectedCallbackMethod = 'Menubar.SelectedCallback'; // Keys for the map representations of menus sent to kMenuSetMethod. /// The ID of the menu item, as an integer. If present, this indicates that the /// menu item should trigger a kMenuItemSelectedCallbackMethod call when /// selected. const String _kIdKey = 'id'; /// The label that should be displayed for the menu, as a string. const String _kLabelKey = 'label'; /// The string corresponding to the shortcut key equivalent without modifiers. /// /// When menu support moves into Flutter itself, this will likely use keyId. /// That's not useable for this plugin-based prototype however, since keyId is /// not stable. const String _kShortcutKeyEquivalent = 'keyEquivalent'; /// An alternative to _kShortcutKeyEquivalent for keys that have no string /// equivalent. Only this or _kShortcutKeyEquivalent should be specified. /// /// This is a partial workaround for the lack of keyId discussed above, to /// handle common shortcut keys that _kShortcutKeyEquivalent can't represent. /// /// See _ShortcutSpecialKeys for possible values. const String _kShortcutSpecialKey = 'specialKey'; /// The modifier flags to apply to the shortcut key. /// /// The value is an int representing a flag set; see below for possible values. const String _kShortcutKeyModifiers = 'keyModifiers'; /// Whether or not the menu item should be enabled, as a boolean. If not present /// the defualt is to enabled the item. const String _kEnabledKey = 'enabled'; /// Menu items that should be shown as a submenu of this item, as an array. const String _kChildrenKey = 'children'; /// Whether or not the menu item is a divider, as a boolean. If true, no other /// keys will be present. const String _kDividerKey = 'isDivider'; // Values for _kShortcutKeyModifiers. const int _shortcutModifierMeta = 1 << 0; const int _shortcutModifierShift = 1 << 1; const int _shortcutModifierAlt = 1 << 2; const int _shortcutModifierControl = 1 << 3; /// Values for _kShortcutSpecialKey. final _shortcutSpecialKeyValues = { LogicalKeyboardKey.f1: 1, LogicalKeyboardKey.f2: 2, LogicalKeyboardKey.f3: 3, LogicalKeyboardKey.f4: 4, LogicalKeyboardKey.f5: 5, LogicalKeyboardKey.f6: 6, LogicalKeyboardKey.f7: 7, LogicalKeyboardKey.f8: 8, LogicalKeyboardKey.f9: 9, LogicalKeyboardKey.f10: 10, LogicalKeyboardKey.f11: 11, LogicalKeyboardKey.f12: 12, LogicalKeyboardKey.backspace: 13, LogicalKeyboardKey.delete: 14, }; /// A singleton object that handles the interaction with the menu bar platform /// channel. class MenuChannel { /// Private constructor. MenuChannel._() { _platformChannel.setMethodCallHandler(_callbackHandler); } final MethodChannel _platformChannel = const MethodChannel(_kMenuChannelName); /// Map from unique identifiers assigned by this class to the callbacks for /// those menu items. final Map _selectionCallbacks = {}; /// The ID to use the next time a menu item needs an ID assigned. int _nextMenuItemId = 1; /// Whether or not a call to [_kMenuSetMethod] is outstanding. /// /// This is used to drop any menu callbacks that aren't received until /// after a new call to setMenu, so that clients don't received unexpected /// stale callbacks. bool _updateInProgress = false; /// The static instance of the menu channel. static final MenuChannel instance = new MenuChannel._(); /// Sets the native application menu to [menus]. /// /// How exactly this is handled is subject to platform interpretation. /// For instance, special menus that are handled entirely on the native /// side might be added to the provided menus. Future setMenu(List menus) async { try { _updateInProgress = true; await _platformChannel.invokeMethod( _kMenuSetMethod, _channelRepresentationForMenus(menus)); _updateInProgress = false; } on PlatformException catch (e) { print('Platform exception setting menu: ${e.message}'); } } /// Converts [menus] to a representation that can be sent in the arguments to /// [_kMenuSetMethod]. /// /// As a side-effect, repopulates _selectionCallbacks with a mapping from /// the IDs assigned to any menu item with a selection handler to the /// callback that should be triggered. List _channelRepresentationForMenus(List menus) { _selectionCallbacks.clear(); _nextMenuItemId = 1; return menus.map(_channelRepresentationForMenuItem).toList(); } /// Returns a representation of [item] suitable for passing over the /// platform channel to the native plugin. Map _channelRepresentationForMenuItem( AbstractNativeMenuItem item) { final representation = {}; if (item is NativeMenuDivider) { representation[_kDividerKey] = true; } else { representation[_kLabelKey] = item.label; if (item is NativeSubmenu) { representation[_kChildrenKey] = _channelRepresentationForMenu(item.children); } else if (item is NativeMenuItem) { final handler = item.onSelected; if (handler == null) { representation[_kEnabledKey] = false; } else { representation[_kIdKey] = _storeMenuCallback(handler); } final shortcut = item.shortcut; if (shortcut != null) { _addShortcutToRepresentation(shortcut, representation); } } else { throw ArgumentError( 'Unknown AbstractNativeMenuItem type: $item (${item.runtimeType})'); } } return representation; } /// Returns the representation of [menu] suitable for passing over the /// platform channel to the native plugin. List _channelRepresentationForMenu( List menu) { final menuItemRepresentations = []; // Dividers are only allowed after non-divider items (see ApplicationMenu). var skipNextDivider = true; for (final menuItem in menu) { final isDivider = menuItem is NativeMenuDivider; if (isDivider && skipNextDivider) { continue; } skipNextDivider = isDivider; menuItemRepresentations.add(_channelRepresentationForMenuItem(menuItem)); } // If the last item is a divider, remove it (see ApplicationMenu). if (skipNextDivider && menuItemRepresentations.isNotEmpty) { menuItemRepresentations.removeLast(); } return menuItemRepresentations; } /// Populates [channelRepresentation] with the platform channel representation /// of [shortcut], using [_kShortcutKeyEquivalent], [_kShortcutSpecialKey], /// and/or [_kShortcutKeyModifiers]. void _addShortcutToRepresentation( LogicalKeySet shortcut, Map channelRepresentation) { var hasNonModifierKey = false; var modifiers = 0; for (final key in shortcut.keys) { if (key == LogicalKeyboardKey.meta) { modifiers |= _shortcutModifierMeta; } else if (key == LogicalKeyboardKey.shift) { modifiers |= _shortcutModifierShift; } else if (key == LogicalKeyboardKey.alt) { modifiers |= _shortcutModifierAlt; } else if (key == LogicalKeyboardKey.control) { modifiers |= _shortcutModifierControl; } else { if (hasNonModifierKey) { throw ArgumentError('Invalid menu item shortcut: $shortcut\n' 'Menu items must have exactly one non-modifier key.'); } if (key.keyLabel.isNotEmpty) { channelRepresentation[_kShortcutKeyEquivalent] = key.keyLabel.toLowerCase(); } else { final specialKey = _shortcutSpecialKeyValues[key]; if (specialKey == null) { throw ArgumentError('Unsupported menu shortcut key: $key\n' 'Please add this key to the special key mapping.'); } channelRepresentation[_kShortcutSpecialKey] = specialKey; } hasNonModifierKey = true; } } if (!hasNonModifierKey) { throw ArgumentError('Invalid menu item shortcut: $shortcut\n' 'Menu items must have exactly one non-modifier key.'); } channelRepresentation[_kShortcutKeyModifiers] = modifiers; } /// Stores [callback] for use plugin callback handling, returning the ID /// under which it was stored. /// /// The returned ID should be attached to the menu so that the native plugin /// can identify the menu item selected in the callback. int _storeMenuCallback(VoidCallback callback) { final id = _nextMenuItemId++; _selectionCallbacks[id] = callback; return id; } /// Mediates between the platform channel callback and the client callback. Future _callbackHandler(MethodCall methodCall) async { if (methodCall.method == _kMenuItemSelectedCallbackMethod) { if (_updateInProgress) { // Drop stale callbacks. // TODO: Evaluate whether this works in practice, or if races are // regular occurences that clients will need to be prepared to // handle (in which case a more complex ID system will be needed). print('Warning: Menu selection callback received during menu update.'); return; } final int menuItemId = methodCall.arguments; final callback = _selectionCallbacks[menuItemId]; if (callback == null) { throw Exception('Unknown menu item ID $menuItemId'); } callback(); } } } ================================================ FILE: plugins/menubar/lib/src/native_menu_item.dart ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'package:flutter/widgets.dart'; /// The base type for an individual menu item that can be shown in a menu. abstract class AbstractNativeMenuItem { /// Creates a new menu item with the give label. const AbstractNativeMenuItem(this.label); /// The displayed label for the menu item. final String label; } /// A standard menu item, with no submenus. class NativeMenuItem extends AbstractNativeMenuItem { /// Creates a new menu item with the given [label] and options. const NativeMenuItem({ required String label, this.shortcut, this.onSelected, }) : super(label); /// The callback to call whenever the menu item is selected. /// /// If null, the menu item is disabled. final VoidCallback? onSelected; /// The shortcut/accelerator for the menu item, if any. /// /// Note: Currently modifiers have only Left or Right variants, so must be /// specified with one of those. The actual left/right distinction will be /// ignored. This part of the API is likely to change in the future. /// /// Example: a Save menu item would likely use: /// LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.keyS) final LogicalKeySet? shortcut; } /// A menu item continaing a submenu. /// /// The item itself can't be selected, it just displays the submenu. class NativeSubmenu extends AbstractNativeMenuItem { /// Creates a new submenu with the given [label] and [children]. const NativeSubmenu({required String label, required this.children}) : super(label); /// The menu items contained in the submenu. final List children; } /// A menu item that serves as a divider, generally drawn as a line. class NativeMenuDivider extends AbstractNativeMenuItem { /// Creates a new divider item. const NativeMenuDivider() : super(''); } ================================================ FILE: plugins/menubar/lib/src/set_application_menu.dart ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'dart:async'; import 'menu_channel.dart'; import 'native_menu_item.dart'; /// Sets the application menu for the app based on the [menuSpec]. /// /// Adjacent [NativeMenuDivider]s will be coalesced, leading and/or trailing /// [NativeMenuDivider]s will be removed. Future setApplicationMenu(List menuSpec) async { await MenuChannel.instance.setMenu(menuSpec); } ================================================ FILE: plugins/menubar/linux/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) set(PROJECT_NAME "menubar") project(${PROJECT_NAME} LANGUAGES CXX) set(PLUGIN_NAME "${PROJECT_NAME}_plugin") add_library(${PLUGIN_NAME} SHARED "${PLUGIN_NAME}.cc" ) apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) ================================================ FILE: plugins/menubar/linux/include/menubar/menubar_plugin.h ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef PLUGINS_MENUBAR_LINUX_MENUBAR_PLUGIN_H_ #define PLUGINS_MENUBAR_LINUX_MENUBAR_PLUGIN_H_ // A plugin to control a native menubar. #include G_BEGIN_DECLS #ifdef FLUTTER_PLUGIN_IMPL #define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) #else #define FLUTTER_PLUGIN_EXPORT #endif G_DECLARE_FINAL_TYPE(FlMenubarPlugin, fl_menubar_plugin, FL, MENUBAR_PLUGIN, GObject) FLUTTER_PLUGIN_EXPORT FlMenubarPlugin* fl_menubar_plugin_new( FlPluginRegistrar* registrar); FLUTTER_PLUGIN_EXPORT void menubar_plugin_register_with_registrar( FlPluginRegistrar* registrar); G_END_DECLS #endif // PLUGINS_MENUBAR_LINUX_MENUBAR_PLUGIN_H_ ================================================ FILE: plugins/menubar/linux/menubar_plugin.cc ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "include/menubar/menubar_plugin.h" #include #include // See menu_channel.dart for documentation. const char kChannelName[] = "flutter/menubar"; const char kBadArgumentsError[] = "Bad Arguments"; const char kNoScreenError[] = "No Screen"; const char kFailureError[] = "Failure"; const char kMenuSetMethod[] = "Menubar.SetMenu"; const char kMenuItemSelectedCallbackMethod[] = "Menubar.SelectedCallback"; const char kIdKey[] = "id"; const char kLabelKey[] = "label"; const char kEnabledKey[] = "enabled"; const char kChildrenKey[] = "children"; const char kIsDividerKey[] = "isDivider"; struct _FlMenubarPlugin { GObject parent_instance; FlPluginRegistrar* registrar; // Connection to Flutter engine. FlMethodChannel* channel; // Special handle used to indicate a divider. GMenuItem* divider_item; // Menu being shown to the user. GMenu* menu; }; G_DEFINE_TYPE(FlMenubarPlugin, fl_menubar_plugin, g_object_get_type()) static GMenu* value_to_menu(FlMenubarPlugin* self, FlValue* value, GError** error); // Convert a value received from Flutter to a GtkMenuItem. static GMenuItem* value_to_menu_item(FlMenubarPlugin* self, FlValue* value, GError** error) { if (fl_value_get_type(value) != FL_VALUE_TYPE_MAP) { g_set_error(error, 0, 0, "Menu item map missing or malformed"); return nullptr; } FlValue* is_divider_value = fl_value_lookup_string(value, kIsDividerKey); if (is_divider_value != nullptr && fl_value_get_type(is_divider_value) == FL_VALUE_TYPE_BOOL && fl_value_get_bool(is_divider_value)) { return G_MENU_ITEM(g_object_ref(self->divider_item)); } g_autoptr(GMenuItem) item = g_menu_item_new(nullptr, nullptr); FlValue* id_value = fl_value_lookup_string(value, kIdKey); if (id_value != nullptr && fl_value_get_type(id_value) == FL_VALUE_TYPE_INT) { g_menu_item_set_action_and_target(item, "app.flutter-menu", "x", fl_value_get_int(id_value)); } FlValue* enabled_value = fl_value_lookup_string(value, kEnabledKey); if (enabled_value != nullptr && fl_value_get_type(enabled_value) == FL_VALUE_TYPE_BOOL && !fl_value_get_bool(enabled_value)) g_menu_item_set_action_and_target(item, "app.flutter-menu-inactive", nullptr); FlValue* label_value = fl_value_lookup_string(value, kLabelKey); if (label_value != nullptr && fl_value_get_type(label_value) == FL_VALUE_TYPE_STRING) g_menu_item_set_label(item, fl_value_get_string(label_value)); FlValue* children = fl_value_lookup_string(value, kChildrenKey); if (children != nullptr) { g_autoptr(GMenu) sub_menu = value_to_menu(self, children, error); if (sub_menu == nullptr) return nullptr; g_menu_item_set_submenu(item, G_MENU_MODEL(sub_menu)); } return G_MENU_ITEM(g_object_ref(item)); } // Convert a value received from Flutter to a GtkMenuItem. static GMenu* value_to_menu(FlMenubarPlugin* self, FlValue* value, GError** error) { if (fl_value_get_type(value) != FL_VALUE_TYPE_LIST) { g_set_error(error, 0, 0, "Menu list missing or malformed"); return nullptr; } g_autoptr(GMenu) menu = g_menu_new(); g_autoptr(GMenu) section = nullptr; for (size_t i = 0; i < fl_value_get_length(value); i++) { g_autoptr(GMenuItem) item = value_to_menu_item(self, fl_value_get_list_value(value, i), error); if (item == nullptr) return nullptr; if (item == self->divider_item) { if (section != nullptr) g_menu_append_section(menu, nullptr, G_MENU_MODEL(section)); g_clear_object(§ion); } else { if (section == nullptr) section = g_menu_new(); g_menu_append_item(section, item); } } if (section != nullptr) g_menu_append_section(menu, nullptr, G_MENU_MODEL(section)); return G_MENU(g_object_ref(menu)); } // Called when a menu item is activated. static void menu_activate_cb(FlMenubarPlugin* self, GVariant* parameter) { gint64 id = g_variant_get_int64(parameter); g_autoptr(FlValue) result = fl_value_new_int(id); fl_method_channel_invoke_method(self->channel, kMenuItemSelectedCallbackMethod, result, nullptr, nullptr, nullptr); } // Sets the menu. static FlMethodResponse* menu_set(FlMenubarPlugin* self, FlValue* args) { g_autoptr(GError) error = nullptr; g_autoptr(GMenu) menu = value_to_menu(self, args, &error); if (menu == nullptr) { return FL_METHOD_RESPONSE(fl_method_error_response_new( kBadArgumentsError, error->message, nullptr)); } FlView* view = fl_plugin_registrar_get_view(self->registrar); if (view == nullptr) { return FL_METHOD_RESPONSE( fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); } GtkApplication* app = gtk_window_get_application( GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view)))); if (app == nullptr) { return FL_METHOD_RESPONSE(fl_method_error_response_new( kFailureError, "Unable to get application", nullptr)); } // Replace existing menu with this one g_menu_remove_all(self->menu); g_menu_append_section(self->menu, nullptr, G_MENU_MODEL(menu)); return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); } // Called when a method call is received from Flutter. static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data) { FlMenubarPlugin* self = FL_MENUBAR_PLUGIN(user_data); const gchar* method = fl_method_call_get_name(method_call); FlValue* args = fl_method_call_get_args(method_call); g_autoptr(FlMethodResponse) response = nullptr; if (strcmp(method, kMenuSetMethod) == 0) { response = menu_set(self, args); } else { response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); } g_autoptr(GError) error = nullptr; if (!fl_method_call_respond(method_call, response, &error)) g_warning("Failed to send method call response: %s", error->message); } static void fl_menubar_plugin_dispose(GObject* object) { FlMenubarPlugin* self = FL_MENUBAR_PLUGIN(object); g_clear_object(&self->registrar); g_clear_object(&self->channel); g_clear_object(&self->menu); g_clear_object(&self->divider_item); G_OBJECT_CLASS(fl_menubar_plugin_parent_class)->dispose(object); } static void fl_menubar_plugin_class_init(FlMenubarPluginClass* klass) { G_OBJECT_CLASS(klass)->dispose = fl_menubar_plugin_dispose; } static void fl_menubar_plugin_init(FlMenubarPlugin* self) { self->divider_item = g_menu_item_new(nullptr, nullptr); } FlMenubarPlugin* fl_menubar_plugin_new(FlPluginRegistrar* registrar) { FlMenubarPlugin* self = FL_MENUBAR_PLUGIN(g_object_new(fl_menubar_plugin_get_type(), nullptr)); self->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar)); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); self->channel = fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), kChannelName, FL_METHOD_CODEC(codec)); fl_method_channel_set_method_call_handler(self->channel, method_call_cb, g_object_ref(self), g_object_unref); // Add a GAction for the menubar to trigger. FlView* view = fl_plugin_registrar_get_view(self->registrar); GtkApplication* app = nullptr; if (view != nullptr) { app = gtk_window_get_application( GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view)))); } if (app != nullptr) { g_autoptr(GSimpleAction) inactive_action = g_simple_action_new("flutter-menu-inactive", nullptr); g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(inactive_action)); g_simple_action_set_enabled(inactive_action, FALSE); g_autoptr(GSimpleAction) action = g_simple_action_new("flutter-menu", G_VARIANT_TYPE_INT64); g_simple_action_set_enabled(action, TRUE); g_signal_connect_object(action, "activate", G_CALLBACK(menu_activate_cb), self, G_CONNECT_SWAPPED); g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(action)); // Set an empty menubar now, as GTK doesn't detect it being changed later // on. https://gitlab.gnome.org/GNOME/gtk/-/issues/2834 self->menu = g_menu_new(); gtk_application_set_menubar(app, G_MENU_MODEL(self->menu)); g_object_notify(G_OBJECT(gtk_settings_get_default()), "gtk-shell-shows-menubar"); } return self; } void menubar_plugin_register_with_registrar(FlPluginRegistrar* registrar) { FlMenubarPlugin* plugin = fl_menubar_plugin_new(registrar); g_object_unref(plugin); } ================================================ FILE: plugins/menubar/macos/Classes/FLEMenubarPlugin.h ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #import #import /** * A Flutter plugin to control the native menu bar. */ @interface FLEMenubarPlugin : NSObject /** * The menu item that Flutter-provided menus should be inserted after. If unset, Flutter-provided * menus will be inserted after the application menu (i.e., starting at index 1). */ @property(nonatomic) NSMenuItem *insertAfterMenuItem; @end ================================================ FILE: plugins/menubar/macos/Classes/FLEMenubarPlugin.m ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #import "FLEMenubarPlugin.h" // See menu_channel.dart for documentation. static NSString *const kChannelName = @"flutter/menubar"; static NSString *const kMenuSetMethod = @"Menubar.SetMenu"; static NSString *const kMenuItemSelectedCallbackMethod = @"Menubar.SelectedCallback"; static NSString *const kIdKey = @"id"; static NSString *const kLabelKey = @"label"; static NSString *const kShortcutKeyEquivalent = @"keyEquivalent"; static NSString *const kShortcutSpecialKey = @"specialKey"; static NSString *const kShortcutKeyModifiers = @"keyModifiers"; static NSString *const kEnabledKey = @"enabled"; static NSString *const kChildrenKey = @"children"; static NSString *const kDividerKey = @"isDivider"; static const int kFlutterShortcutModifierMeta = 1 << 0; static const int kFlutterShortcutModifierShift = 1 << 1; static const int kFlutterShortcutModifierAlt = 1 << 2; static const int kFlutterShortcutModifierControl = 1 << 3; // Returns the string used by NSMenuItem for the given special key. // See _shortcutSpecialKeyValues in menu_channel.dart for values. static NSString *KeyEquivalentCharacterForSpecialKey(int specialKey) { unichar character; switch (specialKey) { case 1: character = NSF1FunctionKey; break; case 2: character = NSF2FunctionKey; break; case 3: character = NSF3FunctionKey; break; case 4: character = NSF4FunctionKey; break; case 5: character = NSF5FunctionKey; break; case 6: character = NSF6FunctionKey; break; case 7: character = NSF7FunctionKey; break; case 8: character = NSF8FunctionKey; break; case 9: character = NSF9FunctionKey; break; case 10: character = NSF10FunctionKey; break; case 11: character = NSF11FunctionKey; break; case 12: character = NSF12FunctionKey; break; case 13: character = NSBackspaceCharacter; break; case 14: character = NSDeleteCharacter; break; default: return nil; } return [NSString stringWithCharacters:&character length:1]; } // Returns the NSEventModifierFlags of |modifiers|, a value from kShortcutKeyModifiers. static NSEventModifierFlags KeyEquivalentModifierMaskForModifiers(NSNumber *modifiers) { int flutterModifierFlags = modifiers.intValue; NSEventModifierFlags flags = 0; if (flutterModifierFlags & kFlutterShortcutModifierMeta) flags |= NSEventModifierFlagCommand; if (flutterModifierFlags & kFlutterShortcutModifierShift) flags |= NSEventModifierFlagShift; if (flutterModifierFlags & kFlutterShortcutModifierAlt) flags |= NSEventModifierFlagOption; if (flutterModifierFlags & kFlutterShortcutModifierControl) flags |= NSEventModifierFlagControl; return flags; } @implementation FLEMenubarPlugin { // The channel used to communicate with Flutter. FlutterMethodChannel *_channel; } - (instancetype)initWithChannel:(FlutterMethodChannel *)channel { self = [super init]; if (self) { _channel = channel; } return self; } /** * Removes any top-level menus added by this plugin. */ - (void)removeFlutterMenus { NSMenu *mainMenu = NSApp.mainMenu; // Remove in reverse order to simplify iteration while removing. for (NSInteger i = mainMenu.numberOfItems - 1; i >= 0; --i) { if ([mainMenu itemAtIndex:i].representedObject == self) { [mainMenu removeItemAtIndex:i]; } } } /** * Returns the index in the application's mainMenu where Flutter menu items should be inserted. */ - (NSInteger)menuInsertionIndex { NSMenu *mainMenu = NSApp.mainMenu; NSInteger index = self.insertAfterMenuItem ? [mainMenu indexOfItem:self.insertAfterMenuItem] : -1; // If there's no (valid) insert-after, insert after the application menu at index zero. if (index == -1) { index = 0; } return index + 1; } /** * Removes an Flutter menu items that were previously added, then builds and adds new top-level menu * items constructed from |representation|. */ - (void)rebuildFlutterMenusFromRepresentation:(NSArray *)representation { [self removeFlutterMenus]; NSMenu *mainMenu = NSApp.mainMenu; NSInteger insertionIndex = [self menuInsertionIndex]; for (NSDictionary *item in representation.reverseObjectEnumerator) { NSMenuItem *menuItem = [self menuItemFromFlutterRepresentation:item]; menuItem.representedObject = self; [mainMenu insertItem:menuItem atIndex:insertionIndex]; } } /** * Constructs and returns an NSMenuItem corresponding to the item in |representation|, including * recursively creating children if it has a submenu. */ - (NSMenuItem *)menuItemFromFlutterRepresentation:(NSDictionary *)representation { if (representation[kDividerKey]) { return [NSMenuItem separatorItem]; } else { NSString *title = representation[kLabelKey]; NSNumber *boxedID = representation[kIdKey]; NSString *keyEquivalent = nil; if (representation[kShortcutKeyEquivalent]) { keyEquivalent = representation[kShortcutKeyEquivalent]; } else if (representation[kShortcutSpecialKey]) { int specialKey = ((NSNumber *)representation[kShortcutSpecialKey]).intValue; keyEquivalent = KeyEquivalentCharacterForSpecialKey(specialKey); } SEL action = (boxedID ? @selector(flutterMenuItemSelected:) : NULL); NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:title action:action keyEquivalent:(keyEquivalent ?: @"")]; if (keyEquivalent) { item.keyEquivalentModifierMask = KeyEquivalentModifierMaskForModifiers(representation[kShortcutKeyModifiers]); } if (boxedID) { item.tag = boxedID.intValue; item.target = self; } NSNumber *enabled = representation[kEnabledKey]; if (enabled) { item.enabled = enabled.boolValue; } NSArray *children = representation[kChildrenKey]; if (children) { NSMenu *submenu = [[NSMenu alloc] initWithTitle:title]; submenu.autoenablesItems = NO; for (NSDictionary *child in children) { [submenu addItem:[self menuItemFromFlutterRepresentation:child]]; } item.submenu = submenu; } return item; } } /** * Invokes kMenuItemSelectedCallbackMethod with the senders ID. * * Used as the callback for all Flutter-created menu items that have IDs. */ - (void)flutterMenuItemSelected:(id)sender { NSMenuItem *item = sender; [_channel invokeMethod:kMenuItemSelectedCallbackMethod arguments:@(item.tag)]; } #pragma FlutterPlugin implementation + (void)registerWithRegistrar:(id)registrar { FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kChannelName binaryMessenger:registrar.messenger]; FLEMenubarPlugin *instance = [[FLEMenubarPlugin alloc] initWithChannel:channel]; [registrar addMethodCallDelegate:instance channel:channel]; } - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { if ([call.method isEqualToString:kMenuSetMethod]) { NSArray *menus = call.arguments; [self rebuildFlutterMenusFromRepresentation:menus]; result(nil); } else { result(FlutterMethodNotImplemented); } } @end ================================================ FILE: plugins/menubar/macos/Classes/MenubarPlugin.swift ================================================ // Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import FlutterMacOS import Foundation public class MenubarPlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { FLEMenubarPlugin.register(with: registrar) } } ================================================ FILE: plugins/menubar/macos/menubar.podspec ================================================ # # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html # Pod::Spec.new do |s| s.name = 'menubar' s.version = '0.0.2' s.summary = 'Provides the ability to add menubar items with Dart callbacks.' s.description = <<-DESC Provides the ability to add menubar items with Dart callbacks. DESC s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/menubar' s.license = { :file => '../LICENSE' } s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'FlutterMacOS' s.platform = :osx s.osx.deployment_target = '10.11' end ================================================ FILE: plugins/menubar/pubspec.yaml ================================================ name: menubar description: Provides the ability to add native menubar items with Dart callbacks. version: 0.2.0 # Do not publish this plugin. See: # https://github.com/google/flutter-desktop-embedding/blob/master/plugins/README.md#using-plugins publish_to: none flutter: plugin: platforms: linux: pluginClass: MenubarPlugin macos: pluginClass: MenubarPlugin windows: pluginClass: MenubarPlugin environment: sdk: '>=2.12.0-0 <3.0.0' dependencies: flutter: sdk: flutter ================================================ FILE: plugins/menubar/windows/.gitignore ================================================ flutter/ # Visual Studio user-specific files. *.suo *.user *.userosscache *.sln.docstates # Visual Studio build-related files. x64/ x86/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ ================================================ FILE: plugins/menubar/windows/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.15) set(PROJECT_NAME "menubar") project(${PROJECT_NAME} LANGUAGES CXX) set(PLUGIN_NAME "${PROJECT_NAME}_plugin") add_library(${PLUGIN_NAME} SHARED "${PLUGIN_NAME}.cpp" ) apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) # List of absolute paths to libraries that should be bundled with the plugin set(menubar_bundled_libraries "" PARENT_SCOPE ) ================================================ FILE: plugins/menubar/windows/include/menubar/menubar_plugin.h ================================================ #ifndef FLUTTER_PLUGIN_MENUBAR_PLUGIN_H_ #define FLUTTER_PLUGIN_MENUBAR_PLUGIN_H_ #include #ifdef FLUTTER_PLUGIN_IMPL #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) #else #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) #endif #if defined(__cplusplus) extern "C" { #endif FLUTTER_PLUGIN_EXPORT void MenubarPluginRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar); #if defined(__cplusplus) } // extern "C" #endif #endif // FLUTTER_PLUGIN_MENUBAR_PLUGIN_H_ ================================================ FILE: plugins/menubar/windows/menubar_plugin.cpp ================================================ #include "include/menubar/menubar_plugin.h" #include #include #include #include #include #include namespace { using flutter::EncodableList; using flutter::EncodableMap; using flutter::EncodableValue; // See menu_channel.dart for documentation. const char kChannelName[] = "flutter/menubar"; const char kMenuSetMethod[] = "Menubar.SetMenu"; const char kMenuItemSelectedCallbackMethod[] = "Menubar.SelectedCallback"; const char kIdKey[] = "id"; const char kLabelKey[] = "label"; const char kEnabledKey[] = "enabled"; const char kChildrenKey[] = "children"; const char kIsDividerKey[] = "isDivider"; const char kBadArgumentsError[] = "Bad Arguments"; const char kMenuConstructionError[] = "Menu Construction Error"; // Starting point for the generated menu IDs. const unsigned int kFirstMenuId = 1000; // Looks for |key| in |map|, returning the associated value if it is present, or // a nullptr if not. const EncodableValue *ValueOrNull(const EncodableMap &map, const char *key) { auto it = map.find(EncodableValue(key)); if (it == map.end()) { return nullptr; } return &(it->second); } // Converts the given UTF-8 string to UTF-16. std::wstring Utf16FromUtf8(const std::string &utf8_string) { if (utf8_string.empty()) { return std::wstring(); } int target_length = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string.data(), static_cast(utf8_string.length()), nullptr, 0); if (target_length == 0) { return std::wstring(); } std::wstring utf16_string; utf16_string.resize(target_length); int converted_length = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string.data(), static_cast(utf8_string.length()), utf16_string.data(), target_length); if (converted_length == 0) { return std::wstring(); } return utf16_string; } class MenubarPlugin : public flutter::Plugin { public: static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); MenubarPlugin( flutter::PluginRegistrarWindows *registrar, std::unique_ptr> channel); virtual ~MenubarPlugin(); private: // Fills |menu| with items constructed from the given method channel // representation of a menu. // // On failure, returns an EncodableValue with error details. static std::optional PopulateMenu( HMENU menu, const EncodableList &representation); // Constructs a menu item corresponding to the item in |representation|, // including recursively creating children if it has a submenu, and adds it to // |menu|. // // On failure, returns an EncodableValue with error details. static std::optional AddMenuItem( HMENU menu, const EncodableMap &representation); // Called when a method is called on this plugin's channel from Dart. void HandleMethodCall( const flutter::MethodCall<> &method_call, std::unique_ptr> result); // Called for top-level WindowProc delegation. std::optional HandleWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); // The registrar for this plugin. flutter::PluginRegistrarWindows *registrar_; // The cannel to send menu item activations on. std::unique_ptr> channel_; // The ID of the registered WindowProc handler. int window_proc_id_; }; // static void MenubarPlugin::RegisterWithRegistrar( flutter::PluginRegistrarWindows *registrar) { auto channel = std::make_unique>( registrar->messenger(), kChannelName, &flutter::StandardMethodCodec::GetInstance()); auto *channel_pointer = channel.get(); auto plugin = std::make_unique(registrar, std::move(channel)); channel_pointer->SetMethodCallHandler( [plugin_pointer = plugin.get()](const auto &call, auto result) { plugin_pointer->HandleMethodCall(call, std::move(result)); }); registrar->AddPlugin(std::move(plugin)); } MenubarPlugin::MenubarPlugin( flutter::PluginRegistrarWindows *registrar, std::unique_ptr> channel) : registrar_(registrar), channel_(std::move(channel)) { window_proc_id_ = registrar_->RegisterTopLevelWindowProcDelegate( [this](HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { return HandleWindowProc(hwnd, message, wparam, lparam); }); } MenubarPlugin::~MenubarPlugin() { registrar_->UnregisterTopLevelWindowProcDelegate(window_proc_id_); } // static std::optional MenubarPlugin::PopulateMenu( HMENU menu, const EncodableList &representation) { for (const auto &item : representation) { auto optional_error = AddMenuItem(menu, std::get(item)); if (optional_error) { return optional_error; } } return std::nullopt; } // static std::optional MenubarPlugin::AddMenuItem( HMENU menu, const EncodableMap &representation) { const auto *is_divider = std::get_if(ValueOrNull(representation, kIsDividerKey)); if (is_divider && *is_divider) { if (!::AppendMenu(menu, MF_SEPARATOR, 0, nullptr)) { return EncodableValue(static_cast(::GetLastError())); } } else { const auto *label = std::get_if(ValueOrNull(representation, kLabelKey)); std::wstring wide_label(label ? Utf16FromUtf8(*label) : L""); UINT flags = MF_STRING; const auto *enabled = std::get_if(ValueOrNull(representation, kEnabledKey)); // Default to enabled if no explicit value is provided. flags |= (enabled == nullptr || *enabled) ? MF_ENABLED : MF_GRAYED; const auto *children = std::get_if(ValueOrNull(representation, kChildrenKey)); UINT_PTR item_id; if (children) { flags |= MF_POPUP; HMENU submenu = ::CreatePopupMenu(); PopulateMenu(submenu, *children); item_id = reinterpret_cast(submenu); } else { const auto *menu_id = std::get_if(ValueOrNull(representation, kIdKey)); item_id = menu_id ? (kFirstMenuId + *menu_id) : 0; } if (!::AppendMenu(menu, flags, item_id, wide_label.c_str())) { return EncodableValue(static_cast(::GetLastError())); } } return std::nullopt; } void MenubarPlugin::HandleMethodCall( const flutter::MethodCall<> &method_call, std::unique_ptr> result) { if (method_call.method_name().compare(kMenuSetMethod) == 0) { flutter::FlutterView *view = registrar_->GetView(); HWND window = view ? GetAncestor(view->GetNativeWindow(), GA_ROOT) : nullptr; if (!window) { result->Error(kMenuConstructionError, "Cannot add a menu to a headless engine."); return; } const auto *menu_list = std::get_if(method_call.arguments()); if (!window) { result->Error(kBadArgumentsError, "Expected a list of menus."); return; } HMENU menu = ::CreateMenu(); HMENU previous_menu = ::GetMenu(window); std::optional optional_error = PopulateMenu(menu, *menu_list); if (optional_error) { result->Error(kMenuConstructionError, "Unable to construct menu", EncodableValue(static_cast(::GetLastError()))); return; } if (!::SetMenu(window, menu)) { result->Error(kMenuConstructionError, "Unable to set menu", EncodableValue(static_cast(::GetLastError()))); return; } if (previous_menu) { ::DestroyMenu(previous_menu); } result->Success(); } else { result->NotImplemented(); } } std::optional MenubarPlugin::HandleWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { if (message == WM_COMMAND) { DWORD menu_id = LOWORD(wparam); if (menu_id >= kFirstMenuId) { int32_t flutter_id = menu_id - kFirstMenuId; channel_->InvokeMethod(kMenuItemSelectedCallbackMethod, std::make_unique(flutter_id)); return 0; } } return std::nullopt; } } // namespace void MenubarPluginRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar) { MenubarPlugin::RegisterWithRegistrar( flutter::PluginRegistrarManager::GetInstance() ->GetRegistrar(registrar)); } ================================================ FILE: plugins/window_size/.gitignore ================================================ .dart_tool .packages .flutter-plugins .flutter-plugins-dependencies pubspec.lock ================================================ FILE: plugins/window_size/.metadata ================================================ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled. version: revision: 507062032fa44678100c46250712f6b9dc07ba4b channel: main project_type: plugin # Tracks metadata for the flutter migrate command migration: platforms: - platform: root create_revision: 507062032fa44678100c46250712f6b9dc07ba4b base_revision: 507062032fa44678100c46250712f6b9dc07ba4b - platform: linux create_revision: 507062032fa44678100c46250712f6b9dc07ba4b base_revision: 507062032fa44678100c46250712f6b9dc07ba4b - platform: macos create_revision: 507062032fa44678100c46250712f6b9dc07ba4b base_revision: 507062032fa44678100c46250712f6b9dc07ba4b - platform: windows create_revision: 507062032fa44678100c46250712f6b9dc07ba4b base_revision: 507062032fa44678100c46250712f6b9dc07ba4b # User provided section # List of Local paths (relative to this file) that should be # ignored by the migrate tool. # # Files that are not part of the templates will be ignored by default. unmanaged_files: - 'lib/main.dart' - 'ios/Runner.xcodeproj/project.pbxproj' ================================================ FILE: plugins/window_size/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: plugins/window_size/README.md ================================================ # window_size This plugin allows resizing and repositioning the window containing the Flutter content, as well as querying screen information. This is a prototype, and in the long term is expected to be replaced by [functionality within the Flutter framework](https://flutter.dev/go/desktop-multi-window-support). ## Scope There are currently no plans to add new functionality, such as window minimization and maximization, to this plugin. The goals of this plugin were to: - unblock certain core use cases among very early adopters, and - validate plugin APIs in Flutter itself during early development of the desktop plugin APIs. Now that those goals have been met, and the plugin APIs have been stabilized such that anyone can create and publish desktop Flutter plugins, new functionality will likely only be added here if unblocks a [Flutter top-tier customer](https://github.com/flutter/flutter/wiki/Issue-hygiene#customers). The community is encouraged to create their own plugins for other window manipulation features. ## Supported Platforms - [x] macOS - [x] Windows - [x] Linux Not all operations have been implemented on all platforms, but the core functionality of resizing and repositioning is available for all three. ## Use See [the plugin README](../README.md) for general instructions on using FDE plugins. ### Linux Requires GTK 3.22 or later. ================================================ FILE: plugins/window_size/analysis_options.yaml ================================================ include: ../../analysis_options.yaml ================================================ FILE: plugins/window_size/example/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ migrate_working_dir/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Symbolication related app.*.symbols # Obfuscation related app.*.map.json # Android Studio will place build artifacts here /android/app/debug /android/app/profile /android/app/release ================================================ FILE: plugins/window_size/example/README.md ================================================ # window_size_example Demonstrates how to use the window_size plugin. ## Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flutter project: - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) For help getting started with Flutter development, view the [online documentation](https://docs.flutter.dev/), which offers tutorials, samples, guidance on mobile development, and a full API reference. ================================================ FILE: plugins/window_size/example/integration_test/plugin_integration_test.dart ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:window_size/window_size.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('getWindowInfo sanity check', (tester) async { final windowInfo = await getWindowInfo(); expect(windowInfo.frame.isEmpty, isFalse); expect(windowInfo.scaleFactor > 0, isTrue); expect(windowInfo.screen, isNotNull); }); } ================================================ FILE: plugins/window_size/example/lib/main.dart ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ignore_for_file: public_member_api_docs import 'dart:io'; import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:window_size/window_size.dart' as window_size; void main() { // Try to resize and reposition the window to be half the width and height // of its screen, centered horizontally and shifted up from center. WidgetsFlutterBinding.ensureInitialized(); window_size.getWindowInfo().then((window) { final screen = window.screen; if (screen != null) { final screenFrame = screen.visibleFrame; final width = math.max((screenFrame.width / 2).roundToDouble(), 800.0); final height = math.max((screenFrame.height / 2).roundToDouble(), 600.0); final left = screenFrame.left + ((screenFrame.width - width) / 2).roundToDouble(); final top = screenFrame.top + ((screenFrame.height - height) / 3).roundToDouble(); final frame = Rect.fromLTWH(left, top, width, height); window_size.setWindowFrame(frame); window_size.setWindowMinSize(Size(0.8 * width, 0.8 * height)); window_size.setWindowMaxSize(Size(1.5 * width, 1.5 * height)); window_size .setWindowTitle('window_size Example on ${Platform.operatingSystem}'); } }); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'window_size Example'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({required this.title, Key? key}) : super(key: key); final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headlineMedium, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } } ================================================ FILE: plugins/window_size/example/linux/.gitignore ================================================ flutter/ephemeral ================================================ FILE: plugins/window_size/example/linux/CMakeLists.txt ================================================ # Project-level configuration. cmake_minimum_required(VERSION 3.10) project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "window_size_example") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID set(APPLICATION_ID "com.example.window_size") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(SET CMP0063 NEW) # Load bundled libraries from the lib/ directory relative to the binary. set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") # Root filesystem for cross-building. if(FLUTTER_TARGET_PLATFORM_SYSROOT) set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) endif() # Define build configuration options. if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() # Compilation settings that should be applied to most targets. # # Be cautious about adding new options here, as plugins use this function by # default. In most cases, you should add new options to specific targets instead # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_14) target_compile_options(${TARGET} PRIVATE -Wall -Werror) target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") endfunction() # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") # Define the application target. To change its name, change BINARY_NAME above, # not the value here, or `flutter run` will no longer work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} "main.cc" "my_application.cc" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add dependency libraries. Add any application-specific dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) # Only the install-generated bundle's copy of the executable will launch # correctly, since the resources must in the right relative locations. To avoid # people trying to run the unbundled copy, put it in a subdirectory instead of # the default top-level location. set_target_properties(${BINARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" ) # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) # === Installation === # By default, "installing" just makes a relocatable bundle in the build # directory. set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() # Start with a clean build bundle directory every time. install(CODE " file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") " COMPONENT Runtime) set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) install(FILES "${bundled_library}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endforeach(bundled_library) # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() ================================================ FILE: plugins/window_size/example/linux/flutter/CMakeLists.txt ================================================ # This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.10) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. # Serves the same purpose as list(TRANSFORM ... PREPEND ...), # which isn't available in 3.10. function(list_prepend LIST_NAME PREFIX) set(NEW_LIST "") foreach(element ${${LIST_NAME}}) list(APPEND NEW_LIST "${PREFIX}${element}") endforeach(element) set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) endfunction() # === Flutter Library === # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "fl_basic_message_channel.h" "fl_binary_codec.h" "fl_binary_messenger.h" "fl_dart_project.h" "fl_engine.h" "fl_json_message_codec.h" "fl_json_method_codec.h" "fl_message_codec.h" "fl_method_call.h" "fl_method_channel.h" "fl_method_codec.h" "fl_method_response.h" "fl_plugin_registrar.h" "fl_plugin_registry.h" "fl_standard_message_codec.h" "fl_standard_method_codec.h" "fl_string_codec.h" "fl_value.h" "fl_view.h" "flutter_linux.h" ) list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") target_link_libraries(flutter INTERFACE PkgConfig::GTK PkgConfig::GLIB PkgConfig::GIO ) add_dependencies(flutter flutter_assemble) # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/_phony_ COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ) ================================================ FILE: plugins/window_size/example/linux/flutter/generated_plugin_registrant.cc ================================================ // // Generated file. Do not edit. // // clang-format off #include "generated_plugin_registrant.h" #include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) window_size_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "WindowSizePlugin"); window_size_plugin_register_with_registrar(window_size_registrar); } ================================================ FILE: plugins/window_size/example/linux/flutter/generated_plugin_registrant.h ================================================ // // Generated file. Do not edit. // // clang-format off #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ #include // Registers Flutter plugins. void fl_register_plugins(FlPluginRegistry* registry); #endif // GENERATED_PLUGIN_REGISTRANT_ ================================================ FILE: plugins/window_size/example/linux/flutter/generated_plugins.cmake ================================================ # # Generated file, do not edit. # list(APPEND FLUTTER_PLUGIN_LIST window_size ) list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) endforeach(ffi_plugin) ================================================ FILE: plugins/window_size/example/linux/main.cc ================================================ #include "my_application.h" int main(int argc, char** argv) { g_autoptr(MyApplication) app = my_application_new(); return g_application_run(G_APPLICATION(app), argc, argv); } ================================================ FILE: plugins/window_size/example/linux/my_application.cc ================================================ #include "my_application.h" #include #ifdef GDK_WINDOWING_X11 #include #endif #include "flutter/generated_plugin_registrant.h" struct _MyApplication { GtkApplication parent_instance; char** dart_entrypoint_arguments; }; G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); GtkWindow* window = GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); // Use a header bar when running in GNOME as this is the common style used // by applications and is the setup most users will be using (e.g. Ubuntu // desktop). // If running on X and not using GNOME then just use a traditional title bar // in case the window manager does more exotic layout, e.g. tiling. // If running on Wayland assume the header bar will work (may need changing // if future cases occur). gboolean use_header_bar = TRUE; #ifdef GDK_WINDOWING_X11 GdkScreen* screen = gtk_window_get_screen(window); if (GDK_IS_X11_SCREEN(screen)) { const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); if (g_strcmp0(wm_name, "GNOME Shell") != 0) { use_header_bar = FALSE; } } #endif if (use_header_bar) { GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); gtk_header_bar_set_title(header_bar, "window_size_example"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); } else { gtk_window_set_title(window, "window_size_example"); } gtk_window_set_default_size(window, 1280, 720); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlDartProject) project = fl_dart_project_new(); fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); FlView* view = fl_view_new(project); gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); } // Implements GApplication::local_command_line. static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { MyApplication* self = MY_APPLICATION(application); // Strip out the first argument as it is the binary name. self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); g_autoptr(GError) error = nullptr; if (!g_application_register(application, nullptr, &error)) { g_warning("Failed to register: %s", error->message); *exit_status = 1; return TRUE; } g_application_activate(application); *exit_status = 0; return TRUE; } // Implements GObject::dispose. static void my_application_dispose(GObject* object) { MyApplication* self = MY_APPLICATION(object); g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); G_OBJECT_CLASS(my_application_parent_class)->dispose(object); } static void my_application_class_init(MyApplicationClass* klass) { G_APPLICATION_CLASS(klass)->activate = my_application_activate; G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; G_OBJECT_CLASS(klass)->dispose = my_application_dispose; } static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { return MY_APPLICATION(g_object_new(my_application_get_type(), "application-id", APPLICATION_ID, "flags", G_APPLICATION_NON_UNIQUE, nullptr)); } ================================================ FILE: plugins/window_size/example/linux/my_application.h ================================================ #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ #include G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, GtkApplication) /** * my_application_new: * * Creates a new Flutter-based application. * * Returns: a new #MyApplication. */ MyApplication* my_application_new(); #endif // FLUTTER_MY_APPLICATION_H_ ================================================ FILE: plugins/window_size/example/macos/.gitignore ================================================ # Flutter-related **/Flutter/ephemeral/ **/Pods/ # Xcode-related **/dgph **/xcuserdata/ ================================================ FILE: plugins/window_size/example/macos/Podfile ================================================ platform :osx, '10.14' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' project 'Runner', { 'Debug' => :debug, 'Profile' => :release, 'Release' => :release, } def flutter_root generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) unless File.exist?(generated_xcode_build_settings_path) raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" end File.foreach(generated_xcode_build_settings_path) do |line| matches = line.match(/FLUTTER_ROOT\=(.*)/) return matches[1].strip if matches end raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" end require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) flutter_macos_podfile_setup target 'Runner' do use_frameworks! use_modular_headers! flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) target 'RunnerTests' do inherit! :search_paths end end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_macos_build_settings(target) end end ================================================ FILE: plugins/window_size/example/macos/Runner/AppDelegate.swift ================================================ import Cocoa import FlutterMacOS @NSApplicationMain class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } } ================================================ FILE: plugins/window_size/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "16x16", "idiom" : "mac", "filename" : "app_icon_16.png", "scale" : "1x" }, { "size" : "16x16", "idiom" : "mac", "filename" : "app_icon_32.png", "scale" : "2x" }, { "size" : "32x32", "idiom" : "mac", "filename" : "app_icon_32.png", "scale" : "1x" }, { "size" : "32x32", "idiom" : "mac", "filename" : "app_icon_64.png", "scale" : "2x" }, { "size" : "128x128", "idiom" : "mac", "filename" : "app_icon_128.png", "scale" : "1x" }, { "size" : "128x128", "idiom" : "mac", "filename" : "app_icon_256.png", "scale" : "2x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "app_icon_256.png", "scale" : "1x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "app_icon_512.png", "scale" : "2x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "app_icon_512.png", "scale" : "1x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "app_icon_1024.png", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: plugins/window_size/example/macos/Runner/Base.lproj/MainMenu.xib ================================================ ================================================ FILE: plugins/window_size/example/macos/Runner/Configs/AppInfo.xcconfig ================================================ // Application-level settings for the Runner target. // // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the // future. If not, the values below would default to using the project name when this becomes a // 'flutter create' template. // The application's name. By default this is also the title of the Flutter window. PRODUCT_NAME = window_size_example // The application's bundle identifier PRODUCT_BUNDLE_IDENTIFIER = com.example.windowSizeExample // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. ================================================ FILE: plugins/window_size/example/macos/Runner/Configs/Debug.xcconfig ================================================ #include "../../Flutter/Flutter-Debug.xcconfig" #include "Warnings.xcconfig" ================================================ FILE: plugins/window_size/example/macos/Runner/Configs/Release.xcconfig ================================================ #include "../../Flutter/Flutter-Release.xcconfig" #include "Warnings.xcconfig" ================================================ FILE: plugins/window_size/example/macos/Runner/Configs/Warnings.xcconfig ================================================ WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings GCC_WARN_UNDECLARED_SELECTOR = YES CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE CLANG_WARN__DUPLICATE_METHOD_MATCH = YES CLANG_WARN_PRAGMA_PACK = YES CLANG_WARN_STRICT_PROTOTYPES = YES CLANG_WARN_COMMA = YES GCC_WARN_STRICT_SELECTOR_MATCH = YES CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES GCC_WARN_SHADOW = YES CLANG_WARN_UNREACHABLE_CODE = YES ================================================ FILE: plugins/window_size/example/macos/Runner/DebugProfile.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.cs.allow-jit com.apple.security.network.server ================================================ FILE: plugins/window_size/example/macos/Runner/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString $(FLUTTER_BUILD_NAME) CFBundleVersion $(FLUTTER_BUILD_NUMBER) LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright $(PRODUCT_COPYRIGHT) NSMainNibFile MainMenu NSPrincipalClass NSApplication ================================================ FILE: plugins/window_size/example/macos/Runner/MainFlutterWindow.swift ================================================ import Cocoa import FlutterMacOS class MainFlutterWindow: NSWindow { override func awakeFromNib() { let flutterViewController = FlutterViewController.init() let windowFrame = self.frame self.contentViewController = flutterViewController self.setFrame(windowFrame, display: true) RegisterGeneratedPlugins(registry: flutterViewController) super.awakeFromNib() } } ================================================ FILE: plugins/window_size/example/macos/Runner/Release.entitlements ================================================ com.apple.security.app-sandbox ================================================ FILE: plugins/window_size/example/macos/Runner.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { isa = PBXAggregateTarget; buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; buildPhases = ( 33CC111E2044C6BF0003C045 /* ShellScript */, ); dependencies = ( ); name = "Flutter Assemble"; productName = FLX; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 300753A3C311BFC7DDEF97DA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F200B2EC0FDA715EE877D19 /* Pods_Runner.framework */; }; 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 375DA0C6BB1D819C66AD27D8 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A3790468400A263AE62E91DD /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; proxyType = 1; remoteGlobalIDString = 33CC10EC2044A3C60003C045; remoteInfo = Runner; }; 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; proxyType = 1; remoteGlobalIDString = 33CC111A2044C6BA0003C045; remoteInfo = FLX; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 33CC110E2044A8840003C045 /* Bundle Framework */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Bundle Framework"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; 33CC10ED2044A3C60003C045 /* window_size_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = window_size_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 51C12AA143ECE0B582B76D69 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 57571EC1886C4E0478EEDB5A /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 618A9A113C9FAE4B397FA82B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 6FAE3B1A223C22460615F578 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; 9F200B2EC0FDA715EE877D19 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A3790468400A263AE62E91DD /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D19F9D26B653A8206042D4A7 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; D8388F048303904C474E8A52 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 331C80D2294CF70F00263BE5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 375DA0C6BB1D819C66AD27D8 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10EA2044A3C60003C045 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 300753A3C311BFC7DDEF97DA /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( 331C80D7294CF71000263BE5 /* RunnerTests.swift */, ); path = RunnerTests; sourceTree = ""; }; 33BA886A226E78AF003329D5 /* Configs */ = { isa = PBXGroup; children = ( 33E5194F232828860026EE4D /* AppInfo.xcconfig */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, ); path = Configs; sourceTree = ""; }; 33CC10E42044A3C60003C045 = { isa = PBXGroup; children = ( 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, D0BB09EFE54DE5703954BE78 /* Pods */, ); sourceTree = ""; }; 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( 33CC10ED2044A3C60003C045 /* window_size_example.app */, 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; }; 33CC11242044D66E0003C045 /* Resources */ = { isa = PBXGroup; children = ( 33CC10F22044A3C60003C045 /* Assets.xcassets */, 33CC10F42044A3C60003C045 /* MainMenu.xib */, 33CC10F72044A3C60003C045 /* Info.plist */, ); name = Resources; path = ..; sourceTree = ""; }; 33CEB47122A05771004F2AC0 /* Flutter */ = { isa = PBXGroup; children = ( 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, ); path = Flutter; sourceTree = ""; }; 33FAB671232836740065AC1E /* Runner */ = { isa = PBXGroup; children = ( 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 33E51913231747F40026EE4D /* DebugProfile.entitlements */, 33E51914231749380026EE4D /* Release.entitlements */, 33CC11242044D66E0003C045 /* Resources */, 33BA886A226E78AF003329D5 /* Configs */, ); path = Runner; sourceTree = ""; }; D0BB09EFE54DE5703954BE78 /* Pods */ = { isa = PBXGroup; children = ( 618A9A113C9FAE4B397FA82B /* Pods-Runner.debug.xcconfig */, D8388F048303904C474E8A52 /* Pods-Runner.release.xcconfig */, 6FAE3B1A223C22460615F578 /* Pods-Runner.profile.xcconfig */, 57571EC1886C4E0478EEDB5A /* Pods-RunnerTests.debug.xcconfig */, D19F9D26B653A8206042D4A7 /* Pods-RunnerTests.release.xcconfig */, 51C12AA143ECE0B582B76D69 /* Pods-RunnerTests.profile.xcconfig */, ); name = Pods; path = Pods; sourceTree = ""; }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( 9F200B2EC0FDA715EE877D19 /* Pods_Runner.framework */, A3790468400A263AE62E91DD /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 331C80D4294CF70F00263BE5 /* RunnerTests */ = { isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( 6394A521FD9F9046B9E83356 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, ); buildRules = ( ); dependencies = ( 331C80DA294CF71000263BE5 /* PBXTargetDependency */, ); name = RunnerTests; productName = RunnerTests; productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 33CC10EC2044A3C60003C045 /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( 0939528D03DF1B1897D3C7D9 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, E5E59AB23121C804C05B3AD5 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( 33CC11202044C79F0003C045 /* PBXTargetDependency */, ); name = Runner; productName = Runner; productReference = 33CC10ED2044A3C60003C045 /* window_size_example.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { CreatedOnToolsVersion = 14.0; TestTargetID = 33CC10EC2044A3C60003C045; }; 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 1100; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.Sandbox = { enabled = 1; }; }; }; 33CC111A2044C6BA0003C045 = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Manual; }; }; }; buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 33CC10E42044A3C60003C045; productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, 331C80D4294CF70F00263BE5 /* RunnerTests */, 33CC111A2044C6BA0003C045 /* Flutter Assemble */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 331C80D3294CF70F00263BE5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 0939528D03DF1B1897D3C7D9 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( Flutter/ephemeral/FlutterInputs.xcfilelist, ); inputPaths = ( Flutter/ephemeral/tripwire, ); outputFileListPaths = ( Flutter/ephemeral/FlutterOutputs.xcfilelist, ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; 6394A521FD9F9046B9E83356 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; E5E59AB23121C804C05B3AD5 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 331C80D1294CF70F00263BE5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10E92044A3C60003C045 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC10EC2044A3C60003C045 /* Runner */; targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; }; 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( 33CC10F52044A3C60003C045 /* Base */, ); name = MainMenu.xib; path = Runner; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 57571EC1886C4E0478EEDB5A /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.windowSizeExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/window_size_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/window_size_example"; }; name = Debug; }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = D19F9D26B653A8206042D4A7 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.windowSizeExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/window_size_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/window_size_example"; }; name = Release; }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 51C12AA143ECE0B582B76D69 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.windowSizeExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/window_size_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/window_size_example"; }; name = Profile; }; 338D0CE9231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Profile; }; 338D0CEA231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Profile; }; 338D0CEB231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Profile; }; 33CC10F92044A3C60003C045 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 33CC10FA2044A3C60003C045 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; 33CC10FC2044A3C60003C045 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; 33CC10FD2044A3C60003C045 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Release; }; 33CC111C2044C6BA0003C045 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 33CC111D2044C6BA0003C045 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 331C80DB294CF71000263BE5 /* Debug */, 331C80DC294CF71000263BE5 /* Release */, 331C80DD294CF71000263BE5 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC10F92044A3C60003C045 /* Debug */, 33CC10FA2044A3C60003C045 /* Release */, 338D0CE9231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC10FC2044A3C60003C045 /* Debug */, 33CC10FD2044A3C60003C045 /* Release */, 338D0CEA231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC111C2044C6BA0003C045 /* Debug */, 33CC111D2044C6BA0003C045 /* Release */, 338D0CEB231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 33CC10E52044A3C60003C045 /* Project object */; } ================================================ FILE: plugins/window_size/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: plugins/window_size/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme ================================================ ================================================ FILE: plugins/window_size/example/macos/Runner.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: plugins/window_size/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: plugins/window_size/example/macos/RunnerTests/RunnerTests.swift ================================================ import FlutterMacOS import Cocoa import XCTest @testable import window_size // This demonstrates a simple unit test of the Swift portion of this plugin's implementation. // // See https://developer.apple.com/documentation/xctest for more information about using XCTest. class RunnerTests: XCTestCase { } ================================================ FILE: plugins/window_size/example/pubspec.yaml ================================================ name: window_size_example description: Demonstrates how to use the window_size plugin. publish_to: 'none' environment: sdk: '>=2.12.0-0 <3.0.0' flutter: '>=3.0.0' dependencies: flutter: sdk: flutter window_size: # When depending on this package from a real application you should use: # window_size: ^x.y.z # See https://dart.dev/tools/pub/dependencies#version-constraints # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ dev_dependencies: integration_test: sdk: flutter flutter_test: sdk: flutter flutter: uses-material-design: true ================================================ FILE: plugins/window_size/example/windows/.gitignore ================================================ flutter/ephemeral/ # Visual Studio user-specific files. *.suo *.user *.userosscache *.sln.docstates # Visual Studio build-related files. x64/ x86/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ ================================================ FILE: plugins/window_size/example/windows/CMakeLists.txt ================================================ # Project-level configuration. cmake_minimum_required(VERSION 3.14) project(window_size_example LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "window_size_example") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(SET CMP0063 NEW) # Define build configuration option. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" CACHE STRING "" FORCE) else() if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() endif() # Define settings for the Profile build mode. set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") # Use Unicode for all projects. add_definitions(-DUNICODE -D_UNICODE) # Compilation settings that should be applied to most targets. # # Be cautious about adding new options here, as plugins use this function by # default. In most cases, you should add new options to specific targets instead # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") target_compile_options(${TARGET} PRIVATE /EHsc) target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") endfunction() # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # Application build; see runner/CMakeLists.txt. add_subdirectory("runner") # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) # === Installation === # Support files are copied into place next to the executable, so that it can # run in place. This is done instead of making a separate bundle (as on Linux) # so that building and running from within Visual Studio will work. set(BUILD_BUNDLE_DIR "$") # Make the "install" step default, as it's required to run. set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) if(PLUGIN_BUNDLED_LIBRARIES) install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" CONFIGURATIONS Profile;Release COMPONENT Runtime) ================================================ FILE: plugins/window_size/example/windows/flutter/CMakeLists.txt ================================================ # This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "flutter_export.h" "flutter_windows.h" "flutter_messenger.h" "flutter_plugin_registrar.h" "flutter_texture_registrar.h" ) list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") add_dependencies(flutter flutter_assemble) # === Wrapper === list(APPEND CPP_WRAPPER_SOURCES_CORE "core_implementations.cc" "standard_codec.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_PLUGIN "plugin_registrar.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_APP "flutter_engine.cc" "flutter_view_controller.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") # Wrapper sources needed for a plugin. add_library(flutter_wrapper_plugin STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ) apply_standard_settings(flutter_wrapper_plugin) set_target_properties(flutter_wrapper_plugin PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(flutter_wrapper_plugin PROPERTIES CXX_VISIBILITY_PRESET hidden) target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) target_include_directories(flutter_wrapper_plugin PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_plugin flutter_assemble) # Wrapper sources needed for the runner. add_library(flutter_wrapper_app STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_APP} ) apply_standard_settings(flutter_wrapper_app) target_link_libraries(flutter_wrapper_app PUBLIC flutter) target_include_directories(flutter_wrapper_app PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_app flutter_assemble) # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ${PHONY_OUTPUT} COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" windows-x64 $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ) ================================================ FILE: plugins/window_size/example/windows/flutter/generated_plugin_registrant.cc ================================================ // // Generated file. Do not edit. // // clang-format off #include "generated_plugin_registrant.h" #include void RegisterPlugins(flutter::PluginRegistry* registry) { WindowSizePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("WindowSizePlugin")); } ================================================ FILE: plugins/window_size/example/windows/flutter/generated_plugin_registrant.h ================================================ // // Generated file. Do not edit. // // clang-format off #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ #include // Registers Flutter plugins. void RegisterPlugins(flutter::PluginRegistry* registry); #endif // GENERATED_PLUGIN_REGISTRANT_ ================================================ FILE: plugins/window_size/example/windows/flutter/generated_plugins.cmake ================================================ # # Generated file, do not edit. # list(APPEND FLUTTER_PLUGIN_LIST window_size ) list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) endforeach(ffi_plugin) ================================================ FILE: plugins/window_size/example/windows/runner/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.14) project(runner LANGUAGES CXX) # Define the application target. To change its name, change BINARY_NAME in the # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer # work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" "utils.cpp" "win32_window.cpp" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "Runner.rc" "runner.exe.manifest" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add preprocessor definitions for the build version. target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") # Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) ================================================ FILE: plugins/window_size/example/windows/runner/Runner.rc ================================================ // Microsoft Visual C++ generated resource script. // #pragma code_page(65001) #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_APP_ICON ICON "resources\\app_icon.ico" ///////////////////////////////////////////////////////////////////////////// // // Version // #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else #define VERSION_AS_NUMBER 1,0,0,0 #endif #if defined(FLUTTER_VERSION) #define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION_AS_NUMBER PRODUCTVERSION VERSION_AS_NUMBER FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "com.example" "\0" VALUE "FileDescription", "window_size_example" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "window_size_example" "\0" VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" VALUE "OriginalFilename", "window_size_example.exe" "\0" VALUE "ProductName", "window_size_example" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: plugins/window_size/example/windows/runner/flutter_window.cpp ================================================ #include "flutter_window.h" #include #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(const flutter::DartProject& project) : project_(project) {} FlutterWindow::~FlutterWindow() {} bool FlutterWindow::OnCreate() { if (!Win32Window::OnCreate()) { return false; } RECT frame = GetClientArea(); // The size here must match the window dimensions to avoid unnecessary surface // creation / destruction in the startup path. flutter_controller_ = std::make_unique( frame.right - frame.left, frame.bottom - frame.top, project_); // Ensure that basic setup of the controller was successful. if (!flutter_controller_->engine() || !flutter_controller_->view()) { return false; } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); }); return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } LRESULT FlutterWindow::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { // Give Flutter, including plugins, an opportunity to handle window messages. if (flutter_controller_) { std::optional result = flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, lparam); if (result) { return *result; } } switch (message) { case WM_FONTCHANGE: flutter_controller_->engine()->ReloadSystemFonts(); break; } return Win32Window::MessageHandler(hwnd, message, wparam, lparam); } ================================================ FILE: plugins/window_size/example/windows/runner/flutter_window.h ================================================ #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ #include #include #include #include "win32_window.h" // A window that does nothing but host a Flutter view. class FlutterWindow : public Win32Window { public: // Creates a new FlutterWindow hosting a Flutter view running |project|. explicit FlutterWindow(const flutter::DartProject& project); virtual ~FlutterWindow(); protected: // Win32Window: bool OnCreate() override; void OnDestroy() override; LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override; private: // The project to run. flutter::DartProject project_; // The Flutter instance hosted by this window. std::unique_ptr flutter_controller_; }; #endif // RUNNER_FLUTTER_WINDOW_H_ ================================================ FILE: plugins/window_size/example/windows/runner/main.cpp ================================================ #include #include #include #include "flutter_window.h" #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { // Attach to console when present (e.g., 'flutter run') or create a // new console when running with a debugger. if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { CreateAndAttachConsole(); } // Initialize COM, so that it is available for use in the library and/or // plugins. ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); flutter::DartProject project(L"data"); std::vector command_line_arguments = GetCommandLineArguments(); project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); if (!window.Create(L"window_size_example", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); ::MSG msg; while (::GetMessage(&msg, nullptr, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } ::CoUninitialize(); return EXIT_SUCCESS; } ================================================ FILE: plugins/window_size/example/windows/runner/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by Runner.rc // #define IDI_APP_ICON 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: plugins/window_size/example/windows/runner/runner.exe.manifest ================================================ PerMonitorV2 ================================================ FILE: plugins/window_size/example/windows/runner/utils.cpp ================================================ #include "utils.h" #include #include #include #include #include void CreateAndAttachConsole() { if (::AllocConsole()) { FILE *unused; if (freopen_s(&unused, "CONOUT$", "w", stdout)) { _dup2(_fileno(stdout), 1); } if (freopen_s(&unused, "CONOUT$", "w", stderr)) { _dup2(_fileno(stdout), 2); } std::ios::sync_with_stdio(); FlutterDesktopResyncOutputStreams(); } } std::vector GetCommandLineArguments() { // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. int argc; wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); if (argv == nullptr) { return std::vector(); } std::vector command_line_arguments; // Skip the first argument as it's the binary name. for (int i = 1; i < argc; i++) { command_line_arguments.push_back(Utf8FromUtf16(argv[i])); } ::LocalFree(argv); return command_line_arguments; } std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } int target_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, nullptr, 0, nullptr, nullptr); std::string utf8_string; if (target_length == 0 || target_length > utf8_string.max_size()) { return utf8_string; } utf8_string.resize(target_length); int converted_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, utf8_string.data(), target_length, nullptr, nullptr); if (converted_length == 0) { return std::string(); } return utf8_string; } ================================================ FILE: plugins/window_size/example/windows/runner/utils.h ================================================ #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ #include #include // Creates a console for the process, and redirects stdout and stderr to // it for both the runner and the Flutter library. void CreateAndAttachConsole(); // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string // encoded in UTF-8. Returns an empty std::string on failure. std::string Utf8FromUtf16(const wchar_t* utf16_string); // Gets the command line arguments passed in as a std::vector, // encoded in UTF-8. Returns an empty std::vector on failure. std::vector GetCommandLineArguments(); #endif // RUNNER_UTILS_H_ ================================================ FILE: plugins/window_size/example/windows/runner/win32_window.cpp ================================================ #include "win32_window.h" #include #include #include "resource.h" namespace { /// Window attribute that enables dark mode window decorations. /// /// Redefined in case the developer's machine has a Windows SDK older than /// version 10.0.22000.0. /// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE #define DWMWA_USE_IMMERSIVE_DARK_MODE 20 #endif constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; /// Registry key for app theme preference. /// /// A value of 0 indicates apps should use dark mode. A non-zero or missing /// value indicates apps should use light mode. constexpr const wchar_t kGetPreferredBrightnessRegKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; // The number of Win32Window objects that currently exist. static int g_active_window_count = 0; using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); // Scale helper to convert logical scaler values to physical using passed in // scale factor int Scale(int source, double scale_factor) { return static_cast(source * scale_factor); } // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. // This API is only needed for PerMonitor V1 awareness mode. void EnableFullDpiSupportIfAvailable(HWND hwnd) { HMODULE user32_module = LoadLibraryA("User32.dll"); if (!user32_module) { return; } auto enable_non_client_dpi_scaling = reinterpret_cast( GetProcAddress(user32_module, "EnableNonClientDpiScaling")); if (enable_non_client_dpi_scaling != nullptr) { enable_non_client_dpi_scaling(hwnd); } FreeLibrary(user32_module); } } // namespace // Manages the Win32Window's window class registration. class WindowClassRegistrar { public: ~WindowClassRegistrar() = default; // Returns the singleton registar instance. static WindowClassRegistrar* GetInstance() { if (!instance_) { instance_ = new WindowClassRegistrar(); } return instance_; } // Returns the name of the window class, registering the class if it hasn't // previously been registered. const wchar_t* GetWindowClass(); // Unregisters the window class. Should only be called if there are no // instances of the window. void UnregisterWindowClass(); private: WindowClassRegistrar() = default; static WindowClassRegistrar* instance_; bool class_registered_ = false; }; WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; const wchar_t* WindowClassRegistrar::GetWindowClass() { if (!class_registered_) { WNDCLASS window_class{}; window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); window_class.lpszClassName = kWindowClassName; window_class.style = CS_HREDRAW | CS_VREDRAW; window_class.cbClsExtra = 0; window_class.cbWndExtra = 0; window_class.hInstance = GetModuleHandle(nullptr); window_class.hIcon = LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); window_class.hbrBackground = 0; window_class.lpszMenuName = nullptr; window_class.lpfnWndProc = Win32Window::WndProc; RegisterClass(&window_class); class_registered_ = true; } return kWindowClassName; } void WindowClassRegistrar::UnregisterWindowClass() { UnregisterClass(kWindowClassName, nullptr); class_registered_ = false; } Win32Window::Win32Window() { ++g_active_window_count; } Win32Window::~Win32Window() { --g_active_window_count; Destroy(); } bool Win32Window::Create(const std::wstring& title, const Point& origin, const Size& size) { Destroy(); const wchar_t* window_class = WindowClassRegistrar::GetInstance()->GetWindowClass(); const POINT target_point = {static_cast(origin.x), static_cast(origin.y)}; HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); double scale_factor = dpi / 96.0; HWND window = CreateWindow( window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); if (!window) { return false; } UpdateTheme(window); return OnCreate(); } bool Win32Window::Show() { return ShowWindow(window_handle_, SW_SHOWNORMAL); } // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { if (message == WM_NCCREATE) { auto window_struct = reinterpret_cast(lparam); SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast(window_struct->lpCreateParams)); auto that = static_cast(window_struct->lpCreateParams); EnableFullDpiSupportIfAvailable(window); that->window_handle_ = window; } else if (Win32Window* that = GetThisFromHandle(window)) { return that->MessageHandler(window, message, wparam, lparam); } return DefWindowProc(window, message, wparam, lparam); } LRESULT Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { switch (message) { case WM_DESTROY: window_handle_ = nullptr; Destroy(); if (quit_on_close_) { PostQuitMessage(0); } return 0; case WM_DPICHANGED: { auto newRectSize = reinterpret_cast(lparam); LONG newWidth = newRectSize->right - newRectSize->left; LONG newHeight = newRectSize->bottom - newRectSize->top; SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE); return 0; } case WM_SIZE: { RECT rect = GetClientArea(); if (child_content_ != nullptr) { // Size and position the child window. MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); } return 0; } case WM_ACTIVATE: if (child_content_ != nullptr) { SetFocus(child_content_); } return 0; case WM_DWMCOLORIZATIONCOLORCHANGED: UpdateTheme(hwnd); return 0; } return DefWindowProc(window_handle_, message, wparam, lparam); } void Win32Window::Destroy() { OnDestroy(); if (window_handle_) { DestroyWindow(window_handle_); window_handle_ = nullptr; } if (g_active_window_count == 0) { WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); } } Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { return reinterpret_cast( GetWindowLongPtr(window, GWLP_USERDATA)); } void Win32Window::SetChildContent(HWND content) { child_content_ = content; SetParent(content, window_handle_); RECT frame = GetClientArea(); MoveWindow(content, frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, true); SetFocus(child_content_); } RECT Win32Window::GetClientArea() { RECT frame; GetClientRect(window_handle_, &frame); return frame; } HWND Win32Window::GetHandle() { return window_handle_; } void Win32Window::SetQuitOnClose(bool quit_on_close) { quit_on_close_ = quit_on_close; } bool Win32Window::OnCreate() { // No-op; provided for subclasses. return true; } void Win32Window::OnDestroy() { // No-op; provided for subclasses. } void Win32Window::UpdateTheme(HWND const window) { DWORD light_mode; DWORD light_mode_size = sizeof(light_mode); LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD, nullptr, &light_mode, &light_mode_size); if (result == ERROR_SUCCESS) { BOOL enable_dark_mode = light_mode == 0; DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, &enable_dark_mode, sizeof(enable_dark_mode)); } } ================================================ FILE: plugins/window_size/example/windows/runner/win32_window.h ================================================ #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ #include #include #include #include // A class abstraction for a high DPI-aware Win32 Window. Intended to be // inherited from by classes that wish to specialize with custom // rendering and input handling class Win32Window { public: struct Point { unsigned int x; unsigned int y; Point(unsigned int x, unsigned int y) : x(x), y(y) {} }; struct Size { unsigned int width; unsigned int height; Size(unsigned int width, unsigned int height) : width(width), height(height) {} }; Win32Window(); virtual ~Win32Window(); // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a // consistent size this function will scale the inputted width and height as // as appropriate for the default monitor. The window is invisible until // |Show| is called. Returns true if the window was created successfully. bool Create(const std::wstring& title, const Point& origin, const Size& size); // Show the current window. Returns true if the window was successfully shown. bool Show(); // Release OS resources associated with window. void Destroy(); // Inserts |content| into the window tree. void SetChildContent(HWND content); // Returns the backing Window handle to enable clients to set icon and other // window properties. Returns nullptr if the window has been destroyed. HWND GetHandle(); // If true, closing this window will quit the application. void SetQuitOnClose(bool quit_on_close); // Return a RECT representing the bounds of the current client area. RECT GetClientArea(); protected: // Processes and route salient window messages for mouse handling, // size change and DPI. Delegates handling of these to member overloads that // inheriting classes can handle. virtual LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Called when CreateAndShow is called, allowing subclass window-related // setup. Subclasses should return false if setup fails. virtual bool OnCreate(); // Called when Destroy is called. virtual void OnDestroy(); private: friend class WindowClassRegistrar; // OS callback called by message pump. Handles the WM_NCCREATE message which // is passed when the non-client area is being created and enables automatic // non-client DPI scaling so that the non-client area automatically // responsponds to changes in DPI. All other messages are handled by // MessageHandler. static LRESULT CALLBACK WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Retrieves a class instance pointer for |window| static Win32Window* GetThisFromHandle(HWND const window) noexcept; // Update the window frame's theme to match the system theme. static void UpdateTheme(HWND const window); bool quit_on_close_ = false; // window handle for top level window. HWND window_handle_ = nullptr; // window handle for hosted content. HWND child_content_ = nullptr; }; #endif // RUNNER_WIN32_WINDOW_H_ ================================================ FILE: plugins/window_size/lib/src/platform_window.dart ================================================ // Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'dart:ui'; import 'screen.dart'; /// Represents a window, containing information about its size, position, and /// properties. class PlatformWindow { /// Create a new window. PlatformWindow(this.frame, this.scaleFactor, this.screen); /// The frame of the screen, in screen coordinates. final Rect frame; /// The number of pixels per screen coordinate for this screen. final double scaleFactor; /// The (or a) screen containing this window, if any. final Screen? screen; } ================================================ FILE: plugins/window_size/lib/src/screen.dart ================================================ // Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'dart:ui'; /// Represents a screen, containing information about its size, position, and /// properties. class Screen { /// Create a new screen. Screen(this.frame, this.visibleFrame, this.scaleFactor); /// The frame of the screen, in screen coordinates. final Rect frame; /// The portion of the screen's frame that is available for use by application /// windows. E.g., on macOS, this excludes the menu bar. final Rect visibleFrame; /// The number of pixels per screen coordinate for this screen. final double scaleFactor; } ================================================ FILE: plugins/window_size/lib/src/window_size_channel.dart ================================================ // Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'dart:async'; import 'dart:ui'; import 'package:flutter/services.dart'; import 'platform_window.dart'; import 'screen.dart'; /// The name of the plugin's platform channel. const String _windowSizeChannelName = 'flutter/windowsize'; /// The method name to request information about the available screens. /// /// Returns a list of screen info maps; see keys below. const String _getScreenListMethod = 'getScreenList'; /// The method name to request information about the window containing the /// Flutter instance. /// /// Returns a list of window info maps; see keys below. const String _getWindowInfoMethod = 'getWindowInfo'; /// The method name to set the frame of a window. /// /// Takes a frame array, as documented for the value of _frameKey. const String _setWindowFrameMethod = 'setWindowFrame'; /// The method name to set the minimum size of a window. /// /// Takes a window size array, with the value is a list of two doubles: /// [width, height]. /// /// A value of zero for width or height is to be interpreted as /// unconstrained in that dimension. const String _setWindowMinimumSizeMethod = 'setWindowMinimumSize'; /// The method name to set the maximum size of a window. /// /// Takes a window size array, with the value is a list of two doubles: /// [width, height]. /// /// A value of `-1` for width or height is to be interpreted as /// unconstrained in that dimension. const String _setWindowMaximumSizeMethod = 'setWindowMaximumSize'; /// The method name to set the window title of a window. const String _setWindowTitleMethod = 'setWindowTitle'; /// The method name to set the window title's represented URL. /// /// Only implemented for macOS. If the URL is a file URL, the /// window shows an icon in its title bar. const String _setWindowTitleRepresentedUrlMethod = 'setWindowTitleRepresentedUrl'; /// The method name to get the minimum size of a window. /// /// Returns a window size array, with the value is a list of two doubles: /// [width, height]. /// /// A value of zero for width or height is to be interpreted as /// unconstrained in that dimension. const String _getWindowMinimumSizeMethod = 'getWindowMinimumSize'; /// The method name to get the maximum size of a window. /// /// Returns a window size array, with the value is a list of two doubles: /// [width, height]. /// /// A value of `-1` for width or height is to be interpreted as /// unconstrained in that dimension. const String _getWindowMaximumSizeMethod = 'getWindowMaximumSize'; /// The method name to set the window visibility. /// /// The argument will be a boolean controlling whether or not the window should /// be visible. const String _setWindowVisibilityMethod = 'setWindowVisibility'; // Keys for screen and window maps returned by _getScreenListMethod. /// The frame of a screen or window. The value is a list of four doubles: /// [left, top, width, height] const String _frameKey = 'frame'; /// The frame of a screen available for use by applications. The value format /// is the same as _frameKey's. /// /// Only used for screens. const String _visibleFrameKey = 'visibleFrame'; /// The scale factor for a screen or window, as a double. /// /// This is the number of pixels per screen coordinate, and thus the ratio /// between sizes as seen by Flutter and sizes in native screen coordinates. const String _scaleFactorKey = 'scaleFactor'; /// The screen containing this window, if any. The value is a screen map, or /// null if the window is not visible on a screen. /// /// Only used for windows. /// /// If a window is on multiple screens, it is up to the platform to decide which /// screen to report. const String _screenKey = 'screen'; /// A singleton object that handles the interaction with the platform channel. class WindowSizeChannel { /// Private constructor. WindowSizeChannel._(); final MethodChannel _platformChannel = const MethodChannel(_windowSizeChannelName); /// The static instance of the menu channel. static final WindowSizeChannel instance = new WindowSizeChannel._(); /// Returns a list of screens. Future> getScreenList() async { final screenList = []; final response = await _platformChannel.invokeMethod(_getScreenListMethod); for (final screenInfo in response) { screenList.add(_screenFromInfoMap(screenInfo)); } return screenList; } /// Returns information about the window containing this Flutter instance. Future getWindowInfo() async { final response = await _platformChannel.invokeMethod(_getWindowInfoMethod); final screenInfo = response[_screenKey]; final screen = screenInfo == null ? null : _screenFromInfoMap(screenInfo); return PlatformWindow(_rectFromLTWHList(response[_frameKey].cast()), response[_scaleFactorKey], screen); } /// Sets the frame of the window containing this Flutter instance, in /// screen coordinates. /// /// The platform may adjust the frame as necessary if the provided frame would /// cause significant usability issues (e.g., a window with no visible portion /// that can be used to move the window). void setWindowFrame(Rect frame) async { assert(!frame.isEmpty, 'Cannot set window frame to an empty rect.'); assert(frame.isFinite, 'Cannot set window frame to a non-finite rect.'); await _platformChannel.invokeMethod(_setWindowFrameMethod, [frame.left, frame.top, frame.width, frame.height]); } /// Sets the minimum size of the window containing this Flutter instance. void setWindowMinSize(Size size) async { await _platformChannel .invokeMethod(_setWindowMinimumSizeMethod, [size.width, size.height]); } /// Sets the visibility of the window. void setWindowVisibility({required bool visible}) async { await _platformChannel.invokeMethod(_setWindowVisibilityMethod, visible); } // Window maximum size unconstrained is passed over the channel as -1. double _channelRepresentationForMaxDimension(double size) { return size == double.infinity ? -1 : size; } /// Sets the maximum size of the window containing this Flutter instance. void setWindowMaxSize(Size size) async { await _platformChannel.invokeMethod(_setWindowMaximumSizeMethod, [ _channelRepresentationForMaxDimension(size.width), _channelRepresentationForMaxDimension(size.height), ]); } /// Sets the title of the window containing this Flutter instance. void setWindowTitle(String title) async { await _platformChannel.invokeMapMethod(_setWindowTitleMethod, title); } /// Sets the title's represented URL of the window containing this Flutter instance. void setWindowTitleRepresentedUrl(Uri file) async { await _platformChannel.invokeMapMethod( _setWindowTitleRepresentedUrlMethod, file.toString()); } /// Gets the minimum size of the window containing this Flutter instance. Future getWindowMinSize() async { final response = await _platformChannel.invokeMethod(_getWindowMinimumSizeMethod); return _sizeFromWHList(List.from(response.cast())); } // Window maximum size unconstrained is passed over the channel as -1. double _maxDimensionFromChannelRepresentation(double size) { return size == -1 ? double.infinity : size; } /// Gets the maximum size of the window containing this Flutter instance. Future getWindowMaxSize() async { final response = await _platformChannel.invokeMethod(_getWindowMaximumSizeMethod); return _sizeFromWHList( List.from( response.cast().map(_maxDimensionFromChannelRepresentation), ), ); } /// Given an array of the form [left, top, width, height], return the /// corresponding [Rect]. /// /// Used for frame deserialization in the platform channel. Rect _rectFromLTWHList(List ltwh) { return Rect.fromLTWH(ltwh[0], ltwh[1], ltwh[2], ltwh[3]); } /// Given an array of the form [width, height], return the corresponding /// [Size]. /// /// Used for window size deserialization in the platform channel. Size _sizeFromWHList(List wh) { return Size(wh[0], wh[1]); } /// Given a map of information about a screen, return the corresponding /// [Screen] object. /// /// Used for screen deserialization in the platform channel. Screen _screenFromInfoMap(Map map) { return Screen( _rectFromLTWHList(map[_frameKey].cast()), _rectFromLTWHList(map[_visibleFrameKey].cast()), map[_scaleFactorKey]); } } ================================================ FILE: plugins/window_size/lib/src/window_size_utils.dart ================================================ // Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'dart:async'; import 'dart:ui'; import 'platform_window.dart'; import 'screen.dart'; import 'window_size_channel.dart'; /// Returns a list of [Screen]s for the current screen configuration. /// /// It is possible for this list to be empty, if the machine is running in /// a headless mode. Future> getScreenList() async { return await WindowSizeChannel.instance.getScreenList(); } /// Returns the [Screen] showing the window that contains this Flutter instance. /// /// If the window is not being displayed, returns null. If the window is being /// displayed on multiple screens, the platform can return any of those screens. Future getCurrentScreen() async { final windowInfo = await WindowSizeChannel.instance.getWindowInfo(); return windowInfo.screen; } /// Returns information about the window containing this Flutter instance. Future getWindowInfo() async { return await WindowSizeChannel.instance.getWindowInfo(); } /// Sets the frame of the window containing this Flutter instance, in /// screen coordinates. /// /// The platform may adjust the frame as necessary if the provided frame would /// cause significant usability issues (e.g., a window with no visible portion /// that can be used to move the window). void setWindowFrame(Rect frame) async { WindowSizeChannel.instance.setWindowFrame(frame); } /// Sets the minimum [Size] of the window containing this Flutter instance. void setWindowMinSize(Size size) async { WindowSizeChannel.instance.setWindowMinSize(size); } /// Sets the maximum [Size] of the window containing this Flutter instance. void setWindowMaxSize(Size size) async { WindowSizeChannel.instance.setWindowMaxSize(size); } /// Sets the window title, as a [String], of the window containing this Flutter instance. void setWindowTitle(String title) async { WindowSizeChannel.instance.setWindowTitle(title); } /// Shows or hides the window. void setWindowVisibility({required bool visible}) async { WindowSizeChannel.instance.setWindowVisibility(visible: visible); } /// Sets the window title's represented [Uri], of the window containing this Flutter instance. /// /// Only implemented for macOS. If the URL is a file URL, the /// window shows an icon in its title bar. void setWindowTitleRepresentedUrl(Uri url) async { WindowSizeChannel.instance.setWindowTitleRepresentedUrl(url); } /// Gets the minimum [Size] of the window containing this Flutter instance. Future getWindowMinSize() async { return WindowSizeChannel.instance.getWindowMinSize(); } /// Gets the maximum [Size] of the window containing this Flutter instance. Future getWindowMaxSize() async { return WindowSizeChannel.instance.getWindowMaxSize(); } ================================================ FILE: plugins/window_size/lib/window_size.dart ================================================ // Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. export 'src/platform_window.dart'; export 'src/screen.dart'; export 'src/window_size_utils.dart'; ================================================ FILE: plugins/window_size/linux/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) set(PROJECT_NAME "window_size") project(${PROJECT_NAME} LANGUAGES CXX) set(PLUGIN_NAME "${PROJECT_NAME}_plugin") add_library(${PLUGIN_NAME} SHARED "${PLUGIN_NAME}.cc" ) apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) ================================================ FILE: plugins/window_size/linux/include/window_size/window_size_plugin.h ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef PLUGINS_WINDOW_SIZE_LINUX_WINDOW_SIZE_PLUGIN_H_ #define PLUGINS_WINDOW_SIZE_LINUX_WINDOW_SIZE_PLUGIN_H_ // A plugin to allow resizing the window. #include G_BEGIN_DECLS #ifdef FLUTTER_PLUGIN_IMPL #define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) #else #define FLUTTER_PLUGIN_EXPORT #endif G_DECLARE_FINAL_TYPE(FlWindowSizePlugin, fl_window_size_plugin, FL, WINDOW_SIZE_PLUGIN, GObject) FLUTTER_PLUGIN_EXPORT FlWindowSizePlugin* fl_window_size_plugin_new( FlPluginRegistrar* registrar); FLUTTER_PLUGIN_EXPORT void window_size_plugin_register_with_registrar( FlPluginRegistrar* registrar); G_END_DECLS #endif // PLUGINS_WINDOW_SIZE_LINUX_WINDOW_SIZE_PLUGIN_H_ ================================================ FILE: plugins/window_size/linux/window_size_plugin.cc ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "include/window_size/window_size_plugin.h" #include #include #include // See window_size_channel.dart for documentation. const char kChannelName[] = "flutter/windowsize"; const char kBadArgumentsError[] = "Bad Arguments"; const char kNoScreenError[] = "No Screen"; const char kGetScreenListMethod[] = "getScreenList"; const char kGetWindowInfoMethod[] = "getWindowInfo"; const char kSetWindowFrameMethod[] = "setWindowFrame"; const char kSetWindowMinimumSizeMethod[] = "setWindowMinimumSize"; const char kSetWindowMaximumSizeMethod[] = "setWindowMaximumSize"; const char kSetWindowTitleMethod[] = "setWindowTitle"; const char ksetWindowVisibilityMethod[] = "setWindowVisibility"; const char kGetWindowMinimumSizeMethod[] = "getWindowMinimumSize"; const char kGetWindowMaximumSizeMethod[] = "getWindowMaximumSize"; const char kFrameKey[] = "frame"; const char kVisibleFrameKey[] = "visibleFrame"; const char kScaleFactorKey[] = "scaleFactor"; const char kScreenKey[] = "screen"; struct _FlWindowSizePlugin { GObject parent_instance; FlPluginRegistrar* registrar; // Connection to Flutter engine. FlMethodChannel* channel; // Requested window geometry. GdkGeometry window_geometry; }; G_DEFINE_TYPE(FlWindowSizePlugin, fl_window_size_plugin, g_object_get_type()) // Gets the window being controlled. GtkWindow* get_window(FlWindowSizePlugin* self) { FlView* view = fl_plugin_registrar_get_view(self->registrar); if (view == nullptr) return nullptr; return GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); } // Gets the display connection. GdkDisplay* get_display(FlWindowSizePlugin* self) { FlView* view = fl_plugin_registrar_get_view(self->registrar); if (view == nullptr) return nullptr; return gtk_widget_get_display(GTK_WIDGET(view)); } // Converts frame dimensions into the Flutter representation. FlValue* make_frame_value(gint x, gint y, gint width, gint height) { g_autoptr(FlValue) value = fl_value_new_list(); fl_value_append_take(value, fl_value_new_float(x)); fl_value_append_take(value, fl_value_new_float(y)); fl_value_append_take(value, fl_value_new_float(width)); fl_value_append_take(value, fl_value_new_float(height)); return fl_value_ref(value); } // Converts monitor information into the Flutter representation. FlValue* make_monitor_value(GdkMonitor* monitor) { g_autoptr(FlValue) value = fl_value_new_map(); GdkRectangle frame; gdk_monitor_get_geometry(monitor, &frame); fl_value_set_string_take( value, kFrameKey, make_frame_value(frame.x, frame.y, frame.width, frame.height)); gdk_monitor_get_workarea(monitor, &frame); fl_value_set_string_take( value, kVisibleFrameKey, make_frame_value(frame.x, frame.y, frame.width, frame.height)); gint scale_factor = gdk_monitor_get_scale_factor(monitor); fl_value_set_string_take(value, kScaleFactorKey, fl_value_new_float(scale_factor)); return fl_value_ref(value); } // Gets the list of current screens. static FlMethodResponse* get_screen_list(FlWindowSizePlugin* self) { g_autoptr(FlValue) screens = fl_value_new_list(); GdkDisplay* display = get_display(self); if (display == nullptr) { return FL_METHOD_RESPONSE( fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); } gint n_monitors = gdk_display_get_n_monitors(display); for (gint i = 0; i < n_monitors; i++) { GdkMonitor* monitor = gdk_display_get_monitor(display, i); fl_value_append_take(screens, make_monitor_value(monitor)); } return FL_METHOD_RESPONSE(fl_method_success_response_new(screens)); } // Gets information about the Flutter window. static FlMethodResponse* get_window_info(FlWindowSizePlugin* self) { GtkWindow* window = get_window(self); if (window == nullptr) { return FL_METHOD_RESPONSE( fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); } g_autoptr(FlValue) window_info = fl_value_new_map(); gint x, y, width, height; gtk_window_get_position(window, &x, &y); gtk_window_get_size(window, &width, &height); fl_value_set_string_take(window_info, kFrameKey, make_frame_value(x, y, width, height)); // Get the monitor this window is inside, or the primary monitor if doesn't // appear to be in any. GdkDisplay* display = get_display(self); GdkMonitor* monitor_with_window = gdk_display_get_primary_monitor(display); int n_monitors = gdk_display_get_n_monitors(display); for (int i = 0; i < n_monitors; i++) { GdkMonitor* monitor = gdk_display_get_monitor(display, i); GdkRectangle frame; gdk_monitor_get_geometry(monitor, &frame); if ((x >= frame.x && x <= frame.x + frame.width) && (y >= frame.y && y <= frame.y + frame.width)) { monitor_with_window = monitor; break; } } fl_value_set_string_take(window_info, kScreenKey, make_monitor_value(monitor_with_window)); gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(window)); fl_value_set_string_take(window_info, kScaleFactorKey, fl_value_new_float(scale_factor)); return FL_METHOD_RESPONSE(fl_method_success_response_new(window_info)); } // Sets the window position and dimensions. static FlMethodResponse* set_window_frame(FlWindowSizePlugin* self, FlValue* args) { if (fl_value_get_type(args) != FL_VALUE_TYPE_LIST || fl_value_get_length(args) != 4) { return FL_METHOD_RESPONSE(fl_method_error_response_new( kBadArgumentsError, "Expected 4-element list", nullptr)); } double x = fl_value_get_float(fl_value_get_list_value(args, 0)); double y = fl_value_get_float(fl_value_get_list_value(args, 1)); double width = fl_value_get_float(fl_value_get_list_value(args, 2)); double height = fl_value_get_float(fl_value_get_list_value(args, 3)); GtkWindow* window = get_window(self); if (window == nullptr) { return FL_METHOD_RESPONSE( fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); } gtk_window_move(window, static_cast(x), static_cast(y)); gtk_window_resize(window, static_cast(width), static_cast(height)); return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); } // Send updated window geometry to GTK. static void update_window_geometry(FlWindowSizePlugin* self) { gtk_window_set_geometry_hints( get_window(self), nullptr, &self->window_geometry, static_cast(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE)); } // Sets the window minimum size. static FlMethodResponse* set_window_minimum_size(FlWindowSizePlugin* self, FlValue* args) { if (fl_value_get_type(args) != FL_VALUE_TYPE_LIST || fl_value_get_length(args) != 2) { return FL_METHOD_RESPONSE(fl_method_error_response_new( kBadArgumentsError, "Expected 2-element list", nullptr)); } double width = fl_value_get_float(fl_value_get_list_value(args, 0)); double height = fl_value_get_float(fl_value_get_list_value(args, 1)); if (get_window(self) == nullptr) { return FL_METHOD_RESPONSE( fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); } if (width >= 0 && height >= 0) { self->window_geometry.min_width = static_cast(width); self->window_geometry.min_height = static_cast(height); } update_window_geometry(self); return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); } // Sets the window maximum size. static FlMethodResponse* set_window_maximum_size(FlWindowSizePlugin* self, FlValue* args) { if (fl_value_get_type(args) != FL_VALUE_TYPE_LIST || fl_value_get_length(args) != 2) { return FL_METHOD_RESPONSE(fl_method_error_response_new( kBadArgumentsError, "Expected 2-element list", nullptr)); } double width = fl_value_get_float(fl_value_get_list_value(args, 0)); double height = fl_value_get_float(fl_value_get_list_value(args, 1)); if (get_window(self) == nullptr) { return FL_METHOD_RESPONSE( fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); } self->window_geometry.max_width = static_cast(width); self->window_geometry.max_height = static_cast(height); // Flutter uses -1 as unconstrained, GTK doesn't have an unconstrained value. if (self->window_geometry.max_width < 0) { self->window_geometry.max_width = G_MAXINT; } if (self->window_geometry.max_height < 0) { self->window_geometry.max_height = G_MAXINT; } update_window_geometry(self); return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); } // Sets the window title. static FlMethodResponse* set_window_title(FlWindowSizePlugin* self, FlValue* args) { if (fl_value_get_type(args) != FL_VALUE_TYPE_STRING) { return FL_METHOD_RESPONSE(fl_method_error_response_new( kBadArgumentsError, "Expected string", nullptr)); } GtkWindow* window = get_window(self); if (window == nullptr) { return FL_METHOD_RESPONSE( fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); } gtk_window_set_title(window, fl_value_get_string(args)); return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); } // Sets the window visibility. static FlMethodResponse* set_window_visible(FlWindowSizePlugin* self, FlValue* args) { if (fl_value_get_type(args) != FL_VALUE_TYPE_BOOL) { return FL_METHOD_RESPONSE(fl_method_error_response_new( kBadArgumentsError, "Expected bool", nullptr)); } GtkWindow* window = get_window(self); if (window == nullptr) { return FL_METHOD_RESPONSE( fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); } if (fl_value_get_bool(args)) { gtk_widget_show(GTK_WIDGET(window)); } else { gtk_widget_hide(GTK_WIDGET(window)); } return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); } // Gets the window minimum size. static FlMethodResponse* get_window_minimum_size(FlWindowSizePlugin* self) { g_autoptr(FlValue) size = fl_value_new_list(); gint min_width = self->window_geometry.min_width; gint min_height = self->window_geometry.min_height; // GTK uses -1 for the requisition size (the size GTK has calculated). // Report this as zero (smallest possible) so this doesn't look like Size(-1, -1). if (min_width < 0) { min_width = 0; } if (min_height < 0) { min_height = 0; } fl_value_append_take(size, fl_value_new_float(min_width)); fl_value_append_take(size, fl_value_new_float(min_height)); return FL_METHOD_RESPONSE(fl_method_success_response_new(size)); } // Gets the window maximum size. static FlMethodResponse* get_window_maximum_size(FlWindowSizePlugin* self) { g_autoptr(FlValue) size = fl_value_new_list(); gint max_width = self->window_geometry.max_width; gint max_height = self->window_geometry.max_height; // Flutter uses -1 as unconstrained, GTK doesn't have an unconstrained value. if (max_width == G_MAXINT) { max_width = -1; } if (max_height == G_MAXINT) { max_height = -1; } fl_value_append_take(size, fl_value_new_float(max_width)); fl_value_append_take(size, fl_value_new_float(max_height)); return FL_METHOD_RESPONSE(fl_method_success_response_new(size)); } // Called when a method call is received from Flutter. static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data) { FlWindowSizePlugin* self = FL_WINDOW_SIZE_PLUGIN(user_data); const gchar* method = fl_method_call_get_name(method_call); FlValue* args = fl_method_call_get_args(method_call); g_autoptr(FlMethodResponse) response = nullptr; if (strcmp(method, kGetScreenListMethod) == 0) { response = get_screen_list(self); } else if (strcmp(method, kGetWindowInfoMethod) == 0) { response = get_window_info(self); } else if (strcmp(method, kSetWindowFrameMethod) == 0) { response = set_window_frame(self, args); } else if (strcmp(method, kSetWindowMinimumSizeMethod) == 0) { response = set_window_minimum_size(self, args); } else if (strcmp(method, kSetWindowMaximumSizeMethod) == 0) { response = set_window_maximum_size(self, args); } else if (strcmp(method, kSetWindowTitleMethod) == 0) { response = set_window_title(self, args); } else if (strcmp(method, ksetWindowVisibilityMethod) == 0) { response = set_window_visible(self, args); } else if (strcmp(method, kGetWindowMinimumSizeMethod) == 0) { response = get_window_minimum_size(self); } else if (strcmp(method, kGetWindowMaximumSizeMethod) == 0) { response = get_window_maximum_size(self); } else { response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); } g_autoptr(GError) error = nullptr; if (!fl_method_call_respond(method_call, response, &error)) g_warning("Failed to send method call response: %s", error->message); } static void fl_window_size_plugin_dispose(GObject* object) { FlWindowSizePlugin* self = FL_WINDOW_SIZE_PLUGIN(object); g_clear_object(&self->registrar); g_clear_object(&self->channel); G_OBJECT_CLASS(fl_window_size_plugin_parent_class)->dispose(object); } static void fl_window_size_plugin_class_init(FlWindowSizePluginClass* klass) { G_OBJECT_CLASS(klass)->dispose = fl_window_size_plugin_dispose; } static void fl_window_size_plugin_init(FlWindowSizePlugin* self) { self->window_geometry.min_width = -1; self->window_geometry.min_height = -1; self->window_geometry.max_width = G_MAXINT; self->window_geometry.max_height = G_MAXINT; } FlWindowSizePlugin* fl_window_size_plugin_new(FlPluginRegistrar* registrar) { FlWindowSizePlugin* self = FL_WINDOW_SIZE_PLUGIN( g_object_new(fl_window_size_plugin_get_type(), nullptr)); self->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar)); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); self->channel = fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), kChannelName, FL_METHOD_CODEC(codec)); fl_method_channel_set_method_call_handler(self->channel, method_call_cb, g_object_ref(self), g_object_unref); return self; } void window_size_plugin_register_with_registrar(FlPluginRegistrar* registrar) { FlWindowSizePlugin* plugin = fl_window_size_plugin_new(registrar); g_object_unref(plugin); } ================================================ FILE: plugins/window_size/macos/Classes/FLEWindowSizePlugin.h ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #import #import /** * A FlutterPlugin to manage macOS's shared NSColorPanel singleton. * Responsible for managing the panel's display state and sending selected color data to Flutter. */ @interface FLEWindowSizePlugin : NSObject @end ================================================ FILE: plugins/window_size/macos/Classes/FLEWindowSizePlugin.mm ================================================ // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #import "FLEWindowSizePlugin.h" #import namespace { // See window_size_channel.dart for documentation. NSString *const kChannelName = @"flutter/windowsize"; NSString *const kGetScreenListMethod = @"getScreenList"; NSString *const kGetWindowInfoMethod = @"getWindowInfo"; NSString *const kSetWindowFrameMethod = @"setWindowFrame"; NSString *const kSetWindowMinimumSizeMethod = @"setWindowMinimumSize"; NSString *const kSetWindowMaximumSizeMethod = @"setWindowMaximumSize"; NSString *const kSetWindowTitleMethod = @"setWindowTitle"; NSString *const kSetWindowTitleRepresentedUrlMethod = @"setWindowTitleRepresentedUrl"; NSString *const kSetWindowVisibilityMethod = @"setWindowVisibility"; NSString *const kGetWindowMinimumSizeMethod = @"getWindowMinimumSize"; NSString *const kGetWindowMaximumSizeMethod = @"getWindowMaximumSize"; NSString *const kFrameKey = @"frame"; NSString *const kVisibleFrameKey = @"visibleFrame"; NSString *const kScaleFactorKey = @"scaleFactor"; NSString *const kScreenKey = @"screen"; /** * Returns the max Y coordinate across all screens. */ CGFloat GetMaxScreenY() { CGFloat maxY = 0; for (NSScreen *screen in [NSScreen screens]) { maxY = MAX(maxY, CGRectGetMaxY(screen.frame)); } return maxY; } /** * Given |frame| in screen coordinates, returns a frame flipped relative to * GetMaxScreenY(). */ NSRect GetFlippedRect(NSRect frame) { CGFloat maxY = GetMaxScreenY(); return NSMakeRect(frame.origin.x, maxY - frame.origin.y - frame.size.height, frame.size.width, frame.size.height); } /** * Converts the channel representation for unconstrained maximum size `-1` to Cocoa's specific * maximum size of `FLT_MAX`. */ double MaxDimensionFromChannelRepresentation(double size) { return size == -1.0 ? FLT_MAX : size; } /** * Converts Cocoa's specific maximum size of `FLT_MAX` to channel representation for unconstrained * maximum size `-1`. */ double ChannelRepresentationForMaxDimension(double size) { return size == FLT_MAX ? -1 : size; } } // namespace @interface FLEWindowSizePlugin () /// The view displaying Flutter content. @property(nonatomic, readonly) NSView *flutterView; /** * Extracts information from |screen| and returns the serializable form expected * by the platform channel. */ - (NSDictionary *)platformChannelRepresentationForScreen:(NSScreen *)screen; /** * Extracts information from |window| and returns the serializable form expected * by the platform channel. */ - (NSDictionary *)platformChannelRepresentationForWindow:(NSWindow *)window; /** * Returns the serializable form of |frame| expected by the platform channel. */ - (NSArray *)platformChannelRepresentationForFrame:(NSRect)frame; @end @implementation FLEWindowSizePlugin { // The channel used to communicate with Flutter. FlutterMethodChannel *_channel; // A reference to the registrar holding the NSView used by the plugin. Holding a reference // since the view might be nil at the time the plugin is created. id _registrar; } - (NSView *)flutterView { return _registrar.view; } + (void)registerWithRegistrar:(id)registrar { FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kChannelName binaryMessenger:registrar.messenger]; FLEWindowSizePlugin *instance = [[FLEWindowSizePlugin alloc] initWithChannel:channel registrar:registrar]; [registrar addMethodCallDelegate:instance channel:channel]; } - (instancetype)initWithChannel:(FlutterMethodChannel *)channel registrar:(id)registrar { self = [super init]; if (self) { _channel = channel; _registrar = registrar; } return self; } /** * Handles platform messages generated by the Flutter framework on the platform channel. */ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { id methodResult = nil; if ([call.method isEqualToString:kGetScreenListMethod]) { NSMutableArray *screenList = [NSMutableArray arrayWithCapacity:[NSScreen screens].count]; for (NSScreen *screen in [NSScreen screens]) { [screenList addObject:[self platformChannelRepresentationForScreen:screen]]; } methodResult = screenList; } else if ([call.method isEqualToString:kGetWindowInfoMethod]) { methodResult = [self platformChannelRepresentationForWindow:self.flutterView.window]; } else if ([call.method isEqualToString:kSetWindowFrameMethod]) { NSArray *arguments = call.arguments; [self.flutterView.window setFrame:GetFlippedRect(NSMakeRect(arguments[0].doubleValue, arguments[1].doubleValue, arguments[2].doubleValue, arguments[3].doubleValue)) display:YES]; methodResult = nil; } else if ([call.method isEqualToString:kSetWindowMinimumSizeMethod]) { NSArray *arguments = call.arguments; self.flutterView.window.minSize = NSMakeSize(arguments[0].doubleValue, arguments[1].doubleValue); methodResult = nil; } else if ([call.method isEqualToString:kSetWindowMaximumSizeMethod]) { NSArray *arguments = call.arguments; self.flutterView.window.maxSize = NSMakeSize(MaxDimensionFromChannelRepresentation(arguments[0].doubleValue), MaxDimensionFromChannelRepresentation(arguments[1].doubleValue)); methodResult = nil; } else if ([call.method isEqualToString:kGetWindowMinimumSizeMethod]) { NSSize size = self.flutterView.window.minSize; methodResult = @[ @(size.width), @(size.height) ]; } else if ([call.method isEqualToString:kGetWindowMaximumSizeMethod]) { NSSize size = self.flutterView.window.maxSize; methodResult = @[ @(ChannelRepresentationForMaxDimension(size.width)), @(ChannelRepresentationForMaxDimension(size.height)) ]; } else if ([call.method isEqualToString:kSetWindowTitleMethod]) { NSString *title = call.arguments; self.flutterView.window.title = title; methodResult = nil; } else if ([call.method isEqualToString:kSetWindowTitleRepresentedUrlMethod]) { NSURL *representedURL = [NSURL URLWithString:call.arguments]; self.flutterView.window.representedURL = representedURL; methodResult = nil; } else if ([call.method isEqualToString:kSetWindowVisibilityMethod]) { bool visible = [call.arguments boolValue]; if (visible) { [self.flutterView.window makeKeyAndOrderFront:self]; } else { [self.flutterView.window orderOut:self]; } methodResult = nil; } else { methodResult = FlutterMethodNotImplemented; } result(methodResult); } #pragma mark - Private methods - (NSDictionary *)platformChannelRepresentationForScreen:(NSScreen *)screen { return @{ kFrameKey : [self platformChannelRepresentationForFrame:GetFlippedRect(screen.frame)], kVisibleFrameKey : [self platformChannelRepresentationForFrame:GetFlippedRect(screen.visibleFrame)], kScaleFactorKey : @(screen.backingScaleFactor), }; } - (NSDictionary *)platformChannelRepresentationForWindow:(NSWindow *)window { return @{ kFrameKey : [self platformChannelRepresentationForFrame:GetFlippedRect(window.frame)], kScreenKey : [self platformChannelRepresentationForScreen:window.screen], kScaleFactorKey : @(window.backingScaleFactor), }; } - (NSArray *)platformChannelRepresentationForFrame:(NSRect)frame { return @[ @(frame.origin.x), @(frame.origin.y), @(frame.size.width), @(frame.size.height) ]; } @end ================================================ FILE: plugins/window_size/macos/Classes/WindowSizePlugin.swift ================================================ // Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import FlutterMacOS import Foundation public class WindowSizePlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { FLEWindowSizePlugin.register(with: registrar) } } ================================================ FILE: plugins/window_size/macos/window_size.podspec ================================================ # # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html # Pod::Spec.new do |s| s.name = 'window_size' s.version = '0.0.2' s.summary = 'Allows resizing and repositioning the window containing Flutter.' s.description = <<-DESC Allows resizing and repositioning the window containing Flutter. DESC s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/window_size' s.license = { :file => '../LICENSE' } s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'FlutterMacOS' s.platform = :osx s.osx.deployment_target = '10.11' end ================================================ FILE: plugins/window_size/pubspec.yaml ================================================ name: window_size description: Allows resizing and repositioning the window containing Flutter. version: 0.1.0 # Do not publish this plugin. See: # https://github.com/google/flutter-desktop-embedding/blob/master/plugins/README.md#using-plugins publish_to: none flutter: plugin: platforms: linux: pluginClass: WindowSizePlugin macos: pluginClass: WindowSizePlugin windows: pluginClass: WindowSizePlugin environment: sdk: '>=2.12.0-0 <3.0.0' dependencies: flutter: sdk: flutter ================================================ FILE: plugins/window_size/windows/.gitignore ================================================ flutter/ # Visual Studio user-specific files. *.suo *.user *.userosscache *.sln.docstates # Visual Studio build-related files. x64/ x86/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ ================================================ FILE: plugins/window_size/windows/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) set(PROJECT_NAME "window_size") project(${PROJECT_NAME} LANGUAGES CXX) set(PLUGIN_NAME "${PROJECT_NAME}_plugin") add_library(${PLUGIN_NAME} SHARED "${PLUGIN_NAME}.cpp" ) apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_compile_definitions(${PLUGIN_NAME} PRIVATE _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) # List of absolute paths to libraries that should be bundled with the plugin set(window_size_bundled_libraries "" PARENT_SCOPE ) ================================================ FILE: plugins/window_size/windows/include/window_size/window_size_plugin.h ================================================ // Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef PLUGINS_WINDOW_SIZE_WINDOWS_WINDOW_SIZE_PLUGIN_H_ #define PLUGINS_WINDOW_SIZE_WINDOWS_WINDOW_SIZE_PLUGIN_H_ // A plugin to allow resizing the window. #include #ifdef FLUTTER_PLUGIN_IMPL #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) #else #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) #endif #if defined(__cplusplus) extern "C" { #endif FLUTTER_PLUGIN_EXPORT void WindowSizePluginRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar); #if defined(__cplusplus) } // extern "C" #endif #endif // PLUGINS_WINDOW_SIZE_WINDOWS_WINDOW_SIZE_PLUGIN_H_ ================================================ FILE: plugins/window_size/windows/window_size_plugin.cpp ================================================ // Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "include/window_size/window_size_plugin.h" #include #include #include #include #include #include #include #include #include #include namespace { using flutter::EncodableList; using flutter::EncodableMap; using flutter::EncodableValue; // See window_size_channel.dart for documentation. const char kChannelName[] = "flutter/windowsize"; const char kGetScreenListMethod[] = "getScreenList"; const char kGetWindowInfoMethod[] = "getWindowInfo"; const char kSetWindowFrameMethod[] = "setWindowFrame"; const char kSetWindowMinimumSize[] = "setWindowMinimumSize"; const char kSetWindowMaximumSize[] = "setWindowMaximumSize"; const char kSetWindowTitleMethod[] = "setWindowTitle"; const char ksetWindowVisibilityMethod[] = "setWindowVisibility"; const char kFrameKey[] = "frame"; const char kVisibleFrameKey[] = "visibleFrame"; const char kScaleFactorKey[] = "scaleFactor"; const char kScreenKey[] = "screen"; const double kBaseDpi = 96.0; // Returns a POINT corresponding to channel representation of a size. POINT GetPointForPlatformChannelRepresentationSize(const EncodableList &size) { POINT point = {}; point.x = static_cast(std::get(size[0])); point.y = static_cast(std::get(size[1])); return point; } // Returns the serializable form of |frame| expected by the platform channel. EncodableValue GetPlatformChannelRepresentationForRect(const RECT &rect) { return EncodableValue(EncodableList{ EncodableValue(static_cast(rect.left)), EncodableValue(static_cast(rect.top)), EncodableValue(static_cast(rect.right) - static_cast(rect.left)), EncodableValue(static_cast(rect.bottom) - static_cast(rect.top)), }); } // Extracts information from monitor |monitor| and returns the // serializable form expected by the platform channel. EncodableValue GetPlatformChannelRepresentationForMonitor(HMONITOR monitor) { if (!monitor) { return EncodableValue(); } MONITORINFO info; info.cbSize = sizeof(MONITORINFO); ::GetMonitorInfo(monitor, &info); UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); double scale_factor = dpi / kBaseDpi; return EncodableValue(EncodableMap{ {EncodableValue(kFrameKey), GetPlatformChannelRepresentationForRect(info.rcMonitor)}, {EncodableValue(kVisibleFrameKey), GetPlatformChannelRepresentationForRect(info.rcWork)}, {EncodableValue(kScaleFactorKey), EncodableValue(scale_factor)}, }); } BOOL CALLBACK MonitorRepresentationEnumProc(HMONITOR monitor, HDC hdc, LPRECT clip, LPARAM list_ref) { EncodableValue *monitors = reinterpret_cast(list_ref); std::get(*monitors).push_back( GetPlatformChannelRepresentationForMonitor(monitor)); return TRUE; } // Extracts information from |window| and returns the serializable form expected // by the platform channel. EncodableValue GetPlatformChannelRepresentationForWindow(HWND window) { if (!window) { return EncodableValue(); } RECT frame; ::GetWindowRect(window, &frame); HMONITOR window_monitor = ::MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); double scale_factor = FlutterDesktopGetDpiForHWND(window) / kBaseDpi; return EncodableValue(EncodableMap{ {EncodableValue(kFrameKey), GetPlatformChannelRepresentationForRect(frame)}, {EncodableValue(kScreenKey), GetPlatformChannelRepresentationForMonitor(window_monitor)}, {EncodableValue(kScaleFactorKey), EncodableValue(scale_factor)}, }); } HWND GetRootWindow(flutter::FlutterView *view) { return ::GetAncestor(view->GetNativeWindow(), GA_ROOT); } class WindowSizePlugin : public flutter::Plugin { public: static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); // Creates a plugin that communicates on the given channel. WindowSizePlugin(flutter::PluginRegistrarWindows *registrar); virtual ~WindowSizePlugin(); private: // Called when a method is called on the plugin channel; void HandleMethodCall(const flutter::MethodCall<> &method_call, std::unique_ptr> result); // Called for top-level WindowProc delegation. std::optional HandleWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); // The registrar for this plugin, for accessing the window. flutter::PluginRegistrarWindows *registrar_; // The ID of the WindowProc delegate registration. int window_proc_id_ = -1; // The minimum size set by the platform channel. POINT min_size_ = {0, 0}; // The maximum size set by the platform channel. POINT max_size_ = {-1, -1}; }; // static void WindowSizePlugin::RegisterWithRegistrar( flutter::PluginRegistrarWindows *registrar) { auto channel = std::make_unique>( registrar->messenger(), kChannelName, &flutter::StandardMethodCodec::GetInstance()); auto plugin = std::make_unique(registrar); channel->SetMethodCallHandler( [plugin_pointer = plugin.get()](const auto &call, auto result) { plugin_pointer->HandleMethodCall(call, std::move(result)); }); registrar->AddPlugin(std::move(plugin)); } WindowSizePlugin::WindowSizePlugin(flutter::PluginRegistrarWindows *registrar) : registrar_(registrar) { window_proc_id_ = registrar_->RegisterTopLevelWindowProcDelegate( [this](HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { return HandleWindowProc(hwnd, message, wparam, lparam); }); } WindowSizePlugin::~WindowSizePlugin() { registrar_->UnregisterTopLevelWindowProcDelegate(window_proc_id_); } void WindowSizePlugin::HandleMethodCall( const flutter::MethodCall<> &method_call, std::unique_ptr> result) { if (method_call.method_name().compare(kGetScreenListMethod) == 0) { EncodableValue screens(std::in_place_type); ::EnumDisplayMonitors(nullptr, nullptr, MonitorRepresentationEnumProc, reinterpret_cast(&screens)); result->Success(screens); } else if (method_call.method_name().compare(kGetWindowInfoMethod) == 0) { result->Success(GetPlatformChannelRepresentationForWindow( GetRootWindow(registrar_->GetView()))); } else if (method_call.method_name().compare(kSetWindowFrameMethod) == 0) { const auto *frame_list = std::get_if(method_call.arguments()); if (!frame_list || frame_list->size() != 4) { result->Error("Bad arguments", "Expected 4-element list"); return; } // Frame validity (e.g., non-zero size) is assumed to be checked on the Dart // side of the call. int x = static_cast(std::get((*frame_list)[0])); int y = static_cast(std::get((*frame_list)[1])); int width = static_cast(std::get((*frame_list)[2])); int height = static_cast(std::get((*frame_list)[3])); ::SetWindowPos(GetRootWindow(registrar_->GetView()), nullptr, x, y, width, height, SWP_NOACTIVATE | SWP_NOOWNERZORDER); result->Success(); } else if (method_call.method_name().compare(kSetWindowMinimumSize) == 0) { const auto *size = std::get_if(method_call.arguments()); if (!size || size->size() != 2) { result->Error("Bad arguments", "Expected 2-element list"); return; } min_size_ = GetPointForPlatformChannelRepresentationSize(*size); result->Success(); } else if (method_call.method_name().compare(kSetWindowMaximumSize) == 0) { const auto *size = std::get_if(method_call.arguments()); if (!size || size->size() != 2) { result->Error("Bad arguments", "Expected 2-element list"); return; } max_size_ = GetPointForPlatformChannelRepresentationSize(*size); result->Success(); } else if (method_call.method_name().compare(kSetWindowTitleMethod) == 0) { const auto *title = std::get_if(method_call.arguments()); if (!title) { result->Error("Bad arguments", "Expected string"); return; } std::wstring wstr = std::wstring_convert, wchar_t>{} .from_bytes(*title); ::SetWindowText(GetRootWindow(registrar_->GetView()), wstr.c_str()); result->Success(); } else if (method_call.method_name().compare(ksetWindowVisibilityMethod) == 0) { const bool *visible = std::get_if(method_call.arguments()); if (visible == nullptr) { result->Error("Bad arguments", "Expected bool"); return; } ::ShowWindow(GetRootWindow(registrar_->GetView()), *visible ? SW_SHOW : SW_HIDE); result->Success(); } else { result->NotImplemented(); } } std::optional WindowSizePlugin::HandleWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { std::optional result; switch (message) { case WM_GETMINMAXINFO: MINMAXINFO *info = reinterpret_cast(lparam); // For the special "unconstrained" values, leave the defaults. if (min_size_.x != 0) info->ptMinTrackSize.x = min_size_.x; if (min_size_.y != 0) info->ptMinTrackSize.y = min_size_.y; if (max_size_.x != -1) info->ptMaxTrackSize.x = max_size_.x; if (max_size_.y != -1) info->ptMaxTrackSize.y = max_size_.y; result = 0; break; } return result; } } // namespace void WindowSizePluginRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar) { WindowSizePlugin::RegisterWithRegistrar( flutter::PluginRegistrarManager::GetInstance() ->GetRegistrar(registrar)); }