From c18704313d5bde43bd7ef66be197b0688dd31d88 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Mon, 11 Nov 2024 11:53:58 +1300 Subject: [PATCH] Remove unused FlMockTextInputHandler This was the only thing that required FlTextInputHandler to be derivable, so also simplify the class. --- shell/platform/linux/BUILD.gn | 1 - .../linux/fl_keyboard_manager_test.cc | 1 - shell/platform/linux/fl_text_input_handler.cc | 400 ++++++++---------- shell/platform/linux/fl_text_input_handler.h | 19 +- .../linux/testing/mock_text_input_handler.cc | 42 -- .../linux/testing/mock_text_input_handler.h | 25 -- 6 files changed, 171 insertions(+), 317 deletions(-) delete mode 100644 shell/platform/linux/testing/mock_text_input_handler.cc delete mode 100644 shell/platform/linux/testing/mock_text_input_handler.h diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index b15f655dac90c..d018c0c172d37 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -252,7 +252,6 @@ executable("flutter_linux_unittests") { "testing/mock_renderer.cc", "testing/mock_settings.cc", "testing/mock_signal_handler.cc", - "testing/mock_text_input_handler.cc", "testing/mock_text_input_view_delegate.cc", "testing/mock_texture_registrar.cc", "testing/mock_window.cc", diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index cdb22ff9cf387..d63715c2bd3ca 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -16,7 +16,6 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" #include "flutter/shell/platform/linux/testing/fl_test.h" #include "flutter/shell/platform/linux/testing/mock_keymap.h" -#include "flutter/shell/platform/linux/testing/mock_text_input_handler.h" #include "flutter/testing/testing.h" #include "gmock/gmock.h" diff --git a/shell/platform/linux/fl_text_input_handler.cc b/shell/platform/linux/fl_text_input_handler.cc index d9a8c08facb7a..8dc44ba290b97 100644 --- a/shell/platform/linux/fl_text_input_handler.cc +++ b/shell/platform/linux/fl_text_input_handler.cc @@ -59,7 +59,7 @@ typedef enum { kFlTextInputTypeNone, } FlTextInputType; -struct FlTextInputHandlerPrivate { +struct _FlTextInputHandler { GObject parent_instance; FlMethodChannel* channel; @@ -97,9 +97,7 @@ struct FlTextInputHandlerPrivate { GdkRectangle composing_rect; }; -G_DEFINE_TYPE_WITH_PRIVATE(FlTextInputHandler, - fl_text_input_handler, - G_TYPE_OBJECT) +G_DEFINE_TYPE(FlTextInputHandler, fl_text_input_handler, G_TYPE_OBJECT) // Completes method call and returns TRUE if the call was successful. static gboolean finish_method(GObject* object, @@ -126,17 +124,14 @@ static void update_editing_state_response_cb(GObject* object, // Informs Flutter of text input changes. static void update_editing_state(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_int(priv->client_id)); + fl_value_append_take(args, fl_value_new_int(self->client_id)); g_autoptr(FlValue) value = fl_value_new_map(); - flutter::TextRange selection = priv->text_model->selection(); + flutter::TextRange selection = self->text_model->selection(); fl_value_set_string_take( value, kTextKey, - fl_value_new_string(priv->text_model->GetText().c_str())); + fl_value_new_string(self->text_model->GetText().c_str())); fl_value_set_string_take(value, kSelectionBaseKey, fl_value_new_int(selection.base())); fl_value_set_string_take(value, kSelectionExtentKey, @@ -144,9 +139,9 @@ static void update_editing_state(FlTextInputHandler* self) { int composing_base = -1; int composing_extent = -1; - if (!priv->text_model->composing_range().collapsed()) { - composing_base = priv->text_model->composing_range().base(); - composing_extent = priv->text_model->composing_range().extent(); + if (!self->text_model->composing_range().collapsed()) { + composing_base = self->text_model->composing_range().base(); + composing_extent = self->text_model->composing_range().extent(); } fl_value_set_string_take(value, kComposingBaseKey, fl_value_new_int(composing_base)); @@ -161,7 +156,7 @@ static void update_editing_state(FlTextInputHandler* self) { fl_value_append(args, value); - fl_method_channel_invoke_method(priv->channel, kUpdateEditingStateMethod, + fl_method_channel_invoke_method(self->channel, kUpdateEditingStateMethod, args, nullptr, update_editing_state_response_cb, self); } @@ -169,11 +164,8 @@ static void update_editing_state(FlTextInputHandler* self) { // Informs Flutter of text input changes by passing just the delta. static void update_editing_state_with_delta(FlTextInputHandler* self, flutter::TextEditingDelta* delta) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_int(priv->client_id)); + fl_value_append_take(args, fl_value_new_int(self->client_id)); g_autoptr(FlValue) deltaValue = fl_value_new_map(); fl_value_set_string_take(deltaValue, "oldText", @@ -188,7 +180,7 @@ static void update_editing_state_with_delta(FlTextInputHandler* self, fl_value_set_string_take(deltaValue, "deltaEnd", fl_value_new_int(delta->delta_end())); - flutter::TextRange selection = priv->text_model->selection(); + flutter::TextRange selection = self->text_model->selection(); fl_value_set_string_take(deltaValue, "selectionBase", fl_value_new_int(selection.base())); @@ -203,9 +195,9 @@ static void update_editing_state_with_delta(FlTextInputHandler* self, int composing_base = -1; int composing_extent = -1; - if (!priv->text_model->composing_range().collapsed()) { - composing_base = priv->text_model->composing_range().base(); - composing_extent = priv->text_model->composing_range().extent(); + if (!self->text_model->composing_range().collapsed()) { + composing_base = self->text_model->composing_range().base(); + composing_extent = self->text_model->composing_range().extent(); } fl_value_set_string_take(deltaValue, "composingBase", fl_value_new_int(composing_base)); @@ -220,7 +212,7 @@ static void update_editing_state_with_delta(FlTextInputHandler* self, fl_value_append(args, value); fl_method_channel_invoke_method( - priv->channel, kUpdateEditingStateWithDeltasMethod, args, nullptr, + self->channel, kUpdateEditingStateWithDeltasMethod, args, nullptr, update_editing_state_response_cb, self); } @@ -236,48 +228,41 @@ static void perform_action_response_cb(GObject* object, // Inform Flutter that the input has been activated. static void perform_action(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - g_return_if_fail(FL_IS_TEXT_INPUT_HANDLER(self)); - g_return_if_fail(priv->client_id != 0); - g_return_if_fail(priv->input_action != nullptr); + g_return_if_fail(self->client_id != 0); + g_return_if_fail(self->input_action != nullptr); g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_int(priv->client_id)); - fl_value_append_take(args, fl_value_new_string(priv->input_action)); + fl_value_append_take(args, fl_value_new_int(self->client_id)); + fl_value_append_take(args, fl_value_new_string(self->input_action)); - fl_method_channel_invoke_method(priv->channel, kPerformActionMethod, args, + fl_method_channel_invoke_method(self->channel, kPerformActionMethod, args, nullptr, perform_action_response_cb, self); } // Signal handler for GtkIMContext::preedit-start static void im_preedit_start_cb(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - priv->text_model->BeginComposing(); + self->text_model->BeginComposing(); } // Signal handler for GtkIMContext::preedit-changed static void im_preedit_changed_cb(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - std::string text_before_change = priv->text_model->GetText(); + std::string text_before_change = self->text_model->GetText(); flutter::TextRange composing_before_change = - priv->text_model->composing_range(); + self->text_model->composing_range(); g_autofree gchar* buf = nullptr; gint cursor_offset = 0; - gtk_im_context_get_preedit_string(priv->im_context, &buf, nullptr, + gtk_im_context_get_preedit_string(self->im_context, &buf, nullptr, &cursor_offset); - if (priv->text_model->composing()) { - cursor_offset += priv->text_model->composing_range().start(); + if (self->text_model->composing()) { + cursor_offset += self->text_model->composing_range().start(); } else { - cursor_offset += priv->text_model->selection().start(); + cursor_offset += self->text_model->selection().start(); } - priv->text_model->UpdateComposingText(buf); - priv->text_model->SetSelection(flutter::TextRange(cursor_offset)); + self->text_model->UpdateComposingText(buf); + self->text_model->SetSelection(flutter::TextRange(cursor_offset)); - if (priv->enable_delta_model) { + if (self->enable_delta_model) { std::string text(buf); flutter::TextEditingDelta delta = flutter::TextEditingDelta( text_before_change, composing_before_change, text); @@ -289,20 +274,18 @@ static void im_preedit_changed_cb(FlTextInputHandler* self) { // Signal handler for GtkIMContext::commit static void im_commit_cb(FlTextInputHandler* self, const gchar* text) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - std::string text_before_change = priv->text_model->GetText(); + std::string text_before_change = self->text_model->GetText(); flutter::TextRange composing_before_change = - priv->text_model->composing_range(); - flutter::TextRange selection_before_change = priv->text_model->selection(); - gboolean was_composing = priv->text_model->composing(); + self->text_model->composing_range(); + flutter::TextRange selection_before_change = self->text_model->selection(); + gboolean was_composing = self->text_model->composing(); - priv->text_model->AddText(text); - if (priv->text_model->composing()) { - priv->text_model->CommitComposing(); + self->text_model->AddText(text); + if (self->text_model->composing()) { + self->text_model->CommitComposing(); } - if (priv->enable_delta_model) { + if (self->enable_delta_model) { flutter::TextRange replace_range = was_composing ? composing_before_change : selection_before_change; std::unique_ptr delta = @@ -316,12 +299,10 @@ static void im_commit_cb(FlTextInputHandler* self, const gchar* text) { // Signal handler for GtkIMContext::preedit-end static void im_preedit_end_cb(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - priv->text_model->EndComposing(); - if (priv->enable_delta_model) { + self->text_model->EndComposing(); + if (self->enable_delta_model) { flutter::TextEditingDelta delta = - flutter::TextEditingDelta(priv->text_model->GetText()); + flutter::TextEditingDelta(self->text_model->GetText()); update_editing_state_with_delta(self, &delta); } else { update_editing_state(self); @@ -330,11 +311,9 @@ static void im_preedit_end_cb(FlTextInputHandler* self) { // Signal handler for GtkIMContext::retrieve-surrounding static gboolean im_retrieve_surrounding_cb(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - auto text = priv->text_model->GetText(); - size_t cursor_offset = priv->text_model->GetCursorOffset(); - gtk_im_context_set_surrounding(priv->im_context, text.c_str(), -1, + auto text = self->text_model->GetText(); + size_t cursor_offset = self->text_model->GetCursorOffset(); + gtk_im_context_set_surrounding(self->im_context, text.c_str(), -1, cursor_offset); return TRUE; } @@ -343,15 +322,12 @@ static gboolean im_retrieve_surrounding_cb(FlTextInputHandler* self) { static gboolean im_delete_surrounding_cb(FlTextInputHandler* self, gint offset, gint n_chars) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - - std::string text_before_change = priv->text_model->GetText(); - if (priv->text_model->DeleteSurrounding(offset, n_chars)) { - if (priv->enable_delta_model) { + std::string text_before_change = self->text_model->GetText(); + if (self->text_model->DeleteSurrounding(offset, n_chars)) { + if (self->enable_delta_model) { flutter::TextEditingDelta delta = flutter::TextEditingDelta( - text_before_change, priv->text_model->composing_range(), - priv->text_model->GetText()); + text_before_change, self->text_model->composing_range(), + self->text_model->GetText()); update_editing_state_with_delta(self, &delta); } else { update_editing_state(self); @@ -367,25 +343,23 @@ static FlMethodResponse* set_client(FlTextInputHandler* self, FlValue* args) { return FL_METHOD_RESPONSE(fl_method_error_response_new( kBadArgumentsError, "Expected 2-element list", nullptr)); } - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - priv->client_id = fl_value_get_int(fl_value_get_list_value(args, 0)); + self->client_id = fl_value_get_int(fl_value_get_list_value(args, 0)); FlValue* config_value = fl_value_get_list_value(args, 1); - g_free(priv->input_action); + g_free(self->input_action); FlValue* input_action_value = fl_value_lookup_string(config_value, kInputActionKey); if (fl_value_get_type(input_action_value) == FL_VALUE_TYPE_STRING) { - priv->input_action = g_strdup(fl_value_get_string(input_action_value)); + self->input_action = g_strdup(fl_value_get_string(input_action_value)); } FlValue* enable_delta_model_value = fl_value_lookup_string(config_value, kEnableDeltaModel); gboolean enable_delta_model = fl_value_get_bool(enable_delta_model_value); - priv->enable_delta_model = enable_delta_model; + self->enable_delta_model = enable_delta_model; // Reset the input type, then set only if appropriate. - priv->input_type = kFlTextInputTypeText; + self->input_type = kFlTextInputTypeText; FlValue* input_type_value = fl_value_lookup_string(config_value, kTextInputTypeKey); if (fl_value_get_type(input_type_value) == FL_VALUE_TYPE_MAP) { @@ -394,9 +368,9 @@ static FlMethodResponse* set_client(FlTextInputHandler* self, FlValue* args) { if (fl_value_get_type(input_type_name) == FL_VALUE_TYPE_STRING) { const gchar* input_type = fl_value_get_string(input_type_name); if (g_strcmp0(input_type, kMultilineInputType) == 0) { - priv->input_type = kFlTextInputTypeMultiline; + self->input_type = kFlTextInputTypeMultiline; } else if (g_strcmp0(input_type, kNoneInputType) == 0) { - priv->input_type = kFlTextInputTypeNone; + self->input_type = kFlTextInputTypeNone; } } } @@ -406,22 +380,18 @@ static FlMethodResponse* set_client(FlTextInputHandler* self, FlValue* args) { // Hides the input method. static FlMethodResponse* hide(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - gtk_im_context_focus_out(priv->im_context); + gtk_im_context_focus_out(self->im_context); return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); } // Shows the input method. static FlMethodResponse* show(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - if (priv->input_type == kFlTextInputTypeNone) { + if (self->input_type == kFlTextInputTypeNone) { return hide(self); } - gtk_im_context_focus_in(priv->im_context); + gtk_im_context_focus_in(self->im_context); return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); } @@ -429,11 +399,9 @@ static FlMethodResponse* show(FlTextInputHandler* self) { // Updates the editing state from Flutter. static FlMethodResponse* set_editing_state(FlTextInputHandler* self, FlValue* args) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); const gchar* text = fl_value_get_string(fl_value_lookup_string(args, kTextKey)); - priv->text_model->SetText(text); + self->text_model->SetText(text); int64_t selection_base = fl_value_get_int(fl_value_lookup_string(args, kSelectionBaseKey)); @@ -444,8 +412,8 @@ static FlMethodResponse* set_editing_state(FlTextInputHandler* self, selection_base = selection_extent = 0; } - priv->text_model->SetText(text); - priv->text_model->SetSelection( + self->text_model->SetText(text); + self->text_model->SetSelection( flutter::TextRange(selection_base, selection_extent)); int64_t composing_base = @@ -453,11 +421,11 @@ static FlMethodResponse* set_editing_state(FlTextInputHandler* self, int64_t composing_extent = fl_value_get_int(fl_value_lookup_string(args, kComposingExtentKey)); if (composing_base == -1 && composing_extent == -1) { - priv->text_model->EndComposing(); + self->text_model->EndComposing(); } else { size_t composing_start = std::min(composing_base, composing_extent); size_t cursor_offset = selection_base - composing_start; - priv->text_model->SetComposingRange( + self->text_model->SetComposingRange( flutter::TextRange(composing_base, composing_extent), cursor_offset); } @@ -466,9 +434,7 @@ static FlMethodResponse* set_editing_state(FlTextInputHandler* self, // Called when the input method client is complete. static FlMethodResponse* clear_client(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - priv->client_id = kClientIdUnset; + self->client_id = kClientIdUnset; return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); } @@ -482,28 +448,25 @@ static FlMethodResponse* clear_client(FlTextInputHandler* self) { // of these updates. It transforms the composing rect to GDK window coordinates // and notifies GTK of the updated cursor position. static void update_im_cursor_position(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - g_autoptr(FlTextInputViewDelegate) view_delegate = - FL_TEXT_INPUT_VIEW_DELEGATE(g_weak_ref_get(&priv->view_delegate)); + FL_TEXT_INPUT_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate)); if (view_delegate == nullptr) { return; } // Skip update if not composing to avoid setting to position 0. - if (!priv->text_model->composing()) { + if (!self->text_model->composing()) { return; } // Transform the x, y positions of the cursor from local coordinates to // Flutter view coordinates. - gint x = priv->composing_rect.x * priv->editabletext_transform[0][0] + - priv->composing_rect.y * priv->editabletext_transform[1][0] + - priv->editabletext_transform[3][0] + priv->composing_rect.width; - gint y = priv->composing_rect.x * priv->editabletext_transform[0][1] + - priv->composing_rect.y * priv->editabletext_transform[1][1] + - priv->editabletext_transform[3][1] + priv->composing_rect.height; + gint x = self->composing_rect.x * self->editabletext_transform[0][0] + + self->composing_rect.y * self->editabletext_transform[1][0] + + self->editabletext_transform[3][0] + self->composing_rect.width; + gint y = self->composing_rect.x * self->editabletext_transform[0][1] + + self->composing_rect.y * self->editabletext_transform[1][1] + + self->editabletext_transform[3][1] + self->composing_rect.height; // Transform from Flutter view coordinates to GTK window coordinates. GdkRectangle preedit_rect = {}; @@ -512,7 +475,7 @@ static void update_im_cursor_position(FlTextInputHandler* self) { // Set the cursor location in window coordinates so that GTK can position any // system input method windows. - gtk_im_context_set_cursor_location(priv->im_context, &preedit_rect); + gtk_im_context_set_cursor_location(self->im_context, &preedit_rect); } // Handles updates to the EditableText size and position from the framework. @@ -530,9 +493,7 @@ static FlMethodResponse* set_editable_size_and_transform( for (size_t i = 0; i < transform_len; ++i) { double val = fl_value_get_float(fl_value_get_list_value(transform, i)); - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - priv->editabletext_transform[i / 4][i % 4] = val; + self->editabletext_transform[i / 4][i % 4] = val; } update_im_cursor_position(self); @@ -547,15 +508,13 @@ static FlMethodResponse* set_editable_size_and_transform( // composing region, the cursor rect is sent. static FlMethodResponse* set_marked_text_rect(FlTextInputHandler* self, FlValue* args) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - priv->composing_rect.x = + self->composing_rect.x = fl_value_get_float(fl_value_lookup_string(args, "x")); - priv->composing_rect.y = + self->composing_rect.y = fl_value_get_float(fl_value_lookup_string(args, "y")); - priv->composing_rect.width = + self->composing_rect.width = fl_value_get_float(fl_value_lookup_string(args, "width")); - priv->composing_rect.height = + self->composing_rect.height = fl_value_get_float(fl_value_lookup_string(args, "height")); update_im_cursor_position(self); @@ -599,43 +558,100 @@ static void method_call_cb(FlMethodChannel* channel, // Disposes of an FlTextInputHandler. static void fl_text_input_handler_dispose(GObject* object) { FlTextInputHandler* self = FL_TEXT_INPUT_HANDLER(object); - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - - g_clear_object(&priv->channel); - g_clear_pointer(&priv->input_action, g_free); - g_clear_object(&priv->im_context); - if (priv->text_model != nullptr) { - delete priv->text_model; - priv->text_model = nullptr; + + g_clear_object(&self->channel); + g_clear_pointer(&self->input_action, g_free); + g_clear_object(&self->im_context); + if (self->text_model != nullptr) { + delete self->text_model; + self->text_model = nullptr; } - g_weak_ref_clear(&priv->view_delegate); + g_weak_ref_clear(&self->view_delegate); G_OBJECT_CLASS(fl_text_input_handler_parent_class)->dispose(object); } -// Implements FlTextInputHandler::filter_keypress. -static gboolean fl_text_input_handler_filter_keypress_default( - FlTextInputHandler* self, - FlKeyEvent* event) { - g_return_val_if_fail(FL_IS_TEXT_INPUT_HANDLER(self), false); +// Initializes the FlTextInputHandler class. +static void fl_text_input_handler_class_init(FlTextInputHandlerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_text_input_handler_dispose; +} + +// Initializes an instance of the FlTextInputHandler class. +static void fl_text_input_handler_init(FlTextInputHandler* self) { + self->client_id = kClientIdUnset; + self->input_type = kFlTextInputTypeText; + self->text_model = new flutter::TextInputModel(); +} + +static void init_im_context(FlTextInputHandler* self, + GtkIMContext* im_context) { + self->im_context = GTK_IM_CONTEXT(g_object_ref(im_context)); + + // On Wayland, this call sets up the input method so it can be enabled + // immediately when required. Without it, on-screen keyboard's don't come up + // the first time a text field is focused. + gtk_im_context_focus_out(self->im_context); + + g_signal_connect_object(self->im_context, "preedit-start", + G_CALLBACK(im_preedit_start_cb), self, + G_CONNECT_SWAPPED); + g_signal_connect_object(self->im_context, "preedit-end", + G_CALLBACK(im_preedit_end_cb), self, + G_CONNECT_SWAPPED); + g_signal_connect_object(self->im_context, "preedit-changed", + G_CALLBACK(im_preedit_changed_cb), self, + G_CONNECT_SWAPPED); + g_signal_connect_object(self->im_context, "commit", G_CALLBACK(im_commit_cb), + self, G_CONNECT_SWAPPED); + g_signal_connect_object(self->im_context, "retrieve-surrounding", + G_CALLBACK(im_retrieve_surrounding_cb), self, + G_CONNECT_SWAPPED); + g_signal_connect_object(self->im_context, "delete-surrounding", + G_CALLBACK(im_delete_surrounding_cb), self, + G_CONNECT_SWAPPED); +} - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); +FlTextInputHandler* fl_text_input_handler_new( + FlBinaryMessenger* messenger, + GtkIMContext* im_context, + FlTextInputViewDelegate* view_delegate) { + g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); + g_return_val_if_fail(GTK_IS_IM_CONTEXT(im_context), nullptr); + g_return_val_if_fail(FL_IS_TEXT_INPUT_VIEW_DELEGATE(view_delegate), nullptr); + + FlTextInputHandler* self = FL_TEXT_INPUT_HANDLER( + g_object_new(fl_text_input_handler_get_type(), nullptr)); + + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + self->channel = + fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec)); + fl_method_channel_set_method_call_handler(self->channel, method_call_cb, self, + nullptr); + + init_im_context(self, im_context); + + g_weak_ref_init(&self->view_delegate, view_delegate); + + return self; +} + +gboolean fl_text_input_handler_filter_keypress(FlTextInputHandler* self, + FlKeyEvent* event) { + g_return_val_if_fail(FL_IS_TEXT_INPUT_HANDLER(self), FALSE); - if (priv->client_id == kClientIdUnset) { + if (self->client_id == kClientIdUnset) { return FALSE; } if (gtk_im_context_filter_keypress( - priv->im_context, + self->im_context, reinterpret_cast(fl_key_event_get_origin(event)))) { return TRUE; } - std::string text_before_change = priv->text_model->GetText(); - flutter::TextRange selection_before_change = priv->text_model->selection(); - std::string text = priv->text_model->GetText(); + std::string text_before_change = self->text_model->GetText(); + flutter::TextRange selection_before_change = self->text_model->selection(); + std::string text = self->text_model->GetText(); // Handle the enter/return key. gboolean do_action = FALSE; @@ -646,17 +662,17 @@ static gboolean fl_text_input_handler_filter_keypress_default( case GDK_KEY_End: case GDK_KEY_KP_End: if (fl_key_event_get_state(event) & GDK_SHIFT_MASK) { - changed = priv->text_model->SelectToEnd(); + changed = self->text_model->SelectToEnd(); } else { - changed = priv->text_model->MoveCursorToEnd(); + changed = self->text_model->MoveCursorToEnd(); } break; case GDK_KEY_Return: case GDK_KEY_KP_Enter: case GDK_KEY_ISO_Enter: - if (priv->input_type == kFlTextInputTypeMultiline && - strcmp(priv->input_action, kNewlineInputAction) == 0) { - priv->text_model->AddCodePoint('\n'); + if (self->input_type == kFlTextInputTypeMultiline && + strcmp(self->input_action, kNewlineInputAction) == 0) { + self->text_model->AddCodePoint('\n'); text = "\n"; changed = TRUE; } @@ -665,9 +681,9 @@ static gboolean fl_text_input_handler_filter_keypress_default( case GDK_KEY_Home: case GDK_KEY_KP_Home: if (fl_key_event_get_state(event) & GDK_SHIFT_MASK) { - changed = priv->text_model->SelectToBeginning(); + changed = self->text_model->SelectToBeginning(); } else { - changed = priv->text_model->MoveCursorToBeginning(); + changed = self->text_model->MoveCursorToBeginning(); } break; case GDK_KEY_BackSpace: @@ -683,7 +699,7 @@ static gboolean fl_text_input_handler_filter_keypress_default( } if (changed) { - if (priv->enable_delta_model) { + if (self->enable_delta_model) { flutter::TextEditingDelta delta = flutter::TextEditingDelta( text_before_change, selection_before_change, text); update_editing_state_with_delta(self, &delta); @@ -697,87 +713,3 @@ static gboolean fl_text_input_handler_filter_keypress_default( return changed; } - -// Initializes the FlTextInputHandler class. -static void fl_text_input_handler_class_init(FlTextInputHandlerClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_text_input_handler_dispose; - FL_TEXT_INPUT_HANDLER_CLASS(klass)->filter_keypress = - fl_text_input_handler_filter_keypress_default; -} - -// Initializes an instance of the FlTextInputHandler class. -static void fl_text_input_handler_init(FlTextInputHandler* self) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - - priv->client_id = kClientIdUnset; - priv->input_type = kFlTextInputTypeText; - priv->text_model = new flutter::TextInputModel(); -} - -static void init_im_context(FlTextInputHandler* self, - GtkIMContext* im_context) { - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - priv->im_context = GTK_IM_CONTEXT(g_object_ref(im_context)); - - // On Wayland, this call sets up the input method so it can be enabled - // immediately when required. Without it, on-screen keyboard's don't come up - // the first time a text field is focused. - gtk_im_context_focus_out(priv->im_context); - - g_signal_connect_object(priv->im_context, "preedit-start", - G_CALLBACK(im_preedit_start_cb), self, - G_CONNECT_SWAPPED); - g_signal_connect_object(priv->im_context, "preedit-end", - G_CALLBACK(im_preedit_end_cb), self, - G_CONNECT_SWAPPED); - g_signal_connect_object(priv->im_context, "preedit-changed", - G_CALLBACK(im_preedit_changed_cb), self, - G_CONNECT_SWAPPED); - g_signal_connect_object(priv->im_context, "commit", G_CALLBACK(im_commit_cb), - self, G_CONNECT_SWAPPED); - g_signal_connect_object(priv->im_context, "retrieve-surrounding", - G_CALLBACK(im_retrieve_surrounding_cb), self, - G_CONNECT_SWAPPED); - g_signal_connect_object(priv->im_context, "delete-surrounding", - G_CALLBACK(im_delete_surrounding_cb), self, - G_CONNECT_SWAPPED); -} - -FlTextInputHandler* fl_text_input_handler_new( - FlBinaryMessenger* messenger, - GtkIMContext* im_context, - FlTextInputViewDelegate* view_delegate) { - g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); - g_return_val_if_fail(GTK_IS_IM_CONTEXT(im_context), nullptr); - g_return_val_if_fail(FL_IS_TEXT_INPUT_VIEW_DELEGATE(view_delegate), nullptr); - - FlTextInputHandler* self = FL_TEXT_INPUT_HANDLER( - g_object_new(fl_text_input_handler_get_type(), nullptr)); - - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - FlTextInputHandlerPrivate* priv = static_cast( - fl_text_input_handler_get_instance_private(self)); - priv->channel = - fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec)); - fl_method_channel_set_method_call_handler(priv->channel, method_call_cb, self, - nullptr); - - init_im_context(self, im_context); - - g_weak_ref_init(&priv->view_delegate, view_delegate); - - return self; -} - -// Filters the a keypress given to the handler through the handler's -// filter_keypress callback. -gboolean fl_text_input_handler_filter_keypress(FlTextInputHandler* self, - FlKeyEvent* event) { - g_return_val_if_fail(FL_IS_TEXT_INPUT_HANDLER(self), FALSE); - if (FL_TEXT_INPUT_HANDLER_GET_CLASS(self)->filter_keypress) { - return FL_TEXT_INPUT_HANDLER_GET_CLASS(self)->filter_keypress(self, event); - } - return FALSE; -} diff --git a/shell/platform/linux/fl_text_input_handler.h b/shell/platform/linux/fl_text_input_handler.h index 9fe4355c67729..f0095b2cde5f3 100644 --- a/shell/platform/linux/fl_text_input_handler.h +++ b/shell/platform/linux/fl_text_input_handler.h @@ -13,11 +13,11 @@ G_BEGIN_DECLS -G_DECLARE_DERIVABLE_TYPE(FlTextInputHandler, - fl_text_input_handler, - FL, - TEXT_INPUT_HANDLER, - GObject); +G_DECLARE_FINAL_TYPE(FlTextInputHandler, + fl_text_input_handler, + FL, + TEXT_INPUT_HANDLER, + GObject); /** * FlTextInputHandler: @@ -26,15 +26,6 @@ G_DECLARE_DERIVABLE_TYPE(FlTextInputHandler, * of SystemChannels.textInput from the Flutter services library. */ -struct _FlTextInputHandlerClass { - GObjectClass parent_class; - - /** - * Virtual method called to filter a keypress. - */ - gboolean (*filter_keypress)(FlTextInputHandler* self, FlKeyEvent* event); -}; - /** * fl_text_input_handler_new: * @messenger: an #FlBinaryMessenger. diff --git a/shell/platform/linux/testing/mock_text_input_handler.cc b/shell/platform/linux/testing/mock_text_input_handler.cc deleted file mode 100644 index 049e36926a9ad..0000000000000 --- a/shell/platform/linux/testing/mock_text_input_handler.cc +++ /dev/null @@ -1,42 +0,0 @@ -// 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/testing/mock_text_input_handler.h" - -struct _FlMockTextInputHandler { - FlTextInputHandler parent_instance; - - gboolean (*filter_keypress)(FlTextInputHandler* self, FlKeyEvent* event); -}; - -G_DEFINE_TYPE(FlMockTextInputHandler, - fl_mock_text_input_handler, - fl_text_input_handler_get_type()) - -static gboolean mock_text_input_handler_filter_keypress( - FlTextInputHandler* self, - FlKeyEvent* event) { - FlMockTextInputHandler* mock_self = FL_MOCK_TEXT_INPUT_HANDLER(self); - if (mock_self->filter_keypress) { - return mock_self->filter_keypress(self, event); - } - return FALSE; -} - -static void fl_mock_text_input_handler_class_init( - FlMockTextInputHandlerClass* klass) { - FL_TEXT_INPUT_HANDLER_CLASS(klass)->filter_keypress = - mock_text_input_handler_filter_keypress; -} - -static void fl_mock_text_input_handler_init(FlMockTextInputHandler* self) {} - -// Creates a mock text_input_handler -FlMockTextInputHandler* fl_mock_text_input_handler_new( - gboolean (*filter_keypress)(FlTextInputHandler* self, FlKeyEvent* event)) { - FlMockTextInputHandler* self = FL_MOCK_TEXT_INPUT_HANDLER( - g_object_new(fl_mock_text_input_handler_get_type(), nullptr)); - self->filter_keypress = filter_keypress; - return self; -} diff --git a/shell/platform/linux/testing/mock_text_input_handler.h b/shell/platform/linux/testing/mock_text_input_handler.h deleted file mode 100644 index 7bb736dd3d14b..0000000000000 --- a/shell/platform/linux/testing/mock_text_input_handler.h +++ /dev/null @@ -1,25 +0,0 @@ -// 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_TESTING_MOCK_TEXT_INPUT_HANDLER_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_TEXT_INPUT_HANDLER_H_ - -#include - -#include "flutter/shell/platform/linux/fl_text_input_handler.h" - -G_BEGIN_DECLS - -G_DECLARE_FINAL_TYPE(FlMockTextInputHandler, - fl_mock_text_input_handler, - FL, - MOCK_TEXT_INPUT_HANDLER, - FlTextInputHandler) - -FlMockTextInputHandler* fl_mock_text_input_handler_new( - gboolean (*filter_keypress)(FlTextInputHandler* self, FlKeyEvent* event)); - -G_END_DECLS - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_TEXT_INPUT_HANDLER_H_