Move FlTextInputHandler from FlView (#162131)

This moves the final part of the keyboard handling from FlView to the
FlEngine and means keyboard should work correctly with multiple views.
This commit is contained in:
Robert Ancell 2025-02-13 15:30:33 +13:00 committed by GitHub
parent a7c6cc19a3
commit 4cc9db4125
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 313 additions and 500 deletions

View File

@ -43908,8 +43908,6 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_text_input_channel.h + ../../..
ORIGIN: ../../../flutter/shell/platform/linux/fl_text_input_handler.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_text_input_handler.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_text_input_handler_test.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_text_input_view_delegate.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_text_input_view_delegate.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_texture.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_texture_gl.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_texture_gl_private.h + ../../../flutter/LICENSE
@ -46910,8 +46908,6 @@ FILE: ../../../flutter/shell/platform/linux/fl_text_input_channel.h
FILE: ../../../flutter/shell/platform/linux/fl_text_input_handler.cc
FILE: ../../../flutter/shell/platform/linux/fl_text_input_handler.h
FILE: ../../../flutter/shell/platform/linux/fl_text_input_handler_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_text_input_view_delegate.cc
FILE: ../../../flutter/shell/platform/linux/fl_text_input_view_delegate.h
FILE: ../../../flutter/shell/platform/linux/fl_texture.cc
FILE: ../../../flutter/shell/platform/linux/fl_texture_gl.cc
FILE: ../../../flutter/shell/platform/linux/fl_texture_gl_private.h

View File

@ -150,7 +150,6 @@ source_set("flutter_linux_sources") {
"fl_task_runner.h",
"fl_text_input_channel.cc",
"fl_text_input_handler.cc",
"fl_text_input_view_delegate.cc",
"fl_texture.cc",
"fl_texture_gl.cc",
"fl_texture_registrar.cc",
@ -262,7 +261,6 @@ executable("flutter_linux_unittests") {
"testing/mock_renderer.cc",
"testing/mock_settings.cc",
"testing/mock_signal_handler.cc",
"testing/mock_text_input_view_delegate.cc",
"testing/mock_texture_registrar.cc",
"testing/mock_window.cc",
]

View File

@ -61,6 +61,9 @@ struct _FlEngine {
// Process keyboard events.
FlKeyboardManager* keyboard_manager;
// Implements the flutter/textinput channel.
FlTextInputHandler* text_input_handler;
// Implements the flutter/keyboard channel.
FlKeyboardHandler* keyboard_handler;
@ -391,9 +394,20 @@ static void fl_engine_update_semantics_cb(const FlutterSemanticsUpdate2* update,
static void setup_keyboard(FlEngine* self) {
g_clear_object(&self->keyboard_manager);
self->keyboard_manager = fl_keyboard_manager_new(self);
g_clear_object(&self->keyboard_handler);
self->keyboard_handler =
fl_keyboard_handler_new(self->binary_messenger, self->keyboard_manager);
GtkWidget* widget =
self->text_input_handler != nullptr
? fl_text_input_handler_get_widget(self->text_input_handler)
: nullptr;
g_clear_object(&self->text_input_handler);
self->text_input_handler = fl_text_input_handler_new(self->binary_messenger);
if (widget != nullptr) {
fl_text_input_handler_set_widget(self->text_input_handler, widget);
}
}
// Called right before the engine is restarted.
@ -474,6 +488,7 @@ static void fl_engine_dispose(GObject* object) {
g_clear_object(&self->settings_handler);
g_clear_object(&self->platform_handler);
g_clear_object(&self->keyboard_manager);
g_clear_object(&self->text_input_handler);
g_clear_object(&self->keyboard_handler);
g_clear_object(&self->mouse_cursor_handler);
g_clear_object(&self->task_runner);
@ -1285,6 +1300,11 @@ FlKeyboardManager* fl_engine_get_keyboard_manager(FlEngine* self) {
return self->keyboard_manager;
}
FlTextInputHandler* fl_engine_get_text_input_handler(FlEngine* self) {
g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
return self->text_input_handler;
}
FlMouseCursorHandler* fl_engine_get_mouse_cursor_handler(FlEngine* self) {
g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
return self->mouse_cursor_handler;

View File

@ -13,6 +13,7 @@
#include "flutter/shell/platform/linux/fl_mouse_cursor_handler.h"
#include "flutter/shell/platform/linux/fl_renderer.h"
#include "flutter/shell/platform/linux/fl_task_runner.h"
#include "flutter/shell/platform/linux/fl_text_input_handler.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
@ -585,6 +586,16 @@ void fl_engine_request_app_exit(FlEngine* engine);
*/
FlKeyboardManager* fl_engine_get_keyboard_manager(FlEngine* engine);
/**
* fl_engine_get_text_input_handler:
* @engine: an #FlEngine.
*
* Gets the text input handler used by this engine.
*
* Returns: a #FlTextInputHandler.
*/
FlTextInputHandler* fl_engine_get_text_input_handler(FlEngine* engine);
/**
* fl_engine_get_mouse_cursor_handler:
* @engine: an #FlEngine.

View File

@ -19,6 +19,9 @@ struct _FlTextInputHandler {
FlTextInputChannel* channel;
// The widget with input focus.
GtkWidget* widget;
// Client ID provided by Flutter to report events with.
int64_t client_id;
@ -37,8 +40,6 @@ struct _FlTextInputHandler {
// Input method.
GtkIMContext* im_context;
GWeakRef view_delegate;
flutter::TextInputModel* text_model;
// A 4x4 matrix that maps from `EditableText` local coordinates to the
@ -316,12 +317,6 @@ static void clear_client(gpointer user_data) {
// after each 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) {
g_autoptr(FlTextInputViewDelegate) 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 (!self->text_model->composing()) {
return;
@ -338,8 +333,9 @@ static void update_im_cursor_position(FlTextInputHandler* self) {
// Transform from Flutter view coordinates to GTK window coordinates.
GdkRectangle preedit_rect = {};
fl_text_input_view_delegate_translate_coordinates(
view_delegate, x, y, &preedit_rect.x, &preedit_rect.y);
gtk_widget_translate_coordinates(self->widget,
gtk_widget_get_toplevel(self->widget), x, y,
&preedit_rect.x, &preedit_rect.y);
// Set the cursor location in window coordinates so that GTK can position
// any system input method windows.
@ -395,7 +391,6 @@ static void fl_text_input_handler_dispose(GObject* object) {
delete self->text_model;
self->text_model = nullptr;
}
g_weak_ref_clear(&self->view_delegate);
g_clear_object(&self->cancellable);
G_OBJECT_CLASS(fl_text_input_handler_parent_class)->dispose(object);
@ -414,9 +409,26 @@ static void fl_text_input_handler_init(FlTextInputHandler* self) {
self->cancellable = g_cancellable_new();
}
static void init_im_context(FlTextInputHandler* self,
GtkIMContext* im_context) {
self->im_context = GTK_IM_CONTEXT(g_object_ref(im_context));
static FlTextInputChannelVTable text_input_vtable = {
.set_client = set_client,
.hide = hide,
.show = show,
.set_editing_state = set_editing_state,
.clear_client = clear_client,
.set_editable_size_and_transform = set_editable_size_and_transform,
.set_marked_text_rect = set_marked_text_rect,
};
FlTextInputHandler* fl_text_input_handler_new(FlBinaryMessenger* messenger) {
g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
FlTextInputHandler* self = FL_TEXT_INPUT_HANDLER(
g_object_new(fl_text_input_handler_get_type(), nullptr));
self->channel =
fl_text_input_channel_new(messenger, &text_input_vtable, self);
self->im_context = GTK_IM_CONTEXT(gtk_im_multicontext_new());
// 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
@ -440,39 +452,28 @@ static void init_im_context(FlTextInputHandler* self,
g_signal_connect_object(self->im_context, "delete-surrounding",
G_CALLBACK(im_delete_surrounding_cb), self,
G_CONNECT_SWAPPED);
}
static FlTextInputChannelVTable text_input_vtable = {
.set_client = set_client,
.hide = hide,
.show = show,
.set_editing_state = set_editing_state,
.clear_client = clear_client,
.set_editable_size_and_transform = set_editable_size_and_transform,
.set_marked_text_rect = set_marked_text_rect,
};
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));
self->channel =
fl_text_input_channel_new(messenger, &text_input_vtable, self);
init_im_context(self, im_context);
g_weak_ref_init(&self->view_delegate, view_delegate);
return self;
}
GtkIMContext* fl_text_input_handler_get_im_context(FlTextInputHandler* self) {
g_return_val_if_fail(FL_IS_TEXT_INPUT_HANDLER(self), nullptr);
return self->im_context;
}
void fl_text_input_handler_set_widget(FlTextInputHandler* self,
GtkWidget* widget) {
g_return_if_fail(FL_IS_TEXT_INPUT_HANDLER(self));
self->widget = widget;
gtk_im_context_set_client_window(self->im_context,
gtk_widget_get_window(self->widget));
}
GtkWidget* fl_text_input_handler_get_widget(FlTextInputHandler* self) {
g_return_val_if_fail(FL_IS_TEXT_INPUT_HANDLER(self), nullptr);
return self->widget;
}
gboolean fl_text_input_handler_filter_keypress(FlTextInputHandler* self,
FlKeyEvent* event) {
g_return_val_if_fail(FL_IS_TEXT_INPUT_HANDLER(self), FALSE);

View File

@ -8,7 +8,6 @@
#include <gtk/gtk.h>
#include "flutter/shell/platform/linux/fl_key_event.h"
#include "flutter/shell/platform/linux/fl_text_input_view_delegate.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
G_BEGIN_DECLS
@ -29,25 +28,50 @@ G_DECLARE_FINAL_TYPE(FlTextInputHandler,
/**
* fl_text_input_handler_new:
* @messenger: an #FlBinaryMessenger.
* @im_context: (allow-none): a #GtkIMContext.
* @view_delegate: an #FlTextInputViewDelegate.
*
* Creates a new handler that implements SystemChannels.textInput from the
* Flutter services library.
*
* Returns: a new #FlTextInputHandler.
*/
FlTextInputHandler* fl_text_input_handler_new(
FlBinaryMessenger* messenger,
GtkIMContext* im_context,
FlTextInputViewDelegate* view_delegate);
FlTextInputHandler* fl_text_input_handler_new(FlBinaryMessenger* messenger);
/**
* fl_text_input_handler_get_im_context:
* @handler: an #FlTextInputHandler.
*
* Get the IM context that is being used. Provided for testing purposes.
*
* Returns: a #GtkIMContext.
*/
GtkIMContext* fl_text_input_handler_get_im_context(FlTextInputHandler* handler);
/**
* fl_text_input_handler_set_widget:
* @handler: an #FlTextInputHandler.
* @widget: the widget with keyboard focus.
*
* Set the widget that has input focus.
*/
void fl_text_input_handler_set_widget(FlTextInputHandler* handler,
GtkWidget* widget);
/**
* fl_text_input_handler_get_widget:
* @handler: an #FlTextInputHandler.
*
* Get the widget that has input focus.
*
* Returns: a #GtkWidget or %NULL if none active.
*/
GtkWidget* fl_text_input_handler_get_widget(FlTextInputHandler* handler);
/**
* fl_text_input_handler_filter_keypress
* @handler: an #FlTextInputHandler.
* @event: a #FlKeyEvent
*
* Process a Gdk key event.
* Process a key event.
*
* Returns: %TRUE if the event was used.
*/

View File

@ -10,7 +10,6 @@
#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h"
#include "flutter/shell/platform/linux/testing/fl_test.h"
#include "flutter/shell/platform/linux/testing/mock_im_context.h"
#include "flutter/shell/platform/linux/testing/mock_text_input_view_delegate.h"
#include "flutter/testing/testing.h"
#include "gmock/gmock.h"
@ -154,10 +153,9 @@ static void send_key_event(FlTextInputHandler* handler,
TEST(FlTextInputHandlerTest, MessageHandler) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
EXPECT_TRUE(
@ -169,10 +167,9 @@ TEST(FlTextInputHandlerTest, MessageHandler) {
TEST(FlTextInputHandlerTest, SetClient) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
set_client(messenger, {.client_id = 1});
@ -183,14 +180,12 @@ TEST(FlTextInputHandlerTest, SetClient) {
TEST(FlTextInputHandlerTest, Show) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
EXPECT_CALL(context,
gtk_im_context_focus_in(::testing::Eq<GtkIMContext*>(context)));
EXPECT_CALL(context, gtk_im_context_focus_in);
gboolean called = FALSE;
fl_mock_binary_messenger_invoke_json_method(
@ -216,14 +211,12 @@ TEST(FlTextInputHandlerTest, Show) {
TEST(FlTextInputHandlerTest, Hide) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
EXPECT_CALL(context,
gtk_im_context_focus_out(::testing::Eq<GtkIMContext*>(context)));
EXPECT_CALL(context, gtk_im_context_focus_out);
gboolean called = FALSE;
fl_mock_binary_messenger_invoke_json_method(
@ -249,10 +242,9 @@ TEST(FlTextInputHandlerTest, Hide) {
TEST(FlTextInputHandlerTest, ClearClient) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
gboolean called = FALSE;
@ -279,10 +271,9 @@ TEST(FlTextInputHandlerTest, ClearClient) {
TEST(FlTextInputHandlerTest, PerformAction) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
set_client(messenger, {
@ -340,10 +331,9 @@ TEST(FlTextInputHandlerTest, PerformAction) {
TEST(FlTextInputHandlerTest, MultilineWithSendAction) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
set_client(messenger, {
@ -399,10 +389,9 @@ TEST(FlTextInputHandlerTest, MultilineWithSendAction) {
TEST(FlTextInputHandlerTest, MoveCursor) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
set_client(messenger, {.client_id = 1});
@ -465,10 +454,9 @@ TEST(FlTextInputHandlerTest, MoveCursor) {
TEST(FlTextInputHandlerTest, Select) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
set_client(messenger, {.client_id = 1});
@ -531,17 +519,15 @@ TEST(FlTextInputHandlerTest, Select) {
TEST(FlTextInputHandlerTest, Composing) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
// update
EXPECT_CALL(context,
gtk_im_context_get_preedit_string(
::testing::Eq<GtkIMContext*>(context),
::testing::A<gchar**>(), ::testing::_, ::testing::A<gint*>()))
EXPECT_CALL(context, gtk_im_context_get_preedit_string(
::testing::_, ::testing::A<gchar**>(), ::testing::_,
::testing::A<gint*>()))
.WillOnce(
::testing::DoAll(::testing::SetArgPointee<1>(g_strdup("Flutter")),
::testing::SetArgPointee<3>(0)));
@ -601,10 +587,14 @@ TEST(FlTextInputHandlerTest, Composing) {
},
&call_count);
g_signal_emit_by_name(context, "preedit-start", nullptr);
g_signal_emit_by_name(context, "preedit-changed", nullptr);
g_signal_emit_by_name(context, "commit", "engine", nullptr);
g_signal_emit_by_name(context, "preedit-end", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler),
"preedit-start", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler),
"preedit-changed", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler), "commit",
"engine", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler),
"preedit-end", nullptr);
EXPECT_EQ(call_count, 3);
fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
@ -613,10 +603,9 @@ TEST(FlTextInputHandlerTest, Composing) {
TEST(FlTextInputHandlerTest, SurroundingText) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
set_client(messenger, {.client_id = 1});
@ -628,11 +617,11 @@ TEST(FlTextInputHandlerTest, SurroundingText) {
// retrieve
EXPECT_CALL(context, gtk_im_context_set_surrounding(
::testing::Eq<GtkIMContext*>(context),
::testing::StrEq("Flutter"), 7, 3));
::testing::_, ::testing::StrEq("Flutter"), -1, 3));
gboolean retrieved = false;
g_signal_emit_by_name(context, "retrieve-surrounding", &retrieved, nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler),
"retrieve-surrounding", &retrieved, nullptr);
EXPECT_TRUE(retrieved);
int call_count = 0;
@ -668,7 +657,8 @@ TEST(FlTextInputHandlerTest, SurroundingText) {
&call_count);
gboolean deleted = false;
g_signal_emit_by_name(context, "delete-surrounding", 1, 2, &deleted, nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler),
"delete-surrounding", 1, 2, &deleted, nullptr);
EXPECT_TRUE(deleted);
EXPECT_EQ(call_count, 1);
@ -678,13 +668,13 @@ TEST(FlTextInputHandlerTest, SurroundingText) {
TEST(FlTextInputHandlerTest, SetMarkedTextRect) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
g_signal_emit_by_name(context, "preedit-start", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler),
"preedit-start", nullptr);
// set editable size and transform
g_autoptr(FlValue) size_and_transform = build_map({
@ -729,15 +719,15 @@ TEST(FlTextInputHandlerTest, SetMarkedTextRect) {
&called);
EXPECT_TRUE(called);
EXPECT_CALL(delegate, fl_text_input_view_delegate_translate_coordinates(
::testing::Eq<FlTextInputViewDelegate*>(delegate),
::testing::Eq(27), ::testing::Eq(32), ::testing::_,
::testing::_))
.WillOnce(::testing::DoAll(::testing::SetArgPointee<3>(123),
::testing::SetArgPointee<4>(456)));
EXPECT_CALL(context, gtk_widget_translate_coordinates(
::testing::_, ::testing::_, ::testing::Eq(27),
::testing::Eq(32), ::testing::_, ::testing::_))
.WillOnce(::testing::DoAll(::testing::SetArgPointee<4>(123),
::testing::SetArgPointee<5>(456),
::testing::Return(true)));
EXPECT_CALL(context, gtk_im_context_set_cursor_location(
::testing::Eq<GtkIMContext*>(context),
::testing::_,
::testing::Pointee(::testing::AllOf(
::testing::Field(&GdkRectangle::x, 123),
::testing::Field(&GdkRectangle::y, 456),
@ -775,10 +765,9 @@ TEST(FlTextInputHandlerTest, SetMarkedTextRect) {
TEST(FlTextInputHandlerTest, TextInputTypeNone) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
set_client(messenger, {
@ -786,11 +775,8 @@ TEST(FlTextInputHandlerTest, TextInputTypeNone) {
.input_type = "TextInputType.none",
});
EXPECT_CALL(context,
gtk_im_context_focus_in(::testing::Eq<GtkIMContext*>(context)))
.Times(0);
EXPECT_CALL(context,
gtk_im_context_focus_out(::testing::Eq<GtkIMContext*>(context)));
EXPECT_CALL(context, gtk_im_context_focus_in).Times(0);
EXPECT_CALL(context, gtk_im_context_focus_out);
gboolean called = FALSE;
fl_mock_binary_messenger_invoke_json_method(
@ -816,10 +802,9 @@ TEST(FlTextInputHandlerTest, TextInputTypeNone) {
TEST(FlTextInputHandlerTest, TextEditingDelta) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
set_client(messenger, {
@ -881,10 +866,9 @@ TEST(FlTextInputHandlerTest, TextEditingDelta) {
TEST(FlTextInputHandlerTest, ComposingDelta) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
// set config
@ -893,13 +877,13 @@ TEST(FlTextInputHandlerTest, ComposingDelta) {
.enable_delta_model = true,
});
g_signal_emit_by_name(context, "preedit-start", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler),
"preedit-start", nullptr);
// update
EXPECT_CALL(context,
gtk_im_context_get_preedit_string(
::testing::Eq<GtkIMContext*>(context),
::testing::A<gchar**>(), ::testing::_, ::testing::A<gint*>()))
EXPECT_CALL(context, gtk_im_context_get_preedit_string(
::testing::_, ::testing::A<gchar**>(), ::testing::_,
::testing::A<gint*>()))
.WillOnce(
::testing::DoAll(::testing::SetArgPointee<1>(g_strdup("Flutter ")),
::testing::SetArgPointee<3>(8)));
@ -982,9 +966,12 @@ TEST(FlTextInputHandlerTest, ComposingDelta) {
},
&call_count);
g_signal_emit_by_name(context, "preedit-changed", nullptr);
g_signal_emit_by_name(context, "commit", "Flutter engine", nullptr);
g_signal_emit_by_name(context, "preedit-end", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler),
"preedit-changed", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler), "commit",
"Flutter engine", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler),
"preedit-end", nullptr);
EXPECT_EQ(call_count, 3);
fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
@ -993,10 +980,9 @@ TEST(FlTextInputHandlerTest, ComposingDelta) {
TEST(FlTextInputHandlerTest, NonComposingDelta) {
g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
::testing::NiceMock<flutter::testing::MockIMContext> context;
::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
FL_BINARY_MESSENGER(messenger), context, delegate);
g_autoptr(FlTextInputHandler) handler =
fl_text_input_handler_new(FL_BINARY_MESSENGER(messenger));
EXPECT_NE(handler, nullptr);
// set config
@ -1173,13 +1159,20 @@ TEST(FlTextInputHandlerTest, NonComposingDelta) {
},
&call_count);
g_signal_emit_by_name(context, "commit", "F", nullptr);
g_signal_emit_by_name(context, "commit", "l", nullptr);
g_signal_emit_by_name(context, "commit", "u", nullptr);
g_signal_emit_by_name(context, "commit", "t", nullptr);
g_signal_emit_by_name(context, "commit", "t", nullptr);
g_signal_emit_by_name(context, "commit", "e", nullptr);
g_signal_emit_by_name(context, "commit", "r", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler), "commit",
"F", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler), "commit",
"l", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler), "commit",
"u", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler), "commit",
"t", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler), "commit",
"t", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler), "commit",
"e", nullptr);
g_signal_emit_by_name(fl_text_input_handler_get_im_context(handler), "commit",
"r", nullptr);
EXPECT_EQ(call_count, 7);
fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));

View File

@ -1,24 +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/fl_text_input_view_delegate.h"
G_DEFINE_INTERFACE(FlTextInputViewDelegate,
fl_text_input_view_delegate,
G_TYPE_OBJECT)
static void fl_text_input_view_delegate_default_init(
FlTextInputViewDelegateInterface* iface) {}
void fl_text_input_view_delegate_translate_coordinates(
FlTextInputViewDelegate* self,
gint view_x,
gint view_y,
gint* window_x,
gint* window_y) {
g_return_if_fail(FL_IS_TEXT_INPUT_VIEW_DELEGATE(self));
FL_TEXT_INPUT_VIEW_DELEGATE_GET_IFACE(self)->translate_coordinates(
self, view_x, view_y, window_x, window_y);
}

View File

@ -1,48 +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_FL_TEXT_INPUT_VIEW_DELEGATE_H_
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXT_INPUT_VIEW_DELEGATE_H_
#include <gdk/gdk.h>
#include "flutter/shell/platform/embedder/embedder.h"
G_BEGIN_DECLS
G_DECLARE_INTERFACE(FlTextInputViewDelegate,
fl_text_input_view_delegate,
FL,
TEXT_INPUT_VIEW_DELEGATE,
GObject);
/**
* FlTextInputViewDelegate:
*
* An interface for a class that provides `FlTextInputHandler` with
* view-related features.
*
* This interface is typically implemented by `FlView`.
*/
struct _FlTextInputViewDelegateInterface {
GTypeInterface g_iface;
void (*translate_coordinates)(FlTextInputViewDelegate* delegate,
gint view_x,
gint view_y,
gint* window_x,
gint* window_y);
};
void fl_text_input_view_delegate_translate_coordinates(
FlTextInputViewDelegate* delegate,
gint view_x,
gint view_y,
gint* window_x,
gint* window_y);
G_END_DECLS
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXT_INPUT_VIEW_DELEGATE_H_

View File

@ -18,8 +18,6 @@
#include "flutter/shell/platform/linux/fl_renderer_gdk.h"
#include "flutter/shell/platform/linux/fl_scrolling_manager.h"
#include "flutter/shell/platform/linux/fl_socket_accessible.h"
#include "flutter/shell/platform/linux/fl_text_input_handler.h"
#include "flutter/shell/platform/linux/fl_text_input_view_delegate.h"
#include "flutter/shell/platform/linux/fl_touch_manager.h"
#include "flutter/shell/platform/linux/fl_view_accessible.h"
#include "flutter/shell/platform/linux/fl_window_state_monitor.h"
@ -62,9 +60,6 @@ struct _FlView {
// Manages touch events.
FlTouchManager* touch_manager;
// Flutter system channel handlers.
FlTextInputHandler* text_input_handler;
// Accessible tree from Flutter, exposed as an AtkPlug.
FlViewAccessible* view_accessible;
@ -83,18 +78,13 @@ static void fl_renderable_iface_init(FlRenderableInterface* iface);
static void fl_view_plugin_registry_iface_init(
FlPluginRegistryInterface* iface);
static void fl_view_text_input_delegate_iface_init(
FlTextInputViewDelegateInterface* iface);
G_DEFINE_TYPE_WITH_CODE(
FlView,
fl_view,
GTK_TYPE_BOX,
G_IMPLEMENT_INTERFACE(fl_renderable_get_type(), fl_renderable_iface_init)
G_IMPLEMENT_INTERFACE(fl_plugin_registry_get_type(),
fl_view_plugin_registry_iface_init)
G_IMPLEMENT_INTERFACE(fl_text_input_view_delegate_get_type(),
fl_view_text_input_delegate_iface_init))
fl_view_plugin_registry_iface_init))
// Emit the first frame signal in the main thread.
static gboolean first_frame_idle_cb(gpointer user_data) {
@ -112,21 +102,6 @@ static gboolean window_delete_event_cb(FlView* self) {
return TRUE;
}
// Initialize keyboard.
static void init_keyboard(FlView* self) {
FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine);
GdkWindow* window =
gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(self)));
g_return_if_fail(GDK_IS_WINDOW(window));
g_autoptr(GtkIMContext) im_context = gtk_im_multicontext_new();
gtk_im_context_set_client_window(im_context, window);
g_clear_object(&self->text_input_handler);
self->text_input_handler = fl_text_input_handler_new(
messenger, im_context, FL_TEXT_INPUT_VIEW_DELEGATE(self));
}
static void init_scrolling(FlView* self) {
g_clear_object(&self->scrolling_manager);
self->scrolling_manager =
@ -277,7 +252,6 @@ static void update_semantics_cb(FlEngine* engine,
// which usually indicates the user has requested a hot restart (Shift-R in the
// Flutter CLI.)
static void on_pre_engine_restart_cb(FlView* self) {
init_keyboard(self);
init_scrolling(self);
init_touch(self);
}
@ -323,18 +297,6 @@ static void fl_view_plugin_registry_iface_init(
iface->get_registrar_for_plugin = fl_view_get_registrar_for_plugin;
}
static void fl_view_text_input_delegate_iface_init(
FlTextInputViewDelegateInterface* iface) {
iface->translate_coordinates = [](FlTextInputViewDelegate* delegate,
gint view_x, gint view_y, gint* window_x,
gint* window_y) {
FlView* self = FL_VIEW(delegate);
gtk_widget_translate_coordinates(GTK_WIDGET(self),
gtk_widget_get_toplevel(GTK_WIDGET(self)),
view_x, view_y, window_x, window_y);
};
}
static void sync_modifier_if_needed(FlView* self, GdkEvent* event) {
guint event_time = gdk_event_get_time(event);
GdkModifierType event_state = static_cast<GdkModifierType>(0);
@ -534,8 +496,6 @@ static void realize_cb(FlView* self) {
g_signal_connect_swapped(toplevel_window, "delete-event",
G_CALLBACK(window_delete_event_cb), self);
init_keyboard(self);
fl_renderer_add_renderable(FL_RENDERER(self->renderer), self->view_id,
FL_RENDERABLE(self));
@ -674,8 +634,9 @@ static gboolean handle_key_event(FlView* self, GdkEventKey* key_event) {
}
if (redispatch_event != nullptr) {
if (!fl_text_input_handler_filter_keypress(self->text_input_handler,
redispatch_event)) {
if (!fl_text_input_handler_filter_keypress(
fl_engine_get_text_input_handler(self->engine),
redispatch_event)) {
fl_keyboard_manager_add_redispatched_event(
fl_engine_get_keyboard_manager(self->engine), redispatch_event);
gdk_event_put(fl_key_event_get_origin(redispatch_event));
@ -687,6 +648,15 @@ static gboolean handle_key_event(FlView* self, GdkEventKey* key_event) {
return TRUE;
}
// Implements GtkWidget::key_press_event.
static gboolean fl_view_focus_in_event(GtkWidget* widget,
GdkEventFocus* event) {
FlView* self = FL_VIEW(widget);
fl_text_input_handler_set_widget(
fl_engine_get_text_input_handler(self->engine), widget);
return FALSE;
}
// Implements GtkWidget::key_press_event.
static gboolean fl_view_key_press_event(GtkWidget* widget,
GdkEventKey* key_event) {
@ -708,6 +678,7 @@ static void fl_view_class_init(FlViewClass* klass) {
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
widget_class->realize = fl_view_realize;
widget_class->focus_in_event = fl_view_focus_in_event;
widget_class->key_press_event = fl_view_key_press_event;
widget_class->key_release_event = fl_view_key_release_event;

View File

@ -60,6 +60,12 @@ MockEpoxy::MockEpoxy() {
mock = this;
}
MockEpoxy::~MockEpoxy() {
if (mock == this) {
mock = nullptr;
}
}
static bool check_display(EGLDisplay dpy) {
if (dpy == nullptr) {
mock_error = EGL_BAD_DISPLAY;

View File

@ -16,6 +16,7 @@ namespace testing {
class MockEpoxy {
public:
MockEpoxy();
~MockEpoxy();
MOCK_METHOD(bool, epoxy_has_gl_extension, (const char* extension));
MOCK_METHOD(bool, epoxy_is_desktop_gl, ());

View File

@ -6,116 +6,87 @@
using namespace flutter::testing;
G_DECLARE_FINAL_TYPE(FlMockIMContext,
fl_mock_im_context,
FL,
MOCK_IM_CONTEXT,
GtkIMContext)
static MockIMContext* mock = nullptr;
struct _FlMockIMContext {
GtkIMContext parent_instance;
MockIMContext* mock;
};
G_DEFINE_TYPE(FlMockIMContext, fl_mock_im_context, GTK_TYPE_IM_CONTEXT)
static void fl_mock_im_context_set_client_window(GtkIMContext* context,
GdkWindow* window) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
self->mock->gtk_im_context_set_client_window(context, window);
}
static void fl_mock_im_context_get_preedit_string(GtkIMContext* context,
gchar** str,
PangoAttrList** attrs,
gint* cursor_pos) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
self->mock->gtk_im_context_get_preedit_string(context, str, attrs,
cursor_pos);
}
static gboolean fl_mock_im_context_filter_keypress(GtkIMContext* context,
GdkEventKey* event) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
return self->mock->gtk_im_context_filter_keypress(context, event);
}
static void fl_mock_im_context_focus_in(GtkIMContext* context) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
self->mock->gtk_im_context_focus_in(context);
}
static void fl_mock_im_context_focus_out(GtkIMContext* context) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
self->mock->gtk_im_context_focus_out(context);
}
static void fl_mock_im_context_reset(GtkIMContext* context) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
self->mock->gtk_im_context_reset(context);
}
static void fl_mock_im_context_set_cursor_location(GtkIMContext* context,
GdkRectangle* area) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
self->mock->gtk_im_context_set_cursor_location(context, area);
}
static void fl_mock_im_context_set_use_preedit(GtkIMContext* context,
gboolean use_preedit) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
self->mock->gtk_im_context_set_use_preedit(context, use_preedit);
}
static void fl_mock_im_context_set_surrounding(GtkIMContext* context,
const gchar* text,
gint len,
gint cursor_index) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
self->mock->gtk_im_context_set_surrounding(context, text, len, cursor_index);
}
static gboolean fl_mock_im_context_get_surrounding(GtkIMContext* context,
gchar** text,
gint* cursor_index) {
FlMockIMContext* self = FL_MOCK_IM_CONTEXT(context);
return self->mock->gtk_im_context_get_surrounding(context, text,
cursor_index);
}
static void fl_mock_im_context_class_init(FlMockIMContextClass* klass) {
GtkIMContextClass* im_context_class = GTK_IM_CONTEXT_CLASS(klass);
im_context_class->set_client_window = fl_mock_im_context_set_client_window;
im_context_class->get_preedit_string = fl_mock_im_context_get_preedit_string;
im_context_class->filter_keypress = fl_mock_im_context_filter_keypress;
im_context_class->focus_in = fl_mock_im_context_focus_in;
im_context_class->focus_out = fl_mock_im_context_focus_out;
im_context_class->reset = fl_mock_im_context_reset;
im_context_class->set_cursor_location =
fl_mock_im_context_set_cursor_location;
im_context_class->set_use_preedit = fl_mock_im_context_set_use_preedit;
im_context_class->set_surrounding = fl_mock_im_context_set_surrounding;
im_context_class->get_surrounding = fl_mock_im_context_get_surrounding;
}
static void fl_mock_im_context_init(FlMockIMContext* self) {}
static GtkIMContext* fl_mock_im_context_new(MockIMContext* mock) {
FlMockIMContext* self =
FL_MOCK_IM_CONTEXT(g_object_new(fl_mock_im_context_get_type(), nullptr));
self->mock = mock;
return GTK_IM_CONTEXT(self);
MockIMContext::MockIMContext() {
mock = this;
}
MockIMContext::~MockIMContext() {
if (FL_IS_MOCK_IM_CONTEXT(instance_)) {
g_clear_object(&instance_);
if (mock == this) {
mock = nullptr;
}
}
MockIMContext::operator GtkIMContext*() {
if (instance_ == nullptr) {
instance_ = fl_mock_im_context_new(this);
void gtk_im_context_set_client_window(GtkIMContext* context,
GdkWindow* window) {
if (mock != nullptr) {
mock->gtk_im_context_set_client_window(context, window);
}
return instance_;
}
void gtk_im_context_get_preedit_string(GtkIMContext* context,
gchar** str,
PangoAttrList** attrs,
gint* cursor_pos) {
if (mock != nullptr) {
mock->gtk_im_context_get_preedit_string(context, str, attrs, cursor_pos);
}
}
gboolean gtk_im_context_filter_keypress(GtkIMContext* context,
GdkEventKey* event) {
if (mock == nullptr) {
return TRUE;
}
return mock->gtk_im_context_filter_keypress(context, event);
}
void gtk_im_context_focus_in(GtkIMContext* context) {
if (mock != nullptr) {
mock->gtk_im_context_focus_in(context);
}
}
void gtk_im_context_focus_out(GtkIMContext* context) {
if (mock != nullptr) {
mock->gtk_im_context_focus_out(context);
}
}
void gtk_im_context_set_cursor_location(GtkIMContext* context,
const GdkRectangle* area) {
if (mock != nullptr) {
mock->gtk_im_context_set_cursor_location(context, area);
}
}
void gtk_im_context_set_surrounding(GtkIMContext* context,
const gchar* text,
gint len,
gint cursor_index) {
if (mock != nullptr) {
mock->gtk_im_context_set_surrounding(context, text, len, cursor_index);
}
}
gboolean gtk_widget_translate_coordinates(GtkWidget* src_widget,
GtkWidget* dest_widget,
gint src_x,
gint src_y,
gint* dest_x,
gint* dest_y) {
if (mock == nullptr) {
*dest_x = src_x;
*dest_y = src_y;
return TRUE;
}
return mock->gtk_widget_translate_coordinates(src_widget, dest_widget, src_x,
src_y, dest_x, dest_y);
}
GtkWidget* gtk_widget_get_toplevel(GtkWidget* widget) {
return widget;
}

View File

@ -14,14 +14,9 @@ namespace testing {
class MockIMContext {
public:
MockIMContext();
~MockIMContext();
// This was an existing use of operator overloading. It's against our style
// guide but enabling clang tidy on header files is a higher priority than
// fixing this.
// NOLINTNEXTLINE(google-explicit-constructor)
operator GtkIMContext*();
MOCK_METHOD(void,
gtk_im_context_set_client_window,
(GtkIMContext * context, GdkWindow* window));
@ -36,23 +31,22 @@ class MockIMContext {
(GtkIMContext * context, GdkEventKey* event));
MOCK_METHOD(gboolean, gtk_im_context_focus_in, (GtkIMContext * context));
MOCK_METHOD(void, gtk_im_context_focus_out, (GtkIMContext * context));
MOCK_METHOD(void, gtk_im_context_reset, (GtkIMContext * context));
MOCK_METHOD(void,
gtk_im_context_set_cursor_location,
(GtkIMContext * context, GdkRectangle* area));
MOCK_METHOD(void,
gtk_im_context_set_use_preedit,
(GtkIMContext * context, gboolean use_preedit));
(GtkIMContext * context, const GdkRectangle* area));
MOCK_METHOD(
void,
gtk_im_context_set_surrounding,
(GtkIMContext * context, const gchar* text, gint len, gint cursor_index));
MOCK_METHOD(gboolean,
gtk_im_context_get_surrounding,
(GtkIMContext * context, gchar** text, gint* cursor_index));
private:
GtkIMContext* instance_ = nullptr;
gtk_widget_translate_coordinates,
(GtkWidget * src_widget,
GtkWidget* dest_widget,
gint src_x,
gint src_y,
gint* dest_x,
gint* dest_y));
MOCK_METHOD(GtkWidget*, gtk_widget_get_toplevel, (GtkWidget * widget));
};
} // namespace testing

View File

@ -28,6 +28,12 @@ MockKeymap::MockKeymap() {
mock = this;
}
MockKeymap::~MockKeymap() {
if (mock == this) {
mock = nullptr;
}
}
GdkKeymap* gdk_keymap_get_for_display(GdkDisplay* display) {
FlMockKeymap* keymap =
FL_MOCK_KEYMAP(g_object_new(fl_mock_keymap_get_type(), nullptr));

View File

@ -15,6 +15,7 @@ namespace testing {
class MockKeymap {
public:
MockKeymap();
~MockKeymap();
MOCK_METHOD(GdkKeymap*, gdk_keymap_get_for_display, (GdkDisplay * display));
MOCK_METHOD(guint,

View File

@ -1,74 +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_view_delegate.h"
using namespace flutter::testing;
G_DECLARE_FINAL_TYPE(FlMockTextInputViewDelegate,
fl_mock_text_input_view_delegate,
FL,
MOCK_TEXT_INPUT_VIEW_DELEGATE,
GObject)
struct _FlMockTextInputViewDelegate {
GObject parent_instance;
MockTextInputViewDelegate* mock;
};
static FlTextInputViewDelegate* fl_mock_text_input_view_delegate_new(
MockTextInputViewDelegate* mock) {
FlMockTextInputViewDelegate* self = FL_MOCK_TEXT_INPUT_VIEW_DELEGATE(
g_object_new(fl_mock_text_input_view_delegate_get_type(), nullptr));
self->mock = mock;
return FL_TEXT_INPUT_VIEW_DELEGATE(self);
}
MockTextInputViewDelegate::MockTextInputViewDelegate()
: instance_(fl_mock_text_input_view_delegate_new(this)) {}
MockTextInputViewDelegate::~MockTextInputViewDelegate() {
if (FL_IS_TEXT_INPUT_VIEW_DELEGATE(instance_)) {
g_clear_object(&instance_);
}
}
MockTextInputViewDelegate::operator FlTextInputViewDelegate*() {
return instance_;
}
static void fl_mock_text_input_view_delegate_iface_init(
FlTextInputViewDelegateInterface* iface);
G_DEFINE_TYPE_WITH_CODE(
FlMockTextInputViewDelegate,
fl_mock_text_input_view_delegate,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(fl_text_input_view_delegate_get_type(),
fl_mock_text_input_view_delegate_iface_init))
static void fl_mock_text_input_view_delegate_class_init(
FlMockTextInputViewDelegateClass* klass) {}
static void fl_mock_text_input_view_delegate_translate_coordinates(
FlTextInputViewDelegate* view_delegate,
gint view_x,
gint view_y,
gint* window_x,
gint* window_y) {
g_return_if_fail(FL_IS_MOCK_TEXT_INPUT_VIEW_DELEGATE(view_delegate));
FlMockTextInputViewDelegate* self =
FL_MOCK_TEXT_INPUT_VIEW_DELEGATE(view_delegate);
self->mock->fl_text_input_view_delegate_translate_coordinates(
view_delegate, view_x, view_y, window_x, window_y);
}
static void fl_mock_text_input_view_delegate_iface_init(
FlTextInputViewDelegateInterface* iface) {
iface->translate_coordinates =
fl_mock_text_input_view_delegate_translate_coordinates;
}
static void fl_mock_text_input_view_delegate_init(
FlMockTextInputViewDelegate* self) {}

View File

@ -1,41 +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_VIEW_DELEGATE_H_
#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_TEXT_INPUT_VIEW_DELEGATE_H_
#include <unordered_map>
#include "flutter/shell/platform/linux/fl_text_input_view_delegate.h"
#include "gmock/gmock.h"
namespace flutter {
namespace testing {
// Mock for FlTextInputVuewDelegate.
class MockTextInputViewDelegate {
public:
MockTextInputViewDelegate();
~MockTextInputViewDelegate();
// NOLINTNEXTLINE(google-explicit-constructor)
operator FlTextInputViewDelegate*();
MOCK_METHOD(void,
fl_text_input_view_delegate_translate_coordinates,
(FlTextInputViewDelegate * delegate,
gint view_x,
gint view_y,
gint* window_x,
gint* window_y));
private:
FlTextInputViewDelegate* instance_ = nullptr;
};
} // namespace testing
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_TEXT_INPUT_VIEW_DELEGATE_H_

View File

@ -12,6 +12,12 @@ MockWindow::MockWindow() {
mock = this;
}
MockWindow::~MockWindow() {
if (mock == this) {
mock = nullptr;
}
}
GdkDisplay* gdk_display_get_default() {
return GDK_DISPLAY(g_object_new(gdk_display_get_type(), nullptr));
}

View File

@ -15,6 +15,7 @@ namespace testing {
class MockWindow {
public:
MockWindow();
~MockWindow();
MOCK_METHOD(GdkWindowState, gdk_window_get_state, (GdkWindow * window));
};