Flutter Linux Embedder
fl_platform_handler.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 kInProgressError[] = "In Progress";
14 static constexpr char kUnknownClipboardFormatError[] =
15  "Unknown Clipboard Format";
16 
17 static constexpr char kTextPlainFormat[] = "text/plain";
18 
19 static constexpr char kSoundTypeAlert[] = "SystemSoundType.alert";
20 static constexpr char kSoundTypeClick[] = "SystemSoundType.click";
21 
23  GObject parent_instance;
24 
25  FlPlatformChannel* channel;
26 
28 
30 
31  GCancellable* cancellable;
32 };
33 
34 G_DEFINE_TYPE(FlPlatformHandler, fl_platform_handler, G_TYPE_OBJECT)
35 
36 // Called when clipboard text received.
37 static void clipboard_text_cb(GtkClipboard* clipboard,
38  const gchar* text,
39  gpointer user_data) {
40  g_autoptr(FlMethodCall) method_call = FL_METHOD_CALL(user_data);
42 }
43 
44 // Called when clipboard text received during has_strings.
45 static void clipboard_text_has_strings_cb(GtkClipboard* clipboard,
46  const gchar* text,
47  gpointer user_data) {
48  g_autoptr(FlMethodCall) method_call = FL_METHOD_CALL(user_data);
50  method_call, text != nullptr && strlen(text) > 0);
51 }
52 
53 // Called when Flutter wants to copy to the clipboard.
54 static FlMethodResponse* clipboard_set_data(FlMethodCall* method_call,
55  const gchar* text,
56  gpointer user_data) {
57  GtkClipboard* clipboard =
58  gtk_clipboard_get_default(gdk_display_get_default());
59  gtk_clipboard_set_text(clipboard, text, -1);
60 
61  return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
62 }
63 
64 // Called when Flutter wants to paste from the clipboard.
65 static FlMethodResponse* clipboard_get_data(FlMethodCall* method_call,
66  const gchar* format,
67  gpointer user_data) {
68  if (strcmp(format, kTextPlainFormat) != 0) {
69  return FL_METHOD_RESPONSE(fl_method_error_response_new(
70  kUnknownClipboardFormatError, "GTK clipboard API only supports text",
71  nullptr));
72  }
73 
74  GtkClipboard* clipboard =
75  gtk_clipboard_get_default(gdk_display_get_default());
76  gtk_clipboard_request_text(clipboard, clipboard_text_cb,
77  g_object_ref(method_call));
78 
79  // Will respond later.
80  return nullptr;
81 }
82 
83 // Called when Flutter wants to know if the content of the clipboard is able to
84 // be pasted, without actually accessing the clipboard content itself.
85 static FlMethodResponse* clipboard_has_strings(FlMethodCall* method_call,
86  gpointer user_data) {
87  GtkClipboard* clipboard =
88  gtk_clipboard_get_default(gdk_display_get_default());
89  gtk_clipboard_request_text(clipboard, clipboard_text_has_strings_cb,
90  g_object_ref(method_call));
91 
92  // Will respond later.
93  return nullptr;
94 }
95 
96 // Quit this application
97 static void quit_application() {
98  GApplication* app = g_application_get_default();
99  if (app == nullptr) {
100  // Unable to gracefully quit, so just exit the process.
101  exit(0);
102  }
103 
104  // GtkApplication windows contain a reference back to the application.
105  // Break them so the application object can cleanup.
106  // See https://gitlab.gnome.org/GNOME/gtk/-/issues/6190
107  if (GTK_IS_APPLICATION(app)) {
108  // List is copied as it will be modified as windows are disconnected from
109  // the application.
110  g_autoptr(GList) windows =
111  g_list_copy(gtk_application_get_windows(GTK_APPLICATION(app)));
112  for (GList* link = windows; link != NULL; link = link->next) {
113  GtkWidget* window = GTK_WIDGET(link->data);
114  gtk_window_set_application(GTK_WINDOW(window), NULL);
115  }
116  }
117 
118  g_application_quit(app);
119 }
120 
121 // Handle response of System.requestAppExit.
122 static void request_app_exit_response_cb(GObject* object,
123  GAsyncResult* result,
124  gpointer user_data) {
125  FlPlatformHandler* self = FL_PLATFORM_HANDLER(user_data);
126 
127  g_autoptr(GError) error = nullptr;
128  FlPlatformChannelExitResponse exit_response;
130  object, result, &exit_response, &error)) {
131  if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
132  return;
133  }
134  g_warning("Failed to complete System.requestAppExit: %s", error->message);
136  return;
137  }
138 
139  if (exit_response == FL_PLATFORM_CHANNEL_EXIT_RESPONSE_EXIT) {
141  }
142 
143  // If request was due to a request from Flutter, pass result back.
144  if (self->exit_application_method_call != nullptr) {
146  self->exit_application_method_call, exit_response);
147  }
148 }
149 
150 // Send a request to Flutter to exit the application, but only if it's ready for
151 // a request.
152 static void request_app_exit(FlPlatformHandler* self,
154  if (!self->app_initialization_complete ||
157  return;
158  }
159 
161  self->channel, type, self->cancellable, request_app_exit_response_cb,
162  self);
163 }
164 
165 // Called when the Dart app has finished initialization and is ready to handle
166 // requests. For the Flutter framework, this means after the ServicesBinding has
167 // been initialized and it sends a System.initializationComplete message.
169  FlPlatformHandler* self = FL_PLATFORM_HANDLER(user_data);
170  self->app_initialization_complete = TRUE;
171 }
172 
173 // Called when Flutter wants to exit the application.
174 static FlMethodResponse* system_exit_application(FlMethodCall* method_call,
176  gpointer user_data) {
177  FlPlatformHandler* self = FL_PLATFORM_HANDLER(user_data);
178  // Save method call to respond to when our request to Flutter completes.
179  if (self->exit_application_method_call != nullptr) {
180  return FL_METHOD_RESPONSE(fl_method_error_response_new(
181  kInProgressError, "Request already in progress", nullptr));
182  }
183  self->exit_application_method_call =
184  FL_METHOD_CALL(g_object_ref(method_call));
185 
186  // Requested to immediately quit if the app hasn't yet signaled that it is
187  // ready to handle requests, or if the type of exit requested is "required".
188  if (!self->app_initialization_complete ||
193  }
194 
195  // Send the request back to Flutter to follow the standard process.
196  request_app_exit(self, type);
197 
198  // Will respond later.
199  return nullptr;
200 }
201 
202 // Called when Flutter wants to play a sound.
203 static void system_sound_play(const gchar* type, gpointer user_data) {
204  if (strcmp(type, kSoundTypeAlert) == 0) {
205  GdkDisplay* display = gdk_display_get_default();
206  if (display != nullptr) {
207  gdk_display_beep(display);
208  }
209  } else if (strcmp(type, kSoundTypeClick) == 0) {
210  // We don't make sounds for keyboard on desktops.
211  } else {
212  g_warning("Ignoring unknown sound type %s in SystemSound.play.\n", type);
213  }
214 }
215 
216 // Called when Flutter wants to quit the application.
217 static void system_navigator_pop(gpointer user_data) {
219 }
220 
221 static void fl_platform_handler_dispose(GObject* object) {
222  FlPlatformHandler* self = FL_PLATFORM_HANDLER(object);
223 
224  g_cancellable_cancel(self->cancellable);
225 
226  g_clear_object(&self->channel);
227  g_clear_object(&self->exit_application_method_call);
228  g_clear_object(&self->cancellable);
229 
230  G_OBJECT_CLASS(fl_platform_handler_parent_class)->dispose(object);
231 }
232 
233 static void fl_platform_handler_class_init(FlPlatformHandlerClass* klass) {
234  G_OBJECT_CLASS(klass)->dispose = fl_platform_handler_dispose;
235 }
236 
237 static void fl_platform_handler_init(FlPlatformHandler* self) {
238  self->cancellable = g_cancellable_new();
239 }
240 
243  .clipboard_get_data = clipboard_get_data,
244  .clipboard_has_strings = clipboard_has_strings,
245  .system_exit_application = system_exit_application,
246  .system_initialization_complete = system_initialization_complete,
247  .system_sound_play = system_sound_play,
248  .system_navigator_pop = system_navigator_pop,
249 };
250 
251 FlPlatformHandler* fl_platform_handler_new(FlBinaryMessenger* messenger) {
252  g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
253 
254  FlPlatformHandler* self = FL_PLATFORM_HANDLER(
255  g_object_new(fl_platform_handler_get_type(), nullptr));
256 
257  self->channel =
259  self->app_initialization_complete = FALSE;
260 
261  return self;
262 }
263 
264 void fl_platform_handler_request_app_exit(FlPlatformHandler* self) {
265  g_return_if_fail(FL_IS_PLATFORM_HANDLER(self));
266  // Request a cancellable exit.
268 }
kSoundTypeClick
static constexpr char kSoundTypeClick[]
Definition: fl_platform_handler.cc:20
fl_platform_channel_system_request_app_exit_finish
gboolean fl_platform_channel_system_request_app_exit_finish(GObject *object, GAsyncResult *result, FlPlatformChannelExitResponse *exit_response, GError **error)
Definition: fl_platform_channel.cc:268
fl_platform_channel_make_system_request_app_exit_response
FlMethodResponse * fl_platform_channel_make_system_request_app_exit_response(FlPlatformChannelExitResponse exit_response)
Definition: fl_platform_channel.cc:330
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
type
uint8_t type
Definition: fl_standard_message_codec_test.cc:1115
clipboard_text_has_strings_cb
static void clipboard_text_has_strings_cb(GtkClipboard *clipboard, const gchar *text, gpointer user_data)
Definition: fl_platform_handler.cc:45
FlPlatformChannelExitResponse
FlPlatformChannelExitResponse
Definition: fl_platform_channel.h:18
fl_platform_handler_request_app_exit
void fl_platform_handler_request_app_exit(FlPlatformHandler *self)
Definition: fl_platform_handler.cc:264
fl_method_channel.h
fl_platform_handler_dispose
static void fl_platform_handler_dispose(GObject *object)
Definition: fl_platform_handler.cc:221
fl_platform_handler_new
FlPlatformHandler * fl_platform_handler_new(FlBinaryMessenger *messenger)
Definition: fl_platform_handler.cc:251
_FlPlatformHandler::channel
FlPlatformChannel * channel
Definition: fl_platform_handler.cc:25
kSoundTypeAlert
static constexpr char kSoundTypeAlert[]
Definition: fl_platform_handler.cc:19
clipboard_get_data
static FlMethodResponse * clipboard_get_data(FlMethodCall *method_call, const gchar *format, gpointer user_data)
Definition: fl_platform_handler.cc:65
request_app_exit
static void request_app_exit(FlPlatformHandler *self, FlPlatformChannelExitType type)
Definition: fl_platform_handler.cc:152
fl_method_success_response_new
G_MODULE_EXPORT FlMethodSuccessResponse * fl_method_success_response_new(FlValue *result)
Definition: fl_method_response.cc:126
_FlPlatformHandler::parent_instance
GObject parent_instance
Definition: fl_platform_handler.cc:23
_FlPlatformHandler::exit_application_method_call
FlMethodCall * exit_application_method_call
Definition: fl_platform_handler.cc:27
user_data
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
Definition: fl_event_channel.h:90
_FlPlatformHandler::cancellable
GCancellable * cancellable
Definition: fl_platform_handler.cc:31
fl_platform_handler_init
static void fl_platform_handler_init(FlPlatformHandler *self)
Definition: fl_platform_handler.cc:237
method_call
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
Definition: fl_method_channel.h:120
FlPlatformChannelExitType
FlPlatformChannelExitType
Definition: fl_platform_channel.h:13
fl_platform_channel_system_request_app_exit
void fl_platform_channel_system_request_app_exit(FlPlatformChannel *self, FlPlatformChannelExitType type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_platform_channel.cc:243
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
kTextPlainFormat
static constexpr char kTextPlainFormat[]
Definition: fl_platform_handler.cc:17
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
platform_channel_vtable
static FlPlatformChannelVTable platform_channel_vtable
Definition: fl_platform_handler.cc:241
fl_platform_channel_respond_clipboard_has_strings
void fl_platform_channel_respond_clipboard_has_strings(FlMethodCall *method_call, gboolean has_strings)
Definition: fl_platform_channel.cc:302
clipboard_text_cb
static void clipboard_text_cb(GtkClipboard *clipboard, const gchar *text, gpointer user_data)
Definition: fl_platform_handler.cc:37
fl_platform_handler.h
kInProgressError
static constexpr char kInProgressError[]
Definition: fl_platform_handler.cc:13
fl_platform_channel_respond_clipboard_get_data
void fl_platform_channel_respond_clipboard_get_data(FlMethodCall *method_call, const gchar *text)
Definition: fl_platform_channel.cc:284
FL_PLATFORM_CHANNEL_EXIT_TYPE_CANCELABLE
@ FL_PLATFORM_CHANNEL_EXIT_TYPE_CANCELABLE
Definition: fl_platform_channel.h:14
system_exit_application
static FlMethodResponse * system_exit_application(FlMethodCall *method_call, FlPlatformChannelExitType type, gpointer user_data)
Definition: fl_platform_handler.cc:174
kUnknownClipboardFormatError
static constexpr char kUnknownClipboardFormatError[]
Definition: fl_platform_handler.cc:14
FlPlatformChannelVTable
Definition: fl_platform_channel.h:36
clipboard_has_strings
static FlMethodResponse * clipboard_has_strings(FlMethodCall *method_call, gpointer user_data)
Definition: fl_platform_handler.cc:85
FL_PLATFORM_CHANNEL_EXIT_TYPE_REQUIRED
@ FL_PLATFORM_CHANNEL_EXIT_TYPE_REQUIRED
Definition: fl_platform_channel.h:15
_FlPlatformHandler
Definition: fl_platform_handler.cc:22
fl_platform_channel_new
FlPlatformChannel * fl_platform_channel_new(FlBinaryMessenger *messenger, FlPlatformChannelVTable *vtable, gpointer user_data)
Definition: fl_platform_channel.cc:222
clipboard_set_data
static FlMethodResponse * clipboard_set_data(FlMethodCall *method_call, const gchar *text, gpointer user_data)
Definition: fl_platform_handler.cc:54
FL_PLATFORM_CHANNEL_EXIT_RESPONSE_EXIT
@ FL_PLATFORM_CHANNEL_EXIT_RESPONSE_EXIT
Definition: fl_platform_channel.h:20
error
const uint8_t uint32_t uint32_t GError ** error
Definition: fl_pixel_buffer_texture_test.cc:40
quit_application
static void quit_application()
Definition: fl_platform_handler.cc:97
fl_platform_handler_class_init
static void fl_platform_handler_class_init(FlPlatformHandlerClass *klass)
Definition: fl_platform_handler.cc:233
request_app_exit_response_cb
static void request_app_exit_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: fl_platform_handler.cc:122
_FlPlatformHandler::app_initialization_complete
bool app_initialization_complete
Definition: fl_platform_handler.cc:29
system_initialization_complete
static void system_initialization_complete(gpointer user_data)
Definition: fl_platform_handler.cc:168
system_sound_play
static void system_sound_play(const gchar *type, gpointer user_data)
Definition: fl_platform_handler.cc:203
format
uint32_t uint32_t * format
Definition: fl_texture_registrar_test.cc:42
fl_platform_channel_respond_system_exit_application
void fl_platform_channel_respond_system_exit_application(FlMethodCall *method_call, FlPlatformChannelExitResponse exit_response)
Definition: fl_platform_channel.cc:318
system_navigator_pop
static void system_navigator_pop(gpointer user_data)
Definition: fl_platform_handler.cc:217
FlPlatformChannelVTable::clipboard_set_data
FlMethodResponse *(* clipboard_set_data)(FlMethodCall *method_call, const gchar *text, gpointer user_data)
Definition: fl_platform_channel.h:37
fl_platform_channel.h