Flutter Linux Embedder
fl_mouse_cursor_plugin.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <gtk/gtk.h>
8 #include <cstring>
9 
12 
13 static constexpr char kChannelName[] = "flutter/mousecursor";
14 static constexpr char kBadArgumentsError[] = "Bad Arguments";
15 static constexpr char kActivateSystemCursorMethod[] = "activateSystemCursor";
16 static constexpr char kKindKey[] = "kind";
17 
18 static constexpr char kFallbackCursor[] = "default";
19 
21  GObject parent_instance;
22 
23  FlMethodChannel* channel;
24 
25  FlView* view;
26 
27  GHashTable* system_cursor_table;
28 };
29 
30 G_DEFINE_TYPE(FlMouseCursorPlugin, fl_mouse_cursor_plugin, G_TYPE_OBJECT)
31 
32 // Insert a new entry into a hashtable from strings to strings.
33 //
34 // Returns whether the newly added value was already in the hash table or not.
35 static bool define_system_cursor(GHashTable* table,
36  const gchar* key,
37  const gchar* value) {
38  return g_hash_table_insert(
39  table, reinterpret_cast<gpointer>(const_cast<gchar*>(key)),
40  reinterpret_cast<gpointer>(const_cast<gchar*>(value)));
41 }
42 
43 // Populate the hash table so that it maps from Flutter's cursor kinds to GTK's
44 // cursor values.
45 //
46 // The table must have been created as a hashtable from strings to strings.
47 static void populate_system_cursor_table(GHashTable* table) {
48  // The following mapping must be kept in sync with Flutter framework's
49  // mouse_cursor.dart.
50  define_system_cursor(table, "alias", "alias");
51  define_system_cursor(table, "allScroll", "all-scroll");
52  define_system_cursor(table, "basic", "default");
53  define_system_cursor(table, "cell", "cell");
54  define_system_cursor(table, "click", "pointer");
55  define_system_cursor(table, "contextMenu", "context-menu");
56  define_system_cursor(table, "copy", "copy");
57  define_system_cursor(table, "forbidden", "not-allowed");
58  define_system_cursor(table, "grab", "grab");
59  define_system_cursor(table, "grabbing", "grabbing");
60  define_system_cursor(table, "help", "help");
61  define_system_cursor(table, "move", "move");
62  define_system_cursor(table, "none", "none");
63  define_system_cursor(table, "noDrop", "no-drop");
64  define_system_cursor(table, "precise", "crosshair");
65  define_system_cursor(table, "progress", "progress");
66  define_system_cursor(table, "text", "text");
67  define_system_cursor(table, "resizeColumn", "col-resize");
68  define_system_cursor(table, "resizeDown", "s-resize");
69  define_system_cursor(table, "resizeDownLeft", "sw-resize");
70  define_system_cursor(table, "resizeDownRight", "se-resize");
71  define_system_cursor(table, "resizeLeft", "w-resize");
72  define_system_cursor(table, "resizeLeftRight", "ew-resize");
73  define_system_cursor(table, "resizeRight", "e-resize");
74  define_system_cursor(table, "resizeRow", "row-resize");
75  define_system_cursor(table, "resizeUp", "n-resize");
76  define_system_cursor(table, "resizeUpDown", "ns-resize");
77  define_system_cursor(table, "resizeUpLeft", "nw-resize");
78  define_system_cursor(table, "resizeUpRight", "ne-resize");
79  define_system_cursor(table, "resizeUpLeftDownRight", "nwse-resize");
80  define_system_cursor(table, "resizeUpRightDownLeft", "nesw-resize");
81  define_system_cursor(table, "verticalText", "vertical-text");
82  define_system_cursor(table, "wait", "wait");
83  define_system_cursor(table, "zoomIn", "zoom-in");
84  define_system_cursor(table, "zoomOut", "zoom-out");
85 }
86 
87 // Sets the mouse cursor.
88 FlMethodResponse* activate_system_cursor(FlMouseCursorPlugin* self,
89  FlValue* args) {
91  return FL_METHOD_RESPONSE(fl_method_error_response_new(
92  kBadArgumentsError, "Argument map missing or malformed", nullptr));
93  }
94 
96  const gchar* kind = nullptr;
97  if (fl_value_get_type(kind_value) == FL_VALUE_TYPE_STRING) {
98  kind = fl_value_get_string(kind_value);
99  }
100 
101  if (self->system_cursor_table == nullptr) {
102  self->system_cursor_table = g_hash_table_new(g_str_hash, g_str_equal);
103  populate_system_cursor_table(self->system_cursor_table);
104  }
105 
106  const gchar* cursor_name = reinterpret_cast<const gchar*>(
107  g_hash_table_lookup(self->system_cursor_table, kind));
108  if (cursor_name == nullptr) {
109  cursor_name = kFallbackCursor;
110  }
111 
112  GdkWindow* window =
113  gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(self->view)));
114  g_autoptr(GdkCursor) cursor =
115  gdk_cursor_new_from_name(gdk_window_get_display(window), cursor_name);
116  gdk_window_set_cursor(window, cursor);
117 
118  return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
119 }
120 
121 // Called when a method call is received from Flutter.
122 static void method_call_cb(FlMethodChannel* channel,
123  FlMethodCall* method_call,
124  gpointer user_data) {
125  FlMouseCursorPlugin* self = FL_MOUSE_CURSOR_PLUGIN(user_data);
126 
127  const gchar* method = fl_method_call_get_name(method_call);
129 
130  g_autoptr(FlMethodResponse) response = nullptr;
131  if (strcmp(method, kActivateSystemCursorMethod) == 0) {
132  response = activate_system_cursor(self, args);
133  } else {
134  response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
135  }
136 
137  g_autoptr(GError) error = nullptr;
138  if (!fl_method_call_respond(method_call, response, &error)) {
139  g_warning("Failed to send method call response: %s", error->message);
140  }
141 }
142 
143 static void fl_mouse_cursor_plugin_dispose(GObject* object) {
144  FlMouseCursorPlugin* self = FL_MOUSE_CURSOR_PLUGIN(object);
145 
146  g_clear_object(&self->channel);
147  if (self->view != nullptr) {
148  g_object_remove_weak_pointer(G_OBJECT(self->view),
149  reinterpret_cast<gpointer*>(&(self->view)));
150  self->view = nullptr;
151  }
152  g_clear_pointer(&self->system_cursor_table, g_hash_table_unref);
153 
154  G_OBJECT_CLASS(fl_mouse_cursor_plugin_parent_class)->dispose(object);
155 }
156 
157 static void fl_mouse_cursor_plugin_class_init(FlMouseCursorPluginClass* klass) {
158  G_OBJECT_CLASS(klass)->dispose = fl_mouse_cursor_plugin_dispose;
159 }
160 
161 static void fl_mouse_cursor_plugin_init(FlMouseCursorPlugin* self) {}
162 
163 FlMouseCursorPlugin* fl_mouse_cursor_plugin_new(FlBinaryMessenger* messenger,
164  FlView* view) {
165  g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
166 
167  FlMouseCursorPlugin* self = FL_MOUSE_CURSOR_PLUGIN(
168  g_object_new(fl_mouse_cursor_plugin_get_type(), nullptr));
169 
170  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
171  self->channel =
172  fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec));
174  nullptr);
175  self->view = view;
176  if (view != nullptr) {
177  g_object_add_weak_pointer(G_OBJECT(view),
178  reinterpret_cast<gpointer*>(&(self->view)));
179  }
180 
181  return self;
182 }
fl_mouse_cursor_plugin_dispose
static void fl_mouse_cursor_plugin_dispose(GObject *object)
Definition: fl_mouse_cursor_plugin.cc:143
FL_VALUE_TYPE_MAP
@ FL_VALUE_TYPE_MAP
Definition: fl_value.h:75
kKindKey
static constexpr char kKindKey[]
Definition: fl_mouse_cursor_plugin.cc:16
fl_method_channel_new
G_MODULE_EXPORT FlMethodChannel * fl_method_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMethodCodec *codec)
Definition: fl_method_channel.cc:112
kChannelName
static constexpr char kChannelName[]
Definition: fl_mouse_cursor_plugin.cc:13
fl_method_error_response_new
G_MODULE_EXPORT FlMethodErrorResponse * fl_method_error_response_new(const gchar *code, const gchar *message, FlValue *details)
Definition: fl_method_response.cc:144
fl_mouse_cursor_plugin_class_init
static void fl_mouse_cursor_plugin_class_init(FlMouseCursorPluginClass *klass)
Definition: fl_mouse_cursor_plugin.cc:157
fl_method_not_implemented_response_new
G_MODULE_EXPORT FlMethodNotImplementedResponse * fl_method_not_implemented_response_new()
Definition: fl_method_response.cc:179
fl_standard_method_codec_new
G_MODULE_EXPORT FlStandardMethodCodec * fl_standard_method_codec_new()
Definition: fl_standard_method_codec.cc:291
activate_system_cursor
FlMethodResponse * activate_system_cursor(FlMouseCursorPlugin *self, FlValue *args)
Definition: fl_mouse_cursor_plugin.cc:88
fl_mouse_cursor_plugin.h
fl_mouse_cursor_plugin_init
static void fl_mouse_cursor_plugin_init(FlMouseCursorPlugin *self)
Definition: fl_mouse_cursor_plugin.cc:161
fl_method_channel.h
FlValue
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:42
user_data
FlKeyEvent uint64_t FlKeyResponderAsyncCallback gpointer user_data
Definition: fl_key_channel_responder.cc:121
fl_value_lookup_string
G_MODULE_EXPORT FlValue * fl_value_lookup_string(FlValue *self, const gchar *key)
Definition: fl_value.cc:811
fl_value_get_string
const G_MODULE_EXPORT gchar * fl_value_get_string(FlValue *self)
Definition: fl_value.cc:682
fl_method_success_response_new
G_MODULE_EXPORT FlMethodSuccessResponse * fl_method_success_response_new(FlValue *result)
Definition: fl_method_response.cc:126
fl_method_call_respond
G_MODULE_EXPORT gboolean fl_method_call_respond(FlMethodCall *self, FlMethodResponse *response, GError **error)
Definition: fl_method_call.cc:77
_FlMouseCursorPlugin::system_cursor_table
GHashTable * system_cursor_table
Definition: fl_mouse_cursor_plugin.cc:27
method_call_cb
static void method_call_cb(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
Definition: fl_mouse_cursor_plugin.cc:122
kFallbackCursor
static constexpr char kFallbackCursor[]
Definition: fl_mouse_cursor_plugin.cc:18
fl_value_get_type
G_MODULE_EXPORT FlValueType fl_value_get_type(FlValue *self)
Definition: fl_value.cc:466
method_call
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
Definition: fl_method_channel.h:120
FL_VALUE_TYPE_STRING
@ FL_VALUE_TYPE_STRING
Definition: fl_value.h:69
fl_method_call_get_name
const G_MODULE_EXPORT gchar * fl_method_call_get_name(FlMethodCall *self)
Definition: fl_method_call.cc:67
_FlMouseCursorPlugin
Definition: fl_mouse_cursor_plugin.cc:20
G_DEFINE_TYPE
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
Definition: fl_basic_message_channel.cc:37
define_system_cursor
static bool define_system_cursor(GHashTable *table, const gchar *key, const gchar *value)
Definition: fl_mouse_cursor_plugin.cc:35
populate_system_cursor_table
static void populate_system_cursor_table(GHashTable *table)
Definition: fl_mouse_cursor_plugin.cc:47
fl_standard_method_codec.h
fl_method_channel_set_method_call_handler
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(FlMethodChannel *self, FlMethodChannelMethodCallHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
Definition: fl_method_channel.cc:134
_FlMouseCursorPlugin::parent_instance
GObject parent_instance
Definition: fl_mouse_cursor_plugin.cc:21
kActivateSystemCursorMethod
static constexpr char kActivateSystemCursorMethod[]
Definition: fl_mouse_cursor_plugin.cc:15
args
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Definition: fl_event_channel.h:89
error
const uint8_t uint32_t uint32_t GError ** error
Definition: fl_pixel_buffer_texture_test.cc:40
fl_mouse_cursor_plugin_new
FlMouseCursorPlugin * fl_mouse_cursor_plugin_new(FlBinaryMessenger *messenger, FlView *view)
Definition: fl_mouse_cursor_plugin.cc:163
fl_method_call_get_args
G_MODULE_EXPORT FlValue * fl_method_call_get_args(FlMethodCall *self)
Definition: fl_method_call.cc:72
kBadArgumentsError
static constexpr char kBadArgumentsError[]
Definition: fl_mouse_cursor_plugin.cc:14
_FlMouseCursorPlugin::view
FlView * view
Definition: fl_mouse_cursor_plugin.cc:25
value
uint8_t value
Definition: fl_standard_message_codec.cc:36
_FlMouseCursorPlugin::channel
FlMethodChannel * channel
Definition: fl_mouse_cursor_plugin.cc:23