@@ -32,138 +32,149 @@ void main() {
3232 final Completer <void > windowCreated = Completer ();
3333 enableFlutterDriverExtension (
3434 handler: (String ? message) async {
35- await windowCreated.future;
36- if (message == null ) {
37- return '' ;
38- }
39-
40- final jsonMap = jsonDecode (message);
41- if (! jsonMap.containsKey ('type' )) {
42- throw ArgumentError ('Message must contain a "type" field.' );
43- }
35+ try {
36+ await windowCreated.future;
37+ if (message == null ) {
38+ return '' ;
39+ }
4440
45- /// This helper method registers a listener on the controller,
46- /// calls [act] to perform some action on the controller, waits for
47- /// the [predicate] to be satisified, and finally cleans up the listener.
48- Future <void > awaitNotification (
49- VoidCallback act,
50- bool Function () predicate,
51- ) async {
52- final StreamController <bool > streamController = StreamController ();
53- void notificationHandler () {
54- streamController.add (true );
41+ final jsonMap = jsonDecode (message);
42+ if (! jsonMap.containsKey ('type' )) {
43+ throw ArgumentError ('Message must contain a "type" field.' );
5544 }
5645
57- controller.addListener (notificationHandler);
46+ /// This helper method registers a listener on the controller,
47+ /// calls [act] to perform some action on the controller, waits for
48+ /// the [predicate] to be satisified, and finally cleans up the listener.
49+ Future <void > awaitNotification (
50+ VoidCallback act,
51+ bool Function () predicate,
52+ ) async {
53+ final StreamController <bool > streamController = StreamController ();
54+ void notificationHandler () {
55+ streamController.add (true );
56+ }
57+
58+ controller.addListener (notificationHandler);
5859
59- act ();
60+ try {
61+ act ();
6062
61- // On macOS, the predicate is immediately true, even though
62- // the animation is in progress and next request for state change
63- // will be ignored. Easiest way to handle this is to just wait.
64- if (defaultTargetPlatform == TargetPlatform .macOS) {
65- await Future .delayed (Duration (seconds: 1 ));
66- }
63+ // On macOS, the predicate is immediately true, even though
64+ // the animation is in progress and next request for state change
65+ // will be ignored. Easiest way to handle this is to just wait.
66+ if (defaultTargetPlatform == TargetPlatform .macOS) {
67+ await Future .delayed (Duration (seconds: 1 ));
68+ }
6769
68- await for (final _ in streamController.stream) {
69- if (predicate ()) {
70- break ;
70+ // Add a timeout to avoid hanging indefinitely
71+ await for (final _ in streamController.stream.timeout (
72+ Duration (seconds: 10 ),
73+ )) {
74+ if (predicate ()) {
75+ break ;
76+ }
77+ }
78+ } finally {
79+ controller.removeListener (notificationHandler);
80+ await streamController.close ();
7181 }
7282 }
73- controller.removeListener (notificationHandler);
74- }
7583
76- if (jsonMap['type' ] == 'ping' ) {
77- return jsonEncode ({'type' : 'pong' });
78- } else if (jsonMap['type' ] == 'get_size' ) {
79- return jsonEncode ({
80- 'width' : controller.contentSize.width,
81- 'height' : controller.contentSize.height,
82- });
83- } else if (jsonMap['type' ] == 'set_size' ) {
84- final Size size = Size (
85- jsonMap['width' ].toDouble (),
86- jsonMap['height' ].toDouble (),
87- );
88- await awaitNotification (() {
89- controller.setSize (size);
90- }, () => controller.contentSize == size);
91- } else if (jsonMap['type' ] == 'set_constraints' ) {
92- final BoxConstraints constraints = BoxConstraints (
93- minWidth: jsonMap['min_width' ].toDouble (),
94- minHeight: jsonMap['min_height' ].toDouble (),
95- maxWidth: jsonMap['max_width' ].toDouble (),
96- maxHeight: jsonMap['max_height' ].toDouble (),
97- );
98- // We assume that this will cause a resize, which the current tests do.
99- final initialSize = controller.contentSize;
100- await awaitNotification (() {
101- controller.setConstraints (constraints);
102- }, () => controller.contentSize != initialSize);
103- } else if (jsonMap['type' ] == 'set_fullscreen' ) {
104- await awaitNotification (() {
105- controller.setFullscreen (true );
106- }, () => controller.isFullscreen);
107- } else if (jsonMap['type' ] == 'unset_fullscreen' ) {
108- await awaitNotification (() {
109- controller.setFullscreen (false );
110- }, () => ! controller.isFullscreen);
111- } else if (jsonMap['type' ] == 'get_fullscreen' ) {
112- return jsonEncode ({'isFullscreen' : controller.isFullscreen});
113- } else if (jsonMap['type' ] == 'set_maximized' ) {
114- await awaitNotification (() {
115- controller.setMaximized (true );
116- }, () => controller.isMaximized);
117- } else if (jsonMap['type' ] == 'unset_maximized' ) {
118- await awaitNotification (() {
119- controller.setMaximized (false );
120- }, () => ! controller.isMaximized);
121- } else if (jsonMap['type' ] == 'get_maximized' ) {
122- return jsonEncode ({'isMaximized' : controller.isMaximized});
123- } else if (jsonMap['type' ] == 'set_minimized' ) {
124- await awaitNotification (() {
125- controller.setMinimized (true );
126- }, () => controller.isMinimized);
127- } else if (jsonMap['type' ] == 'unset_minimized' ) {
128- await awaitNotification (() {
129- controller.setMinimized (false );
130- }, () => ! controller.isMinimized);
131- } else if (jsonMap['type' ] == 'get_minimized' ) {
132- return jsonEncode ({'isMinimized' : controller.isMinimized});
133- } else if (jsonMap['type' ] == 'set_title' ) {
134- final String title = jsonMap['title' ];
135- await awaitNotification (() {
136- controller.setTitle (title);
137- }, () => controller.title == title);
138- } else if (jsonMap['type' ] == 'get_title' ) {
139- return jsonEncode ({'title' : controller.title});
140- } else if (jsonMap['type' ] == 'set_activated' ) {
141- await awaitNotification (() {
142- controller.activate ();
143- }, () => controller.isActivated);
144- } else if (jsonMap['type' ] == 'get_activated' ) {
145- return jsonEncode ({'isActivated' : controller.isActivated});
146- } else if (jsonMap['type' ] == 'open_dialog' ) {
147- if (dialogController.value != null ) {
148- return jsonEncode ({'result' : false });
84+ if (jsonMap['type' ] == 'ping' ) {
85+ return jsonEncode ({'type' : 'pong' });
86+ } else if (jsonMap['type' ] == 'get_size' ) {
87+ return jsonEncode ({
88+ 'width' : controller.contentSize.width,
89+ 'height' : controller.contentSize.height,
90+ });
91+ } else if (jsonMap['type' ] == 'set_size' ) {
92+ final Size size = Size (
93+ jsonMap['width' ].toDouble (),
94+ jsonMap['height' ].toDouble (),
95+ );
96+ await awaitNotification (() {
97+ controller.setSize (size);
98+ }, () => controller.contentSize == size);
99+ } else if (jsonMap['type' ] == 'set_constraints' ) {
100+ final BoxConstraints constraints = BoxConstraints (
101+ minWidth: jsonMap['min_width' ].toDouble (),
102+ minHeight: jsonMap['min_height' ].toDouble (),
103+ maxWidth: jsonMap['max_width' ].toDouble (),
104+ maxHeight: jsonMap['max_height' ].toDouble (),
105+ );
106+ // We assume that this will cause a resize, which the current tests do.
107+ final initialSize = controller.contentSize;
108+ await awaitNotification (() {
109+ controller.setConstraints (constraints);
110+ }, () => controller.contentSize != initialSize);
111+ } else if (jsonMap['type' ] == 'set_fullscreen' ) {
112+ await awaitNotification (() {
113+ controller.setFullscreen (true );
114+ }, () => controller.isFullscreen);
115+ } else if (jsonMap['type' ] == 'unset_fullscreen' ) {
116+ await awaitNotification (() {
117+ controller.setFullscreen (false );
118+ }, () => ! controller.isFullscreen);
119+ } else if (jsonMap['type' ] == 'get_fullscreen' ) {
120+ return jsonEncode ({'isFullscreen' : controller.isFullscreen});
121+ } else if (jsonMap['type' ] == 'set_maximized' ) {
122+ await awaitNotification (() {
123+ controller.setMaximized (true );
124+ }, () => controller.isMaximized);
125+ } else if (jsonMap['type' ] == 'unset_maximized' ) {
126+ await awaitNotification (() {
127+ controller.setMaximized (false );
128+ }, () => ! controller.isMaximized);
129+ } else if (jsonMap['type' ] == 'get_maximized' ) {
130+ return jsonEncode ({'isMaximized' : controller.isMaximized});
131+ } else if (jsonMap['type' ] == 'set_minimized' ) {
132+ await awaitNotification (() {
133+ controller.setMinimized (true );
134+ }, () => controller.isMinimized);
135+ } else if (jsonMap['type' ] == 'unset_minimized' ) {
136+ await awaitNotification (() {
137+ controller.setMinimized (false );
138+ }, () => ! controller.isMinimized);
139+ } else if (jsonMap['type' ] == 'get_minimized' ) {
140+ return jsonEncode ({'isMinimized' : controller.isMinimized});
141+ } else if (jsonMap['type' ] == 'set_title' ) {
142+ final String title = jsonMap['title' ];
143+ await awaitNotification (() {
144+ controller.setTitle (title);
145+ }, () => controller.title == title);
146+ } else if (jsonMap['type' ] == 'get_title' ) {
147+ return jsonEncode ({'title' : controller.title});
148+ } else if (jsonMap['type' ] == 'set_activated' ) {
149+ await awaitNotification (() {
150+ controller.activate ();
151+ }, () => controller.isActivated);
152+ } else if (jsonMap['type' ] == 'get_activated' ) {
153+ return jsonEncode ({'isActivated' : controller.isActivated});
154+ } else if (jsonMap['type' ] == 'open_dialog' ) {
155+ if (dialogController.value != null ) {
156+ return jsonEncode ({'result' : false });
157+ }
158+ dialogController.value = DialogWindowController (
159+ preferredSize: const Size (200 , 200 ),
160+ parent: controller,
161+ delegate: MyDialogWindowControllerDelegate (
162+ onDestroyed: () {
163+ dialogController.value = null ;
164+ },
165+ ),
166+ );
167+ return jsonEncode ({'result' : true });
168+ } else if (jsonMap['type' ] == 'close_dialog' ) {
169+ dialogController.value? .destroy ();
170+ return jsonEncode ({'result' : true });
171+ } else {
172+ throw ArgumentError ('Unknown message type: ${jsonMap ['type' ]}' );
149173 }
150- dialogController.value = DialogWindowController (
151- preferredSize: const Size (200 , 200 ),
152- parent: controller,
153- delegate: MyDialogWindowControllerDelegate (
154- onDestroyed: () {
155- dialogController.value = null ;
156- },
157- ),
158- );
159- return jsonEncode ({'result' : true });
160- } else if (jsonMap['type' ] == 'close_dialog' ) {
161- dialogController.value? .destroy ();
162- return jsonEncode ({'result' : true });
163- } else {
164- throw ArgumentError ('Unknown message type: ${jsonMap ['type' ]}' );
174+ return '' ;
175+ } catch (e) {
176+ return jsonEncode ({'error' : e.toString ()});
165177 }
166- return '' ;
167178 },
168179 );
169180 controller = RegularWindowController (
0 commit comments