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 all 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
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,7 @@ FILE: ../../../flutter/shell/platform/glfw/platform_handler.h
FILE: ../../../flutter/shell/platform/glfw/public/flutter_glfw.h
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.cc
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.h
FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel.cc
FILE: ../../../flutter/shell/platform/linux/fl_binary_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_binary_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_binary_messenger.cc
Expand All @@ -1207,6 +1208,7 @@ FILE: ../../../flutter/shell/platform/linux/fl_string_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_value.cc
FILE: ../../../flutter/shell/platform/linux/fl_value_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_view.cc
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h
Expand Down
2 changes: 2 additions & 0 deletions shell/platform/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ if (build_glfw_shell) {
}

_public_headers = [
"public/flutter_linux/fl_basic_message_channel.h",
"public/flutter_linux/fl_binary_codec.h",
"public/flutter_linux/fl_binary_messenger.h",
"public/flutter_linux/fl_dart_project.h",
Expand All @@ -64,6 +65,7 @@ source_set("flutter_linux") {
public = _public_headers

sources = [
"fl_basic_message_channel.cc",
"fl_binary_codec.cc",
"fl_binary_messenger.cc",
"fl_dart_project.cc",
Expand Down
206 changes: 206 additions & 0 deletions shell/platform/linux/fl_basic_message_channel.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

#include <gmodule.h>

struct _FlBasicMessageChannel {
GObject parent_instance;

// Messenger to communicate on
FlBinaryMessenger* messenger;

// Channel name
gchar* name;

// Codec to en/decode messages
FlMessageCodec* codec;

// Function called when a message is received
FlBasicMessageChannelMessageHandler message_handler;
gpointer message_handler_data;
};

// Wrap the binary messenger handle for type safety and to make the API
// consistent
struct _FlBasicMessageChannelResponseHandle {
FlBinaryMessengerResponseHandle* response_handle;
};

static FlBasicMessageChannelResponseHandle* response_handle_new(
FlBinaryMessengerResponseHandle* response_handle) {
FlBasicMessageChannelResponseHandle* handle =
static_cast<FlBasicMessageChannelResponseHandle*>(
g_malloc0(sizeof(FlBasicMessageChannelResponseHandle)));
handle->response_handle = response_handle;

return handle;
}

static void response_handle_free(FlBasicMessageChannelResponseHandle* handle) {
g_free(handle);
}

G_DEFINE_AUTOPTR_CLEANUP_FUNC(FlBasicMessageChannelResponseHandle,
response_handle_free);

// Added here to stop the compiler from optimising this function away
G_MODULE_EXPORT GType fl_basic_message_channel_get_type();

G_DEFINE_TYPE(FlBasicMessageChannel, fl_basic_message_channel, G_TYPE_OBJECT)

// Called when a binary message is received on this channel
static void message_cb(FlBinaryMessenger* messenger,
const gchar* channel,
GBytes* message,
FlBinaryMessengerResponseHandle* response_handle,
gpointer user_data) {
FlBasicMessageChannel* self = FL_BASIC_MESSAGE_CHANNEL(user_data);

if (self->message_handler == nullptr) {
fl_binary_messenger_send_response(messenger, response_handle, nullptr,
nullptr);
return;
}

g_autoptr(GError) error = nullptr;
g_autoptr(FlValue) message_value =
fl_message_codec_decode_message(self->codec, message, &error);
if (message_value == nullptr) {
g_warning("Failed to decode message: %s", error->message);
fl_binary_messenger_send_response(messenger, response_handle, nullptr,
nullptr);
}

self->message_handler(self, message_value,
response_handle_new(response_handle),
self->message_handler_data);
}

// Called when a response is received to a sent message
static void message_response_cb(GObject* object,
GAsyncResult* result,
gpointer user_data) {
GTask* task = G_TASK(user_data);
g_task_return_pointer(task, result, g_object_unref);
}

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);

g_clear_object(&self->messenger);
g_clear_pointer(&self->name, g_free);
g_clear_object(&self->codec);

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

static void fl_basic_message_channel_class_init(
FlBasicMessageChannelClass* klass) {
G_OBJECT_CLASS(klass)->dispose = fl_basic_message_channel_dispose;
}

static void fl_basic_message_channel_init(FlBasicMessageChannel* self) {}

G_MODULE_EXPORT FlBasicMessageChannel* fl_basic_message_channel_new(
FlBinaryMessenger* messenger,
const gchar* name,
FlMessageCodec* codec) {
g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
g_return_val_if_fail(name != nullptr, nullptr);
g_return_val_if_fail(FL_IS_MESSAGE_CODEC(codec), nullptr);

FlBasicMessageChannel* self = FL_BASIC_MESSAGE_CHANNEL(
g_object_new(fl_basic_message_channel_get_type(), nullptr));

self->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger));
self->name = g_strdup(name);
self->codec = FL_MESSAGE_CODEC(g_object_ref(codec));

fl_binary_messenger_set_message_handler_on_channel(
self->messenger, self->name, message_cb, self);

return self;
}

