diff --git a/lib/src/widgets/window_caption.dart b/lib/src/widgets/window_caption.dart index ebf0ff65..d708a7d5 100644 --- a/lib/src/widgets/window_caption.dart +++ b/lib/src/widgets/window_caption.dart @@ -104,7 +104,12 @@ class _WindowCaptionState extends State { () => nativeapi.Window.isCloseSupported() && window.close(), ) ?? false); - if (!closed) { + // Window.close() returns true once the request is made; a veto arrives + // asynchronously, so false means the request could not be made. Only a + // caption that follows the current window may then quit the app: a + // caption given its window must not end the whole application, which may + // have other windows. + if (!closed && widget.window == null) { tryNative(() => nativeapi.Application.instance.quit(0)); } } diff --git a/test/window_caption_close_test.dart b/test/window_caption_close_test.dart new file mode 100644 index 00000000..d45addf2 --- /dev/null +++ b/test/window_caption_close_test.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:window_manager/window_manager.dart'; + +// A window whose close request cannot be made, as when the platform refuses +// it. No native window is created. +class _RefusingWindow extends Window { + _RefusingWindow() : super.borrowed(0); + + int closes = 0; + + @override + bool get isMaximized => false; + + @override + bool close() { + closes++; + return false; + } +} + +void main() { + testWidgets('close button of an explicit window only addresses that window', ( + tester, + ) async { + final window = _RefusingWindow(); + await tester.pumpWidget( + MaterialApp( + home: SizedBox( + height: kWindowCaptionHeight, + child: WindowCaption(window: window), + ), + ), + ); + + await tester.tap(find.byType(WindowCaptionButton).last); + await tester.pump(); + + // The request went to the given window and nothing else was attempted: + // with an explicit window the caption no longer falls back to quitting + // the application when the window does not close. + expect(window.closes, Window.isCloseSupported() ? 1 : 0); + expect(tester.takeException(), isNull); + }); +}