Giter VIP home page Giter VIP logo

macosui / macos_window_utils.dart Goto Github PK

View Code? Open in Web Editor NEW
46.0 4.0 9.0 518 KB

macos_window_utils is a Flutter package that provides a set of methods for modifying the NSWindow of a Flutter application on macOS.

Home Page: https://pub.dev/packages/macos_window_utils

License: MIT License

Kotlin 0.05% Swift 24.68% Objective-C 0.01% Dart 58.04% CMake 6.79% C++ 7.61% C 0.52% HTML 0.66% Ruby 1.44% Shell 0.20%
dart flutter macos nswindow transparent-window window-blur wallpaper-tinting

macos_window_utils.dart's Introduction

English | 简体中文

macos_window_utils is a Flutter package that provides a set of methods for modifying the NSWindow of a Flutter application on macOS. With this package, you can easily customize the appearance and behavior of your app's window, including the title bar, transparency effects, shadow, and more.

Features

macos_window_utils provides, among other things, the following features:

  • Methods to set the application window's material.
  • Methods to enter/exit fullscreen mode or (un)zoom the window.
  • Methods to mark a window as “document edited”.
  • Methods to set represented filenames and URLs.
  • Methods to hide/show the window's title.
  • Methods to enable/disable the full-size content view.
  • Methods to show/hide and enable/disable the window's traffic light buttons.
  • A method to set the window's alpha value.
  • Methods to add a toolbar to the window and set its style.
  • A method to add a subtitle to the window.
  • Methods to make the window ignore mouse events.
  • A method that makes the window fully transparent (with no blur effect).
  • Methods to enable/disable the window's shadow.
  • Methods and widgets to add, remove, and modify visual effect subviews.
  • Methods to set the window's level as well as reorder the window within its level.
  • Methods to modify the window's style mask.
  • An abstract NSWindowDelegate class that can be used to detect NSWindow events, such as window resizing, moving, exposing, and minimizing.
  • An NSAppPresentationOptions class that allows modifications to the window's fullscreen presentation options.
  • Methods to get and set the positions of the window’s standard window buttons (such as the close, miniaturize, and zoom buttons).
  • Methods to control whether the window should be closable by the user, as well as methods to close the window programmatically.

Additionally, the package ships with an example project that showcases the plugin's features via an intuitive searchable user interface:

screenshot of example project

Getting started

First, install the package via the following command:

flutter pub add macos_window_utils

Afterward, open the macos/Runner.xcworkspace folder of your project using Xcode, press ⇧ + ⌘ + O and search for Runner.xcodeproj.

Go to Info > Deployment Target and set the macOS Deployment Target to 10.14.6 or above. Then, open your project's Podfile (if it doesn't show up in Xcode, you can find it in your project's macos directory via VS Code) and set the minimum deployment version in the first line to 10.14.6 or above:

platform :osx, '10.14.6'

Depending on your use case, you may want to extend the area of the window that Flutter can draw to to the entire window, such that you are able to draw onto the window's title bar as well (for example when you're only trying to make the sidebar transparent while the rest of the window is meant to stay opaque).

To do so, enable the full-size content view with the following Dart code:

WindowManipulator.makeTitlebarTransparent();
WindowManipulator.enableFullSizeContentView();

When you decide to do this, it is recommended to wrap your application (or parts of it) in a TitlebarSafeArea widget as follows:

TitlebarSafeArea(
  child: YourApp(),
)

This ensures that your app is not covered by the window's title bar.

Additionally, it may be worth considering to split your sidebar and your main view into multiple NSVisualEffectView's inside your app. This is because macOS has a feature called “wallpaper tinting,” which is enabled by default. This feature allows windows to blend in with the desktop wallpaper:

macos_wallpaper_tinting

To achieve the same effect in your Flutter application, you can set the window's material to NSVisualEffectViewMaterial.windowBackground and wrap your sidebar widget with a TransparentMacOSSidebar widget like so:

TransparentMacOSSidebar(
  child: YourSidebarWidget(),
)

