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:
parent
a7c6cc19a3
commit
4cc9db4125
@ -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
|
||||
|
@ -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",
|
||||
]
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
@ -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_
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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, ());
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -15,6 +15,7 @@ namespace testing {
|
||||
class MockKeymap {
|
||||
public:
|
||||
MockKeymap();
|
||||
~MockKeymap();
|
||||
|
||||
MOCK_METHOD(GdkKeymap*, gdk_keymap_get_for_display, (GdkDisplay * display));
|
||||
MOCK_METHOD(guint,
|
||||
|
@ -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) {}
|
@ -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_
|
@ -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));
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ namespace testing {
|
||||
class MockWindow {
|
||||
public:
|
||||
MockWindow();
|
||||
~MockWindow();
|
||||
|
||||
MOCK_METHOD(GdkWindowState, gdk_window_get_state, (GdkWindow * window));
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user