Skip to content

Commit 4026506

Browse files
Move FlMouseCursorHandler from FlView to FlEngine (flutter/engine#56026)
1 parent 9442880 commit 4026506

File tree

7 files changed

+124
-26
lines changed

7 files changed

+124
-26
lines changed

engine/src/flutter/shell/platform/linux/fl_engine.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ struct _FlEngine {
5454
// Implements the flutter/platform channel.
5555
FlPlatformHandler* platform_handler;
5656

57+
// Implements the flutter/mousecursor channel.
58+
FlMouseCursorHandler* mouse_cursor_handler;
59+
5760
// Manages textures rendered by native code.
5861
FlTextureRegistrar* texture_registrar;
5962

@@ -449,6 +452,7 @@ static void fl_engine_dispose(GObject* object) {
449452
g_clear_object(&self->binary_messenger);
450453
g_clear_object(&self->settings_handler);
451454
g_clear_object(&self->platform_handler);
455+
g_clear_object(&self->mouse_cursor_handler);
452456
g_clear_object(&self->task_runner);
453457

454458
if (self->platform_message_handler_destroy_notify) {
@@ -629,6 +633,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
629633
fl_settings_handler_start(self->settings_handler, settings);
630634

631635
self->platform_handler = fl_platform_handler_new(self->binary_messenger);
636+
self->mouse_cursor_handler =
637+
fl_mouse_cursor_handler_new(self->binary_messenger);
632638

633639
result = self->embedder_api.UpdateSemanticsEnabled(self->engine, TRUE);
634640
if (result != kSuccess) {
@@ -1051,3 +1057,8 @@ void fl_engine_request_app_exit(FlEngine* self) {
10511057
g_return_if_fail(FL_IS_ENGINE(self));
10521058
fl_platform_handler_request_app_exit(self->platform_handler);
10531059
}
1060+
1061+
FlMouseCursorHandler* fl_engine_get_mouse_cursor_handler(FlEngine* self) {
1062+
g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
1063+
return self->mouse_cursor_handler;
1064+
}

engine/src/flutter/shell/platform/linux/fl_engine_private.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <glib-object.h>
99

1010
#include "flutter/shell/platform/embedder/embedder.h"
11+
#include "flutter/shell/platform/linux/fl_mouse_cursor_handler.h"
1112
#include "flutter/shell/platform/linux/fl_renderer.h"
1213
#include "flutter/shell/platform/linux/fl_task_runner.h"
1314
#include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h"
@@ -424,6 +425,16 @@ void fl_engine_update_accessibility_features(FlEngine* engine, int32_t flags);
424425
*/
425426
void fl_engine_request_app_exit(FlEngine* engine);
426427

428+
/**
429+
* fl_engine_get_mouse_cursor_handler:
430+
* @engine: an #FlEngine.
431+
*
432+
* Gets the mouse cursor handler used by this engine.
433+
*
434+
* Returns: a #FlMouseCursorHandler.
435+
*/
436+
FlMouseCursorHandler* fl_engine_get_mouse_cursor_handler(FlEngine* engine);
437+
427438
G_END_DECLS
428439

429440
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_ENGINE_PRIVATE_H_

engine/src/flutter/shell/platform/linux/fl_mouse_cursor_handler.cc

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
#include "flutter/shell/platform/linux/fl_mouse_cursor_handler.h"
66

7-
#include <gtk/gtk.h>
87
#include <cstring>
98

109
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
@@ -22,11 +21,16 @@ struct _FlMouseCursorHandler {
2221

2322
FlMethodChannel* channel;
2423

25-
GWeakRef view;
26-
2724
GHashTable* system_cursor_table;
25+
26+
// The current cursor.
27+
gchar* cursor_name;
2828
};
2929

30+
enum { kSignalCursorChanged, kSignalLastSignal };
31+
32+
static guint fl_mouse_cursor_handler_signals[kSignalLastSignal];
33+
3034
G_DEFINE_TYPE(FlMouseCursorHandler, fl_mouse_cursor_handler, G_TYPE_OBJECT)
3135

3236
// Insert a new entry into a hashtable from strings to strings.
@@ -109,14 +113,10 @@ FlMethodResponse* activate_system_cursor(FlMouseCursorHandler* self,
109113
cursor_name = kFallbackCursor;
110114
}
111115

112-
g_autoptr(FlView) view = FL_VIEW(g_weak_ref_get(&self->view));
113-
if (view != nullptr) {
114-
GdkWindow* window =
115-
gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(view)));
116-
g_autoptr(GdkCursor) cursor =
117-
gdk_cursor_new_from_name(gdk_window_get_display(window), cursor_name);
118-
gdk_window_set_cursor(window, cursor);
119-
}
116+
g_free(self->cursor_name);
117+
self->cursor_name = g_strdup(cursor_name);
118+
119+
g_signal_emit(self, fl_mouse_cursor_handler_signals[kSignalCursorChanged], 0);
120120

121121
return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
122122
}
@@ -147,21 +147,27 @@ static void fl_mouse_cursor_handler_dispose(GObject* object) {
147147
FlMouseCursorHandler* self = FL_MOUSE_CURSOR_HANDLER(object);
148148

149149
g_clear_object(&self->channel);
150-
g_weak_ref_clear(&self->view);
151150
g_clear_pointer(&self->system_cursor_table, g_hash_table_unref);
151+
g_clear_pointer(&self->cursor_name, g_free);
152152

153153
G_OBJECT_CLASS(fl_mouse_cursor_handler_parent_class)->dispose(object);
154154
}
155155

156156
static void fl_mouse_cursor_handler_class_init(
157157
FlMouseCursorHandlerClass* klass) {
158158
G_OBJECT_CLASS(klass)->dispose = fl_mouse_cursor_handler_dispose;
159+
160+
fl_mouse_cursor_handler_signals[kSignalCursorChanged] =
161+
g_signal_new("cursor-changed", fl_mouse_cursor_handler_get_type(),
162+
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
159163
}
160164

161-
static void fl_mouse_cursor_handler_init(FlMouseCursorHandler* self) {}
165+
static void fl_mouse_cursor_handler_init(FlMouseCursorHandler* self) {
166+
self->cursor_name = g_strdup("");
167+
}
162168

163-
FlMouseCursorHandler* fl_mouse_cursor_handler_new(FlBinaryMessenger* messenger,
164-
FlView* view) {
169+
FlMouseCursorHandler* fl_mouse_cursor_handler_new(
170+
FlBinaryMessenger* messenger) {
165171
g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
166172

167173
FlMouseCursorHandler* self = FL_MOUSE_CURSOR_HANDLER(
@@ -172,7 +178,12 @@ FlMouseCursorHandler* fl_mouse_cursor_handler_new(FlBinaryMessenger* messenger,
172178
fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec));
173179
fl_method_channel_set_method_call_handler(self->channel, method_call_cb, self,
174180
nullptr);
175-
g_weak_ref_init(&self->view, view);
176181

177182
return self;
178183
}
184+
185+
const gchar* fl_mouse_cursor_handler_get_cursor_name(
186+
FlMouseCursorHandler* self) {
187+
g_return_val_if_fail(FL_IS_MOUSE_CURSOR_HANDLER(self), nullptr);
188+
return self->cursor_name;
189+
}

engine/src/flutter/shell/platform/linux/fl_mouse_cursor_handler.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include <gdk/gdk.h>
99

1010
#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
11-
#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"
1211

1312
G_BEGIN_DECLS
1413

@@ -28,15 +27,24 @@ G_DECLARE_FINAL_TYPE(FlMouseCursorHandler,
2827
/**
2928
* fl_mouse_cursor_handler_new:
3029
* @messenger: an #FlBinaryMessenger.
31-
* @view: an #FlView to control.
3230
*
3331
* Creates a new handler that implements SystemChannels.mouseCursor from the
3432
* Flutter services library.
3533
*
3634
* Returns: a new #FlMouseCursorHandler.
3735
*/
38-
FlMouseCursorHandler* fl_mouse_cursor_handler_new(FlBinaryMessenger* messenger,
39-
FlView* view);
36+
FlMouseCursorHandler* fl_mouse_cursor_handler_new(FlBinaryMessenger* messenger);
37+
38+
/**
39+
* fl_mouse_cursor_handler_get_cursor_name:
40+
* @handler: an #FlMouseCursorHandler.
41+
*
42+
* Get the name of the current mouse cursor.
43+
*
44+
* Returns: a mouse cursor name.
45+
*/
46+
const gchar* fl_mouse_cursor_handler_get_cursor_name(
47+
FlMouseCursorHandler* handler);
4048

4149
G_END_DECLS
4250

engine/src/flutter/shell/platform/linux/fl_view.cc

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include "flutter/shell/platform/linux/fl_keyboard_handler.h"
1717
#include "flutter/shell/platform/linux/fl_keyboard_manager.h"
1818
#include "flutter/shell/platform/linux/fl_keyboard_view_delegate.h"
19-
#include "flutter/shell/platform/linux/fl_mouse_cursor_handler.h"
2019
#include "flutter/shell/platform/linux/fl_plugin_registrar_private.h"
2120
#include "flutter/shell/platform/linux/fl_pointer_manager.h"
2221
#include "flutter/shell/platform/linux/fl_renderer_gdk.h"
@@ -68,11 +67,13 @@ struct _FlView {
6867
// Flutter system channel handlers.
6968
FlKeyboardHandler* keyboard_handler;
7069
FlTextInputHandler* text_input_handler;
71-
FlMouseCursorHandler* mouse_cursor_handler;
7270

7371
// Accessible tree from Flutter, exposed as an AtkPlug.
7472
FlViewAccessible* view_accessible;
7573

74+
// Signal subscripton for cursor changes.
75+
guint cursor_changed_cb_id;
76+
7677
GCancellable* cancellable;
7778
};
7879

@@ -184,6 +185,28 @@ static gboolean get_mouse_button(GdkEvent* event, int64_t* button) {
184185
}
185186
}
186187

188+
// Called when the mouse cursor changes.
189+
static void cursor_changed_cb(FlView* self) {
190+
FlMouseCursorHandler* handler =
191+
fl_engine_get_mouse_cursor_handler(self->engine);
192+
const gchar* cursor_name = fl_mouse_cursor_handler_get_cursor_name(handler);
193+
GdkWindow* window =
194+
gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(self)));
195+
g_autoptr(GdkCursor) cursor =
196+
gdk_cursor_new_from_name(gdk_window_get_display(window), cursor_name);
197+
gdk_window_set_cursor(window, cursor);
198+
}
199+
200+
// Set the mouse cursor.
201+
static void setup_cursor(FlView* self) {
202+
FlMouseCursorHandler* handler =
203+
fl_engine_get_mouse_cursor_handler(self->engine);
204+
205+
self->cursor_changed_cb_id = g_signal_connect_swapped(
206+
handler, "cursor-changed", G_CALLBACK(cursor_changed_cb), self);
207+
cursor_changed_cb(self);
208+
}
209+
187210
// Updates the engine with the current window metrics.
188211
static void handle_geometry_changed(FlView* self) {
189212
GtkAllocation allocation;
@@ -457,10 +480,7 @@ static GdkGLContext* create_context_cb(FlView* self) {
457480
fl_renderer_gdk_set_window(self->renderer,
458481
gtk_widget_get_parent_window(GTK_WIDGET(self)));
459482

460-
// Create system channel handlers.
461-
FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine);
462483
init_scrolling(self);
463-
self->mouse_cursor_handler = fl_mouse_cursor_handler_new(messenger, self);
464484

465485
g_autoptr(GError) error = nullptr;
466486
if (!fl_renderer_gdk_create_contexts(self->renderer, &error)) {
@@ -505,6 +525,8 @@ static void realize_cb(FlView* self) {
505525
return;
506526
}
507527

528+
setup_cursor(self);
529+
508530
handle_geometry_changed(self);
509531

510532
self->view_accessible = fl_view_accessible_new(self->engine);
@@ -567,6 +589,13 @@ static void fl_view_dispose(GObject* object) {
567589
fl_engine_set_update_semantics_handler(self->engine, nullptr, nullptr,
568590
nullptr);
569591

592+
FlMouseCursorHandler* handler =
593+
fl_engine_get_mouse_cursor_handler(self->engine);
594+
if (self->cursor_changed_cb_id != 0) {
595+
g_signal_handler_disconnect(handler, self->cursor_changed_cb_id);
596+
self->cursor_changed_cb_id = 0;
597+
}
598+
570599
// Stop rendering.
571600
fl_renderer_remove_view(FL_RENDERER(self->renderer), self->view_id);
572601

@@ -589,7 +618,6 @@ static void fl_view_dispose(GObject* object) {
589618
g_clear_object(&self->pointer_manager);
590619
g_clear_object(&self->keyboard_manager);
591620
g_clear_object(&self->keyboard_handler);
592-
g_clear_object(&self->mouse_cursor_handler);
593621
g_clear_object(&self->view_accessible);
594622
g_clear_object(&self->cancellable);
595623

@@ -750,6 +778,8 @@ G_MODULE_EXPORT FlView* fl_view_new_for_engine(FlEngine* engine) {
750778

751779
self->pointer_manager = fl_pointer_manager_new(self->view_id, engine);
752780

781+
setup_cursor(self);
782+
753783
return self;
754784
}
755785

engine/src/flutter/shell/platform/linux/fl_view_test.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ TEST(FlViewTest, SecondaryView) {
8282
return kSuccess;
8383
}));
8484

85+
g_autoptr(GError) error = nullptr;
86+
EXPECT_TRUE(fl_engine_start(engine, &error));
87+
8588
FlView* secondary_view = fl_view_new_for_engine(engine);
8689
EXPECT_EQ(view_id, fl_view_get_id(secondary_view));
8790
}
@@ -103,6 +106,9 @@ TEST(FlViewTest, SecondaryViewError) {
103106
return kInvalidArguments;
104107
}));
105108

109+
g_autoptr(GError) error = nullptr;
110+
EXPECT_TRUE(fl_engine_start(engine, &error));
111+
106112
FlView* secondary_view = fl_view_new_for_engine(engine);
107113
EXPECT_EQ(view_id, fl_view_get_id(secondary_view));
108114
}
@@ -125,6 +131,9 @@ TEST(FlViewTest, ViewDestroy) {
125131
return kSuccess;
126132
}));
127133