Note: The widget will automatically resize the NSVisualEffectView when a resize is detected in the widget's build method. If you are animating your sidebar's size using a TweenAnimationBuilder, please make sure that the TransparentMacOSSidebar widget is built within the TweenAnimationBuilder's build method, in order to guarantee that a rebuild is triggered when the size changes. For reference, there is a working example in the transparent_sidebar_and_content.dart file of the example project.

Usage

Initialize the plugin as follows:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await WindowManipulator.initialize();
  runApp(MyApp());
}

Afterwards, call any method of the WindowManipulator class to manipulate your application's window.

Using NSWindowDelegate

NSWindowDelegate can be used to listen to NSWindow events, such as window resizing, moving, exposing, and minimizing. To use it, first make sure that enableWindowDelegate is set to true in your WindowManipulator.initialize call:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // By default, enableWindowDelegate is set to false to ensure compatibility
  // with other plugins. Set it to true if you wish to use NSWindowDelegate.
  await WindowManipulator.initialize(enableWindowDelegate: true);
  runApp(MyApp());
}

Afterwards, create a class that extends it:

class _MyDelegate extends NSWindowDelegate {
  @override
  void windowDidEnterFullScreen() {
    print('The window has entered fullscreen mode.');
    
    super.windowDidEnterFullScreen();
  }
}

This class overrides the NSWindowDelegate's windowDidEnterFullScreen method in order to respond to it.

The following methods are currently supported by NSWindowDelegate:

Supported methods
  • Managing Sheets
    • windowWillBeginSheet
    • windowDidEndSheet
  • Sizing Windows
    • windowWillResize
    • windowDidResize
    • windowWillStartLiveResize
    • windowDidEndLiveResize
  • Minimizing Windows
    • windowWillMiniaturize
    • windowDidMiniaturize
    • windowDidDeminiaturize
  • Zooming Window
    • windowWillUseStandardFrame
    • windowShouldZoom
  • Managing Full-Screen Presentation
    • windowWillEnterFullScreen
    • windowDidEnterFullScreen
    • windowWillExitFullScreen
    • windowDidExitFullScreen
  • Moving Windows
    • windowWillMove
    • windowDidMove
    • windowDidChangeScreen
    • windowDidChangeScreenProfile
    • windowDidChangeBackingProperties
  • Closing Windows
    • windowShouldClose
    • windowWillClose
  • Managing Key Status
    • windowDidBecomeKey
    • windowDidResignKey
  • Managing Main Status
    • windowDidBecomeMain
    • windowDidResignMain
  • Exposing Windows
    • windowDidExpose
  • Managing Occlusion State
    • windowDidChangeOcclusionState
  • Managing Presentation in Version Browsers
    • windowWillEnterVersionBrowser
    • windowDidEnterVersionBrowser
    • windowWillExitVersionBrowser
    • windowDidExitVersionBrowser

Then, add an instance of it via the WindowManipulator.addNSWindowDelegate method:

 final delegate = _MyDelegate();
 final handle = WindowManipulator.addNSWindowDelegate(delegate);

WindowManipulator.addNSWindowDelegate returns a NSWindowDelegateHandle which can be used to remove this NSWindowDelegate again later:

handle.removeFromHandler();

Using NSAppPresentationOptions

Say we would like to automatically hide the toolbar when the window is in fullscreen mode. Using NSAppPresentationOptions this can be done as follows:

// Create NSAppPresentationOptions instance.
final options = NSAppPresentationOptions.from({
  // fullScreen needs to be present as a fullscreen presentation option at all
  // times.
  NSAppPresentationOption.fullScreen,

  // Hide the toolbar automatically in fullscreen mode.
  NSAppPresentationOption.autoHideToolbar,

  // autoHideToolbar must be accompanied by autoHideMenuBar.
  NSAppPresentationOption.autoHideMenuBar,

  // autoHideMenuBar must be accompanied by either autoHideDock or hideDock.
  NSAppPresentationOption.autoHideDock,
});

// Apply the options as fullscreen presentation options.
options.applyAsFullScreenPresentationOptions();

Note: NSAppPresentationOptions uses the NSWindow's delegate to change the window's fullscreen presentation options. Therefore, enableWindowDelegate needs to be set to true in your WindowManipulator.initialize call for it to work.

