Initial commit: RustDesk 1.4.7 macOS desktop port
- Filled empty libs/hbb_common/ submodule (cloned from rustdesk/hbb_common) - Patched Flutter 3.44 / Dart 3.12 compatibility: * flutter/lib/generated_bridge.dart: asTypedList with cast<>, DartPort=Int64 * flutter/lib/common.dart: DialogTheme->DialogThemeData, TabBarTheme->TabBarThemeData * flutter/pubspec.yaml: extended_text 14.0.0->15.0.2, google_fonts override 5.0.0 * flutter/macos/Runner/Configs/Release.xcconfig: EXCLUDED_ARCHS=x86_64 - Build verified: cargo check + cargo build --features flutter + cargo build --release --features flutter - Verified flutter build macos --debug and --release both produce working .app - Verified .dmg installer (27MB arm64) created via hdiutil - Build deps: Xcode 26.5, CocoaPods 1.16.2, Flutter 3.44, VCPKG arm64-osx
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
// ignore_for_file: avoid_web_libraries_in_flutter
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:js_interop';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:js';
|
||||
import 'dart:html';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_hbb/common/widgets/login.dart';
|
||||
import 'package:flutter_hbb/models/state_model.dart';
|
||||
|
||||
import 'package:flutter_hbb/web/bridge.dart';
|
||||
import 'package:flutter_hbb/common.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
final List<StreamSubscription<MouseEvent>> mouseListeners = [];
|
||||
final List<StreamSubscription<KeyboardEvent>> keyListeners = [];
|
||||
|
||||
typedef HandleEvent = Future<void> Function(Map<String, dynamic> evt);
|
||||
|
||||
class PlatformFFI {
|
||||
final _eventHandlers = <String, Map<String, HandleEvent>>{};
|
||||
final RustdeskImpl _ffiBind = RustdeskImpl();
|
||||
|
||||
static String getByName(String name, [String arg = '']) {
|
||||
return context.callMethod('getByName', [name, arg]);
|
||||
}
|
||||
|
||||
static void setByName(String name, [String value = '']) {
|
||||
context.callMethod('setByName', [name, value]);
|
||||
}
|
||||
|
||||
PlatformFFI._() {
|
||||
window.document.addEventListener(
|
||||
'visibilitychange',
|
||||
(event) => {
|
||||
stateGlobal.isWebVisible =
|
||||
window.document.visibilityState == 'visible'
|
||||
});
|
||||
}
|
||||
|
||||
static final PlatformFFI instance = PlatformFFI._();
|
||||
|
||||
static get localeName => window.navigator.language;
|
||||
RustdeskImpl get ffiBind => _ffiBind;
|
||||
|
||||
static Future<String> getVersion() async {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
bool registerEventHandler(
|
||||
String eventName, String handlerName, HandleEvent handler,
|
||||
{bool replace = false}) {
|
||||
debugPrint('registerEventHandler $eventName $handlerName');
|
||||
var handlers = _eventHandlers[eventName];
|
||||
if (handlers == null) {
|
||||
_eventHandlers[eventName] = {handlerName: handler};
|
||||
return true;
|
||||
} else {
|
||||
if (!replace && handlers.containsKey(handlerName)) {
|
||||
return false;
|
||||
} else {
|
||||
handlers[handlerName] = handler;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unregisterEventHandler(String eventName, String handlerName) {
|
||||
debugPrint('unregisterEventHandler $eventName $handlerName');
|
||||
var handlers = _eventHandlers[eventName];
|
||||
if (handlers != null) {
|
||||
handlers.remove(handlerName);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> tryHandle(Map<String, dynamic> evt) async {
|
||||
final name = evt['name'];
|
||||
if (name != null) {
|
||||
final handlers = _eventHandlers[name];
|
||||
if (handlers != null) {
|
||||
if (handlers.isNotEmpty) {
|
||||
for (var handler in handlers.values) {
|
||||
await handler(evt);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String translate(String name, String locale) =>
|
||||
_ffiBind.translate(name: name, locale: locale);
|
||||
|
||||
Uint8List? getRgba(SessionID sessionId, int display, int bufSize) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
int getRgbaSize(SessionID sessionId, int display) =>
|
||||
_ffiBind.sessionGetRgbaSize(sessionId: sessionId, display: display);
|
||||
void nextRgba(SessionID sessionId, int display) =>
|
||||
_ffiBind.sessionNextRgba(sessionId: sessionId, display: display);
|
||||
void registerPixelbufferTexture(SessionID sessionId, int display, int ptr) =>
|
||||
_ffiBind.sessionRegisterPixelbufferTexture(
|
||||
sessionId: sessionId, display: display, ptr: ptr);
|
||||
void registerGpuTexture(SessionID sessionId, int display, int ptr) =>
|
||||
_ffiBind.sessionRegisterGpuTexture(
|
||||
sessionId: sessionId, display: display, ptr: ptr);
|
||||
|
||||
Future<void> init(String appType) async {
|
||||
Completer completer = Completer();
|
||||
context["onInitFinished"] = () {
|
||||
completer.complete();
|
||||
};
|
||||
context['dialog'] = (type, title, text) {
|
||||
final uuid = Uuid();
|
||||
msgBox(SessionID(uuid.v4()), type, title, text, '', gFFI.dialogManager);
|
||||
};
|
||||
context['loginDialog'] = () {
|
||||
loginDialog();
|
||||
};
|
||||
context['closeConnection'] = () {
|
||||
gFFI.dialogManager.dismissAll();
|
||||
closeConnection();
|
||||
};
|
||||
context.callMethod('init');
|
||||
version = getByName('version');
|
||||
window.onContextMenu.listen((event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
context['onRegisteredEvent'] = (String message) {
|
||||
try {
|
||||
Map<String, dynamic> event = json.decode(message);
|
||||
tryHandle(event);
|
||||
} catch (e) {
|
||||
print('json.decode fail(): $e');
|
||||
}
|
||||
};
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
void setEventCallback(void Function(Map<String, dynamic>) fun) {
|
||||
context["onGlobalEvent"] = (String message) {
|
||||
try {
|
||||
Map<String, dynamic> event = json.decode(message);
|
||||
fun(event);
|
||||
} catch (e) {
|
||||
print('json.decode fail(): $e');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void setRgbaCallback(void Function(int, Uint8List) fun) {
|
||||
context["onRgba"] = (int display, Uint8List? rgba) {
|
||||
if (rgba != null) {
|
||||
fun(display, rgba);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void startDesktopWebListener() {
|
||||
mouseListeners.add(
|
||||
window.document.onContextMenu.listen((evt) => evt.preventDefault()));
|
||||
}
|
||||
|
||||
void stopDesktopWebListener() {
|
||||
for (var ml in mouseListeners) {
|
||||
ml.cancel();
|
||||
}
|
||||
mouseListeners.clear();
|
||||
for (var kl in keyListeners) {
|
||||
kl.cancel();
|
||||
}
|
||||
keyListeners.clear();
|
||||
}
|
||||
|
||||
void setMethodCallHandler(FMethod callback) {}
|
||||
|
||||
invokeMethod(String method, [dynamic arguments]) async {
|
||||
return true;
|
||||
}
|
||||
|
||||
// just for compilation
|
||||
void syncAndroidServiceAppDirConfigPath() {}
|
||||
|
||||
void setFullscreenCallback(void Function(bool) fun) {
|
||||
context["onFullscreenChanged"] = (bool v) {
|
||||
fun(v);
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user