diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 4e9744912..13ee4dd84 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; +import 'dart:io'; import 'package:back_button_interceptor/back_button_interceptor.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart'; @@ -3459,6 +3460,35 @@ Widget buildPresetPasswordWarning() { ); } +bool get isLinuxMateDesktop => + isLinux && + (Platform.environment['XDG_CURRENT_DESKTOP']?.toLowerCase() == 'mate' || + Platform.environment['XDG_SESSION_DESKTOP']?.toLowerCase() == 'mate' || + Platform.environment['DESKTOP_SESSION']?.toLowerCase() == 'mate'); + +Map? _linuxOsDistro; + +String getLinuxOsDistroId() { + if (_linuxOsDistro == null) { + String osInfo = bind.getOsDistroInfo(); + if (osInfo.isEmpty) { + _linuxOsDistro = {}; + } else { + try { + _linuxOsDistro = jsonDecode(osInfo); + } catch (e) { + debugPrint('Failed to parse os info: $e'); + // Don't call `bind.getOsDistroInfo()` again if failed to parse osInfo. + _linuxOsDistro = {}; + } + } + } + return (_linuxOsDistro?['id'] ?? '') as String; +} + +bool get isLinuxMint => + getLinuxOsDistroId().toLowerCase().contains('linuxmint'); + // https://github.com/leanflutter/window_manager/blob/87dd7a50b4cb47a375b9fc697f05e56eea0a2ab3/lib/src/widgets/virtual_window_frame.dart#L44 Widget buildVirtualWindowFrame(BuildContext context, Widget child) { boxShadow() => isMainDesktopWindow diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 00afbb001..3176bfb86 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -483,7 +483,16 @@ class _AppState extends State with WidgetsBindingObserver { child = keyListenerBuilder(context, child); } if (isLinux) { - child = buildVirtualWindowFrame(context, child); + // `(!(isLinuxMateDesktop || isLinuxMint))` is not used here for clarity. + // `isLinuxMint` will call ffi function. + if (!isLinuxMateDesktop) { + if (!isLinuxMint) { + debugPrint( + 'Linux distro is not linuxmint, and desktop is not mate, ' + 'so we build virtual window frame.'); + child = buildVirtualWindowFrame(context, child); + } + } } return child; }, diff --git a/flutter/lib/web/bridge.dart b/flutter/lib/web/bridge.dart index 208912814..ffbf66382 100644 --- a/flutter/lib/web/bridge.dart +++ b/flutter/lib/web/bridge.dart @@ -1828,5 +1828,9 @@ class RustdeskImpl { throw UnimplementedError("sessionGetConnToken"); } + String getOsDistroInfo({dynamic hint}) { + return ''; + } + void dispose() {} } diff --git a/flutter/linux/my_application.cc b/flutter/linux/my_application.cc index f4247bd94..9fa947002 100644 --- a/flutter/linux/my_application.cc +++ b/flutter/linux/my_application.cc @@ -17,6 +17,7 @@ G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) extern bool gIsConnectionManager; GtkWidget *find_gl_area(GtkWidget *widget); +void try_set_transparent(GtkWindow* window, GdkScreen* screen, FlView* view); // Implements GApplication::activate. static void my_application_activate(GApplication* application) { @@ -79,21 +80,7 @@ static void my_application_activate(GApplication* application) { gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - // https://github.com/flutter/flutter/issues/152154 - // Remove this workaround when flutter version is updated. - GtkWidget *gl_area = find_gl_area(GTK_WIDGET(view)); - if (gl_area != NULL) { - gtk_gl_area_set_has_alpha(GTK_GL_AREA(gl_area), TRUE); - } - - if (screen != NULL) { - GdkVisual *visual = NULL; - gtk_widget_set_app_paintable(GTK_WIDGET(window), TRUE); - visual = gdk_screen_get_rgba_visual(screen); - if (visual != NULL && gdk_screen_is_composited(screen)) { - gtk_widget_set_visual(GTK_WIDGET(window), visual); - } - } + try_set_transparent(window, screen, view); fl_register_plugins(FL_PLUGIN_REGISTRY(view)); @@ -162,3 +149,84 @@ GtkWidget *find_gl_area(GtkWidget *widget) return NULL; } + +bool is_linux_mint() +{ + bool is_mint = false; + char line[256]; + FILE *fp = fopen("/etc/os-release", "r"); + if (fp == NULL) { + return false; + } + while (fgets(line, sizeof(line), fp)) { + if (strstr(line, "ID=linuxmint") != NULL) { + is_mint = true; + break; + } + } + fclose(fp); + + return is_mint; +} + +bool is_desktop_mate() +{ + const char* desktop = NULL; + desktop = getenv("XDG_CURRENT_DESKTOP"); + printf("Linux desktop, XDG_CURRENT_DESKTOP: %s\n", desktop == NULL ? "" : desktop); + if (desktop == NULL) { + desktop = getenv("XDG_SESSION_DESKTOP"); + printf("Linux desktop, XDG_SESSION_DESKTOP: %s\n", desktop == NULL ? "" : desktop); + } + if (desktop == NULL) { + desktop = getenv("DESKTOP_SESSION"); + printf("Linux desktop, DESKTOP_SESSION: %s\n", desktop == NULL ? "" : desktop); + } + if (desktop != NULL && strcasecmp(desktop, "mate") == 0) { + return true; + } + return false; +} + +bool skip_setting_transparent() +{ + if (is_desktop_mate()) { + printf("Linux desktop, MATE\n"); + return true; + } + + if (is_linux_mint()) { + printf("Linux desktop, Linux Mint\n"); + return true; + } + + return false; +} + +// https://github.com/flutter/flutter/issues/152154 +// Remove this workaround when flutter version is updated. +void try_set_transparent(GtkWindow* window, GdkScreen* screen, FlView* view) +{ + GtkWidget *gl_area = NULL; + + if (skip_setting_transparent()) { + printf("Skip setting transparent\n"); + return; + } + + printf("Try setting transparent\n"); + + gl_area = find_gl_area(GTK_WIDGET(view)); + if (gl_area != NULL) { + gtk_gl_area_set_has_alpha(GTK_GL_AREA(gl_area), TRUE); + } + + if (screen != NULL) { + GdkVisual *visual = NULL; + gtk_widget_set_app_paintable(GTK_WIDGET(window), TRUE); + visual = gdk_screen_get_rgba_visual(screen); + if (visual != NULL && gdk_screen_is_composited(screen)) { + gtk_widget_set_visual(GTK_WIDGET(window), visual); + } + } +} diff --git a/libs/hbb_common/src/platform/linux.rs b/libs/hbb_common/src/platform/linux.rs index 60c8714d8..31481ca78 100644 --- a/libs/hbb_common/src/platform/linux.rs +++ b/libs/hbb_common/src/platform/linux.rs @@ -13,22 +13,35 @@ pub const XDG_CURRENT_DESKTOP: &str = "XDG_CURRENT_DESKTOP"; pub struct Distro { pub name: String, + pub id: String, pub version_id: String, } impl Distro { fn new() -> Self { + // to-do: + // 1. Remove `run_cmds`, read file once + // 2. Add more distro infos let name = run_cmds("awk -F'=' '/^NAME=/ {print $2}' /etc/os-release") .unwrap_or_default() .trim() .trim_matches('"') .to_string(); + let id = run_cmds("awk -F'=' '/^ID=/ {print $2}' /etc/os-release") + .unwrap_or_default() + .trim() + .trim_matches('"') + .to_string(); let version_id = run_cmds("awk -F'=' '/^VERSION_ID=/ {print $2}' /etc/os-release") .unwrap_or_default() .trim() .trim_matches('"') .to_string(); - Self { name, version_id } + Self { + name, + id, + version_id, + } } } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 4c875be49..4630ac333 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -19,6 +19,7 @@ use hbb_common::allow_err; use hbb_common::{ config::{self, LocalConfig, PeerConfig, PeerInfoSerde}, fs, lazy_static, log, + message_proto::Hash, rendezvous_proto::ConnType, ResultType, }; @@ -2341,6 +2342,25 @@ pub fn main_audio_support_loopback() -> SyncReturn { SyncReturn(is_surpport) } +pub fn get_os_distro_info() -> SyncReturn { + #[cfg(target_os = "linux")] + { + let distro = &hbb_common::platform::linux::DISTRO; + SyncReturn( + serde_json::to_string(&HashMap::from([ + ("name", distro.name.clone()), + ("id", distro.id.clone()), + ("version_id", distro.version_id.clone()), + ])) + .unwrap_or_default(), + ) + } + #[cfg(not(target_os = "linux"))] + { + SyncReturn("".to_owned()) + } +} + #[cfg(target_os = "android")] pub mod server_side { use hbb_common::{config, log};