License

MIT License

macos_window_utils.dart's People

Contributors

adrian-samoticha avatar kacikgoez avatar lollipopkit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

macos_window_utils.dart's Issues

global keyboard capture? (possible feature bounty)

I've longed for an easy way to easily capture global keyboard hotkeys for apps like screen capture (think ShareX) etc... looking to start a bounty for this (not sure how, but definitely need this lol)

Make it possible to center the window on the screen

Is there currently a set of APIs that makes it possible to set the size of the window and place it at the center of the screen?

If not, it would be great to have those APIs. I'm trying to control the initial launch of the app to center a window of a particular window size.

Create a TrafficLightsSafeArea widget

This library has TitlebarSafeArea, which pushes content down below the title bar.

I'm displaying tabs in the title bar area and I need the tabs to avoid the traffic lights, but not by pushing the content down. Instead, I need to push the content to the right of the traffic lights, but remain at the top of the screen.

Consider offering a TrafficLightsSafeArea for this purpose. Or, consider adding a property to TitlebarSafeArea that toggles between pushing content down, vs pushing content away from the traffic lights within the title bar.

I filed an equivalent issue in macos_ui before seeing that this package already has a TitlebarSafeArea: macosui/macos_ui#437

I'll let the maintainers hash out where that belongs.

Add `miniaturize`, `deminiaturize`, `performMiniaturize`, and `isMiniaturized` methods

Add methods for the miniaturize, deminiaturize, performMiniaturize, and isMiniaturized methods of the NSWindow.

None of those methods require any arguments (except for a sender, which may be nil), and are therefore very straightforward to implement, which is why I have marked this issue as a “good first issue”.

If this is your first time contributing to a macOS plugin, feel free to use the CONTRIBUTING.md file as guidance.

Resolve minimum deployment version inconsistency

According to the README.md file, the macOS Deployment Target needs to be set to 10.13 or above:

Now press ⇧ + ⌘ + O once more and search for Runner.xcodeproj. Go to info > Deployment Target and set the macOS Deployment Target to 10.13 or above.

However, in the Podfile, of the example project, the first line reads as follows:

platform :osx, '10.14.6' # IMPORTANT: Make sure this is set to 10.14.6 or above!

There is no mention of this in the README.md file. This could cause confusion for users trying to implement this plugin into their projects.

[Question] Transparency compatibility with desktop_multi_window

Hello, I saw that it is possible to make sub window transparent like so: macosui/macos_ui#322 (reply in thread)
image

How did you manage to make it work?
I want to implement it in a fork of this since it would be unreasonable to introduce breaking changes.
It could be helpful for others too, as I honestly don't see official multi-window implementation happening this year.

As of now, calling WindowManipulator.makeWindowFullyTransparent() on sub windows really doesn't do anything as far as I notice.

Let user's specify a static window size

By default, a window is resizable. I'd like to display a window at a set width, that the user isn't allowed to change. I'd like the height to respect a minimum and maximum height if the user tries to resize the window.

Please consider adding an API to specify imposed window constraints that prevent the user from making a window thinner/wider/taller/shorter than desired.

On a related note, I found that the only control I have over window sizing is to set the global rect, which requires knowledge of screen space. I'd prefer to just set the window size, and retain the existing location.

Similarly, the window delegate notifies us when the window will resize to a given Size, but if we want to then further resize the window, based on that new Size, we're forced to create a Rect in global screen space, so that we can use the Rect-based sizing method.

Please consider creating a symmetric API in which we can read and write sizes with Size, and we can read and write global positions with Rect. As of right now, we read Sizes and we write Rects, which is asymmetric.

Lastly, on a further related note, you might consider providing a method to change only the windows offset, without exposing the full Rect. Perhaps I want to move the (x,y) offset of the window, but I don't know the size, and I don't care about the size.

deployment target 11.0 does not work

Environment

CPU M1 Pro
macOs 14.3
Flutter 3.19.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision abb292a07e (7 days ago) • 2024-02-20 14:35:05 -0800
Engine • revision 04817c99c9
Tools • Dart 3.3.0 • DevTools 2.31.1

