Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions shell/platform/linux/fl_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct _FlEngine {
FlBinaryMessenger* binary_messenger;
FlSettingsHandler* settings_handler;
FlPlatformHandler* platform_handler;
FlMouseCursorHandler* mouse_cursor_handler;
FlTextureRegistrar* texture_registrar;
FlTaskRunner* task_runner;
FlutterEngineAOTData aot_data;
Expand Down Expand Up @@ -429,6 +430,7 @@ static void fl_engine_dispose(GObject* object) {
g_clear_object(&self->binary_messenger);
g_clear_object(&self->settings_handler);
g_clear_object(&self->platform_handler);
g_clear_object(&self->mouse_cursor_handler);
g_clear_object(&self->task_runner);

if (self->platform_message_handler_destroy_notify) {
Expand Down Expand Up @@ -609,6 +611,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
fl_settings_handler_start(self->settings_handler, settings);

self->platform_handler = fl_platform_handler_new(self->binary_messenger);
self->mouse_cursor_handler =
fl_mouse_cursor_handler_new(self->binary_messenger);

result = self->embedder_api.UpdateSemanticsEnabled(self->engine, TRUE);
if (result != kSuccess) {
Expand Down Expand Up @@ -1031,3 +1035,8 @@ void fl_engine_request_app_exit(FlEngine* self) {
g_return_if_fail(FL_IS_ENGINE(self));
fl_platform_handler_request_app_exit(self->platform_handler);
}

FlMouseCursorHandler* fl_engine_get_mouse_cursor_handler(FlEngine* self) {
g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
return self->mouse_cursor_handler;
}
11 changes: 11 additions & 0 deletions shell/platform/linux/fl_engine_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <glib-object.h>

#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/linux/fl_mouse_cursor_handler.h"
#include "flutter/shell/platform/linux/fl_renderer.h"
#include "flutter/shell/platform/linux/fl_task_runner.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h"
Expand Down Expand Up @@ -424,6 +425,16 @@ void fl_engine_update_accessibility_features(FlEngine* engine, int32_t flags);
*/
void fl_engine_request_app_exit(FlEngine* engine);

/**
* fl_engine_get_mouse_cursor_handler:
* @engine: an #FlEngine.
*
* Gets the mouse cursor handler used by this engine.
*
* Returns: a #FlMouseCursorHandler.
*/
FlMouseCursorHandler* fl_engine_get_mouse_cursor_handler(FlEngine* engine);

G_END_DECLS

#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_ENGINE_PRIVATE_H_
43 changes: 27 additions & 16 deletions shell/platform/linux/fl_mouse_cursor_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

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

#include <gtk/gtk.h>
#include <cstring>

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

FlMethodChannel* channel;

GWeakRef view;

GHashTable* system_cursor_table;

// The current cursor.
gchar* cursor_name;
};

enum { kSignalCursorChanged, kSignalLastSignal };

static guint fl_mouse_cursor_handler_signals[kSignalLastSignal];

G_DEFINE_TYPE(FlMouseCursorHandler, fl_mouse_cursor_handler, G_TYPE_OBJECT)

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

g_autoptr(FlView) view = FL_VIEW(g_weak_ref_get(&self->view));
if (view != nullptr) {
GdkWindow* window =
gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(view)));
g_autoptr(GdkCursor) cursor =
gdk_cursor_new_from_name(gdk_window_get_display(window), cursor_name);
gdk_window_set_cursor(window, cursor);
}
g_free(self->cursor_name);
self->cursor_name = g_strdup(cursor_name);

g_signal_emit(self, fl_mouse_cursor_handler_signals[kSignalCursorChanged], 0);

return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
}
Expand Down Expand Up @@ -147,21 +147,27 @@ static void fl_mouse_cursor_handler_dispose(GObject* object) {
FlMouseCursorHandler* self = FL_MOUSE_CURSOR_HANDLER(object);

g_clear_object(&self->channel);
g_weak_ref_clear(&self->view);
g_clear_pointer(&self->system_cursor_table, g_hash_table_unref);
g_clear_pointer(&self->cursor_name, g_free);

G_OBJECT_CLASS(fl_mouse_cursor_handler_parent_class)->dispose(object);
}

