mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add GDestroyNotify callbacks on handlers (#18546)
This commit is contained in:
parent
5d8c3a07ef
commit
79b136534a
@ -12,6 +12,9 @@ struct _FlBasicMessageChannel {
|
||||
// Messenger to communicate on
|
||||
FlBinaryMessenger* messenger;
|
||||
|
||||
// TRUE if the channel has been closed
|
||||
gboolean channel_closed;
|
||||
|
||||
// Channel name
|
||||
gchar* name;
|
||||
|
||||
@ -21,6 +24,7 @@ struct _FlBasicMessageChannel {
|
||||
// Function called when a message is received
|
||||
FlBasicMessageChannelMessageHandler message_handler;
|
||||
gpointer message_handler_data;
|
||||
GDestroyNotify message_handler_destroy_notify;
|
||||
};
|
||||
|
||||
struct _FlBasicMessageChannelResponseHandle {
|
||||
@ -106,17 +110,37 @@ static void message_response_cb(GObject* object,
|
||||
g_task_return_pointer(task, result, g_object_unref);
|
||||
}
|
||||
|
||||
// Called when the channel handler is closed
|
||||
static void channel_closed_cb(gpointer user_data) {
|
||||
g_autoptr(FlBasicMessageChannel) self = FL_BASIC_MESSAGE_CHANNEL(user_data);
|
||||
|
||||
self->channel_closed = TRUE;
|
||||
|
||||
// Disconnect handler
|
||||
if (self->message_handler_destroy_notify != nullptr)
|
||||
self->message_handler_destroy_notify(self->message_handler_data);
|
||||
self->message_handler = nullptr;
|
||||
self->message_handler_data = nullptr;
|
||||
self->message_handler_destroy_notify = nullptr;
|
||||
}
|
||||
|
||||
static void fl_basic_message_channel_dispose(GObject* object) {
|
||||
FlBasicMessageChannel* self = FL_BASIC_MESSAGE_CHANNEL(object);
|
||||
|
||||
if (self->messenger != nullptr)
|
||||
fl_binary_messenger_set_message_handler_on_channel(
|
||||
self->messenger, self->name, nullptr, nullptr);
|
||||
self->messenger, self->name, nullptr, nullptr, nullptr);
|
||||
|
||||
g_clear_object(&self->messenger);
|
||||
g_clear_pointer(&self->name, g_free);
|
||||
g_clear_object(&self->codec);
|
||||
|
||||
if (self->message_handler_destroy_notify != nullptr)
|
||||
self->message_handler_destroy_notify(self->message_handler_data);
|
||||
self->message_handler = nullptr;
|
||||
self->message_handler_data = nullptr;
|
||||
self->message_handler_destroy_notify = nullptr;
|
||||
|
||||
G_OBJECT_CLASS(fl_basic_message_channel_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
@ -143,7 +167,8 @@ G_MODULE_EXPORT FlBasicMessageChannel* fl_basic_message_channel_new(
|
||||
self->codec = FL_MESSAGE_CODEC(g_object_ref(codec));
|
||||
|
||||
fl_binary_messenger_set_message_handler_on_channel(
|
||||
self->messenger, self->name, message_cb, self);
|
||||
self->messenger, self->name, message_cb, g_object_ref(self),
|
||||
channel_closed_cb);
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -151,11 +176,25 @@ G_MODULE_EXPORT FlBasicMessageChannel* fl_basic_message_channel_new(
|
||||
G_MODULE_EXPORT void fl_basic_message_channel_set_message_handler(
|
||||
FlBasicMessageChannel* self,
|
||||
FlBasicMessageChannelMessageHandler handler,
|
||||
gpointer user_data) {
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify) {
|
||||
g_return_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self));
|
||||
|
||||
// Don't set handler if channel closed
|
||||
if (self->channel_closed) {
|
||||
g_warning(
|
||||
"Attempted to set message handler on closed FlBasicMessageChannel");
|
||||
if (destroy_notify != nullptr)
|
||||
destroy_notify(user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->message_handler_destroy_notify != nullptr)
|
||||
self->message_handler_destroy_notify(self->message_handler_data);
|
||||
|
||||
self->message_handler = handler;
|
||||
self->message_handler_data = user_data;
|
||||
self->message_handler_destroy_notify = destroy_notify;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT gboolean fl_basic_message_channel_respond(
|
||||
|
||||
@ -76,26 +76,34 @@ static FlBinaryMessengerResponseHandle* fl_binary_messenger_response_handle_new(
|
||||
typedef struct {
|
||||
FlBinaryMessengerMessageHandler message_handler;
|
||||
gpointer message_handler_data;
|
||||
GDestroyNotify message_handler_destroy_notify;
|
||||
} PlatformMessageHandler;
|
||||
|
||||
static PlatformMessageHandler* platform_message_handler_new(
|
||||
FlBinaryMessengerMessageHandler handler,
|
||||
gpointer user_data) {
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify) {
|
||||
PlatformMessageHandler* self = static_cast<PlatformMessageHandler*>(
|
||||
g_malloc0(sizeof(PlatformMessageHandler)));
|
||||
self->message_handler = handler;
|
||||
self->message_handler_data = user_data;
|
||||
self->message_handler_destroy_notify = destroy_notify;
|
||||
return self;
|
||||
}
|
||||
|
||||
static void platform_message_handler_free(gpointer data) {
|
||||
PlatformMessageHandler* self = static_cast<PlatformMessageHandler*>(data);
|
||||
if (self->message_handler_destroy_notify)
|
||||
self->message_handler_destroy_notify(self->message_handler_data);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static void engine_weak_notify_cb(gpointer user_data, GObject* object) {
|
||||
FlBinaryMessenger* self = FL_BINARY_MESSENGER(user_data);
|
||||
self->engine = nullptr;
|
||||
|
||||
// Disconnect any handlers
|
||||
g_hash_table_remove_all(self->platform_message_handlers);
|
||||
}
|
||||
|
||||
static gboolean fl_binary_messenger_platform_message_cb(
|
||||
@ -151,7 +159,7 @@ FlBinaryMessenger* fl_binary_messenger_new(FlEngine* engine) {
|
||||
g_object_weak_ref(G_OBJECT(engine), engine_weak_notify_cb, self);
|
||||
|
||||
fl_engine_set_platform_message_handler(
|
||||
engine, fl_binary_messenger_platform_message_cb, self);
|
||||
engine, fl_binary_messenger_platform_message_cb, self, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -160,13 +168,25 @@ G_MODULE_EXPORT void fl_binary_messenger_set_message_handler_on_channel(
|
||||
FlBinaryMessenger* self,
|
||||
const gchar* channel,
|
||||
FlBinaryMessengerMessageHandler handler,
|
||||
gpointer user_data) {
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify) {
|
||||
g_return_if_fail(FL_IS_BINARY_MESSENGER(self));
|
||||
g_return_if_fail(channel != nullptr);
|
||||
|
||||
// Don't set handlers if engine already gone
|
||||
if (self->engine == nullptr) {
|
||||
g_warning(
|
||||
"Attempted to set message handler on closed FlBinaryMessenger without "
|
||||
"engine");
|
||||
if (destroy_notify != nullptr)
|
||||
destroy_notify(user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler != nullptr)
|
||||
g_hash_table_replace(self->platform_message_handlers, g_strdup(channel),
|
||||
platform_message_handler_new(handler, user_data));
|
||||
g_hash_table_replace(
|
||||
self->platform_message_handlers, g_strdup(channel),
|
||||
platform_message_handler_new(handler, user_data, destroy_notify));
|
||||
else
|
||||
g_hash_table_remove(self->platform_message_handlers, channel);
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ struct _FlEngine {
|
||||
// Function to call when a platform message is received
|
||||
FlEnginePlatformMessageHandler platform_message_handler;
|
||||
gpointer platform_message_handler_data;
|
||||
GDestroyNotify platform_message_handler_destroy_notify;
|
||||
};
|
||||
|
||||
G_DEFINE_QUARK(fl_engine_error_quark, fl_engine_error)
|
||||
@ -161,6 +162,12 @@ static void fl_engine_dispose(GObject* object) {
|
||||
g_clear_object(&self->renderer);
|
||||
g_clear_object(&self->binary_messenger);
|
||||
|
||||
if (self->platform_message_handler_destroy_notify)
|
||||
self->platform_message_handler_destroy_notify(
|
||||
self->platform_message_handler_data);
|
||||
self->platform_message_handler_data = nullptr;
|
||||
self->platform_message_handler_destroy_notify = nullptr;
|
||||
|
||||
G_OBJECT_CLASS(fl_engine_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
@ -240,12 +247,18 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
|
||||
void fl_engine_set_platform_message_handler(
|
||||
FlEngine* self,
|
||||
FlEnginePlatformMessageHandler handler,
|
||||
gpointer user_data) {
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify) {
|
||||
g_return_if_fail(FL_IS_ENGINE(self));
|
||||
g_return_if_fail(handler != nullptr);
|
||||
|
||||
if (self->platform_message_handler_destroy_notify)
|
||||
self->platform_message_handler_destroy_notify(
|
||||
self->platform_message_handler_data);
|
||||
|
||||
self->platform_message_handler = handler;
|
||||
self->platform_message_handler_data = user_data;
|
||||
self->platform_message_handler_destroy_notify = destroy_notify;
|
||||
}
|
||||
|
||||
gboolean fl_engine_send_platform_message_response(
|
||||
|
||||
@ -60,6 +60,8 @@ FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer);
|
||||
* @engine: an #FlEngine.
|
||||
* @handler: function to call when a platform message is received.
|
||||
* @user_data: (closure): user data to pass to @handler.
|
||||
* @destroy_notify: (allow-none): a function which gets called to free
|
||||
* @user_data, or %NULL.
|
||||
*
|
||||
* Registers the function called when a platform message is reveived. Call
|
||||
* fl_engine_send_platform_message_response() with the response to this message.
|
||||
@ -70,7 +72,8 @@ FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer);
|
||||
void fl_engine_set_platform_message_handler(
|
||||
FlEngine* engine,
|
||||
FlEnginePlatformMessageHandler handler,
|
||||
gpointer user_data);
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify);
|
||||
|
||||
/**
|
||||
* fl_engine_start:
|
||||
|
||||
@ -16,6 +16,9 @@ struct _FlMethodChannel {
|
||||
// Messenger to communicate on
|
||||
FlBinaryMessenger* messenger;
|
||||
|
||||
// TRUE if the channel has been closed
|
||||
gboolean channel_closed;
|
||||
|
||||
// Channel name
|
||||
gchar* name;
|
||||
|
||||
@ -25,6 +28,7 @@ struct _FlMethodChannel {
|
||||
// Function called when a method call is received
|
||||
FlMethodChannelMethodCallHandler method_call_handler;
|
||||
gpointer method_call_handler_data;
|
||||
GDestroyNotify method_call_handler_destroy_notify;
|
||||
};
|
||||
|
||||
// Added here to stop the compiler from optimising this function away
|
||||
@ -65,17 +69,37 @@ static void message_response_cb(GObject* object,
|
||||
g_task_return_pointer(task, result, g_object_unref);
|
||||
}
|
||||
|
||||
// Called when the channel handler is closed
|
||||
static void channel_closed_cb(gpointer user_data) {
|
||||
g_autoptr(FlMethodChannel) self = FL_METHOD_CHANNEL(user_data);
|
||||
|
||||
self->channel_closed = TRUE;
|
||||
|
||||
// Disconnect handler
|
||||
if (self->method_call_handler_destroy_notify != nullptr)
|
||||
self->method_call_handler_destroy_notify(self->method_call_handler_data);
|
||||
self->method_call_handler = nullptr;
|
||||
self->method_call_handler_data = nullptr;
|
||||
self->method_call_handler_destroy_notify = nullptr;
|
||||
}
|
||||
|
||||
static void fl_method_channel_dispose(GObject* object) {
|
||||
FlMethodChannel* self = FL_METHOD_CHANNEL(object);
|
||||
|
||||
if (self->messenger != nullptr)
|
||||
fl_binary_messenger_set_message_handler_on_channel(
|
||||
self->messenger, self->name, nullptr, nullptr);
|
||||
self->messenger, self->name, nullptr, nullptr, nullptr);
|
||||
|
||||
g_clear_object(&self->messenger);
|
||||
g_clear_pointer(&self->name, g_free);
|
||||
g_clear_object(&self->codec);
|
||||
|
||||
if (self->method_call_handler_destroy_notify != nullptr)
|
||||
self->method_call_handler_destroy_notify(self->method_call_handler_data);
|
||||
self->method_call_handler = nullptr;
|
||||
self->method_call_handler_data = nullptr;
|
||||
self->method_call_handler_destroy_notify = nullptr;
|
||||
|
||||
G_OBJECT_CLASS(fl_method_channel_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
@ -101,7 +125,8 @@ G_MODULE_EXPORT FlMethodChannel* fl_method_channel_new(
|
||||
self->codec = FL_METHOD_CODEC(g_object_ref(codec));
|
||||
|
||||
fl_binary_messenger_set_message_handler_on_channel(
|
||||
self->messenger, self->name, message_cb, self);
|
||||
self->messenger, self->name, message_cb, g_object_ref(self),
|
||||
channel_closed_cb);
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -109,11 +134,24 @@ G_MODULE_EXPORT FlMethodChannel* fl_method_channel_new(
|
||||
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(
|
||||
FlMethodChannel* self,
|
||||
FlMethodChannelMethodCallHandler handler,
|
||||
gpointer user_data) {
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify) {
|
||||
g_return_if_fail(FL_IS_METHOD_CHANNEL(self));
|
||||
|
||||
// Don't set handler if channel closed
|
||||
if (self->channel_closed) {
|
||||
g_warning("Attempted to set method call handler on closed FlMethodChannel");
|
||||
if (destroy_notify != nullptr)
|
||||
destroy_notify(user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->method_call_handler_destroy_notify != nullptr)
|
||||
self->method_call_handler_destroy_notify(self->method_call_handler_data);
|
||||
|
||||
self->method_call_handler = handler;
|
||||
self->method_call_handler_data = user_data;
|
||||
self->method_call_handler_destroy_notify = destroy_notify;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void fl_method_channel_invoke_method(
|
||||
|
||||
@ -70,7 +70,8 @@ G_DECLARE_FINAL_TYPE(FlBasicMessageChannelResponseHandle,
|
||||
* g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new ();
|
||||
* channel = fl_basic_message_channel_new (messenger, "flutter/foo",
|
||||
* FL_MESSAGE_CODEC (codec));
|
||||
* fl_basic_message_channel_set_message_handler (channel, message_cb, NULL);
|
||||
* fl_basic_message_channel_set_message_handler (channel, message_cb, NULL,
|
||||
* NULL);
|
||||
*
|
||||
* g_autoptr(FlValue) message = fl_value_new_string ("Hello World");
|
||||
* fl_basic_message_channel_send (channel, message, NULL,
|
||||
@ -131,13 +132,21 @@ FlBasicMessageChannel* fl_basic_message_channel_new(
|
||||
* @handler: (allow-none): function to call when a message is received on this
|
||||
* channel or %NULL to disable the handler.
|
||||
* @user_data: (closure): user data to pass to @handler.
|
||||
* @destroy_notify: (allow-none): a function which gets called to free
|
||||
* @user_data, or %NULL.
|
||||
*
|
||||
* Sets the function called when a message is received.
|
||||
* Sets the function called when a message is received from the Dart side of the
|
||||
* channel. See #FlBasicMessageChannelMessageHandler for details on how to
|
||||
* respond to messages.
|
||||
*
|
||||
* The handler is removed if the channel is closed or is replaced by another
|
||||
* handler, set @destroy_notify if you want to detect this.
|
||||
*/
|
||||
void fl_basic_message_channel_set_message_handler(
|
||||
FlBasicMessageChannel* channel,
|
||||
FlBasicMessageChannelMessageHandler handler,
|
||||
gpointer user_data);
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify);
|
||||
|
||||
/**
|
||||
* fl_basic_message_channel_respond:
|
||||
|
||||
@ -83,17 +83,22 @@ typedef void (*FlBinaryMessengerMessageHandler)(
|
||||
* @handler: (allow-none): function to call when a message is received on this
|
||||
* channel or %NULL to disable a handler
|
||||
* @user_data: (closure): user data to pass to @handler.
|
||||
* @destroy_notify: (allow-none): a function which gets called to free
|
||||
* @user_data, or %NULL.
|
||||
*
|
||||
* Sets the function called when a platform message is received on the given
|
||||
* channel. Call fl_binary_messenger_send_response() when the message is
|
||||
* handled. Ownership of #FlBinaryMessengerResponseHandle is transferred to the
|
||||
* caller, and the call must be responded to to avoid memory leaks.
|
||||
* channel. See #FlBinaryMessengerMessageHandler for details on how to respond
|
||||
* to messages.
|
||||
*
|
||||
* The handler is removed if the channel is closed or is replaced by another
|
||||
* handler, set @destroy_notify if you want to detect this.
|
||||
*/
|
||||
void fl_binary_messenger_set_message_handler_on_channel(
|
||||
FlBinaryMessenger* messenger,
|
||||
const gchar* channel,
|
||||
FlBinaryMessengerMessageHandler handler,
|
||||
gpointer user_data);
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify);
|
||||
|
||||
/**
|
||||
* fl_binary_messenger_send_response:
|
||||
|
||||
@ -84,7 +84,8 @@ G_DECLARE_FINAL_TYPE(FlMethodChannel,
|
||||
* g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new ();
|
||||
* channel =
|
||||
* fl_method_channel_new(messenger, "flutter/foo", FL_METHOD_CODEC (codec));
|
||||
* fl_method_channel_set_method_call_handler (channel, method_call_cb, NULL);
|
||||
* fl_method_channel_set_method_call_handler (channel, method_call_cb, NULL,
|
||||
* NULL);
|
||||
*
|
||||
* g_autoptr(FlValue) args = fl_value_new_string ("Hello World");
|
||||
* fl_method_channel_invoke_method (channel, "Foo.foo", args,
|
||||
@ -105,7 +106,7 @@ G_DECLARE_FINAL_TYPE(FlMethodChannel,
|
||||
* Function called when a method call is received. Respond to the method call
|
||||
* with fl_method_call_respond(). If the response is not occurring in this
|
||||
* callback take a reference to @method_call and release that once it has been
|
||||
* responded to.Failing to respond before the last reference to @method_call is
|
||||
* responded to. Failing to respond before the last reference to @method_call is
|
||||
* dropped is a programming error.
|
||||
*/
|
||||
typedef void (*FlMethodChannelMethodCallHandler)(FlMethodChannel* channel,
|
||||
@ -132,14 +133,21 @@ FlMethodChannel* fl_method_channel_new(FlBinaryMessenger* messenger,
|
||||
* @channel: an #FlMethodChannel.
|
||||
* @handler: function to call when a method call is received on this channel.
|
||||
* @user_data: (closure): user data to pass to @handler.
|
||||
* @destroy_notify: (allow-none): a function which gets called to free
|
||||
* @user_data, or %NULL.
|
||||
*
|
||||
* Sets the function called when a method is called. Call
|
||||
* fl_method_call_respond() when the method completes.
|
||||
* Sets the function called when a method call is received from the Dart side of
|
||||
* the channel. See #FlMethodChannelMethodCallHandler for details on how to
|
||||
* respond to method calls.
|
||||
*
|
||||
* The handler is removed if the channel is closed or is replaced by another
|
||||
* handler, set @destroy_notify if you want to detect this.
|
||||
*/
|
||||
void fl_method_channel_set_method_call_handler(
|
||||
FlMethodChannel* channel,
|
||||
FlMethodChannelMethodCallHandler handler,
|
||||
gpointer user_data);
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify);
|
||||
|
||||
/**
|
||||
* fl_method_channel_invoke_method:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user