5#include "flutter/shell/platform/linux/fl_text_input_plugin.h"
9#include "flutter/shell/platform/common/text_editing_delta.h"
10#include "flutter/shell/platform/common/text_input_model.h"
11#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h"
12#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
24 "TextInputClient.updateEditingState";
26 "TextInputClient.updateEditingStateWithDeltas";
29 "TextInput.setEditableSizeAndTransform";
101 fl_text_input_plugin,
110 if (response ==
nullptr) {
120 g_autoptr(GError)
error =
nullptr;
130 fl_text_input_plugin_get_instance_private(
self));
145 int composing_base = -1;
146 int composing_extent = -1;
147 if (!
priv->text_model->composing_range().collapsed()) {
148 composing_base =
priv->text_model->composing_range().base();
149 composing_extent =
priv->text_model->composing_range().extent();
173 fl_text_input_plugin_get_instance_private(
self));
204 int composing_base = -1;
205 int composing_extent = -1;
206 if (!
priv->text_model->composing_range().collapsed()) {
207 composing_base =
priv->text_model->composing_range().base();
208 composing_extent =
priv->text_model->composing_range().extent();
231 g_autoptr(GError)
error =
nullptr;
240 fl_text_input_plugin_get_instance_private(
self));
242 g_return_if_fail(FL_IS_TEXT_INPUT_PLUGIN(
self));
243 g_return_if_fail(
priv->client_id != 0);
244 g_return_if_fail(
priv->input_action !=
nullptr);
257 fl_text_input_plugin_get_instance_private(
self));
258 priv->text_model->BeginComposing();
264 fl_text_input_plugin_get_instance_private(
self));
265 std::string text_before_change =
priv->text_model->GetText();
267 priv->text_model->composing_range();
268 g_autofree gchar* buf =
nullptr;
269 gint cursor_offset = 0;
270 gtk_im_context_get_preedit_string(
priv->im_context, &buf,
nullptr,
272 if (
priv->text_model->composing()) {
273 cursor_offset +=
priv->text_model->composing_range().start();
275 cursor_offset +=
priv->text_model->selection().start();
277 priv->text_model->UpdateComposingText(buf);
280 if (
priv->enable_delta_model) {
281 std::string
text(buf);
283 text_before_change, composing_before_change,
text);
293 fl_text_input_plugin_get_instance_private(
self));
294 std::string text_before_change =
priv->text_model->GetText();
296 priv->text_model->composing_range();
298 gboolean was_composing =
priv->text_model->composing();
301 if (
priv->text_model->composing()) {
302 priv->text_model->CommitComposing();
305 if (
priv->enable_delta_model) {
307 was_composing ? composing_before_change : selection_before_change;
308 std::unique_ptr<flutter::TextEditingDelta>
delta =
309 std::make_unique<flutter::TextEditingDelta>(text_before_change,
310 replace_range,
text);
320 fl_text_input_plugin_get_instance_private(
self));
321 priv->text_model->EndComposing();
322 if (
priv->enable_delta_model) {
334 fl_text_input_plugin_get_instance_private(
self));
335 auto text =
priv->text_model->GetText();
336 size_t cursor_offset =
priv->text_model->GetCursorOffset();
337 gtk_im_context_set_surrounding(
priv->im_context,
text.c_str(), -1,
347 fl_text_input_plugin_get_instance_private(
self));
349 std::string text_before_change =
priv->text_model->GetText();
350 if (
priv->text_model->DeleteSurrounding(
offset, n_chars)) {
351 if (
priv->enable_delta_model) {
353 text_before_change,
priv->text_model->composing_range(),
354 priv->text_model->GetText());
371 fl_text_input_plugin_get_instance_private(
self));
375 g_free(
priv->input_action);
382 FlValue* enable_delta_model_value =
385 priv->enable_delta_model = enable_delta_model;
408static FlMethodResponse*
hide(FlTextInputPlugin*
self) {
410 fl_text_input_plugin_get_instance_private(
self));
411 gtk_im_context_focus_out(
priv->im_context);
417static FlMethodResponse*
show(FlTextInputPlugin*
self) {
419 fl_text_input_plugin_get_instance_private(
self));
424 gtk_im_context_focus_in(
priv->im_context);
433 fl_text_input_plugin_get_instance_private(
self));
438 int64_t selection_base =
440 int64_t selection_extent =
443 if (selection_base == -1 && selection_extent == -1) {
444 selection_base = selection_extent = 0;
448 priv->text_model->SetSelection(
451 int64_t composing_base =
453 int64_t composing_extent =
455 if (composing_base == -1 && composing_extent == -1) {
456 priv->text_model->EndComposing();
458 size_t composing_start =
std::min(composing_base, composing_extent);
459 size_t cursor_offset = selection_base - composing_start;
460 priv->text_model->SetComposingRange(
470 fl_text_input_plugin_get_instance_private(
self));
486 fl_text_input_plugin_get_instance_private(
self));
489 if (!
priv->text_model->composing()) {
495 gint
x =
priv->composing_rect.x *
priv->editabletext_transform[0][0] +
496 priv->composing_rect.y *
priv->editabletext_transform[1][0] +
497 priv->editabletext_transform[3][0] +
priv->composing_rect.width;
498 gint
y =
priv->composing_rect.x *
priv->editabletext_transform[0][1] +
499 priv->composing_rect.y *
priv->editabletext_transform[1][1] +
500 priv->editabletext_transform[3][1] +
priv->composing_rect.height;
503 GdkRectangle preedit_rect = {};
505 priv->view_delegate,
x,
y, &preedit_rect.x, &preedit_rect.y);
509 gtk_im_context_set_cursor_location(
priv->im_context, &preedit_rect);
519 FlTextInputPlugin*
self,
523 g_warn_if_fail(transform_len == 16);
525 for (
size_t i = 0;
i < transform_len; ++
i) {
528 fl_text_input_plugin_get_instance_private(
self));
529 priv->editabletext_transform[
i / 4][
i % 4] = val;
545 fl_text_input_plugin_get_instance_private(
self));
546 priv->composing_rect.x =
548 priv->composing_rect.y =
550 priv->composing_rect.width =
552 priv->composing_rect.height =
568 g_autoptr(FlMethodResponse) response =
nullptr;
587 g_autoptr(GError)
error =
nullptr;
589 g_warning(
"Failed to send method call response: %s",
error->message);
595 FlTextInputPlugin*
self = FL_TEXT_INPUT_PLUGIN(
object);
597 fl_text_input_plugin_get_instance_private(
self));
599 g_clear_object(&
priv->channel);
600 g_clear_pointer(&
priv->input_action, g_free);
601 g_clear_object(&
priv->im_context);
602 if (
priv->text_model !=
nullptr) {
603 delete priv->text_model;
604 priv->text_model =
nullptr;
606 if (
priv->view_delegate !=
nullptr) {
607 g_object_remove_weak_pointer(
608 G_OBJECT(
priv->view_delegate),
609 reinterpret_cast<gpointer*
>(&(
priv->view_delegate)));
610 priv->view_delegate =
nullptr;
613 G_OBJECT_CLASS(fl_text_input_plugin_parent_class)->dispose(
object);
618 FlTextInputPlugin*
self,
620 g_return_val_if_fail(FL_IS_TEXT_INPUT_PLUGIN(
self),
false);
623 fl_text_input_plugin_get_instance_private(
self));
629 if (gtk_im_context_filter_keypress(
634 std::string text_before_change =
priv->text_model->GetText();
636 std::string
text =
priv->text_model->GetText();
639 gboolean do_action =
FALSE;
641 gboolean changed =
FALSE;
647 changed =
priv->text_model->SelectToEnd();
649 changed =
priv->text_model->MoveCursorToEnd();
653 case GDK_KEY_KP_Enter:
654 case GDK_KEY_ISO_Enter:
657 priv->text_model->AddCodePoint(
'\n');
664 case GDK_KEY_KP_Home:
666 changed =
priv->text_model->SelectToBeginning();
668 changed =
priv->text_model->MoveCursorToBeginning();
671 case GDK_KEY_BackSpace:
673 case GDK_KEY_KP_Delete:
675 case GDK_KEY_KP_Left:
677 case GDK_KEY_KP_Right:
684 if (
priv->enable_delta_model) {
686 text_before_change, selection_before_change,
text);
702 FL_TEXT_INPUT_PLUGIN_CLASS(klass)->filter_keypress =
709 fl_text_input_plugin_get_instance_private(
self));
718 fl_text_input_plugin_get_instance_private(
self));
719 priv->im_context = GTK_IM_CONTEXT(g_object_ref(im_context));
724 gtk_im_context_focus_out(
priv->im_context);
726 g_signal_connect_object(
priv->im_context,
"preedit-start",
729 g_signal_connect_object(
priv->im_context,
"preedit-end",
732 g_signal_connect_object(
priv->im_context,
"preedit-changed",
735 g_signal_connect_object(
priv->im_context,
"commit", G_CALLBACK(
im_commit_cb),
736 self, G_CONNECT_SWAPPED);
737 g_signal_connect_object(
priv->im_context,
"retrieve-surrounding",
740 g_signal_connect_object(
priv->im_context,
"delete-surrounding",
746 FlBinaryMessenger* messenger,
747 GtkIMContext* im_context,
748 FlTextInputViewDelegate* view_delegate) {
749 g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger),
nullptr);
750 g_return_val_if_fail(GTK_IS_IM_CONTEXT(im_context),
nullptr);
751 g_return_val_if_fail(FL_IS_TEXT_INPUT_VIEW_DELEGATE(view_delegate),
nullptr);
753 FlTextInputPlugin*
self = FL_TEXT_INPUT_PLUGIN(
754 g_object_new(fl_text_input_plugin_get_type(),
nullptr));
758 fl_text_input_plugin_get_instance_private(
self));
766 priv->view_delegate = view_delegate;
767 g_object_add_weak_pointer(
768 G_OBJECT(view_delegate),
769 reinterpret_cast<gpointer*
>(&(
priv->view_delegate)));
778 g_return_val_if_fail(FL_IS_TEXT_INPUT_PLUGIN(
self),
FALSE);
779 if (FL_TEXT_INPUT_PLUGIN_GET_CLASS(
self)->filter_keypress) {
780 return FL_TEXT_INPUT_PLUGIN_GET_CLASS(
self)->filter_keypress(
self,
event);
static gboolean finish_method(GObject *object, GAsyncResult *result, GError **error)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
G_MODULE_EXPORT FlJsonMethodCodec * fl_json_method_codec_new()
G_MODULE_EXPORT const gchar * fl_method_call_get_name(FlMethodCall *self)
G_MODULE_EXPORT gboolean fl_method_call_respond(FlMethodCall *self, FlMethodResponse *response, GError **error)
G_MODULE_EXPORT FlValue * fl_method_call_get_args(FlMethodCall *self)
G_MODULE_EXPORT FlMethodResponse * fl_method_channel_invoke_method_finish(FlMethodChannel *self, GAsyncResult *result, GError **error)
G_MODULE_EXPORT FlMethodChannel * fl_method_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMethodCodec *codec)
G_MODULE_EXPORT void fl_method_channel_invoke_method(FlMethodChannel *self, const gchar *method, FlValue *args, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(FlMethodChannel *self, FlMethodChannelMethodCallHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
G_MODULE_EXPORT FlMethodErrorResponse * fl_method_error_response_new(const gchar *code, const gchar *message, FlValue *details)
G_MODULE_EXPORT FlMethodSuccessResponse * fl_method_success_response_new(FlValue *result)
G_MODULE_EXPORT FlMethodNotImplementedResponse * fl_method_not_implemented_response_new()
FlPixelBufferTexturePrivate * priv
static constexpr char kClearClientMethod[]
static constexpr char kSetEditableSizeAndTransform[]
static void method_call_cb(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
static constexpr char kSetMarkedTextRect[]
static constexpr char kEnableDeltaModel[]
static constexpr char kNoneInputType[]
static FlMethodResponse * clear_client(FlTextInputPlugin *self)
return fl_method_response_get_result(response, error) !
static void init_im_context(FlTextInputPlugin *self, GtkIMContext *im_context)
static void im_preedit_changed_cb(FlTextInputPlugin *self)
static constexpr char kTransform[]
static constexpr char kSelectionIsDirectionalKey[]
static constexpr char kHideMethod[]
static constexpr char kMultilineInputType[]
static FlMethodResponse * set_client(FlTextInputPlugin *self, FlValue *args)
static void update_editing_state_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
static constexpr char kSetEditingStateMethod[]
static constexpr char kSelectionExtentKey[]
static FlMethodResponse * show(FlTextInputPlugin *self)
static void perform_action_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
static constexpr char kTextInputTypeNameKey[]
static FlMethodResponse * set_marked_text_rect(FlTextInputPlugin *self, FlValue *args)
static FlMethodResponse * set_editable_size_and_transform(FlTextInputPlugin *self, FlValue *args)
static constexpr char kNewlineInputAction[]
static void update_editing_state(FlTextInputPlugin *self)
static constexpr char kChannelName[]
static void im_preedit_end_cb(FlTextInputPlugin *self)
static void perform_action(FlTextInputPlugin *self)
G_DEFINE_TYPE_WITH_PRIVATE(FlTextInputPlugin, fl_text_input_plugin, G_TYPE_OBJECT) static gboolean finish_method(GObject *object
static constexpr char kSetClientMethod[]
static gboolean im_delete_surrounding_cb(FlTextInputPlugin *self, gint offset, gint n_chars)
static void fl_text_input_plugin_dispose(GObject *object)
static constexpr char kUpdateEditingStateMethod[]
gboolean fl_text_input_plugin_filter_keypress(FlTextInputPlugin *self, FlKeyEvent *event)
static constexpr char kTextInputTypeKey[]
static void update_editing_state_with_delta(FlTextInputPlugin *self, flutter::TextEditingDelta *delta)
static constexpr char kBadArgumentsError[]
static constexpr char kPerformActionMethod[]
static constexpr char kShowMethod[]
static void update_im_cursor_position(FlTextInputPlugin *self)
static gboolean fl_text_input_plugin_filter_keypress_default(FlTextInputPlugin *self, FlKeyEvent *event)
static FlMethodResponse * hide(FlTextInputPlugin *self)
static constexpr char kComposingExtentKey[]
static constexpr char kTextAffinityDownstream[]
static void im_preedit_start_cb(FlTextInputPlugin *self)
static void im_commit_cb(FlTextInputPlugin *self, const gchar *text)
GAsyncResult GError ** error
static constexpr char kInputActionKey[]
static constexpr char kComposingBaseKey[]
static constexpr char kUpdateEditingStateWithDeltasMethod[]
static FlMethodResponse * set_editing_state(FlTextInputPlugin *self, FlValue *args)
FlTextInputPlugin * fl_text_input_plugin_new(FlBinaryMessenger *messenger, GtkIMContext *im_context, FlTextInputViewDelegate *view_delegate)
static gboolean im_retrieve_surrounding_cb(FlTextInputPlugin *self)
static void fl_text_input_plugin_init(FlTextInputPlugin *self)
@ kFlTextInputTypeMultiline
static constexpr int64_t kClientIdUnset
static constexpr char kSelectionAffinityKey[]
static constexpr char kTextKey[]
static void fl_text_input_plugin_class_init(FlTextInputPluginClass *klass)
static constexpr char kSelectionBaseKey[]
void fl_text_input_view_delegate_translate_coordinates(FlTextInputViewDelegate *self, gint view_x, gint view_y, gint *window_x, gint *window_y)
G_MODULE_EXPORT void fl_value_set_string(FlValue *self, const gchar *key, FlValue *value)
G_MODULE_EXPORT FlValue * fl_value_new_map()
G_MODULE_EXPORT void fl_value_set_string_take(FlValue *self, const gchar *key, FlValue *value)
G_MODULE_EXPORT FlValue * fl_value_lookup_string(FlValue *self, const gchar *key)
G_MODULE_EXPORT int64_t fl_value_get_int(FlValue *self)
G_MODULE_EXPORT FlValueType fl_value_get_type(FlValue *self)
G_MODULE_EXPORT FlValue * fl_value_new_string(const gchar *value)
G_MODULE_EXPORT void fl_value_append(FlValue *self, FlValue *value)
G_MODULE_EXPORT FlValue * fl_value_new_bool(bool value)
G_MODULE_EXPORT const gchar * fl_value_get_string(FlValue *self)
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
G_MODULE_EXPORT void fl_value_append_take(FlValue *self, FlValue *value)
G_MODULE_EXPORT FlValue * fl_value_get_list_value(FlValue *self, size_t index)
G_MODULE_EXPORT bool fl_value_get_bool(FlValue *self)
G_MODULE_EXPORT FlValue * fl_value_new_list()
G_MODULE_EXPORT double fl_value_get_float(FlValue *self)
G_MODULE_EXPORT size_t fl_value_get_length(FlValue *self)
typedefG_BEGIN_DECLS struct _FlValue FlValue
static float min(float r, float g, float b)
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
FlTextInputType input_type
gboolean enable_delta_model
flutter::TextInputModel * text_model
GdkRectangle composing_rect
double editabletext_transform[4][4]
FlMethodChannel * channel
FlTextInputViewDelegate * view_delegate
GtkIMContext * im_context
A change in the state of an input field.