static void fl_mouse_cursor_handler_class_init(
FlMouseCursorHandlerClass* klass) {
G_OBJECT_CLASS(klass)->dispose = fl_mouse_cursor_handler_dispose;

fl_mouse_cursor_handler_signals[kSignalCursorChanged] =
g_signal_new("cursor-changed", fl_mouse_cursor_handler_get_type(),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}

static void fl_mouse_cursor_handler_init(FlMouseCursorHandler* self) {}
static void fl_mouse_cursor_handler_init(FlMouseCursorHandler* self) {
self->cursor_name = g_strdup("");
}

FlMouseCursorHandler* fl_mouse_cursor_handler_new(FlBinaryMessenger* messenger,
FlView* view) {
FlMouseCursorHandler* fl_mouse_cursor_handler_new(
FlBinaryMessenger* messenger) {
g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);

FlMouseCursorHandler* self = FL_MOUSE_CURSOR_HANDLER(
Expand All @@ -172,7 +178,12 @@ FlMouseCursorHandler* fl_mouse_cursor_handler_new(FlBinaryMessenger* messenger,
fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec));
fl_method_channel_set_method_call_handler(self->channel, method_call_cb, self,
nullptr);
g_weak_ref_init(&self->view, view);

return self;
}

const gchar* fl_mouse_cursor_handler_get_cursor_name(
FlMouseCursorHandler* self) {
g_return_val_if_fail(FL_IS_MOUSE_CURSOR_HANDLER(self), nullptr);
return self->cursor_name;
}
16 changes: 12 additions & 4 deletions shell/platform/linux/fl_mouse_cursor_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <gdk/gdk.h>

#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"

G_BEGIN_DECLS

Expand All @@ -28,15 +27,24 @@ G_DECLARE_FINAL_TYPE(FlMouseCursorHandler,
/**
* fl_mouse_cursor_handler_new:
* @messenger: an #FlBinaryMessenger.
* @view: an #FlView to control.
*
* Creates a new handler that implements SystemChannels.mouseCursor from the
* Flutter services library.
*
* Returns: a new #FlMouseCursorHandler.
*/
FlMouseCursorHandler* fl_mouse_cursor_handler_new(FlBinaryMessenger* messenger,
FlView* view);
FlMouseCursorHandler* fl_mouse_cursor_handler_new(FlBinaryMessenger* messenger);

/**
* fl_mouse_cursor_handler_get_cursor_name:
* @handler: an #FlMouseCursorHandler.
*
* Get the name of the current mouse cursor.
*
* Returns: a mouse cursor name.
*/
const gchar* fl_mouse_cursor_handler_get_cursor_name(
FlMouseCursorHandler* handler);

G_END_DECLS

Expand Down
42 changes: 36 additions & 6 deletions shell/platform/linux/fl_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include "flutter/shell/platform/linux/fl_keyboard_handler.h"
#include "flutter/shell/platform/linux/fl_keyboard_manager.h"
#include "flutter/shell/platform/linux/fl_keyboard_view_delegate.h"
#include "flutter/shell/platform/linux/fl_mouse_cursor_handler.h"
#include "flutter/shell/platform/linux/fl_plugin_registrar_private.h"
#include "flutter/shell/platform/linux/fl_renderer_gdk.h"
#include "flutter/shell/platform/linux/fl_scrolling_manager.h"
Expand Down Expand Up @@ -69,14 +68,16 @@ struct _FlView {
// Flutter system channel handlers.
FlKeyboardHandler* keyboard_handler;
FlTextInputHandler* text_input_handler;
FlMouseCursorHandler* mouse_cursor_handler;

// TRUE if the mouse pointer is inside the view.
gboolean pointer_inside;

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

// Signal subscripton for cursor changes.
guint cursor_changed_cb_id;

GCancellable* cancellable;
};

Expand Down Expand Up @@ -250,6 +251,28 @@ static void check_pointer_inside(FlView* self, GdkEvent* event) {
}
}

// Called when the mouse cursor changes.
static void cursor_changed_cb(FlView* self) {
FlMouseCursorHandler* handler =
fl_engine_get_mouse_cursor_handler(self->engine);
const gchar* cursor_name = fl_mouse_cursor_handler_get_cursor_name(handler);
GdkWindow* window =
gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(self)));
g_autoptr(GdkCursor) cursor =
gdk_cursor_new_from_name(gdk_window_get_display(window), cursor_name);
gdk_window_set_cursor(window, cursor);
}

// Set the mouse cursor.
static void setup_cursor(FlView* self) {
FlMouseCursorHandler* handler =
fl_engine_get_mouse_cursor_handler(self->engine);

self->cursor_changed_cb_id = g_signal_connect_swapped(
handler, "cursor-changed", G_CALLBACK(cursor_changed_cb), self);
cursor_changed_cb(self);
}

