fix(desktop): wakelock issue with multiple tabs in same window (#13956)

Each desktop isolate now independently tracks wakelock state.
  WakelockPlus.disable() is only called when all tabs within the
  same isolate are closed/minimized.

  WakelockPlus ensures screen stays awake as long as any isolate
  has wakelock enabled.

Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
21pages
2026-01-05 22:16:35 +08:00
committed by GitHub
parent 7ac03ffefc
commit f65952cf1c
4 changed files with 41 additions and 39 deletions

View File

@@ -24,6 +24,7 @@ import 'package:provider/provider.dart';
import 'package:uni_links/uni_links.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:window_manager/window_manager.dart';
import 'package:window_size/window_size.dart' as window_size;
@@ -2676,6 +2677,31 @@ class SimpleWrapper<T> {
SimpleWrapper(this.value);
}
/// Wakelock manager with reference counting for desktop.
/// Ensures wakelock is only disabled when all sessions are closed/minimized.
///
/// Note: Each isolate has its own WakelockPlus instance with independent assertion.
/// As long as one isolate has wakelock enabled, the screen stays awake.
/// This manager handles multiple tabs within the same isolate.
class WakelockManager {
static final Set<UniqueKey> _enabledKeys = {};
static void enable(UniqueKey key) {
if (isLinux) return;
_enabledKeys.add(key);
WakelockPlus.enable();
}
static void disable(UniqueKey key) {
if (isLinux) return;
if (_enabledKeys.remove(key)) {
if (_enabledKeys.isEmpty) {
WakelockPlus.disable();
}
}
}
}
/// call this to reload current window.
///
/// [Note]

View File

@@ -17,7 +17,6 @@ import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import 'package:flutter_hbb/models/file_model.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:flutter_hbb/web/dummy.dart'
if (dart.library.html) 'package:flutter_hbb/web/web_unique.dart';
@@ -86,6 +85,7 @@ class _FileManagerPageState extends State<FileManagerPage>
final _dropMaskVisible = false.obs; // TODO impl drop mask
final _overlayKeyState = OverlayKeyState();
final _uniqueKey = UniqueKey();
late FFI _ffi;
@@ -107,9 +107,7 @@ class _FileManagerPageState extends State<FileManagerPage>
.showLoading(translate('Connecting...'), onCancel: closeConnection);
});
Get.put<FFI>(_ffi, tag: 'ft_${widget.id}');
if (!isLinux) {
WakelockPlus.enable();
}
WakelockManager.enable(_uniqueKey);
if (isWeb) {
_ffi.ffiModel.updateEventListener(_ffi.sessionId, widget.id);
}
@@ -127,9 +125,7 @@ class _FileManagerPageState extends State<FileManagerPage>
model.close().whenComplete(() {
_ffi.close();
_ffi.dialogManager.dismissAll();
if (!isLinux) {
WakelockPlus.disable();
}
WakelockManager.disable(_uniqueKey);
Get.delete<FFI>(tag: 'ft_${widget.id}');
});
WidgetsBinding.instance.removeObserver(this);

View File

@@ -6,7 +6,6 @@ import 'package:flutter/services.dart';
import 'package:flutter/scheduler.dart';
import 'package:get/get.dart';
import 'package:provider/provider.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:flutter_hbb/models/state_model.dart';
import '../../consts.dart';
@@ -85,6 +84,7 @@ class _RemotePageState extends State<RemotePage>
late RxBool _zoomCursor;
late RxBool _remoteCursorMoved;
late RxBool _keyboardEnabled;
final _uniqueKey = UniqueKey();
var _blockableOverlayState = BlockableOverlayState();
@@ -138,9 +138,7 @@ class _RemotePageState extends State<RemotePage>
_ffi.dialogManager
.showLoading(translate('Connecting...'), onCancel: closeConnection);
});
if (!isLinux) {
WakelockPlus.enable();
}
WakelockManager.enable(_uniqueKey);
_ffi.ffiModel.updateEventListener(sessionId, widget.id);
if (!isWeb) bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote);
@@ -206,26 +204,20 @@ class _RemotePageState extends State<RemotePage>
if (isWindows) {
_isWindowBlur = false;
}
if (!isLinux) {
WakelockPlus.enable();
}
WakelockManager.enable(_uniqueKey);
}
// When the window is unminimized, onWindowMaximize or onWindowRestore can be called when the old state was maximized or not.
@override
void onWindowMaximize() {
super.onWindowMaximize();
if (!isLinux) {
WakelockPlus.enable();
}
WakelockManager.enable(_uniqueKey);
}
@override
void onWindowMinimize() {
super.onWindowMinimize();
if (!isLinux) {
WakelockPlus.disable();
}
WakelockManager.disable(_uniqueKey);
}
@override
@@ -268,9 +260,7 @@ class _RemotePageState extends State<RemotePage>
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
}
if (!isLinux) {
await WakelockPlus.disable();
}
WakelockManager.disable(_uniqueKey);
await Get.delete<FFI>(tag: widget.id);
removeSharedStates(widget.id);
}

View File

@@ -6,7 +6,6 @@ import 'package:flutter/services.dart';
import 'package:flutter_hbb/common/widgets/remote_input.dart';
import 'package:get/get.dart';
import 'package:provider/provider.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:flutter_hbb/models/state_model.dart';
import '../../consts.dart';
@@ -77,6 +76,7 @@ class _ViewCameraPageState extends State<ViewCameraPage>
String keyboardMode = "legacy";
bool _isWindowBlur = false;
final _cursorOverImage = false.obs;
final _uniqueKey = UniqueKey();
var _blockableOverlayState = BlockableOverlayState();
@@ -124,9 +124,7 @@ class _ViewCameraPageState extends State<ViewCameraPage>
_ffi.dialogManager
.showLoading(translate('Connecting...'), onCancel: closeConnection);
});
if (!isLinux) {
WakelockPlus.enable();
}
WakelockManager.enable(_uniqueKey);
_ffi.ffiModel.updateEventListener(sessionId, widget.id);
if (!isWeb) bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote);
@@ -185,26 +183,20 @@ class _ViewCameraPageState extends State<ViewCameraPage>
if (isWindows) {
_isWindowBlur = false;
}
if (!isLinux) {
WakelockPlus.enable();
}
WakelockManager.enable(_uniqueKey);
}
// When the window is unminimized, onWindowMaximize or onWindowRestore can be called when the old state was maximized or not.
@override
void onWindowMaximize() {
super.onWindowMaximize();
if (!isLinux) {
WakelockPlus.enable();
}
WakelockManager.enable(_uniqueKey);
}
@override
void onWindowMinimize() {
super.onWindowMinimize();
if (!isLinux) {
WakelockPlus.disable();
}
WakelockManager.disable(_uniqueKey);
}
@override
@@ -247,9 +239,7 @@ class _ViewCameraPageState extends State<ViewCameraPage>
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
}
if (!isLinux) {
await WakelockPlus.disable();
}
WakelockManager.disable(_uniqueKey);
await Get.delete<FFI>(tag: widget.id);
removeSharedStates(widget.id);
}