G_MODULE_EXPORT void fl_basic_message_channel_set_message_handler(
FlBasicMessageChannel* self,
FlBasicMessageChannelMessageHandler handler,
gpointer user_data) {
g_return_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self));

self->message_handler = handler;
self->message_handler_data = user_data;
}

G_MODULE_EXPORT gboolean fl_basic_message_channel_respond(
FlBasicMessageChannel* self,
FlBasicMessageChannelResponseHandle* response_handle,
FlValue* message,
GError** error) {
g_return_val_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self), FALSE);
g_return_val_if_fail(response_handle != nullptr, FALSE);

// Take reference to ensure it is freed
g_autoptr(FlBasicMessageChannelResponseHandle) owned_response_handle =
response_handle;

g_autoptr(GBytes) data =
fl_message_codec_encode_message(self->codec, message, error);
if (data == nullptr)
return FALSE;

return fl_binary_messenger_send_response(
self->messenger, owned_response_handle->response_handle, data, error);
}

G_MODULE_EXPORT void fl_basic_message_channel_send(FlBasicMessageChannel* self,
FlValue* message,
GCancellable* cancellable,
GAsyncReadyCallback callback,
gpointer user_data) {
g_return_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self));
g_return_if_fail(message != nullptr);

g_autoptr(GTask) task =
callback != nullptr ? g_task_new(self, cancellable, callback, user_data)
: nullptr;

g_autoptr(GError) error = nullptr;
g_autoptr(GBytes) data =
fl_message_codec_encode_message(self->codec, message, &error);
if (data == nullptr) {
if (task != nullptr)
g_task_return_error(task, error);
return;
}

fl_binary_messenger_send_on_channel(
self->messenger, self->name, data, cancellable,
callback != nullptr ? message_response_cb : nullptr,
g_steal_pointer(&task));
}

G_MODULE_EXPORT FlValue* fl_basic_message_channel_send_on_channel_finish(
FlBasicMessageChannel* self,
GAsyncResult* result,
GError** error) {
g_return_val_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self), nullptr);
g_return_val_if_fail(g_task_is_valid(result, self), nullptr);

g_autoptr(GTask) task = G_TASK(result);
GAsyncResult* r = G_ASYNC_RESULT(g_task_propagate_pointer(task, nullptr));

g_autoptr(GBytes) message =
fl_binary_messenger_send_on_channel_finish(self->messenger, r, error);
if (message == nullptr)
return nullptr;

return fl_message_codec_decode_message(self->codec, message, error);
}
143 changes: 143 additions & 0 deletions shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_BASIC_MESSAGE_CHANNEL_H_
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_BASIC_MESSAGE_CHANNEL_H_

#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION)
#error "Only <flutter_linux/flutter_linux.h> can be included directly."
#endif

#include <gio/gio.h>
#include <glib-object.h>

#include "fl_binary_messenger.h"
#include "fl_message_codec.h"

G_BEGIN_DECLS

