Browse Source

Replaces refresh hook with a configurable minimum delay between refreshes

devmil 4 years ago
parent
commit
611584e7af
2 changed files with 46 additions and 9 deletions
  1. 7 9
      lib/terminal/terminal_isolate.dart
  2. 39 0
      lib/util/event_debouncer.dart

+ 7 - 9
lib/terminal/terminal_isolate.dart

@@ -11,6 +11,7 @@ import 'package:xterm/terminal/terminal_backend.dart';
 import 'package:xterm/terminal/terminal_ui_interaction.dart';
 import 'package:xterm/theme/terminal_theme.dart';
 import 'package:xterm/theme/terminal_themes.dart';
+import 'package:xterm/util/event_debouncer.dart';
 import 'package:xterm/util/observable.dart';
 
 enum _IsolateCommand {
@@ -212,15 +213,13 @@ class TerminalIsolate with Observable implements TerminalUiInteraction {
   final TerminalTheme theme;
   final int maxLines;
 
+  final Duration minRefreshDelay;
+  final EventDebouncer _refreshEventDebouncer;
+
   TerminalState? _lastState;
   final _backendExited = Completer<int>();
   Future<int> get backendExited => _backendExited.future;
 
-  final Function(Function) _doRequestNewState;
-
-  static final _defaultRequestNewStateFunction =
-      (Function requestFun) => requestFun();
-
   TerminalState? get lastState {
     return _lastState;
   }
@@ -232,11 +231,10 @@ class TerminalIsolate with Observable implements TerminalUiInteraction {
       this.onIconChange = _defaultIconHandler,
       PlatformBehavior platform = PlatformBehaviors.unix,
       this.theme = TerminalThemes.defaultTheme,
-      Function(Function)? doRequestNewState,
+      this.minRefreshDelay = const Duration(milliseconds: 16),
       required this.maxLines})
       : _platform = platform,
-        _doRequestNewState =
-            doRequestNewState ?? _defaultRequestNewStateFunction;
+        _refreshEventDebouncer = EventDebouncer(minRefreshDelay);
 
   @override
   int get scrollOffsetFromBottom => _lastState!.scrollOffsetFromBottom;
@@ -336,7 +334,7 @@ class TerminalIsolate with Observable implements TerminalUiInteraction {
           this.onIconChange(message[1]);
           break;
         case _IsolateEvent.NotifyChange:
-          _doRequestNewState(() {
+          _refreshEventDebouncer.notifyEvent(() {
             poll();
           });
           break;

+ 39 - 0
lib/util/event_debouncer.dart

@@ -0,0 +1,39 @@
+import 'dart:async';
+
+/// EventDebouncer makes sure that events aren't fired at a higher frequency
+/// than specified.
+/// To ensure that EventDebouncer will ignore events that happen in between
+/// and just call the latest event that happened.
+class EventDebouncer {
+  final Duration _debounceDuration;
+  Timer? _debounceTimer;
+  Function? _latestCallback;
+
+  EventDebouncer(this._debounceDuration);
+
+  void _consumeLatestCallback() {
+    if (!(_debounceTimer?.isActive ?? false)) {
+      _debounceTimer = null;
+    }
+
+    if (_latestCallback == null) {
+      return;
+    }
+
+    if (_debounceTimer == null) {
+      _latestCallback!();
+      _latestCallback = null;
+      _debounceTimer = Timer(
+        _debounceDuration,
+        () {
+          _consumeLatestCallback();
+        },
+      );
+    }
+  }
+
+  void notifyEvent(Function callback) {
+    _latestCallback = callback;
+    _consumeLatestCallback();
+  }
+}