Issue

As described in getting start section, I changed the minimum deployment target to 11.0. But Is still got "increase your application's deployment target to at least 10.14.6" error. By the way, I can find "MACOSX_DEPLOYMENT_TARGET = 11.0;" in project/macos/Runner.xcodeproj/project.pbxproj file, which means I successfully changed the deployment target.

Add query and mutation controls for the traffic light window buttons

Every Mac desktop window has three little window control buttons, often called "traffic lights".

These buttons have a default appearance, but their location can be changed by the developer.

The traffic lights create at least a couple of issues for UI developers.

First, content needs to avoid the traffic lights. If I'm building a custom app bar, or allowing my content to flow to the top of the window, how do I know where those traffic lights are? This requires an ability to query the current size and location of the traffic lights, from the platform.

Second, if I'm building a custom app bar, it's conventional that the traffic light buttons should appear vertically centered in that app bar. Therefore, I'd like to be able to tell the platform where to put the traffic lights.

I recommend approaching this problem as pass-through control of the platform. I don't recommend trying to hide information, or simplify behavior. The platform has an API for these details - making that API available through this package via Dart is the most versatile option available. Simplified behaviors and widgets can be added on top in macos_ui.

Consider offering a widget for window configuration

As far as I can tell, based on the README documentation, all window configurations go through imperative static methods.

Consider offering a widget for most/all of these configurations. You don't need to remove the imperative configurations, but it might be a lot more natural for Flutter developers to consume these options as a widget.

Widget build(BuildContext context) {
  return MacWindow(
    initialSize: const Size(1000, 650),
    titlebarStyle: const MacWindowTitleBarStyle(
      transparent: true,
      hideTitle: true,
    ),
    fullSizeContentView: true,
    child: MaterialApp(
      home: MyHomePage(),
    ),
  );
}

By offering these capabilities as a widget, you don't need for developers to explicitly initialize the Flutter binding. You don't need developers to create a place for asynchronous execution. You don't need developers to leave the widget tree.

macos_window_utils/MainFlutterWindowManipulator.swift:370: Fatal error: Unexpectedly found nil while unwrapping an Optional value

macos_window_utils/MainFlutterWindowManipulator.swift:370: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Got this when running old code.

Here is the setup in main.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()
  }
}

Consider moving away from static methods

WindowManipulator is completely based on static methods. This seems to create at least three limitations:

Developers can't use Dart's built-in builder syntax:

WindowManipulator
  ..makeTitlebarTransparent()
  ..enableFullSizeContentView()
  ..etc

It seems unlikely that this API will work in a world with multiple windows.

The implementation can't be replaced with a fake version for tests.

All of these issues could be alleviated by using a typical singleton implementation: WindowManipulator.instance or WindowManipulator.primary, etc.

Avoid visual glitch on launch

When setting the window size, background, etc, upon launch, there's a visual glitch because the window begins with the standard Flutter configuration and then switches to the desired configuration when the Dart application starts running.

This glitch can be avoided by coding the application delegate to set all of these properties on launch, but writing Swift in the XCode project largely eliminates the value of this package from a window configuration standpoint.

Is there anything that can be done about this initial glitch? Is there a way to avoid showing any window until the Dart app starts up, and therefore the Dart code can set the configuration before any window is visible?

Flutter view not showing on older MacOS versions

Running the example in this repo renders an empty window on macOS 12.7.1 and 10.15.7 (both running on Intel) but works as expected on an Apple Silicon machine with macOS 14.2.1:
Screenshot 2023-12-24 at 14 25 59

I first tested older Flutter versions and then older versions of this repo. Using git bisect I was able to track it down to this one commit: 9f09f88

So I am guessing the changes in 24fe66e somehow only work for newer macOS versions? @Adrian-Samoticha do you have any ideas why this might be the case and how to fix it?

Fix typo in readme

Change this line:

An abstract NSWindowDelegate class that can be used detect NSWindow events, such as window resizing, moving, exposing, and minimizing.

to

“An abstract NSWindowDelegate class that can be used to detect NSWindow events, such as window resizing, moving, exposing, and minimizing.”

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.