Flutter Engine
fl_platform_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 
5 #include "flutter/shell/platform/linux/fl_platform_plugin.h"
6 
7 #include <gtk/gtk.h>
8 #include <cstring>
9 
10 #include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h"
11 #include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
12 
13 static constexpr char kChannelName[] = "flutter/platform";
14 static constexpr char kBadArgumentsError[] = "Bad Arguments";
15 static constexpr char kUnknownClipboardFormatError[] =
16  "Unknown Clipboard Format";
17 static constexpr char kFailedError[] = "Failed";
18 static constexpr char kGetClipboardDataMethod[] = "Clipboard.getData";
19 static constexpr char kSetClipboardDataMethod[] = "Clipboard.setData";
20 static constexpr char kClipboardHasStringsMethod[] = "Clipboard.hasStrings";
21 static constexpr char kSystemNavigatorPopMethod[] = "SystemNavigator.pop";
22 static constexpr char kTextKey[] = "text";
23 static constexpr char kValueKey[] = "value";
24 
25 static constexpr char kTextPlainFormat[] = "text/plain";
26 
28  GObject parent_instance;
29 
30  FlMethodChannel* channel;
31 };
32 
33 G_DEFINE_TYPE(FlPlatformPlugin, fl_platform_plugin, G_TYPE_OBJECT)
34 
35 // Sends the method call response to Flutter.
36 static void send_response(FlMethodCall* method_call,
37  FlMethodResponse* response) {
38  g_autoptr(GError) error = nullptr;
39  if (!fl_method_call_respond(method_call, response, &error)) {
40  g_warning("Failed to send method call response: %s", error->message);
41  }
42 }
43 
44 // Called when clipboard text received.
45 static void clipboard_text_cb(GtkClipboard* clipboard,
46  const gchar* text,
47  gpointer user_data) {
48  g_autoptr(FlMethodCall) method_call = FL_METHOD_CALL(user_data);
49 
50  g_autoptr(FlValue) result = nullptr;
51  if (text != nullptr) {
52  result = fl_value_new_map();
54  }
55 
56  g_autoptr(FlMethodResponse) response =
57  FL_METHOD_RESPONSE(fl_method_success_response_new(result));
58  send_response(method_call, response);
59 }
60 
61 // Called when clipboard text received during has_strings.
62 static void clipboard_text_has_strings_cb(GtkClipboard* clipboard,
63  const gchar* text,
64  gpointer user_data) {
65  g_autoptr(FlMethodCall) method_call = FL_METHOD_CALL(user_data);
66 
67  g_autoptr(FlValue) result = fl_value_new_map();
69  result, kValueKey,
70  fl_value_new_bool(text != nullptr && strlen(text) > 0));
71 
72  g_autoptr(FlMethodResponse) response =
73  FL_METHOD_RESPONSE(fl_method_success_response_new(result));
74  send_response(method_call, response);
75 }
76 
77 // Called when Flutter wants to copy to the clipboard.
78 static FlMethodResponse* clipboard_set_data(FlPlatformPlugin* self,
79  FlValue* args) {
80  if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) {
81  return FL_METHOD_RESPONSE(fl_method_error_response_new(
82  kBadArgumentsError, "Argument map missing or malformed", nullptr));
83  }
84 
85  FlValue* text_value = fl_value_lookup_string(args, kTextKey);
86  if (text_value == nullptr ||
87  fl_value_get_type(text_value) != FL_VALUE_TYPE_STRING) {
88  return FL_METHOD_RESPONSE(fl_method_error_response_new(
89  kBadArgumentsError, "Missing clipboard text", nullptr));
90  }
91 
92  GtkClipboard* clipboard =
93  gtk_clipboard_get_default(gdk_display_get_default());
94  gtk_clipboard_set_text(clipboard, fl_value_get_string(text_value), -1);
95 
96  return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
97 }
98 
99 // Called when Flutter wants to paste from the clipboard.
100 static FlMethodResponse* clipboard_get_data_async(FlPlatformPlugin* self,
101  FlMethodCall* method_call) {
102  FlValue* args = fl_method_call_get_args(method_call);
103 
105  return FL_METHOD_RESPONSE(fl_method_error_response_new(
106  kBadArgumentsError, "Expected string", nullptr));
107  }
108 
109  const gchar* format = fl_value_get_string(args);
110  if (strcmp(format, kTextPlainFormat) != 0) {
111  return FL_METHOD_RESPONSE(fl_method_error_response_new(
112  kUnknownClipboardFormatError, "GTK clipboard API only supports text",
113  nullptr));
114  }
115 
116  GtkClipboard* clipboard =
117  gtk_clipboard_get_default(gdk_display_get_default());
118  gtk_clipboard_request_text(clipboard, clipboard_text_cb,
119  g_object_ref(method_call));
120 
121  // Will respond later.
122  return nullptr;
123 }
124 
125 // Called when Flutter wants to know if the content of the clipboard is able to
126 // be pasted, without actually accessing the clipboard content itself.
127 static FlMethodResponse* clipboard_has_strings_async(
128  FlPlatformPlugin* self,
129  FlMethodCall* method_call) {
130  GtkClipboard* clipboard =
131  gtk_clipboard_get_default(gdk_display_get_default());
132  gtk_clipboard_request_text(clipboard, clipboard_text_has_strings_cb,
133  g_object_ref(method_call));
134 
135  // Will respond later.
136  return nullptr;
137 }
138 
139 // Called when Flutter wants to quit the application.
140 static FlMethodResponse* system_navigator_pop(FlPlatformPlugin* self) {
141  GApplication* app = g_application_get_default();
142  if (app == nullptr) {
143  return FL_METHOD_RESPONSE(fl_method_error_response_new(
144  kFailedError, "Unable to get GApplication", nullptr));
145  }
146 
147  g_application_quit(app);
148 
149  return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
150 }
151 
152 // Called when a method call is received from Flutter.
153 static void method_call_cb(FlMethodChannel* channel,
154  FlMethodCall* method_call,
155  gpointer user_data) {
156  FlPlatformPlugin* self = FL_PLATFORM_PLUGIN(user_data);
157 
158  const gchar* method = fl_method_call_get_name(method_call);
159  FlValue* args = fl_method_call_get_args(method_call);
160 
161  g_autoptr(FlMethodResponse) response = nullptr;
162  if (strcmp(method, kSetClipboardDataMethod) == 0) {
163  response = clipboard_set_data(self, args);
164  } else if (strcmp(method, kGetClipboardDataMethod) == 0) {
165  response = clipboard_get_data_async(self, method_call);
166  } else if (strcmp(method, kClipboardHasStringsMethod) == 0) {
167  response = clipboard_has_strings_async(self, method_call);
168  } else if (strcmp(method, kSystemNavigatorPopMethod) == 0) {
169  response = system_navigator_pop(self);
170  } else {
171  response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
172  }
173 
174  if (response != nullptr) {
175  send_response(method_call, response);
176  }
177 }
178 
179 static void fl_platform_plugin_dispose(GObject* object) {
180  FlPlatformPlugin* self = FL_PLATFORM_PLUGIN(object);
181 
182  g_clear_object(&self->channel);
183 
184  G_OBJECT_CLASS(fl_platform_plugin_parent_class)->dispose(object);
185 }
186 
187 static void fl_platform_plugin_class_init(FlPlatformPluginClass* klass) {
188  G_OBJECT_CLASS(klass)->dispose = fl_platform_plugin_dispose;
189 }
190 
191 static void fl_platform_plugin_init(FlPlatformPlugin* self) {}
192 
193 FlPlatformPlugin* fl_platform_plugin_new(FlBinaryMessenger* messenger) {
194  g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
195 
196  FlPlatformPlugin* self =
197  FL_PLATFORM_PLUGIN(g_object_new(fl_platform_plugin_get_type(), nullptr));
198 
199  g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new();
200  self->channel =
201  fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec));
203  nullptr);
204 
205  return self;
206 }
static constexpr char kClipboardHasStringsMethod[]
G_MODULE_EXPORT FlMethodSuccessResponse * fl_method_success_response_new(FlValue *result)
G_BEGIN_DECLS FlMethodCall * method_call
G_MODULE_EXPORT FlValueType fl_value_get_type(FlValue *self)
Definition: fl_value.cc:395
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:39
G_MODULE_EXPORT FlJsonMethodCodec * fl_json_method_codec_new()
FlMethodResponse GError ** error
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition: fl_value.cc:327
static constexpr char kFailedError[]
static constexpr char kChannelName[]
static constexpr char kGetClipboardDataMethod[]
static constexpr char kTextPlainFormat[]
static FlMethodResponse * clipboard_has_strings_async(FlPlatformPlugin *self, FlMethodCall *method_call)
G_MODULE_EXPORT FlValue * fl_value_new_bool(bool value)
Definition: fl_value.cc:226
static constexpr char kBadArgumentsError[]
G_MODULE_EXPORT FlValue * fl_method_call_get_args(FlMethodCall *self)
static void send_response(FlMethodCall *method_call, FlMethodResponse *response)
static constexpr char kSetClipboardDataMethod[]
static constexpr char kUnknownClipboardFormatError[]
static void clipboard_text_has_strings_cb(GtkClipboard *clipboard, const gchar *text, gpointer user_data)
static constexpr char kSystemNavigatorPopMethod[]
static void clipboard_text_cb(GtkClipboard *clipboard, const gchar *text, gpointer user_data)
static void fl_platform_plugin_init(FlPlatformPlugin *self)
G_MODULE_EXPORT FlValue * fl_value_lookup_string(FlValue *self, const gchar *key)
Definition: fl_value.cc:712
G_MODULE_EXPORT gboolean fl_method_call_respond(FlMethodCall *self, FlMethodResponse *response, GError **error)
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(FlMethodChannel *self, FlMethodChannelMethodCallHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
G_MODULE_EXPORT const gchar * fl_method_call_get_name(FlMethodCall *self)
G_MODULE_EXPORT FlMethodChannel * fl_method_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMethodCodec *codec)
static void fl_platform_plugin_class_init(FlPlatformPluginClass *klass)
static void method_call_cb(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
FlMethodChannel * channel
G_BEGIN_DECLS FlMethodCall gpointer user_data
G_MODULE_EXPORT FlValue * fl_value_new_string(const gchar *value)
Definition: fl_value.cc:247
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
G_MODULE_EXPORT const gchar * fl_value_get_string(FlValue *self)
Definition: fl_value.cc:596
FlPlatformPlugin * fl_platform_plugin_new(FlBinaryMessenger *messenger)
static constexpr char kValueKey[]
static FlMethodResponse * clipboard_get_data_async(FlPlatformPlugin *self, FlMethodCall *method_call)
G_MODULE_EXPORT FlMethodNotImplementedResponse * fl_method_not_implemented_response_new()
G_MODULE_EXPORT void fl_value_set_string_take(FlValue *self, const gchar *key, FlValue *value)
Definition: fl_value.cc:564
static FlMethodResponse * clipboard_set_data(FlPlatformPlugin *self, FlValue *args)
static FlMethodResponse * system_navigator_pop(FlPlatformPlugin *self)
static void fl_platform_plugin_dispose(GObject *object)
G_MODULE_EXPORT FlMethodErrorResponse * fl_method_error_response_new(const gchar *code, const gchar *message, FlValue *details)
static constexpr char kTextKey[]