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();
300 priv->text_model->AddText(text);
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;
408 static FlMethodResponse*
hide(FlTextInputPlugin*
self) {
410 fl_text_input_plugin_get_instance_private(
self));
411 gtk_im_context_focus_out(
priv->im_context);
417 static 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));
436 priv->text_model->SetText(text);
438 int64_t selection_base =
440 int64_t selection_extent =
443 if (selection_base == -1 && selection_extent == -1) {
444 selection_base = selection_extent = 0;
447 priv->text_model->SetText(text);
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 =
563 FlTextInputPlugin*
self = FL_TEXT_INPUT_PLUGIN(
user_data);
568 g_autoptr(FlMethodResponse) response =
nullptr;
572 response =
show(
self);
578 response =
hide(
self);
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);