Skip to content

Commit f3c1d7b

Browse files
Make fl_key_channel_responder_handle_event async (flutter/engine#56959)
Replace a callback with a more standard async call
1 parent 529d0d6 commit f3c1d7b

File tree

4 files changed

+111
-125
lines changed

4 files changed

+111
-125
lines changed

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

Lines changed: 32 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -9,71 +9,6 @@
99

1010
#include "flutter/shell/platform/linux/fl_key_event_channel.h"
1111

12-
/* Declare and define FlKeyChannelUserData */
13-
14-
/**
15-
* FlKeyChannelUserData:
16-
* The user_data used when #FlKeyChannelResponder sends message through the
17-
* channel.
18-
*/
19-
G_DECLARE_FINAL_TYPE(FlKeyChannelUserData,
20-
fl_key_channel_user_data,
21-
FL,
22-
KEY_CHANNEL_USER_DATA,
23-
GObject);
24-
25-
struct _FlKeyChannelUserData {
26-
GObject parent_instance;
27-
28-
// The current responder.
29-
GWeakRef responder;
30-
// The callback provided by the caller #FlKeyboardHandler.
31-
FlKeyChannelResponderAsyncCallback callback;
32-
// The user_data provided by the caller #FlKeyboardHandler.
33-
gpointer user_data;
34-
};
35-
36-
// Definition for FlKeyChannelUserData private class.
37-
G_DEFINE_TYPE(FlKeyChannelUserData, fl_key_channel_user_data, G_TYPE_OBJECT)
38-
39-
// Dispose method for FlKeyChannelUserData private class.
40-
static void fl_key_channel_user_data_dispose(GObject* object) {
41-
g_return_if_fail(FL_IS_KEY_CHANNEL_USER_DATA(object));
42-
FlKeyChannelUserData* self = FL_KEY_CHANNEL_USER_DATA(object);
43-
44-
g_weak_ref_clear(&self->responder);
45-
46-
G_OBJECT_CLASS(fl_key_channel_user_data_parent_class)->dispose(object);
47-
}
48-
49-
// Class initialization method for FlKeyChannelUserData private class.
50-
static void fl_key_channel_user_data_class_init(
51-
FlKeyChannelUserDataClass* klass) {
52-
G_OBJECT_CLASS(klass)->dispose = fl_key_channel_user_data_dispose;
53-
}
54-
55-
// Instance initialization method for FlKeyChannelUserData private class.
56-
static void fl_key_channel_user_data_init(FlKeyChannelUserData* self) {}
57-
58-
// Creates a new FlKeyChannelUserData private class with all information.
59-
//
60-
// The callback and the user_data might be nullptr.
61-
static FlKeyChannelUserData* fl_key_channel_user_data_new(
62-
FlKeyChannelResponder* responder,
63-
FlKeyChannelResponderAsyncCallback callback,
64-
gpointer user_data) {
65-
FlKeyChannelUserData* self = FL_KEY_CHANNEL_USER_DATA(
66-
g_object_new(fl_key_channel_user_data_get_type(), nullptr));
67-
68-
g_weak_ref_init(&self->responder, responder);
69-
self->callback = callback;
70-
self->user_data = user_data;
71-
return self;
72-
}
73-
74-
/* Define FlKeyChannelResponder */
75-
76-
// Definition of the FlKeyChannelResponder GObject class.
7712
struct _FlKeyChannelResponder {
7813
GObject parent_instance;
7914

@@ -87,20 +22,17 @@ G_DEFINE_TYPE(FlKeyChannelResponder, fl_key_channel_responder, G_TYPE_OBJECT)
8722
static void handle_response(GObject* object,
8823
GAsyncResult* result,
8924
gpointer user_data) {
90-
g_autoptr(FlKeyChannelUserData) data = FL_KEY_CHANNEL_USER_DATA(user_data);
91-
92-
g_autoptr(FlKeyChannelResponder) self =
93-
FL_KEY_CHANNEL_RESPONDER(g_weak_ref_get(&data->responder));
94-
if (self == nullptr) {
95-
return;
96-
}
25+
g_autoptr(GTask) task = G_TASK(user_data);
9726

9827
gboolean handled = FALSE;
9928
g_autoptr(GError) error = nullptr;
10029
if (!fl_key_event_channel_send_finish(object, result, &handled, &error)) {
10130
g_warning("Unable to retrieve framework response: %s", error->message);
10231
}
103-
data->callback(handled, data->user_data);
32+
33+
gboolean* return_value = g_new0(gboolean, 1);
34+
*return_value = handled;
35+
g_task_return_pointer(task, return_value, g_free);
10436
}
10537

10638
// Disposes of an FlKeyChannelResponder instance.
@@ -136,12 +68,12 @@ FlKeyChannelResponder* fl_key_channel_responder_new(
13668
return self;
13769
}
13870

139-
void fl_key_channel_responder_handle_event(
140-
FlKeyChannelResponder* self,
141-
FlKeyEvent* event,
142-
uint64_t specified_logical_key,
143-
FlKeyChannelResponderAsyncCallback callback,
144-
gpointer user_data) {
71+
void fl_key_channel_responder_handle_event(FlKeyChannelResponder* self,
72+
FlKeyEvent* event,
73+
uint64_t specified_logical_key,
74+
GCancellable* cancellable,
75+
GAsyncReadyCallback callback,
76+
gpointer user_data) {
14577
g_return_if_fail(event != nullptr);
14678
g_return_if_fail(callback != nullptr);
14779

@@ -198,10 +130,25 @@ void fl_key_channel_responder_handle_event(
198130
state |= (shift_lock_pressed || caps_lock_pressed) ? GDK_LOCK_MASK : 0x0;
199131
state |= num_lock_pressed ? GDK_MOD2_MASK : 0x0;
200132

201-
FlKeyChannelUserData* data =
202-
fl_key_channel_user_data_new(self, callback, user_data);
203-
fl_key_event_channel_send(self->channel, type, scan_code,
204-
fl_key_event_get_keyval(event), state,
205-
unicode_scalar_values, specified_logical_key,
206-
nullptr, handle_response, data);
133+
fl_key_event_channel_send(
134+
self->channel, type, scan_code, fl_key_event_get_keyval(event), state,
135+
unicode_scalar_values, specified_logical_key, nullptr, handle_response,
136+
g_task_new(self, cancellable, callback, user_data));
137+
}
138+
139+
gboolean fl_key_channel_responder_handle_event_finish(
140+
FlKeyChannelResponder* self,
141+
GAsyncResult* result,
142+
gboolean* handled,
143+
GError** error) {
144+
g_return_val_if_fail(g_task_is_valid(result, self), FALSE);
145+
146+
g_autofree gboolean* return_value =
147+
static_cast<gboolean*>(g_task_propagate_pointer(G_TASK(result), error));
148+
if (return_value == nullptr) {
149+
return FALSE;
150+
}
151+
152+
*handled = *return_value;
153+
return TRUE;
207154
}

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

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,6 @@ G_DECLARE_FINAL_TYPE(FlKeyChannelResponder,
1616
KEY_CHANNEL_RESPONDER,
1717
GObject);
1818

19-
/**
20-
* FlKeyChannelResponderAsyncCallback:
21-
* @event: whether the event has been handled.
22-
* @user_data: the same value as user_data sent by
23-
* #fl_key_responder_handle_event.
24-
*
25-
* The signature for a callback with which a #FlKeyChannelResponder
26-
*asynchronously reports whether the responder handles the event.
27-
**/
28-
typedef void (*FlKeyChannelResponderAsyncCallback)(bool handled,
29-
gpointer user_data);
30-
3119
/**
3220
* FlKeyChannelResponder:
3321
*
@@ -54,21 +42,37 @@ FlKeyChannelResponder* fl_key_channel_responder_new(
5442
* @event: the event to be handled. Must not be null. The object is managed by
5543
* callee and must not be assumed available after this function.
5644
* @specified_logical_key:
57-
* @callback: the callback to report the result. It should be called exactly
58-
* once. Must not be null.
59-
* @user_data: a value that will be sent back in the callback. Can be null.
45+
* @cancellable: (allow-none): a #GCancellable or %NULL.
46+
* @callback: (scope async): a #GAsyncReadyCallback to call when the event has
47+
* been processed.
48+
* @user_data: (closure): user data to pass to @callback.
49+
*
50+
* Let the responder handle an event.
51+
*/
52+
void fl_key_channel_responder_handle_event(FlKeyChannelResponder* responder,
53+
FlKeyEvent* event,
54+
uint64_t specified_logical_key,
55+
GCancellable* cancellable,
56+
GAsyncReadyCallback callback,
57+
gpointer user_data);
58+
59+
/**
60+
* fl_key_channel_responder_handle_event_finish:
61+
* @responder: an #FlKeyChannelResponder.
62+
* @result: a #GAsyncResult.
63+
* @handled: location to write if this event was handled by the platform.
64+
* @error: (allow-none): #GError location to store the error occurring, or %NULL
65+
* to ignore.
66+
*
67+
* Completes request started with fl_key_channel_responder_handle_event().
6068
*
61-
* Let the responder handle an event, expecting the responder to report
62-
* whether to handle the event. The result will be reported by invoking
63-
* `callback` exactly once, which might happen after
64-
* `fl_key_channel_responder_handle_event` or during it.
69+
* Returns %TRUE on success.
6570
*/
66-
void fl_key_channel_responder_handle_event(
71+
gboolean fl_key_channel_responder_handle_event_finish(
6772
FlKeyChannelResponder* responder,
68-
FlKeyEvent* event,
69-
uint64_t specified_logical_key,
70-
FlKeyChannelResponderAsyncCallback callback,
71-
gpointer user_data);
73+
GAsyncResult* result,
74+
gboolean* handled,
75+
GError** error);
7276

7377
G_END_DECLS
7478

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

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,11 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) {
5757
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
5858
12345, TRUE, 0x04, GDK_KEY_A, static_cast<GdkModifierType>(0), 0);
5959
fl_key_channel_responder_handle_event(
60-
responder, event1, 0,
61-
[](bool handled, gpointer user_data) {
60+
responder, event1, 0, nullptr,
61+
[](GObject* object, GAsyncResult* result, gpointer user_data) {
62+
gboolean handled;
63+
EXPECT_TRUE(fl_key_channel_responder_handle_event_finish(
64+
FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr));
6265
EXPECT_FALSE(handled);
6366
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
6467
},
@@ -73,8 +76,11 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) {
7376
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
7477
23456, FALSE, 0x04, GDK_KEY_A, static_cast<GdkModifierType>(0), 0);
7578
fl_key_channel_responder_handle_event(
76-
responder, event2, 0,
77-
[](bool handled, gpointer user_data) {
79+
responder, event2, 0, nullptr,
80+
[](GObject* object, GAsyncResult* result, gpointer user_data) {
81+
gboolean handled;
82+
EXPECT_TRUE(fl_key_channel_responder_handle_event_finish(
83+
FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr));
7884
EXPECT_FALSE(handled);
7985
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
8086
},
@@ -97,8 +103,11 @@ void test_lock_event(guint key_code,
97103
g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
98104
12345, TRUE, 0x04, key_code, static_cast<GdkModifierType>(0), 0);
99105
fl_key_channel_responder_handle_event(
100-
responder, event1, 0,
101-
[](bool handled, gpointer user_data) {
106+
responder, event1, 0, nullptr,
107+
[](GObject* object, GAsyncResult* result, gpointer user_data) {
108+
gboolean handled;
109+
EXPECT_TRUE(fl_key_channel_responder_handle_event_finish(
110+
FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr));
102111
EXPECT_FALSE(handled);
103112
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
104113
},
@@ -109,8 +118,11 @@ void test_lock_event(guint key_code,
109118
g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
110119
12346, FALSE, 0x04, key_code, static_cast<GdkModifierType>(0), 0);
111120
fl_key_channel_responder_handle_event(
112-
responder, event2, 0,
113-
[](bool handled, gpointer user_data) {
121+
responder, event2, 0, nullptr,
122+
[](GObject* object, GAsyncResult* result, gpointer user_data) {
123+
gboolean handled;
124+
EXPECT_TRUE(fl_key_channel_responder_handle_event_finish(
125+
FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr));
114126
EXPECT_FALSE(handled);
115127
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
116128
},
@@ -162,8 +174,11 @@ TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) {
162174
g_autoptr(FlKeyEvent) event = fl_key_event_new(
163175
12345, TRUE, 0x04, GDK_KEY_A, static_cast<GdkModifierType>(0), 0);
164176
fl_key_channel_responder_handle_event(
165-
responder, event, 0,
166-
[](bool handled, gpointer user_data) {
177+
responder, event, 0, nullptr,
178+
[](GObject* object, GAsyncResult* result, gpointer user_data) {
179+
gboolean handled;
180+
EXPECT_TRUE(fl_key_channel_responder_handle_event_finish(
181+
FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr));
167182
EXPECT_TRUE(handled);
168183
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
169184
},
@@ -189,8 +204,11 @@ TEST(FlKeyChannelResponderTest, UseSpecifiedLogicalKey) {
189204
g_autoptr(FlKeyEvent) event = fl_key_event_new(
190205
12345, TRUE, 0x04, GDK_KEY_A, static_cast<GdkModifierType>(0), 0);
191206
fl_key_channel_responder_handle_event(
192-
responder, event, 888,
193-
[](bool handled, gpointer user_data) {
207+
responder, event, 888, nullptr,
208+
[](GObject* object, GAsyncResult* result, gpointer user_data) {
209+
gboolean handled;
210+
EXPECT_TRUE(fl_key_channel_responder_handle_event_finish(
211+
FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr));
194212
EXPECT_TRUE(handled);
195213
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
196214
},

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ struct _FlKeyboardManager {
167167
GdkKeymap* keymap;
168168
gulong keymap_keys_changed_cb_id; // Signal connection ID for
169169
// keymap-keys-changed
170+
171+
GCancellable* cancellable;
170172
};
171173

172174
G_DEFINE_TYPE(FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT);
@@ -274,18 +276,29 @@ static void responder_handle_embedder_event_callback(bool handled,
274276
responder_handle_event_callback(self, data->pending);
275277
}
276278

277-
static void responder_handle_channel_event_callback(bool handled,
278-
gpointer user_data) {
279+
static void responder_handle_channel_event_cb(GObject* object,
280+
GAsyncResult* result,
281+
gpointer user_data) {
279282
g_autoptr(FlKeyboardManagerData) data = FL_KEYBOARD_MANAGER_DATA(user_data);
280283

281-
fl_keyboard_pending_event_mark_channel_replied(data->pending, handled);
284+
g_autoptr(GError) error = nullptr;
285+
gboolean handled;
286+
if (!fl_key_channel_responder_handle_event_finish(
287+
FL_KEY_CHANNEL_RESPONDER(object), result, &handled, &error)) {
288+
if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
289+
g_warning("Failed to handle key event in platform: %s", error->message);
290+
}
291+
return;
292+
}
282293

283294
g_autoptr(FlKeyboardManager) self =
284295
FL_KEYBOARD_MANAGER(g_weak_ref_get(&data->manager));
285296
if (self == nullptr) {
286297
return;
287298
}
288299

300+
fl_keyboard_pending_event_mark_channel_replied(data->pending, handled);
301+
289302
responder_handle_event_callback(self, data->pending);
290303
}
291304

@@ -395,6 +408,8 @@ static void guarantee_layout(FlKeyboardManager* self, FlKeyEvent* event) {
395408
static void fl_keyboard_manager_dispose(GObject* object) {
396409
FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object);
397410

411+
g_cancellable_cancel(self->cancellable);
412+
398413
g_weak_ref_clear(&self->engine);
399414
g_weak_ref_clear(&self->view_delegate);
400415

@@ -411,6 +426,7 @@ static void fl_keyboard_manager_dispose(GObject* object) {
411426
g_signal_handler_disconnect(self->keymap, self->keymap_keys_changed_cb_id);
412427
self->keymap_keys_changed_cb_id = 0;
413428
}
429+
g_clear_object(&self->cancellable);
414430

415431
G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object);
416432
}
@@ -439,6 +455,7 @@ static void fl_keyboard_manager_init(FlKeyboardManager* self) {
439455
self->keymap = gdk_keymap_get_for_display(gdk_display_get_default());
440456
self->keymap_keys_changed_cb_id = g_signal_connect_swapped(
441457
self->keymap, "keys-changed", G_CALLBACK(keymap_keys_changed_cb), self);
458+
self->cancellable = g_cancellable_new();
442459
}
443460

444461
FlKeyboardManager* fl_keyboard_manager_new(
@@ -499,7 +516,7 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self,
499516
responder_handle_embedder_event_callback, g_object_ref(data));
500517
fl_key_channel_responder_handle_event(
501518
self->key_channel_responder, event, specified_logical_key,
502-
responder_handle_channel_event_callback, g_object_ref(data));
519+
self->cancellable, responder_handle_channel_event_cb, g_object_ref(data));
503520

504521
return TRUE;
505522
}

0 commit comments

Comments
 (0)