From 5764443362de70928ce20269abc4a74dd5c62b2a Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Tue, 26 Nov 2024 21:39:47 +0800 Subject: [PATCH] #3963 Fix window resizing not work on linux --- .../launcher/wox_launcher_controller.dart | 16 ++--- .../lib/services/linux_window_manager.dart | 23 +++++++ .../wox/lib/utils/linux_window_manager.dart | 21 +++++++ Wox.UI.Flutter/wox/linux/CMakeLists.txt | 9 +-- Wox.UI.Flutter/wox/linux/gtk_window.cc | 44 +++++++++++++ Wox.UI.Flutter/wox/linux/gtk_window.h | 9 +++ Wox.UI.Flutter/wox/linux/my_application.cc | 62 +++++++++++++++++++ 7 files changed, 169 insertions(+), 15 deletions(-) create mode 100644 Wox.UI.Flutter/wox/lib/services/linux_window_manager.dart create mode 100644 Wox.UI.Flutter/wox/lib/utils/linux_window_manager.dart create mode 100644 Wox.UI.Flutter/wox/linux/gtk_window.cc create mode 100644 Wox.UI.Flutter/wox/linux/gtk_window.h diff --git a/Wox.UI.Flutter/wox/lib/modules/launcher/wox_launcher_controller.dart b/Wox.UI.Flutter/wox/lib/modules/launcher/wox_launcher_controller.dart index c3a2b3c80..4f996c2a0 100644 --- a/Wox.UI.Flutter/wox/lib/modules/launcher/wox_launcher_controller.dart +++ b/Wox.UI.Flutter/wox/lib/modules/launcher/wox_launcher_controller.dart @@ -35,6 +35,7 @@ import 'package:wox/utils/wox_setting_util.dart'; import 'package:wox/utils/wox_theme_util.dart'; import 'package:wox/utils/wox_websocket_msg_util.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; +import 'package:wox/utils/linux_window_manager.dart'; class WoxLauncherController extends GetxController { //query related variables @@ -659,20 +660,13 @@ class WoxLauncherController extends GetxController { final totalHeight = WoxThemeUtil.instance.getQueryBoxHeight() + resultHeight; if (Platform.isWindows) { - // on windows, if I set screen ratio to 2.0, then the window height should add more 4.5 pixel, otherwise it will show render error - // still don't know why. here is the test result: ratio -> additional window height - // 1.0 -> 9 - // 1.25-> 7.8 - // 1.5-> 6.3 - // 1.75-> 5.3 - // 2.0-> 4.5 - // 2.25-> 4.3 - // 2.5-> 3.8 - // 3.0-> 3 - final totalHeightFinal = totalHeight.toDouble() + (10 / PlatformDispatcher.instance.views.first.devicePixelRatio).ceil(); if (LoggerSwitch.enableSizeAndPositionLog) Logger.instance.info(const UuidV4().generate(), "Resize: window height to $totalHeightFinal"); await windowManager.setSize(Size(800, totalHeightFinal)); + } else if (Platform.isLinux) { + // window manager setSize is not working on linux, so we need to implement it by ourselves + if (LoggerSwitch.enableSizeAndPositionLog) Logger.instance.info(const UuidV4().generate(), "Resize: window height to $totalHeight"); + await LinuxWindowManager.instance.setSize(800, totalHeight.toDouble()); } else { if (LoggerSwitch.enableSizeAndPositionLog) Logger.instance.info(const UuidV4().generate(), "Resize: window height to $totalHeight"); await windowManager.setSize(Size(800, totalHeight.toDouble())); diff --git a/Wox.UI.Flutter/wox/lib/services/linux_window_manager.dart b/Wox.UI.Flutter/wox/lib/services/linux_window_manager.dart new file mode 100644 index 000000000..087e01672 --- /dev/null +++ b/Wox.UI.Flutter/wox/lib/services/linux_window_manager.dart @@ -0,0 +1,23 @@ +import 'package:flutter/services.dart'; +import 'package:wox/utils/log.dart'; + +class LinuxWindowManager { + static const _channel = MethodChannel('com.wox.window_manager'); + + static final LinuxWindowManager instance = LinuxWindowManager._(); + + LinuxWindowManager._(); + + Future setSize(double width, double height) async { + try { + Logger.instance.info("LinuxWindowManager", "Setting size to: $width x $height"); + final Map arguments = { + 'width': width, + 'height': height, + }; + await _channel.invokeMethod('setSize', arguments); + } catch (e) { + Logger.instance.error("LinuxWindowManager", "Error setting window size: $e"); + } + } +} \ No newline at end of file diff --git a/Wox.UI.Flutter/wox/lib/utils/linux_window_manager.dart b/Wox.UI.Flutter/wox/lib/utils/linux_window_manager.dart new file mode 100644 index 000000000..711feade4 --- /dev/null +++ b/Wox.UI.Flutter/wox/lib/utils/linux_window_manager.dart @@ -0,0 +1,21 @@ +import 'package:flutter/services.dart'; +import 'package:wox/utils/log.dart'; + +class LinuxWindowManager { + static const _channel = MethodChannel('com.wox.window_manager'); + + static final LinuxWindowManager instance = LinuxWindowManager._(); + + LinuxWindowManager._(); + + Future setSize(double width, double height) async { + try { + await _channel.invokeMethod('setSize', { + 'width': width, + 'height': height, + }); + } catch (e) { + Logger.instance.error("LinuxWindowManager", "Error setting window size: $e"); + } + } +} \ No newline at end of file diff --git a/Wox.UI.Flutter/wox/linux/CMakeLists.txt b/Wox.UI.Flutter/wox/linux/CMakeLists.txt index 0ebe4bed2..554432ad3 100644 --- a/Wox.UI.Flutter/wox/linux/CMakeLists.txt +++ b/Wox.UI.Flutter/wox/linux/CMakeLists.txt @@ -7,7 +7,7 @@ project(runner LANGUAGES CXX) set(BINARY_NAME "wox") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.wox") +set(APPLICATION_ID "com.github.com.woxlauncer.wox") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. @@ -63,6 +63,7 @@ add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") add_executable(${BINARY_NAME} "main.cc" "my_application.cc" + "gtk_window.cc" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" ) @@ -117,11 +118,11 @@ install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR} install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) -endforeach(bundled_library) +endif() # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. diff --git a/Wox.UI.Flutter/wox/linux/gtk_window.cc b/Wox.UI.Flutter/wox/linux/gtk_window.cc new file mode 100644 index 000000000..29dac6390 --- /dev/null +++ b/Wox.UI.Flutter/wox/linux/gtk_window.cc @@ -0,0 +1,44 @@ +#include "gtk_window.h" + +bool is_gtk_available() { + // Check if we're running under GTK + const char* xdg_session_type = g_getenv("XDG_SESSION_TYPE"); + const char* desktop_session = g_getenv("DESKTOP_SESSION"); + const char* current_desktop = g_getenv("XDG_CURRENT_DESKTOP"); + + if (xdg_session_type != nullptr && + (g_strcmp0(xdg_session_type, "wayland") == 0 || g_strcmp0(xdg_session_type, "x11") == 0)) { + if (current_desktop != nullptr && + (g_strstr_len(current_desktop, -1, "GNOME") != nullptr || + g_strstr_len(current_desktop, -1, "Unity") != nullptr || + g_strstr_len(current_desktop, -1, "XFCE") != nullptr || + g_strstr_len(current_desktop, -1, "Pantheon") != nullptr || + g_strstr_len(current_desktop, -1, "MATE") != nullptr || + g_strstr_len(current_desktop, -1, "Cinnamon") != nullptr)) { + return true; + } + if (desktop_session != nullptr && + (g_strstr_len(desktop_session, -1, "gnome") != nullptr || + g_strstr_len(desktop_session, -1, "unity") != nullptr || + g_strstr_len(desktop_session, -1, "xfce") != nullptr || + g_strstr_len(desktop_session, -1, "mate") != nullptr || + g_strstr_len(desktop_session, -1, "cinnamon") != nullptr)) { + return true; + } + } + return false; +} + +void resize_gtk_window(GtkWindow* window, int width, int height) { + if (window == nullptr) { + return; + } + + // Set minimum size to prevent window from becoming too small + gtk_window_set_resizable(window, TRUE); + gtk_window_set_default_size(window, width, height); + gtk_window_resize(window, width, height); + + // Force the window to process the resize + gtk_widget_queue_resize(GTK_WIDGET(window)); +} \ No newline at end of file diff --git a/Wox.UI.Flutter/wox/linux/gtk_window.h b/Wox.UI.Flutter/wox/linux/gtk_window.h new file mode 100644 index 000000000..f4c876478 --- /dev/null +++ b/Wox.UI.Flutter/wox/linux/gtk_window.h @@ -0,0 +1,9 @@ +#ifndef GTK_WINDOW_H_ +#define GTK_WINDOW_H_ + +#include + +bool is_gtk_available(); +void resize_gtk_window(GtkWindow* window, int width, int height); + +#endif // GTK_WINDOW_H_ \ No newline at end of file diff --git a/Wox.UI.Flutter/wox/linux/my_application.cc b/Wox.UI.Flutter/wox/linux/my_application.cc index 6cbd41e4f..e8cd062c3 100644 --- a/Wox.UI.Flutter/wox/linux/my_application.cc +++ b/Wox.UI.Flutter/wox/linux/my_application.cc @@ -1,4 +1,5 @@ #include "my_application.h" +#include "gtk_window.h" #include #ifdef GDK_WINDOWING_X11 @@ -6,6 +7,8 @@ #endif #include "flutter/generated_plugin_registrant.h" +#include +#include struct _MyApplication { GtkApplication parent_instance; @@ -14,6 +17,56 @@ struct _MyApplication { G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) +static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data) { + const gchar* method = fl_method_call_get_name(method_call); + + if (strcmp(method, "setSize") == 0) { + + + FlValue* args = fl_method_call_get_args(method_call); + + if (fl_value_get_type(args) == FL_VALUE_TYPE_MAP) { + FlValue* width_value = fl_value_lookup_string(args, "width"); + FlValue* height_value = fl_value_lookup_string(args, "height"); + + if (width_value == nullptr || height_value == nullptr) { + g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE( + fl_method_error_response_new("INVALID_ARGUMENTS", + "Width or height is missing", + nullptr)); + fl_method_call_respond(method_call, response, nullptr); + return; + } + + double width = fl_value_get_float(width_value); + double height = fl_value_get_float(height_value); + + MyApplication* self = MY_APPLICATION(user_data); + GtkWindow* window = GTK_WINDOW(gtk_application_get_active_window(GTK_APPLICATION(self))); + + if (window == nullptr) { + g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_error_response_new("WINDOW_ERROR", "Window is null", nullptr)); + fl_method_call_respond(method_call, response, nullptr); + return; + } + + if (is_gtk_available()) { + resize_gtk_window(window, (int)width, (int)height); + } + + g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + fl_method_call_respond(method_call, response, nullptr); + } else { + g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE( + fl_method_error_response_new("INVALID_ARGUMENTS", "Expected width and height", nullptr)); + fl_method_call_respond(method_call, response, nullptr); + } + } else { + g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_error_response_new("NOT_IMPLEMENTED","Method not implemented",nullptr)); + fl_method_call_respond(method_call, response, nullptr); + } +} + // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); @@ -62,6 +115,15 @@ static void my_application_activate(GApplication* application) { fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + // Add channel setup BEFORE showing the window + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(FlMethodChannel) channel = fl_method_channel_new( + fl_engine_get_binary_messenger(fl_view_get_engine(view)), + "com.wox.window_manager", + FL_METHOD_CODEC(codec)); + fl_method_channel_set_method_call_handler(channel, method_call_cb, self, nullptr); + + gtk_widget_show(GTK_WIDGET(window)); gtk_widget_grab_focus(GTK_WIDGET(view)); }