134+
g_autoptr(GError) error = nullptr;
135+
EXPECT_TRUE(fl_engine_start(engine, &error));
136+
128137
FlView* secondary_view = fl_view_new_for_engine(engine);
129138

130139
int64_t implicit_view_id = fl_view_get_id(implicit_view);
@@ -155,6 +164,9 @@ TEST(FlViewTest, ViewDestroyError) {
155164
return kInvalidArguments;
156165
}));
157166

167+
g_autoptr(GError) error = nullptr;
168+
EXPECT_TRUE(fl_engine_start(engine, &error));
169+
158170
FlView* secondary_view = fl_view_new_for_engine(engine);
159171

160172
gtk_widget_destroy(GTK_WIDGET(secondary_view));

engine/src/flutter/shell/platform/linux/testing/mock_window.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,18 @@ MockWindow::MockWindow() {
1515
GdkWindowState gdk_window_get_state(GdkWindow* window) {
1616
return mock->gdk_window_get_state(window);
1717
}
18+
19+
GdkDisplay* gdk_window_get_display(GdkWindow* window) {
20+
return nullptr;
21+
}
22+
23+
GdkMonitor* gdk_display_get_monitor_at_window(GdkDisplay* display,
24+
GdkWindow* window) {
25+
return nullptr;
26+
}
27+
28+
GdkCursor* gdk_cursor_new_from_name(GdkDisplay* display, const gchar* name) {
29+
return nullptr;
30+
}
31+
32+
void gdk_window_set_cursor(GdkWindow* window, GdkCursor* cursor) {}

0 commit comments

Comments
 (0)