G_DECLARE_FINAL_TYPE(FlBasicMessageChannel,
fl_basic_message_channel,
FL,
BASIC_MESSAGE_CHANNEL,
GObject)

/**
* FlBasicMessageChannel:
*
* #FlBasicMessageChannel is an object that allows sending and receiving
* messages to/from Dart code over platform channels.
*
* #FlBasicMessageChannel matches the BasicMessageChannel class in the Flutter
* services library.
*/

/**
* FlBasicMessageChannelResponseHandle:
*
* A handle used to respond to messages.
*/
typedef struct _FlBasicMessageChannelResponseHandle
FlBasicMessageChannelResponseHandle;

/**
* FlBasicMessageChannelMessageHandler:
* @channel: a #FlBasicMessageChannel
* @message: message received
* @response_handle: (transfer full): a handle to respond to the message with
* @user_data: (closure): data provided when registering this handler
*
* Function called when a message is received.
*/
typedef void (*FlBasicMessageChannelMessageHandler)(
FlBasicMessageChannel* channel,
FlValue* message,
FlBasicMessageChannelResponseHandle* response_handle,
gpointer user_data);

/**
* fl_basic_message_channel_new:
* @messenger: a #FlBinaryMessenger
* @name: a channel name
* @codec: the message codec
*
* Create a new basic message channel. @codec must match the codec used on the
* Dart end of the channel.
*
* Returns: a new #FlBasicMessageChannel.
*/
FlBasicMessageChannel* fl_basic_message_channel_new(
FlBinaryMessenger* messenger,
const gchar* name,
FlMessageCodec* codec);

/**
* fl_basic_message_channel_set_message_handler:
* @channel: a #FlBasicMessageChannel
* @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
*
* Set the function called when a message is received.
*/
void fl_basic_message_channel_set_message_handler(
FlBasicMessageChannel* channel,
FlBasicMessageChannelMessageHandler handler,
gpointer user_data);

/**
* fl_basic_message_channel_send_response:
* @channel: a #FlBasicMessageChannel
* @response_handle: (transfer full): handle that was provided in a
* #FlBasicMessageChannelMessageHandler
* @response: (allow-none): response to send or %NULL for an empty response
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore
*
* Respond to a message.
*
* Returns: %TRUE on success.
*/
gboolean fl_basic_message_channel_send_response(
FlBasicMessageChannel* channel,
FlBasicMessageChannelResponseHandle* response_handle,
FlValue* response,
GError** error);

/**
* fl_basic_message_channel_send:
* @channel: a #FlBasicMessageChannel
* @message: message to send, must match what the #FlMessageCodec supports
* @cancellable: (allow-none): a #GCancellable or %NULL
* @callback: (scope async): (allow-none): a #GAsyncReadyCallback to call when
* the request is satisfied or %NULL to ignore the response.
* @user_data: (closure): user data to pass to @callback
*
* Asynchronously send a message.
*/
void fl_basic_message_channel_send(FlBasicMessageChannel* channel,
FlValue* message,
GCancellable* cancellable,
GAsyncReadyCallback callback,
gpointer user_data);

/**
* fl_basic_message_channel_send_finish:
* @channel: a #FlBasicMessageChannel
* @result: a #GAsyncResult
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Complete request started with fl_basic_message_channel_send().
*
* Returns: message response on success or %NULL on error.
*/
FlValue* fl_basic_message_channel_send_on_channel_finish(
FlBasicMessageChannel* channel,
GAsyncResult* result,
GError** error);

G_END_DECLS

#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_BASIC_MESSAGE_CHANNEL_H_
1 change: 1 addition & 0 deletions shell/platform/linux/public/flutter_linux/flutter_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#define __FLUTTER_LINUX_INSIDE__

#include <flutter_linux/fl_basic_message_channel.h>
#include <flutter_linux/fl_binary_codec.h>
#include <flutter_linux/fl_binary_messenger.h>
#include <flutter_linux/fl_dart_project.h>
Expand Down