// Updates the engine with the current window metrics.
static void handle_geometry_changed(FlView* self) {
GtkAllocation allocation;
Expand Down Expand Up @@ -517,10 +540,7 @@ static GdkGLContext* create_context_cb(FlView* self) {
fl_renderer_gdk_set_window(self->renderer,
gtk_widget_get_parent_window(GTK_WIDGET(self)));

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

g_autoptr(GError) error = nullptr;
if (!fl_renderer_gdk_create_contexts(self->renderer, &error)) {
Expand Down Expand Up @@ -565,6 +585,8 @@ static void realize_cb(FlView* self) {
return;
}

setup_cursor(self);

handle_geometry_changed(self);

self->view_accessible = fl_view_accessible_new(self->engine);
Expand Down Expand Up @@ -627,6 +649,13 @@ static void fl_view_dispose(GObject* object) {
fl_engine_set_update_semantics_handler(self->engine, nullptr, nullptr,
nullptr);

FlMouseCursorHandler* handler =
fl_engine_get_mouse_cursor_handler(self->engine);
if (self->cursor_changed_cb_id != 0) {
g_signal_handler_disconnect(handler, self->cursor_changed_cb_id);
self->cursor_changed_cb_id = 0;
}

// Stop rendering.
fl_renderer_remove_view(FL_RENDERER(self->renderer), self->view_id);

Expand All @@ -648,7 +677,6 @@ static void fl_view_dispose(GObject* object) {
g_clear_object(&self->scrolling_manager);
g_clear_object(&self->keyboard_manager);
g_clear_object(&self->keyboard_handler);
g_clear_object(&self->mouse_cursor_handler);
g_clear_object(&self->view_accessible);
g_clear_object(&self->cancellable);

Expand Down Expand Up @@ -802,6 +830,8 @@ G_MODULE_EXPORT FlView* fl_view_new_for_engine(FlEngine* engine) {
fl_renderer_add_renderable(FL_RENDERER(self->renderer), self->view_id,
FL_RENDERABLE(self));

setup_cursor(self);

return self;
}

Expand Down
12 changes: 12 additions & 0 deletions shell/platform/linux/fl_view_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ TEST(FlViewTest, SecondaryView) {
return kSuccess;
}));

g_autoptr(GError) error = nullptr;
EXPECT_TRUE(fl_engine_start(engine, &error));

FlView* secondary_view = fl_view_new_for_engine(engine);
EXPECT_EQ(view_id, fl_view_get_id(secondary_view));
}
Expand All @@ -103,6 +106,9 @@ TEST(FlViewTest, SecondaryViewError) {
return kInvalidArguments;
}));

g_autoptr(GError) error = nullptr;
EXPECT_TRUE(fl_engine_start(engine, &error));

FlView* secondary_view = fl_view_new_for_engine(engine);
EXPECT_EQ(view_id, fl_view_get_id(secondary_view));
}
Expand All @@ -125,6 +131,9 @@ TEST(FlViewTest, ViewDestroy) {
return kSuccess;
}));

g_autoptr(GError) error = nullptr;
EXPECT_TRUE(fl_engine_start(engine, &error));

FlView* secondary_view = fl_view_new_for_engine(engine);

int64_t implicit_view_id = fl_view_get_id(implicit_view);
Expand Down Expand Up @@ -155,6 +164,9 @@ TEST(FlViewTest, ViewDestroyError) {
return kInvalidArguments;
}));

g_autoptr(GError) error = nullptr;
EXPECT_TRUE(fl_engine_start(engine, &error));

FlView* secondary_view = fl_view_new_for_engine(engine);

gtk_widget_destroy(GTK_WIDGET(secondary_view));
Expand Down
15 changes: 15 additions & 0 deletions shell/platform/linux/testing/mock_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,18 @@ MockWindow::MockWindow() {
GdkWindowState gdk_window_get_state(GdkWindow* window) {
return mock->gdk_window_get_state(window);
}

GdkDisplay* gdk_window_get_display(GdkWindow* window) {
return nullptr;
}

GdkMonitor* gdk_display_get_monitor_at_window(GdkDisplay* display,
GdkWindow* window) {
return nullptr;
}

GdkCursor* gdk_cursor_new_from_name(GdkDisplay* display, const gchar* name) {
return nullptr;
}

void gdk_window_set_cursor(GdkWindow* window, GdkCursor* cursor) {}