From fa0adb099817cc8b100c082c5dd3830c6b4e2c47 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Thu, 23 Apr 2026 09:47:44 +0200 Subject: [PATCH] fix mouse jumping: query GDK pointer position at call time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flutter's globalPosition is window-relative, not screen-absolute. Now using gdk_device_get_position() on the native side to get the actual screen coordinates at the moment startDrag/startResize is called. Dart no longer passes coordinates — the native handler queries the pointer directly. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/app.dart | 2 +- lib/kernel/src/window_controls.dart | 15 ++++---------- lib/widgets/src/clide_column_hat.dart | 2 +- lib/widgets/src/clide_resize_border.dart | 2 +- linux/runner/my_application.cc | 26 ++++++++++++------------ 5 files changed, 20 insertions(+), 27 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index e431368b..ee7b6643 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -221,7 +221,7 @@ class _HatBar extends StatelessWidget { Widget build(BuildContext context) { final tokens = ClideTheme.of(context).surface; return GestureDetector( - onPanStart: (d) => kernel.window.startDrag(d.globalPosition), + onPanStart: (_) => kernel.window.startDrag(), child: Container( height: hatHeight, decoration: BoxDecoration( diff --git a/lib/kernel/src/window_controls.dart b/lib/kernel/src/window_controls.dart index de6c2f7c..c08607d5 100644 --- a/lib/kernel/src/window_controls.dart +++ b/lib/kernel/src/window_controls.dart @@ -17,24 +17,17 @@ class WindowControls extends ChangeNotifier { notifyListeners(); } - Future startResize(ResizeEdge edge, Offset screenPosition) async { + Future startResize(ResizeEdge edge) async { try { - await _channel.invokeMethod('startResize', { - 'edge': edge.index, - 'x': screenPosition.dx.round(), - 'y': screenPosition.dy.round(), - }); + await _channel.invokeMethod('startResize', edge.index); } on MissingPluginException { // no-op } } - Future startDrag(Offset screenPosition) async { + Future startDrag() async { try { - await _channel.invokeMethod('startDrag', { - 'x': screenPosition.dx.round(), - 'y': screenPosition.dy.round(), - }); + await _channel.invokeMethod('startDrag'); } on MissingPluginException { // no-op } diff --git a/lib/widgets/src/clide_column_hat.dart b/lib/widgets/src/clide_column_hat.dart index 5ba181f4..cf4cbc17 100644 --- a/lib/widgets/src/clide_column_hat.dart +++ b/lib/widgets/src/clide_column_hat.dart @@ -33,7 +33,7 @@ class ColumnHat extends StatelessWidget { Widget build(BuildContext context) { final tokens = ClideTheme.of(context).surface; return GestureDetector( - onPanStart: (d) => windowControls.startDrag(d.globalPosition), + onPanStart: (_) => windowControls.startDrag(), child: Container( height: hatHeight, color: tokens.panelHeader, diff --git a/lib/widgets/src/clide_resize_border.dart b/lib/widgets/src/clide_resize_border.dart index 84b068e9..3298a83c 100644 --- a/lib/widgets/src/clide_resize_border.dart +++ b/lib/widgets/src/clide_resize_border.dart @@ -45,7 +45,7 @@ class ClideResizeBorder extends StatelessWidget { return MouseRegion( cursor: cursor, child: GestureDetector( - onPanStart: (d) => windowControls.startResize(edge, d.globalPosition), + onPanStart: (_) => windowControls.startResize(edge), child: const ColoredBox(color: Color(0x00000000)), ), ); diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index d6ced1fa..f2cb8be8 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -157,28 +157,28 @@ static void my_application_activate(GApplication* application) { g_autoptr(FlMethodResponse) response = nullptr; if (g_strcmp0(method, "startDrag") == 0) { - FlValue* args = fl_method_call_get_args(method_call); - int x = 0, y = 0; - if (fl_value_get_type(args) == FL_VALUE_TYPE_MAP) { - FlValue* vx = fl_value_lookup_string(args, "x"); - FlValue* vy = fl_value_lookup_string(args, "y"); - if (vx) x = (int)fl_value_get_int(vx); - if (vy) y = (int)fl_value_get_int(vy); - } + GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(w)); + GdkSeat* seat = gdk_display_get_default_seat(display); + GdkDevice* pointer = gdk_seat_get_pointer(seat); + gint x = 0, y = 0; + gdk_device_get_position(pointer, nullptr, &x, &y); gtk_window_begin_move_drag(w, 1, x, y, GDK_CURRENT_TIME); response = FL_METHOD_RESPONSE( fl_method_success_response_new(fl_value_new_null())); } else if (g_strcmp0(method, "startResize") == 0) { FlValue* args = fl_method_call_get_args(method_call); - int edge = 7, x = 0, y = 0; + int edge = 7; if (fl_value_get_type(args) == FL_VALUE_TYPE_MAP) { FlValue* ve = fl_value_lookup_string(args, "edge"); - FlValue* vx = fl_value_lookup_string(args, "x"); - FlValue* vy = fl_value_lookup_string(args, "y"); if (ve) edge = (int)fl_value_get_int(ve); - if (vx) x = (int)fl_value_get_int(vx); - if (vy) y = (int)fl_value_get_int(vy); + } else if (fl_value_get_type(args) == FL_VALUE_TYPE_INT) { + edge = (int)fl_value_get_int(args); } + GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(w)); + GdkSeat* seat = gdk_display_get_default_seat(display); + GdkDevice* pointer = gdk_seat_get_pointer(seat); + gint x = 0, y = 0; + gdk_device_get_position(pointer, nullptr, &x, &y); static const GdkWindowEdge edges[] = { GDK_WINDOW_EDGE_NORTH_WEST, GDK_WINDOW_EDGE_NORTH, GDK_WINDOW_EDGE_NORTH_EAST, GDK_WINDOW_EDGE_WEST,