From 5e296c4c8f70f8b1478e804e0bee25a68d335f3f Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 31 Mar 2026 14:45:36 +0900 Subject: [PATCH 01/11] Remove ecore dependency and migrate to tizen-core APIs Replace ecore, ecore-wl2, ecore-imf, ecore-input, eina dependencies with tizen-core, tizen-core-wayland (tizen-core-wl C API), and tizen-core-imf libraries. Key changes: - BUILD.gn: Remove ecore/eina/efl include dirs and libs, add tizen-core variants and glib-2.0 - tizen_window_ecore_wl2: Migrate from Ecore_Wl2 APIs to tizen_core_wl C APIs for display, window, EGL window, event handling, and input - tizen_input_method_context: Migrate from Ecore_IMF to tizen_core_imf using opaque handle-based key event API - tizen_event_loop: Replace ecore_pipe/ecore_timer with POSIX pipe and GLib GIOChannel/g_timeout_add for cross-thread task notification - tizen_clipboard: Migrate clipboard operations to tizen_core_wl data sharing APIs - tizen_renderer_egl: Use tizen_core_wl_egl_window_native_get - flutter_tizen_display_monitor: Use default 60Hz refresh rate - generate_sysroot.py: Add tizen-core, tizen-core-imf, tizen-core-wayland, and wayland-egl-tizen packages --- flutter/shell/platform/tizen/BUILD.gn | 21 +- .../platform/tizen/channels/key_mapping.cc | 2 +- .../platform/tizen/channels/key_mapping.h | 10 +- .../tizen/channels/keyboard_channel.cc | 37 +- .../tizen/channels/text_input_channel.cc | 47 +- .../tizen/flutter_tizen_display_monitor.cc | 10 +- .../tizen/flutter_tizen_engine_unittest.cc | 4 +- ...utter_tizen_texture_registrar_unittests.cc | 4 +- .../platform/tizen/flutter_tizen_view.cc | 30 + .../platform/tizen/public/flutter_tizen.h | 2 +- .../shell/platform/tizen/tizen_clipboard.cc | 191 ++-- .../shell/platform/tizen/tizen_clipboard.h | 12 +- .../shell/platform/tizen/tizen_event_loop.cc | 59 +- .../shell/platform/tizen/tizen_event_loop.h | 6 +- .../tizen/tizen_input_method_context.cc | 464 ++++----- .../tizen/tizen_input_method_context.h | 19 +- .../platform/tizen/tizen_renderer_egl.cc | 7 +- .../shell/platform/tizen/tizen_view_nui.cc | 15 + .../platform/tizen/tizen_window_ecore_wl2.cc | 893 +++++++++++------- .../platform/tizen/tizen_window_ecore_wl2.h | 18 +- .../accessibility/ax/ax_active_popup.h | 1 + .../accessibility/ax/ax_event_generator.h | 8 +- tools/generate_sysroot.py | 8 + 23 files changed, 1152 insertions(+), 716 deletions(-) diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index 3d9dfd0b..5fba7c67 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -17,17 +17,11 @@ config("flutter_tizen_config") { "${sysroot_path}/usr/include/dali-adaptor", "${sysroot_path}/usr/include/dali-toolkit", "${sysroot_path}/usr/include/dlog", - "${sysroot_path}/usr/include/ecore-1", - "${sysroot_path}/usr/include/ecore-imf-1", - "${sysroot_path}/usr/include/ecore-input-1", - "${sysroot_path}/usr/include/ecore-wayland-1", - "${sysroot_path}/usr/include/ecore-wl2-1", - "${sysroot_path}/usr/include/efl-1", - "${sysroot_path}/usr/include/eina-1", - "${sysroot_path}/usr/include/eina-1/eina", - "${sysroot_path}/usr/include/eo-1", "${sysroot_path}/usr/include/feedback", "${sysroot_path}/usr/include/system", + "${sysroot_path}/usr/include/tizen-core", + "${sysroot_path}/usr/include/tizen-core-imf", + "${sysroot_path}/usr/include/tizen-core-wl", "${sysroot_path}/usr/include/tzsh", "${sysroot_path}/usr/include/vconf", "${sysroot_path}/usr/include/wayland-extension", @@ -113,11 +107,10 @@ template("embedder") { "capi-system-info", "capi-system-system-settings", "dlog", - "ecore", - "ecore_imf", - "ecore_input", - "ecore_wl2", - "eina", + "tizen-core", + "tizen-core-imf", + "tizen-core-wl", + "glib-2.0", "gio-2.0", "feedback", "flutter_engine", diff --git a/flutter/shell/platform/tizen/channels/key_mapping.cc b/flutter/shell/platform/tizen/channels/key_mapping.cc index 35c0f368..54ea04de 100644 --- a/flutter/shell/platform/tizen/channels/key_mapping.cc +++ b/flutter/shell/platform/tizen/channels/key_mapping.cc @@ -177,7 +177,7 @@ std::map kScanCodeToGtkKeyCode = { {0x0000024d, 269025069}, // launchScreenSaver }; -std::map kEcoreModifierToGtkModifier = { +std::map kModifierToGtkModifier = { {0x0001, 1 << 0}, // SHIFT -> modifierShift {0x0002, 1 << 2}, // CTRL -> modifierControl {0x0004, 1 << 3}, // ALT -> modifierMod1 diff --git a/flutter/shell/platform/tizen/channels/key_mapping.h b/flutter/shell/platform/tizen/channels/key_mapping.h index d2ec300b..e07e1fb6 100644 --- a/flutter/shell/platform/tizen/channels/key_mapping.h +++ b/flutter/shell/platform/tizen/channels/key_mapping.h @@ -19,15 +19,15 @@ // legacy RawKeyboard API is removed from the framework in the future. extern std::map kScanCodeToGtkKeyCode; -// Maps Ecore modifiers to GTK modifiers. +// Maps Tizen modifier bitmask values to GTK modifiers. // -// The values are originally defined in: -// - efl/Ecore_Input.h -// - flutter/raw_keyboard_linux.dart (GtkKeyHelper) +// The modifier bitmask values match tizen_core_wl_modifier_e. +// The GTK modifier values are from flutter/raw_keyboard_linux.dart +// (GtkKeyHelper). // // Provided only for backward compatibility. This will be removed after the // legacy RawKeyboard API is removed from the framework in the future. -extern std::map kEcoreModifierToGtkModifier; +extern std::map kModifierToGtkModifier; // Maps XKB scan codes to Flutter's physical key codes. // diff --git a/flutter/shell/platform/tizen/channels/keyboard_channel.cc b/flutter/shell/platform/tizen/channels/keyboard_channel.cc index d48caecb..37b351ea 100644 --- a/flutter/shell/platform/tizen/channels/keyboard_channel.cc +++ b/flutter/shell/platform/tizen/channels/keyboard_channel.cc @@ -119,6 +119,12 @@ void KeyboardChannel::SendKey(const char* key, uint32_t scan_code, bool is_down, std::function callback) { + FT_LOG(Error) << "KeyboardChannel::SendKey: key=" << (key ? key : "null") + << ", string=" << (string ? string : "null") + << ", compose=" << (compose ? compose : "null") + << ", modifiers=" << modifiers << ", scan_code=" << scan_code + << ", is_down=" << is_down; + uint64_t sequence_id = last_sequence_id_++; PendingEvent pending; @@ -139,8 +145,14 @@ void KeyboardChannel::SendKey(const char* key, if (scan_code == 0) { scan_code = GetFallbackScanCodeFromKey(key); + FT_LOG(Error) + << "KeyboardChannel::SendKey: scan_code was 0, fallback scan_code=" + << scan_code; } + FT_LOG(Error) << "KeyboardChannel::SendKey: sending embedder+channel events, " + "sequence_id=" + << sequence_id; SendEmbedderEvent(key, string, compose, modifiers, scan_code, is_down, sequence_id); // The channel-based API (RawKeyEvent) is deprecated and |SendChannelEvent| @@ -164,7 +176,7 @@ void KeyboardChannel::SendChannelEvent(const char* key, } int gtk_modifiers = 0; - for (auto element : kEcoreModifierToGtkModifier) { + for (auto element : kModifierToGtkModifier) { if (element.first & modifiers) { gtk_modifiers |= element.second; } @@ -210,6 +222,12 @@ void KeyboardChannel::SendEmbedderEvent(const char* key, uint64_t logical_key = GetLogicalKey(key); const char* character = is_down ? string : nullptr; + FT_LOG(Error) << "KeyboardChannel::SendEmbedderEvent: key=" + << (key ? key : "null") << ", physical_key=" << physical_key + << ", logical_key=" << logical_key + << ", scan_code=" << scan_code << ", is_down=" << is_down + << ", sequence_id=" << sequence_id; + uint64_t last_logical_record = 0; auto iter = pressing_records_.find(physical_key); if (iter != pressing_records_.end()) { @@ -231,6 +249,8 @@ void KeyboardChannel::SendEmbedderEvent(const char* key, // The physical key has been released before. It might indicate a missed // event due to loss of focus, or multiple keyboards pressed keys with the // same physical key. Ignore the up event. + FT_LOG(Error) << "KeyboardChannel::SendEmbedderEvent: key up without " + "prior key down, synthesizing empty event"; FlutterKeyEvent empty_event = { .struct_size = sizeof(FlutterKeyEvent), .timestamp = static_cast( @@ -264,6 +284,12 @@ void KeyboardChannel::SendEmbedderEvent(const char* key, event.character = character; event.synthesized = false; + FT_LOG(Error) + << "KeyboardChannel::SendEmbedderEvent: sending FlutterKeyEvent, type=" + << static_cast(type) << ", physical=" << event.physical + << ", logical=" << event.logical + << ", character=" << (event.character ? event.character : "null"); + send_event_( event, [](bool handled, void* user_data) { @@ -277,19 +303,28 @@ void KeyboardChannel::SendEmbedderEvent(const char* key, } void KeyboardChannel::ResolvePendingEvent(uint64_t sequence_id, bool handled) { + FT_LOG(Error) << "KeyboardChannel::ResolvePendingEvent: sequence_id=" + << sequence_id << ", handled=" << handled; auto iter = pending_events_.find(sequence_id); if (iter != pending_events_.end()) { PendingEvent* event = iter->second.get(); event->any_handled = event->any_handled || handled; event->unreplied -= 1; + FT_LOG(Error) << "KeyboardChannel::ResolvePendingEvent: unreplied=" + << event->unreplied << ", any_handled=" << event->any_handled; // If all handlers have replied, report if any of them handled the event. if (event->unreplied == 0) { + FT_LOG(Error) << "KeyboardChannel::ResolvePendingEvent: all handlers " + "replied, calling callback"; event->callback(event->any_handled); pending_events_.erase(iter); } return; } // The pending event should always be found. + FT_LOG(Error) << "KeyboardChannel::ResolvePendingEvent: pending event NOT " + "found for sequence_id=" + << sequence_id; FT_ASSERT_NOT_REACHED(); } diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index 7e2b3435..b373b79a 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -66,18 +66,29 @@ TextInputChannel::TextInputChannel( TextInputChannel::~TextInputChannel() {} void TextInputChannel::OnComposeBegin() { + FT_LOG(Error) << "TextInputChannel::OnComposeBegin: active_model_=" + << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { + FT_LOG(Error) + << "TextInputChannel::OnComposeBegin: active_model_ is null, returning"; return; } active_model_->BeginComposing(); } void TextInputChannel::OnComposeChange(const std::string& str, int cursor_pos) { + FT_LOG(Error) << "TextInputChannel::OnComposeChange: str=" << str + << ", cursor_pos=" << cursor_pos + << ", active_model_=" << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { + FT_LOG(Error) << "TextInputChannel::OnComposeChange: active_model_ is " + "null, returning"; return; } if (str == "") { // Enter pre-edit end stage. + FT_LOG(Error) << "TextInputChannel::OnComposeChange: empty str, entering " + "pre-edit end stage"; return; } active_model_->UpdateComposingText(str); @@ -85,12 +96,17 @@ void TextInputChannel::OnComposeChange(const std::string& str, int cursor_pos) { } void TextInputChannel::OnComposeEnd() { + FT_LOG(Error) << "TextInputChannel::OnComposeEnd: active_model_=" + << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { + FT_LOG(Error) + << "TextInputChannel::OnComposeEnd: active_model_ is null, returning"; return; } // Delete preedit-string, it will be committed. int count = active_model_->composing_range().extent() - active_model_->composing_range().base(); + FT_LOG(Error) << "TextInputChannel::OnComposeEnd: composing count=" << count; active_model_->CommitComposing(); active_model_->EndComposing(); @@ -99,11 +115,16 @@ void TextInputChannel::OnComposeEnd() { } void TextInputChannel::OnCommit(const std::string& str) { + FT_LOG(Error) << "TextInputChannel::OnCommit: str=" << str + << ", active_model_=" << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { + FT_LOG(Error) + << "TextInputChannel::OnCommit: active_model_ is null, returning"; return; } active_model_->AddText(str); if (active_model_->composing()) { + FT_LOG(Error) << "TextInputChannel::OnCommit: committing composing text"; active_model_->CommitComposing(); active_model_->EndComposing(); } @@ -116,12 +137,22 @@ bool TextInputChannel::SendKey(const char* key, uint32_t modifiers, uint32_t scan_code, bool is_down) { + FT_LOG(Error) << "TextInputChannel::SendKey: key=" << (key ? key : "null") + << ", string=" << (string ? string : "null") + << ", compose=" << (compose ? compose : "null") + << ", modifiers=" << modifiers << ", scan_code=" << scan_code + << ", is_down=" << is_down + << ", active_model_=" << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { + FT_LOG(Error) + << "TextInputChannel::SendKey: active_model_ is null, returning false"; return false; } if (is_down) { - return HandleKey(key, string, modifiers); + bool result = HandleKey(key, string, modifiers); + FT_LOG(Error) << "TextInputChannel::SendKey: HandleKey result=" << result; + return result; } return false; @@ -319,23 +350,32 @@ void TextInputChannel::SendStateUpdate() { bool TextInputChannel::HandleKey(const char* key, const char* string, uint32_t modifires) { + FT_LOG(Error) << "TextInputChannel::HandleKey: key=" << (key ? key : "null") + << ", string=" << (string ? string : "null") + << ", modifiers=" << modifires; bool needs_update = false; std::string key_str = key; if (string && strlen(string) == 1 && IsAsciiPrintableKey(string[0])) { // This is a fallback for printable keys not handled by IMF. + FT_LOG(Error) + << "TextInputChannel::HandleKey: printable key fallback, char=" + << string[0]; active_model_->AddCodePoint(string[0]); needs_update = true; } else if (key_str == "Return") { + FT_LOG(Error) << "TextInputChannel::HandleKey: Return key pressed"; EnterPressed(); return true; #ifdef TV_PROFILE } else if (key_str == "Select") { + FT_LOG(Error) << "TextInputChannel::HandleKey: Select key pressed"; SelectPressed(); return true; #endif } else { - FT_LOG(Info) << "Key[" << key << "] is unhandled."; + FT_LOG(Error) << "TextInputChannel::HandleKey: key[" << key + << "] is unhandled."; return false; } @@ -346,6 +386,9 @@ bool TextInputChannel::HandleKey(const char* key, } void TextInputChannel::EnterPressed() { + FT_LOG(Error) << "TextInputChannel::EnterPressed: input_type_=" << input_type_ + << ", input_action_=" << input_action_ + << ", client_id_=" << client_id_; if (input_type_ == kMultilineInputType) { active_model_->AddCodePoint('\n'); SendStateUpdate(); diff --git a/flutter/shell/platform/tizen/flutter_tizen_display_monitor.cc b/flutter/shell/platform/tizen/flutter_tizen_display_monitor.cc index 0a5bdf61..d9141772 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_display_monitor.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_display_monitor.cc @@ -3,7 +3,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include #include #include "flutter/shell/platform/tizen/flutter_tizen_display_monitor.h" @@ -29,12 +28,9 @@ void FlutterTizenDisplayMonitor::UpdateDisplays() { display.display_id = 0; display.single_display = true; - double fps = ecore_animator_frametime_get(); - if (fps <= 0.0) { - display.refresh_rate = 0.0; - } else { - display.refresh_rate = 1 / fps; - } + // Default to 60Hz refresh rate since the Tizen platform does not + // provide a direct API to query the display refresh rate. + display.refresh_rate = 60.0; int32_t width = 0, height = 0, dpi = 0; FlutterTizenView* view = engine_->view(); diff --git a/flutter/shell/platform/tizen/flutter_tizen_engine_unittest.cc b/flutter/shell/platform/tizen/flutter_tizen_engine_unittest.cc index 55978b69..0633bf92 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_engine_unittest.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_engine_unittest.cc @@ -4,7 +4,7 @@ #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" -#include +#include #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" #include "flutter/shell/platform/tizen/testing/engine_modifier.h" @@ -15,7 +15,7 @@ namespace testing { class FlutterTizenEngineTest : public ::testing::Test { public: - FlutterTizenEngineTest() { ecore_init(); } + FlutterTizenEngineTest() { tizen_core_wl_init(); } protected: void SetUp() { diff --git a/flutter/shell/platform/tizen/flutter_tizen_texture_registrar_unittests.cc b/flutter/shell/platform/tizen/flutter_tizen_texture_registrar_unittests.cc index 535bf476..1ab256c4 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_texture_registrar_unittests.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_texture_registrar_unittests.cc @@ -4,7 +4,7 @@ #include "flutter/shell/platform/tizen/flutter_tizen_texture_registrar.h" -#include +#include #include @@ -18,7 +18,7 @@ namespace testing { class FlutterTizenTextureRegistrarTest : public ::testing::Test { public: - FlutterTizenTextureRegistrarTest() { ecore_init(); } + FlutterTizenTextureRegistrarTest() { tizen_core_wl_init(); } protected: void SetUp() { diff --git a/flutter/shell/platform/tizen/flutter_tizen_view.cc b/flutter/shell/platform/tizen/flutter_tizen_view.cc index 8e665707..5b4102cb 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_view.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_view.cc @@ -250,6 +250,13 @@ void FlutterTizenView::OnKey(const char* key, uint32_t scan_code, const char* device_name, bool is_down) { + FT_LOG(Error) << "OnKey: key=" << (key ? key : "null") + << ", string=" << (string ? string : "null") + << ", compose=" << (compose ? compose : "null") + << ", modifiers=" << modifiers << ", scan_code=" << scan_code + << ", device_name=" << (device_name ? device_name : "null") + << ", is_down=" << is_down; + if (is_down) { FT_LOG(Info) << "Key symbol: " << key << ", code: 0x" << std::setw(8) << std::setfill('0') << std::right << std::hex << scan_code; @@ -257,6 +264,7 @@ void FlutterTizenView::OnKey(const char* key, // Do not handle the TV system menu key. if (strcmp(key, kSysMenuKey) == 0) { + FT_LOG(Error) << "OnKey: ignoring system menu key"; return; } @@ -266,25 +274,36 @@ void FlutterTizenView::OnKey(const char* key, } if (text_input_channel_) { + FT_LOG(Error) << "OnKey: sending to text_input_channel_"; if (text_input_channel_->SendKey(key, string, compose, modifiers, scan_code, is_down)) { + FT_LOG(Error) << "OnKey: handled by text_input_channel_"; return; } + FT_LOG(Error) << "OnKey: not handled by text_input_channel_"; + } else { + FT_LOG(Error) << "OnKey: text_input_channel_ is null"; } if (platform_view_channel_) { + FT_LOG(Error) << "OnKey: sending to platform_view_channel_"; if (platform_view_channel_->SendKey(key, string, compose, modifiers, scan_code, is_down)) { + FT_LOG(Error) << "OnKey: handled by platform_view_channel_"; return; } + FT_LOG(Error) << "OnKey: not handled by platform_view_channel_"; } if (engine_->keyboard_channel()) { + FT_LOG(Error) << "OnKey: sending to keyboard_channel_"; bool& backkey_handled = backkey_handled_; engine_->keyboard_channel()->SendKey( key, string, compose, modifiers, scan_code, is_down, [engine = engine_.get(), symbol = std::string(key), is_down, &backkey_handled](bool handled) { + FT_LOG(Error) << "OnKey: keyboard_channel_ callback, handled=" + << handled << ", symbol=" << symbol; // If System's back key is handled in key-down, it should be // handled so that "popRoute" is not called in key-up. if (symbol == kBackKey) { @@ -306,22 +325,33 @@ void FlutterTizenView::OnKey(const char* key, ui_app_exit(); } }); + } else { + FT_LOG(Error) << "OnKey: keyboard_channel_ is null"; } } void FlutterTizenView::OnComposeBegin() { + FT_LOG(Error) << "OnComposeBegin: text_input_channel_=" + << (text_input_channel_ ? "set" : "null"); text_input_channel_->OnComposeBegin(); } void FlutterTizenView::OnComposeChange(const std::string& str, int cursor_pos) { + FT_LOG(Error) << "OnComposeChange: str=" << str + << ", cursor_pos=" << cursor_pos << ", text_input_channel_=" + << (text_input_channel_ ? "set" : "null"); text_input_channel_->OnComposeChange(str, cursor_pos); } void FlutterTizenView::OnComposeEnd() { + FT_LOG(Error) << "OnComposeEnd: text_input_channel_=" + << (text_input_channel_ ? "set" : "null"); text_input_channel_->OnComposeEnd(); } void FlutterTizenView::OnCommit(const std::string& str) { + FT_LOG(Error) << "OnCommit: str=" << str << ", text_input_channel_=" + << (text_input_channel_ ? "set" : "null"); text_input_channel_->OnCommit(str); } diff --git a/flutter/shell/platform/tizen/public/flutter_tizen.h b/flutter/shell/platform/tizen/public/flutter_tizen.h index 6e9c27b4..466356cd 100644 --- a/flutter/shell/platform/tizen/public/flutter_tizen.h +++ b/flutter/shell/platform/tizen/public/flutter_tizen.h @@ -206,7 +206,7 @@ FLUTTER_EXPORT void FlutterDesktopViewDestroy(FlutterDesktopViewRef view); // Returns a native UI toolkit handle for manipulation in host application. // // Cast the returned void* -// - window ecore wl2 : to Ecore_Wl2_Window* +// - window ecore wl2 : to tizen_core_wl_window_h // @warning This API is a work-in-progress and may change. FLUTTER_EXPORT void* FlutterDesktopViewGetNativeHandle( FlutterDesktopViewRef view); diff --git a/flutter/shell/platform/tizen/tizen_clipboard.cc b/flutter/shell/platform/tizen/tizen_clipboard.cc index c8393aae..1c381cfa 100644 --- a/flutter/shell/platform/tizen/tizen_clipboard.cc +++ b/flutter/shell/platform/tizen/tizen_clipboard.cc @@ -4,6 +4,8 @@ #include "tizen_clipboard.h" +#include + #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_window.h" #include "flutter/shell/platform/tizen/tizen_window_ecore_wl2.h" @@ -18,75 +20,98 @@ constexpr char kMimeTypeTextPlain[] = "text/plain;charset=utf-8"; TizenClipboard::TizenClipboard(TizenViewBase* view) { if (auto* window = dynamic_cast(view)) { - auto* ecore_wl2_window = - static_cast(window->GetNativeHandle()); - display_ = ecore_wl2_window_display_get(ecore_wl2_window); + tizen_core_wl_window_h tcore_window = + static_cast(window->GetNativeHandle()); + tizen_core_wl_window_get_display(tcore_window, &display_); } else { - display_ = ecore_wl2_connected_display_get(NULL); + // tizen_core_wl_get_connected_display() will deprecated. + tizen_core_wl_get_connected_display(nullptr, &display_); } - send_handler = ecore_event_handler_add( - ECORE_WL2_EVENT_DATA_SOURCE_SEND, - [](void* data, int type, void* event) -> Eina_Bool { - auto* self = reinterpret_cast(data); + tizen_core_wl_display_get_event(display_, &tcore_wl_event_); + + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_DATA_SOURCE_SEND, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); self->SendData(event); - return ECORE_CALLBACK_PASS_ON; }, - this); - receive_handler = ecore_event_handler_add( - ECORE_WL2_EVENT_OFFER_DATA_READY, - [](void* data, int type, void* event) -> Eina_Bool { - auto* self = reinterpret_cast(data); + this, &send_listener_); + + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_DATA_READY, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); self->ReceiveData(event); - return ECORE_CALLBACK_PASS_ON; }, - this); + this, &receive_listener_); } TizenClipboard::~TizenClipboard() { on_data_callback_ = nullptr; - ecore_event_handler_del(send_handler); - ecore_event_handler_del(receive_handler); + if (send_listener_) { + tizen_core_wl_event_remove_listener(tcore_wl_event_, send_listener_); + } + if (receive_listener_) { + tizen_core_wl_event_remove_listener(tcore_wl_event_, receive_listener_); + } } void TizenClipboard::SendData(void* event) { if (!event) { return; } - auto* send_event = reinterpret_cast(event); - - // TODO(jsuya): If the type of Ecore_Wl2_Event_Data_Source_Send is empty, it - // is assumed to be "text/plain". - if (!send_event->type || (strlen(send_event->type) != 0 && - strcmp(send_event->type, kMimeTypeTextPlain))) { - FT_LOG(Error) << "Invaild mime type(" - << (send_event->type ? send_event->type : "null") << ")."; - if (send_event->fd >= 0) { - close(send_event->fd); + tizen_core_wl_event_data_source_send_h send_event = + static_cast(event); + + char* mime_type = nullptr; + tizen_core_wl_event_data_source_send_get_type(send_event, &mime_type); + int fd = -1; + tizen_core_wl_event_data_source_send_get_fd(send_event, &fd); + + // Get serial from base event. + tizen_core_wl_event_data_source_base_h base_event = + static_cast(event); + unsigned int serial = 0; + tizen_core_wl_event_data_source_base_get_serial(base_event, &serial); + + if (!mime_type || + (strlen(mime_type) != 0 && strcmp(mime_type, kMimeTypeTextPlain))) { + FT_LOG(Error) << "Invaild mime type(" << (mime_type ? mime_type : "null") + << ")."; + if (fd >= 0) { + close(fd); } return; } - if (send_event->serial != selection_serial_) { + if (serial != selection_serial_) { FT_LOG(Error) << "The serial doesn't match."; - if (send_event->fd >= 0) { - close(send_event->fd); + if (fd >= 0) { + close(fd); } return; } - write(send_event->fd, data_.c_str(), data_.length()); - close(send_event->fd); + write(fd, data_.c_str(), data_.length()); + close(fd); } void TizenClipboard::ReceiveData(void* event) { if (!event) { return; } - auto* ready_event = - reinterpret_cast(event); - if (ready_event->data == nullptr || ready_event->len < 1) { + tizen_core_wl_event_data_ready_h ready_event = + static_cast(event); + + void* raw_data = nullptr; + tizen_core_wl_event_data_ready_get_data(ready_event, &raw_data); + const char* data = static_cast(raw_data); + int len = 0; + tizen_core_wl_event_data_ready_get_len(ready_event, &len); + + if (data == nullptr || len < 1) { FT_LOG(Info) << "No data available."; if (on_data_callback_) { on_data_callback_(""); @@ -95,7 +120,10 @@ void TizenClipboard::ReceiveData(void* event) { return; } - if (ready_event->offer != selection_offer_) { + tizen_core_wl_data_offer_h offer = nullptr; + tizen_core_wl_event_data_ready_get_offer(ready_event, &offer); + + if (offer != selection_offer_) { FT_LOG(Error) << "The offer doesn't match."; if (on_data_callback_) { on_data_callback_(std::nullopt); @@ -104,14 +132,14 @@ void TizenClipboard::ReceiveData(void* event) { return; } - size_t data_length = strlen(ready_event->data); - size_t buffer_size = ready_event->len; + size_t data_length = strlen(data); + size_t buffer_size = len; std::string content; if (data_length < buffer_size) { - content.append(ready_event->data, data_length); + content.append(data, data_length); } else { - content.append(ready_event->data, buffer_size); + content.append(data, buffer_size); } if (on_data_callback_) { @@ -125,56 +153,91 @@ void TizenClipboard::SetData(const std::string& data) { const char* mime_types[3]; mime_types[0] = kMimeTypeTextPlain; - // TODO(jsuya): There is an issue where ECORE_WL2_EVENT_DATA_SOURCE_SEND event - // does not work properly even if ecore_wl2_dnd_selection_set() is called in - // Tizen 6.5 or lower. Therefore, add empty mimetype for event call from the - // cbhm module. Since it works normally from Tizen 8.0, this part may be - // modified in the future. mime_types[1] = ""; mime_types[2] = nullptr; - Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display_); - selection_serial_ = ecore_wl2_dnd_selection_set(input, mime_types); - ecore_wl2_display_flush(display_); + tizen_core_wl_seat_h default_seat = nullptr; + tizen_core_wl_display_get_default_seat(display_, &default_seat); + if (default_seat) { + tizen_core_wl_data_h data_handle = nullptr; + tizen_core_wl_seat_get_data(default_seat, &data_handle); + if (data_handle) { + tizen_core_wl_data_set_selection(data_handle, mime_types, + &selection_serial_); + } + } + tizen_core_wl_display_flush(display_); } bool TizenClipboard::GetData(ClipboardCallback on_data_callback) { on_data_callback_ = std::move(on_data_callback); - Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display_); - selection_offer_ = ecore_wl2_dnd_selection_get(input); + tizen_core_wl_seat_h default_seat = nullptr; + tizen_core_wl_display_get_default_seat(display_, &default_seat); + if (!default_seat) { + if (on_data_callback_) { + on_data_callback_ = nullptr; + } + return false; + } + + tizen_core_wl_data_h data_handle = nullptr; + tizen_core_wl_seat_get_data(default_seat, &data_handle); + if (!data_handle) { + if (on_data_callback_) { + on_data_callback_ = nullptr; + } + return false; + } + tizen_core_wl_data_offer_h offer = nullptr; + tizen_core_wl_data_get_selection(data_handle, &offer); + selection_offer_ = offer; if (!selection_offer_) { - FT_LOG(Error) << "ecore_wl2_dnd_selection_get() failed."; - + FT_LOG(Error) << "tizen_core_wl_data_get_selection() failed."; if (on_data_callback_) { on_data_callback_ = nullptr; } return false; } - ecore_wl2_offer_receive(selection_offer_, - const_cast(kMimeTypeTextPlain)); + tizen_core_wl_data_receive(selection_offer_, + const_cast(kMimeTypeTextPlain)); return true; } bool TizenClipboard::HasStrings() { - Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display_); - selection_offer_ = ecore_wl2_dnd_selection_get(input); + tizen_core_wl_seat_h default_seat = nullptr; + tizen_core_wl_display_get_default_seat(display_, &default_seat); + if (!default_seat) { + return false; + } + + tizen_core_wl_data_h data_handle = nullptr; + tizen_core_wl_seat_get_data(default_seat, &data_handle); + if (!data_handle) { + return false; + } + tizen_core_wl_data_offer_h offer = nullptr; + tizen_core_wl_data_get_selection(data_handle, &offer); + selection_offer_ = offer; if (!selection_offer_) { return false; } - Eina_Array* available_types = ecore_wl2_offer_mimes_get(selection_offer_); - unsigned int type_count = eina_array_count(available_types); + char** mimes = nullptr; + int mime_count = 0; + tizen_core_wl_data_get_mimes(selection_offer_, &mimes, &mime_count); - for (unsigned int i = 0; i < type_count; ++i) { - auto* available_type = - static_cast(eina_array_data_get(available_types, i)); - if (!strcmp(kMimeTypeTextPlain, available_type)) { - return true; + if (mimes) { + for (int i = 0; i < mime_count; ++i) { + if (mimes[i] && !strcmp(kMimeTypeTextPlain, mimes[i])) { + free(mimes); + return true; + } } + free(mimes); } return false; } diff --git a/flutter/shell/platform/tizen/tizen_clipboard.h b/flutter/shell/platform/tizen/tizen_clipboard.h index 244eafe8..2583f307 100644 --- a/flutter/shell/platform/tizen/tizen_clipboard.h +++ b/flutter/shell/platform/tizen/tizen_clipboard.h @@ -5,8 +5,7 @@ #ifndef EMBEDDER_TIZEN_CLIPBOARD_H_ #define EMBEDDER_TIZEN_CLIPBOARD_H_ -#define EFL_BETA_API_SUPPORT -#include +#include #include #include @@ -35,10 +34,11 @@ class TizenClipboard { std::string data_; ClipboardCallback on_data_callback_; uint32_t selection_serial_ = 0; - Ecore_Wl2_Offer* selection_offer_ = nullptr; - Ecore_Wl2_Display* display_ = nullptr; - Ecore_Event_Handler* send_handler = nullptr; - Ecore_Event_Handler* receive_handler = nullptr; + tizen_core_wl_data_offer_h selection_offer_ = nullptr; + tizen_core_wl_display_h display_ = nullptr; + tizen_core_event_h tcore_wl_event_ = nullptr; + tizen_core_wl_event_listener_h send_listener_ = nullptr; + tizen_core_wl_event_listener_h receive_listener_ = nullptr; }; } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_event_loop.cc b/flutter/shell/platform/tizen/tizen_event_loop.cc index ce528e3b..edf010f7 100644 --- a/flutter/shell/platform/tizen/tizen_event_loop.cc +++ b/flutter/shell/platform/tizen/tizen_event_loop.cc @@ -5,6 +5,8 @@ #include "tizen_event_loop.h" +#include + #include namespace flutter { @@ -15,17 +17,34 @@ TizenEventLoop::TizenEventLoop(std::thread::id main_thread_id, : main_thread_id_(main_thread_id), get_current_time_(get_current_time), on_task_expired_(std::move(on_task_expired)) { - ecore_pipe_ = ecore_pipe_add( - [](void* data, void* buffer, unsigned int nbyte) -> void { - auto* self = static_cast(data); - self->ExecuteTaskEvents(); - }, - this); + if (pipe(pipe_fds_) == 0) { + pipe_channel_ = g_io_channel_unix_new(pipe_fds_[0]); + pipe_watch_id_ = g_io_add_watch( + pipe_channel_, G_IO_IN, + [](GIOChannel* source, GIOCondition condition, + gpointer data) -> gboolean { + auto* self = static_cast(data); + char buf[64]; + read(self->pipe_fds_[0], buf, sizeof(buf)); + self->ExecuteTaskEvents(); + return G_SOURCE_CONTINUE; + }, + this); + } } TizenEventLoop::~TizenEventLoop() { - if (ecore_pipe_) { - ecore_pipe_del(ecore_pipe_); + if (pipe_watch_id_ > 0) { + g_source_remove(pipe_watch_id_); + } + if (pipe_channel_) { + g_io_channel_unref(pipe_channel_); + } + if (pipe_fds_[0] >= 0) { + close(pipe_fds_[0]); + } + if (pipe_fds_[1] >= 0) { + close(pipe_fds_[1]); } } @@ -74,19 +93,23 @@ void TizenEventLoop::PostTask(FlutterTask flutter_task, const double flutter_duration = static_cast(flutter_target_time_nanos) - get_current_time_(); if (flutter_duration > 0) { - ecore_timer_add( - flutter_duration / 1000000000.0, - [](void* data) -> Eina_Bool { - auto* self = static_cast(data); - if (self->ecore_pipe_) { - ecore_pipe_write(self->ecore_pipe_, nullptr, 0); + int* pipe_write_fd = new int(pipe_fds_[1]); + g_timeout_add( + static_cast(flutter_duration / 1000000.0), + [](gpointer data) -> gboolean { + int* fd = static_cast(data); + if (*fd >= 0) { + char c = 1; + write(*fd, &c, 1); } - return ECORE_CALLBACK_CANCEL; + delete fd; + return G_SOURCE_REMOVE; }, - this); + pipe_write_fd); } else { - if (ecore_pipe_) { - ecore_pipe_write(ecore_pipe_, nullptr, 0); + if (pipe_fds_[1] >= 0) { + char c = 1; + write(pipe_fds_[1], &c, 1); } } } diff --git a/flutter/shell/platform/tizen/tizen_event_loop.h b/flutter/shell/platform/tizen/tizen_event_loop.h index bf7817e6..83911975 100644 --- a/flutter/shell/platform/tizen/tizen_event_loop.h +++ b/flutter/shell/platform/tizen/tizen_event_loop.h @@ -6,7 +6,7 @@ #ifndef EMBEDDER_TIZEN_EVENT_LOOP_H_ #define EMBEDDER_TIZEN_EVENT_LOOP_H_ -#include +#include #include #include @@ -73,7 +73,9 @@ class TizenEventLoop { std::atomic task_order_ = 0; private: - Ecore_Pipe* ecore_pipe_ = nullptr; + int pipe_fds_[2] = {-1, -1}; + GIOChannel* pipe_channel_ = nullptr; + guint pipe_watch_id_ = 0; // Returns a TaskTimePoint computed from the given target time from Flutter. TaskTimePoint TimePointFromFlutterTime(uint64_t flutter_target_time_nanos); diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index 869d2c03..6b70a558 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -8,111 +8,120 @@ namespace { -const char* GetEcoreImfContextAvailableId() { - Eina_List* modules; - - modules = ecore_imf_context_available_ids_get(); - if (modules) { - void* module; - EINA_LIST_FREE(modules, module) { - return static_cast(module); - } - } - return nullptr; -} - -Ecore_IMF_Input_Panel_Layout TextInputTypeToEcoreImfInputPanelLayout( +tizen_core_imf_input_panel_layout_e TextInputTypeToImfInputPanelLayout( const std::string& text_input_type) { if (text_input_type == "TextInputType.text" || text_input_type == "TextInputType.multiline") { - return ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; } else if (text_input_type == "TextInputType.number") { - return ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY; + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY; } else if (text_input_type == "TextInputType.phone") { - return ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER; + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER; } else if (text_input_type == "TextInputType.datetime") { - return ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME; + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_DATETIME; } else if (text_input_type == "TextInputType.emailAddress" || text_input_type == "TextInputType.twitter") { - return ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL; + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_EMAIL; } else if (text_input_type == "TextInputType.url" || text_input_type == "TextInputType.webSearch") { - return ECORE_IMF_INPUT_PANEL_LAYOUT_URL; + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_URL; } else if (text_input_type == "TextInputType.visiblePassword") { - return ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD; + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD; } else { FT_LOG(Warn) << "The requested input type " << text_input_type << " is not supported."; - return ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; } } -Ecore_IMF_Keyboard_Modifiers EcoreInputModifiersToEcoreImfModifiers( - unsigned int ecore_modifiers) { - unsigned int modifiers(ECORE_IMF_KEYBOARD_MODIFIER_NONE); - if (ecore_modifiers & ECORE_EVENT_MODIFIER_SHIFT) { - modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT; +tizen_core_imf_keyboard_modifiers_e ModifiersToImfModifiers( + unsigned int modifiers) { + unsigned int imf_modifiers = TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_NONE; + if (modifiers & TIZEN_CORE_WL_MODIFIER_SHIFT) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_SHIFT; } - if (ecore_modifiers & ECORE_EVENT_MODIFIER_ALT) { - modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_ALT; + if (modifiers & TIZEN_CORE_WL_MODIFIER_ALT) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_ALT; } - if (ecore_modifiers & ECORE_EVENT_MODIFIER_CTRL) { - modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL; + if (modifiers & TIZEN_CORE_WL_MODIFIER_CTRL) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_CTRL; } - if (ecore_modifiers & ECORE_EVENT_MODIFIER_WIN) { - modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_WIN; + if (modifiers & TIZEN_CORE_WL_MODIFIER_WIN) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_WIN; } - if (ecore_modifiers & ECORE_EVENT_MODIFIER_ALTGR) { - modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR; + if (modifiers & TIZEN_CORE_WL_MODIFIER_ALTGR) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_ALTGR; } - return static_cast(modifiers); + return static_cast(imf_modifiers); } -Ecore_IMF_Keyboard_Locks EcoreInputModifiersToEcoreImfLocks( - unsigned int modifiers) { - // If no other matches, returns NONE. - unsigned int locks(ECORE_IMF_KEYBOARD_LOCK_NONE); - if (modifiers & ECORE_EVENT_LOCK_NUM) { - locks |= ECORE_IMF_KEYBOARD_LOCK_NUM; +tizen_core_imf_keyboard_locks_e ModifiersToImfLocks(unsigned int modifiers) { + unsigned int locks = TIZEN_CORE_IMF_KEYBOARD_LOCKS_NONE; + if (modifiers & TIZEN_CORE_WL_MODIFIER_NUM) { + locks |= TIZEN_CORE_IMF_KEYBOARD_LOCKS_NUM; } - if (modifiers & ECORE_EVENT_LOCK_CAPS) { - locks |= ECORE_IMF_KEYBOARD_LOCK_CAPS; + if (modifiers & TIZEN_CORE_WL_MODIFIER_CAPS) { + locks |= TIZEN_CORE_IMF_KEYBOARD_LOCKS_CAPS; } - if (modifiers & ECORE_EVENT_LOCK_SCROLL) { - locks |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; + if (modifiers & TIZEN_CORE_WL_MODIFIER_SCROLL) { + locks |= TIZEN_CORE_IMF_KEYBOARD_LOCKS_SCROLL; } - return static_cast(locks); + return static_cast(locks); } -template -T EcoreEventKeyToEcoreImfEvent(Ecore_Event_Key* event) { - T imf_event; - - imf_event.keyname = event->keyname; - imf_event.key = event->key; - imf_event.string = event->string; - imf_event.compose = event->compose; - imf_event.timestamp = event->timestamp; - imf_event.keycode = event->keycode; - - imf_event.modifiers = - EcoreInputModifiersToEcoreImfModifiers(event->modifiers); - imf_event.locks = EcoreInputModifiersToEcoreImfLocks(event->modifiers); - - if (event->dev) { - const char* device_name = ecore_device_name_get(event->dev); - imf_event.dev_name = device_name ? device_name : ""; - imf_event.dev_class = - static_cast(ecore_device_class_get(event->dev)); - imf_event.dev_subclass = static_cast( - ecore_device_subclass_get(event->dev)); - } else { - imf_event.dev_name = ""; - imf_event.dev_class = ECORE_IMF_DEVICE_CLASS_NONE; - imf_event.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE; +tizen_core_imf_event_key_h CreateImfKeyEventFromTcoreWlEvent(void* event) { + auto* ev = static_cast(event); + + tizen_core_imf_event_key_h imf_key = nullptr; + tizen_core_imf_event_key_create(&imf_key); + if (!imf_key) { + return nullptr; + } + + char* keyname = nullptr; + tizen_core_wl_event_key_get_keyname(ev, &keyname); + if (keyname) { + tizen_core_imf_event_key_set_keyname(imf_key, keyname); + tizen_core_imf_event_key_set_key(imf_key, keyname); + free(keyname); } - return imf_event; + char* keysymbol = nullptr; + tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); + if (keysymbol) { + tizen_core_imf_event_key_set_string(imf_key, keysymbol); + free(keysymbol); + } + + char* compose = nullptr; + tizen_core_wl_event_key_get_compose(ev, &compose); + if (compose) { + tizen_core_imf_event_key_set_compose(imf_key, compose); + free(compose); + } + + unsigned int keycode = 0; + tizen_core_wl_event_key_get_keycode(ev, &keycode); + tizen_core_imf_event_key_set_keycode(imf_key, keycode); + + unsigned int modifiers = 0; + tizen_core_wl_event_key_get_modifiers(ev, &modifiers); + tizen_core_imf_event_key_set_modifiers(imf_key, + ModifiersToImfModifiers(modifiers)); + tizen_core_imf_event_key_set_locks(imf_key, ModifiersToImfLocks(modifiers)); + + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + tizen_core_imf_event_key_set_timestamp(imf_key, timestamp); + + char* dev_identifier = nullptr; + tizen_core_wl_event_input_base_get_device_identifier(ev, &dev_identifier); + if (dev_identifier) { + tizen_core_imf_event_key_set_device_name(imf_key, dev_identifier); + free(dev_identifier); + } + + return imf_key; } } // namespace @@ -120,26 +129,16 @@ T EcoreEventKeyToEcoreImfEvent(Ecore_Event_Key* event) { namespace flutter { TizenInputMethodContext::TizenInputMethodContext(uintptr_t window_id) { - ecore_imf_init(); - - const char* imf_id = ecore_imf_context_default_id_get(); - if (imf_id == nullptr) { - // Try to get a fallback ID. - imf_id = GetEcoreImfContextAvailableId(); - } - if (imf_id == nullptr) { - FT_LOG(Error) << "Failed to get an IMF context ID."; - return; - } + tizen_core_imf_init(); - imf_context_ = ecore_imf_context_add(imf_id); - if (imf_context_ == nullptr) { - FT_LOG(Error) << "Failed to create Ecore_IMF_Context."; + if (tizen_core_imf_context_create(&imf_context_) != + TIZEN_CORE_IMF_ERROR_NONE) { + FT_LOG(Error) << "Failed to create tizen_core_imf_context."; return; } - ecore_imf_context_client_window_set(imf_context_, - reinterpret_cast(window_id)); + tizen_core_imf_context_set_client_window(imf_context_, + reinterpret_cast(window_id)); SetContextOptions(); SetInputPanelOptions(); RegisterEventCallbacks(); @@ -150,36 +149,35 @@ TizenInputMethodContext::~TizenInputMethodContext() { UnregisterInputPanelEventCallback(); UnregisterEventCallbacks(); -#ifdef NUI_SUPPORT - if (ecore_device_) { - ecore_device_del(ecore_device_); - } -#endif - if (imf_context_) { - ecore_imf_context_del(imf_context_); + tizen_core_imf_context_destroy(imf_context_); } - ecore_imf_shutdown(); + tizen_core_imf_shutdown(); } -bool TizenInputMethodContext::HandleEcoreEventKey(Ecore_Event_Key* event, - bool is_down) { +bool TizenInputMethodContext::HandleTcoreWlEventKey(void* event, bool is_down) { FT_ASSERT(imf_context_); FT_ASSERT(event); - Ecore_IMF_Event imf_event; - if (is_down) { - imf_event.key_down = - EcoreEventKeyToEcoreImfEvent(event); - return ecore_imf_context_filter_event(imf_context_, - ECORE_IMF_EVENT_KEY_DOWN, &imf_event); - } else { - imf_event.key_up = - EcoreEventKeyToEcoreImfEvent(event); - return ecore_imf_context_filter_event(imf_context_, ECORE_IMF_EVENT_KEY_UP, - &imf_event); + FT_LOG(Error) << "HandleTcoreWlEventKey: is_down=" << is_down; + + tizen_core_imf_event_key_h imf_key = CreateImfKeyEventFromTcoreWlEvent(event); + if (!imf_key) { + FT_LOG(Error) << "HandleTcoreWlEventKey: failed to create imf_key event"; + return false; } + + bool filter_result = false; + int ret = tizen_core_imf_context_filter_event( + imf_context_, + is_down ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN + : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, + imf_key, &filter_result); + FT_LOG(Error) << "HandleTcoreWlEventKey: filter_event ret=" << ret + << ", filter_result=" << filter_result; + tizen_core_imf_event_key_destroy(imf_key); + return filter_result; } #ifdef NUI_SUPPORT @@ -192,219 +190,245 @@ bool TizenInputMethodContext::HandleNuiKeyEvent(const char* device_name, uint32_t scan_code, size_t timestamp, bool is_down) { - Ecore_Event_Key event; - event.keyname = event.key = key ? key : ""; - event.string = string ? string : ""; - event.modifiers = modifiers; - event.keycode = scan_code; - event.timestamp = timestamp; - if (device_name) { - if (!ecore_device_) { - ecore_device_ = ecore_device_add(); - } - - event.dev = ecore_device_; - ecore_device_name_set(event.dev, device_name); - ecore_device_class_set(event.dev, - static_cast(device_class)); - ecore_device_subclass_set( - event.dev, static_cast(device_subclass)); + FT_LOG(Error) << "HandleNuiKeyEvent: key=" << (key ? key : "null") + << ", string=" << (string ? string : "null") + << ", modifiers=" << modifiers << ", scan_code=" << scan_code + << ", is_down=" << is_down; + + tizen_core_imf_event_key_h imf_key = nullptr; + tizen_core_imf_event_key_create(&imf_key); + if (!imf_key) { + FT_LOG(Error) << "HandleNuiKeyEvent: failed to create imf_key event"; + return false; } - Ecore_IMF_Event imf_event; - if (is_down) { - imf_event.key_down = - EcoreEventKeyToEcoreImfEvent(&event); - return ecore_imf_context_filter_event(imf_context_, - ECORE_IMF_EVENT_KEY_DOWN, &imf_event); - } else { - imf_event.key_up = - EcoreEventKeyToEcoreImfEvent(&event); - return ecore_imf_context_filter_event(imf_context_, ECORE_IMF_EVENT_KEY_UP, - &imf_event); + if (key) { + tizen_core_imf_event_key_set_keyname(imf_key, key); + tizen_core_imf_event_key_set_key(imf_key, key); + } + if (string) { + tizen_core_imf_event_key_set_string(imf_key, string); + } + + tizen_core_imf_event_key_set_modifiers(imf_key, + ModifiersToImfModifiers(modifiers)); + tizen_core_imf_event_key_set_locks(imf_key, ModifiersToImfLocks(modifiers)); + tizen_core_imf_event_key_set_keycode(imf_key, scan_code); + tizen_core_imf_event_key_set_timestamp(imf_key, timestamp); + + if (device_name) { + tizen_core_imf_event_key_set_device_name(imf_key, device_name); } + tizen_core_imf_event_key_set_device_class( + imf_key, static_cast(device_class)); + tizen_core_imf_event_key_set_device_subclass( + imf_key, static_cast(device_subclass)); + + bool filter_result = false; + int ret = tizen_core_imf_context_filter_event( + imf_context_, + is_down ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN + : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, + imf_key, &filter_result); + FT_LOG(Error) << "HandleNuiKeyEvent: filter_event ret=" << ret + << ", filter_result=" << filter_result; + tizen_core_imf_event_key_destroy(imf_key); + return filter_result; } #endif InputPanelGeometry TizenInputMethodContext::GetInputPanelGeometry() { FT_ASSERT(imf_context_); InputPanelGeometry geometry; - ecore_imf_context_input_panel_geometry_get( + tizen_core_imf_context_get_input_panel_geometry( imf_context_, &geometry.x, &geometry.y, &geometry.w, &geometry.h); return geometry; } void TizenInputMethodContext::ResetInputMethodContext() { FT_ASSERT(imf_context_); - ecore_imf_context_reset(imf_context_); + tizen_core_imf_context_reset(imf_context_); } void TizenInputMethodContext::ShowInputPanel() { FT_ASSERT(imf_context_); - ecore_imf_context_input_panel_show(imf_context_); - ecore_imf_context_focus_in(imf_context_); + FT_LOG(Error) << "ShowInputPanel: called"; + tizen_core_imf_context_input_panel_show(imf_context_); + tizen_core_imf_context_focus_in(imf_context_); } void TizenInputMethodContext::HideInputPanel() { FT_ASSERT(imf_context_); - ecore_imf_context_focus_out(imf_context_); - ecore_imf_context_input_panel_hide(imf_context_); + FT_LOG(Error) << "HideInputPanel: called"; + tizen_core_imf_context_focus_out(imf_context_); + tizen_core_imf_context_input_panel_hide(imf_context_); } bool TizenInputMethodContext::IsInputPanelShown() { - Ecore_IMF_Input_Panel_State state = - ecore_imf_context_input_panel_state_get(imf_context_); - return state == ECORE_IMF_INPUT_PANEL_STATE_SHOW; + tizen_core_imf_input_panel_state_e state; + int ret = tizen_core_imf_context_get_input_panel_state(imf_context_, &state); + FT_LOG(Error) << "IsInputPanelShown: ret=" << ret << ", state=" << state; + return state == TIZEN_CORE_IMF_INPUT_PANEL_STATE_SHOW; } void TizenInputMethodContext::SetInputPanelLayout( const std::string& input_type) { FT_ASSERT(imf_context_); - Ecore_IMF_Input_Panel_Layout panel_layout = - TextInputTypeToEcoreImfInputPanelLayout(input_type); - ecore_imf_context_input_panel_layout_set(imf_context_, panel_layout); + tizen_core_imf_input_panel_layout_e panel_layout = + TextInputTypeToImfInputPanelLayout(input_type); + tizen_core_imf_context_set_input_panel_layout(imf_context_, panel_layout); } void TizenInputMethodContext::SetInputPanelLayoutVariation(bool is_signed, bool is_decimal) { - Ecore_IMF_Input_Panel_Layout_Numberonly_Variation variation; + tizen_core_imf_layout_numberonly_variation_e variation; if (is_signed && is_decimal) { - variation = - ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL; + variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL; } else if (is_signed) { - variation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED; + variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_SIGNED; } else if (is_decimal) { - variation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_DECIMAL; + variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_DECIMAL; } else { - variation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_NORMAL; + variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_NORMAL; } - ecore_imf_context_input_panel_layout_variation_set(imf_context_, variation); + tizen_core_imf_context_set_input_panel_layout_variation(imf_context_, + variation); } void TizenInputMethodContext::SetAutocapitalType(const std::string& type) { - Ecore_IMF_Autocapital_Type autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE; + tizen_core_imf_autocapital_type_e autocapital_type = + TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_NONE; if (type == "TextCapitalization.characters") { - autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER; + autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER; } else if (type == "TextCapitalization.words") { - autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_WORD; + autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_WORD; } else if (type == "TextCapitalization.sentences") { - autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE; + autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_SENTENCE; } else if (type == "TextCapitalization.none") { - autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE; + autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_NONE; } - ecore_imf_context_autocapital_type_set(imf_context_, autocapital_type); + tizen_core_imf_context_set_autocapital_type(imf_context_, autocapital_type); } void TizenInputMethodContext::RegisterEventCallbacks() { FT_ASSERT(imf_context_); // commit callback - event_callbacks_[ECORE_IMF_CALLBACK_COMMIT] = - [](void* data, Ecore_IMF_Context* ctx, void* event_info) { + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_COMMIT] = + [](tizen_core_imf_context_h ctx, void* event_info, void* data) { auto* self = static_cast(data); char* str = static_cast(event_info); + FT_LOG(Error) << "IMF_CALLBACK_COMMIT: str=" << (str ? str : "null") + << ", on_commit_=" << (self->on_commit_ ? "set" : "null"); if (self->on_commit_) { self->on_commit_(str); } }; - ecore_imf_context_event_callback_add( - imf_context_, ECORE_IMF_CALLBACK_COMMIT, - event_callbacks_[ECORE_IMF_CALLBACK_COMMIT], this); + tizen_core_imf_context_add_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_COMMIT, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_COMMIT], this); // pre-edit start callback - event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_START] = - [](void* data, Ecore_IMF_Context* ctx, void* event_info) { + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START] = + [](tizen_core_imf_context_h ctx, void* event_info, void* data) { auto* self = static_cast(data); + FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_START: on_preedit_start_=" + << (self->on_preedit_start_ ? "set" : "null"); if (self->on_preedit_start_) { self->on_preedit_start_(); } }; - ecore_imf_context_event_callback_add( - imf_context_, ECORE_IMF_CALLBACK_PREEDIT_START, - event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_START], this); + tizen_core_imf_context_add_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_START, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START], this); // pre-edit end callback - event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_END] = - [](void* data, Ecore_IMF_Context* ctx, void* event_info) { + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END] = + [](tizen_core_imf_context_h ctx, void* event_info, void* data) { auto* self = static_cast(data); + FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_END: on_preedit_end_=" + << (self->on_preedit_end_ ? "set" : "null"); if (self->on_preedit_end_) { self->on_preedit_end_(); } }; - ecore_imf_context_event_callback_add( - imf_context_, ECORE_IMF_CALLBACK_PREEDIT_END, - event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_END], this); + tizen_core_imf_context_add_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_END, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END], this); // pre-edit changed callback - event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_CHANGED] = - [](void* data, Ecore_IMF_Context* ctx, void* event_info) { + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED] = + [](tizen_core_imf_context_h ctx, void* event_info, void* data) { auto* self = static_cast(data); + FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_CHANGED: on_preedit_changed_=" + << (self->on_preedit_changed_ ? "set" : "null"); if (self->on_preedit_changed_) { char* str = nullptr; int cursor_pos = 0; - ecore_imf_context_preedit_string_get(ctx, &str, &cursor_pos); + tizen_core_imf_context_get_preedit_string(ctx, &str, nullptr, nullptr, + &cursor_pos); + FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_CHANGED: str=" + << (str ? str : "null") + << ", cursor_pos=" << cursor_pos; if (str) { self->on_preedit_changed_(str, cursor_pos); free(str); } } }; - ecore_imf_context_event_callback_add( - imf_context_, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, - event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_CHANGED], this); + tizen_core_imf_context_add_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED], this); } void TizenInputMethodContext::UnregisterEventCallbacks() { FT_ASSERT(imf_context_); - ecore_imf_context_event_callback_del( - imf_context_, ECORE_IMF_CALLBACK_COMMIT, - event_callbacks_[ECORE_IMF_CALLBACK_COMMIT]); - ecore_imf_context_event_callback_del( - imf_context_, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, - event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_CHANGED]); - ecore_imf_context_event_callback_del( - imf_context_, ECORE_IMF_CALLBACK_PREEDIT_START, - event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_START]); - ecore_imf_context_event_callback_del( - imf_context_, ECORE_IMF_CALLBACK_PREEDIT_END, - event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_END]); + tizen_core_imf_context_del_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_COMMIT, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_COMMIT]); + tizen_core_imf_context_del_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED]); + tizen_core_imf_context_del_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_START, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START]); + tizen_core_imf_context_del_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_END, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END]); } void TizenInputMethodContext::SetContextOptions() { FT_ASSERT(imf_context_); - ecore_imf_context_autocapital_type_set(imf_context_, - ECORE_IMF_AUTOCAPITAL_TYPE_NONE); - ecore_imf_context_prediction_allow_set(imf_context_, EINA_FALSE); + tizen_core_imf_context_set_autocapital_type( + imf_context_, TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_NONE); } void TizenInputMethodContext::SetInputPanelOptions() { FT_ASSERT(imf_context_); - ecore_imf_context_input_panel_layout_set(imf_context_, - ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); - ecore_imf_context_input_panel_return_key_type_set( - imf_context_, ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT); - ecore_imf_context_input_panel_language_set( - imf_context_, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC); + tizen_core_imf_context_set_input_panel_layout( + imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); + tizen_core_imf_context_set_input_panel_return_key_type( + imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT); } void TizenInputMethodContext::InputPanelStateChangedCallback( - void* data, - Ecore_IMF_Context* ctx, - int value) { + tizen_core_imf_context_h ctx, + int value, + void* data) { auto* self = static_cast(data); - Ecore_IMF_Input_Panel_State state = - static_cast(value); + tizen_core_imf_input_panel_state_e state = + static_cast(value); std::string state_str; switch (state) { - case ECORE_IMF_INPUT_PANEL_STATE_SHOW: + case TIZEN_CORE_IMF_INPUT_PANEL_STATE_SHOW: state_str = "show"; break; - case ECORE_IMF_INPUT_PANEL_STATE_HIDE: + case TIZEN_CORE_IMF_INPUT_PANEL_STATE_HIDE: state_str = "hide"; break; - case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW: + case TIZEN_CORE_IMF_INPUT_PANEL_STATE_WILL_SHOW: state_str = "will_show"; break; default: @@ -412,6 +436,10 @@ void TizenInputMethodContext::InputPanelStateChangedCallback( break; } + FT_LOG(Error) << "InputPanelStateChangedCallback: state=" << state_str + << ", on_input_panel_state_changed_=" + << (self->on_input_panel_state_changed_ ? "set" : "null"); + if (self->on_input_panel_state_changed_) { self->on_input_panel_state_changed_(state_str); } @@ -420,16 +448,16 @@ void TizenInputMethodContext::InputPanelStateChangedCallback( void TizenInputMethodContext::RegisterInputPanelEventCallback() { FT_ASSERT(imf_context_); - ecore_imf_context_input_panel_event_callback_add( - imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, + tizen_core_imf_context_add_input_panel_event_callback( + imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_EVENT_STATE, InputPanelStateChangedCallback, this); } void TizenInputMethodContext::UnregisterInputPanelEventCallback() { FT_ASSERT(imf_context_); - ecore_imf_context_input_panel_event_callback_del( - imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, + tizen_core_imf_context_del_input_panel_event_callback( + imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_EVENT_STATE, InputPanelStateChangedCallback); } diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index 6915dd51..f0a0314d 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -5,8 +5,8 @@ #ifndef EMBEDDER_TIZEN_INPUT_METHOD_CONTEXT_H_ #define EMBEDDER_TIZEN_INPUT_METHOD_CONTEXT_H_ -#include -#include +#include +#include #include #include @@ -29,7 +29,7 @@ class TizenInputMethodContext { TizenInputMethodContext(uintptr_t window_id); ~TizenInputMethodContext(); - bool HandleEcoreEventKey(Ecore_Event_Key* event, bool is_down); + bool HandleTcoreWlEventKey(void* event, bool is_down); #ifdef NUI_SUPPORT bool HandleNuiKeyEvent(const char* device_name, @@ -79,9 +79,9 @@ class TizenInputMethodContext { void UnregisterInputPanelEventCallback(); private: - static void InputPanelStateChangedCallback(void* data, - Ecore_IMF_Context* ctx, - int value); + static void InputPanelStateChangedCallback(tizen_core_imf_context_h ctx, + int value, + void* data); void RegisterEventCallbacks(); void UnregisterEventCallbacks(); @@ -89,16 +89,13 @@ class TizenInputMethodContext { void SetContextOptions(); void SetInputPanelOptions(); -#ifdef NUI_SUPPORT - Ecore_Device* ecore_device_ = nullptr; -#endif - Ecore_IMF_Context* imf_context_ = nullptr; + tizen_core_imf_context_h imf_context_ = nullptr; OnCommit on_commit_; OnPreeditChanged on_preedit_changed_; OnPreeditStart on_preedit_start_; OnPreeditEnd on_preedit_end_; OnInputPanelStateChanged on_input_panel_state_changed_; - std::unordered_map + std::unordered_map event_callbacks_; }; diff --git a/flutter/shell/platform/tizen/tizen_renderer_egl.cc b/flutter/shell/platform/tizen/tizen_renderer_egl.cc index d618943c..ad103cab 100644 --- a/flutter/shell/platform/tizen/tizen_renderer_egl.cc +++ b/flutter/shell/platform/tizen/tizen_renderer_egl.cc @@ -4,8 +4,7 @@ #include "flutter/shell/platform/tizen/tizen_renderer_egl.h" -#define EFL_BETA_API_SUPPORT -#include +#include #include #include #ifdef NUI_SUPPORT @@ -94,8 +93,8 @@ bool TizenRendererEgl::CreateSurface(void* render_target, const EGLint attribs[] = {EGL_NONE}; if (render_target_display) { - const auto egl_window = ecore_wl2_egl_window_native_get( - static_cast(render_target)); + const auto egl_window = tizen_core_wl_egl_window_native_get( + static_cast(render_target)); egl_surface_ = eglCreateWindowSurface( egl_display_, egl_config_, reinterpret_cast(egl_window), attribs); diff --git a/flutter/shell/platform/tizen/tizen_view_nui.cc b/flutter/shell/platform/tizen/tizen_view_nui.cc index f3b93477..e4355560 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.cc +++ b/flutter/shell/platform/tizen/tizen_view_nui.cc @@ -88,15 +88,30 @@ void TizenViewNui::OnKey(const char* device_name, uint32_t scan_code, size_t timestamp, bool is_down) { + FT_LOG(Error) << "TizenViewNui::OnKey: key=" << (key ? key : "null") + << ", string=" << (string ? string : "null") + << ", compose=" << (compose ? compose : "null") + << ", modifiers=" << modifiers << ", scan_code=" << scan_code + << ", device_name=" << (device_name ? device_name : "null") + << ", device_class=" << device_class + << ", device_subclass=" << device_subclass + << ", timestamp=" << timestamp << ", is_down=" << is_down; + bool handled = false; if (input_method_context_->IsInputPanelShown()) { + FT_LOG(Error) << "TizenViewNui::OnKey: input panel shown, passing to " + "HandleNuiKeyEvent"; handled = input_method_context_->HandleNuiKeyEvent( device_name, device_class, device_subclass, key, string, modifiers, scan_code, timestamp, is_down); + FT_LOG(Error) << "TizenViewNui::OnKey: IMF handled=" << handled; + } else { + FT_LOG(Error) << "TizenViewNui::OnKey: input panel NOT shown"; } if (!handled) { + FT_LOG(Error) << "TizenViewNui::OnKey: forwarding to view_delegate_->OnKey"; view_delegate_->OnKey(key, string, compose, modifiers, scan_code, device_name, is_down); } diff --git a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc index 41d16b9d..f3514873 100644 --- a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc +++ b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc @@ -17,6 +17,21 @@ #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" +// Forward declarations for rotation APIs that exist in the library +// but are not yet declared in the public header. +extern "C" { +tizen_core_wl_error_e tizen_core_wl_window_set_rotation_angle( + tizen_core_wl_window_h window, + tizen_core_wl_window_angle_e angle); +tizen_core_wl_error_e tizen_core_wl_window_get_rotation_angle( + tizen_core_wl_window_h window, + tizen_core_wl_window_angle_e* angle); +tizen_core_wl_error_e tizen_core_wl_window_set_available_rotation_angle_list( + tizen_core_wl_window_h window, + tizen_core_wl_window_angle_e* available_angles, + size_t available_angle_count); +} + namespace flutter { namespace { @@ -29,7 +44,7 @@ constexpr char kSysMouseCursorPointerSizeVConfKey[] = "db/menu/system/mouse-pointer-size"; constexpr char kSysPointingDeviceSupportToastSharedPreferenceKey[] = "flutter-tizen/preference/pointing-device-support-toast"; -constexpr char kEcoreWL2InputCursorThemeName[] = "vd-cursors"; +constexpr char kTcoreWlInputCursorThemeName[] = "vd-cursors"; #endif FlutterPointerMouseButtons ToFlutterPointerButton(int32_t button) { @@ -42,16 +57,17 @@ FlutterPointerMouseButtons ToFlutterPointerButton(int32_t button) { } } -FlutterPointerDeviceKind ToFlutterDeviceKind(const Ecore_Device* dev) { - Ecore_Device_Class device_class = ecore_device_class_get(dev); - if (device_class == ECORE_DEVICE_CLASS_MOUSE) { - return kFlutterPointerDeviceKindMouse; - } else if (device_class == ECORE_DEVICE_CLASS_PEN) { - return kFlutterPointerDeviceKindStylus; - } else { - return kFlutterPointerDeviceKindTouch; - } -} +// FlutterPointerDeviceKind GetDeviceKindFromEventType(int event_type) { +// if (event_type == TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_DOWN || +// event_type == TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_UP || +// event_type == TIZEN_CORE_WL_EVENT_MOUSE_MOVE || +// event_type == TIZEN_CORE_WL_EVENT_MOUSE_WHEEL) { +// // The event system doesn't distinguish mouse vs touch at event level. +// // Default to touch; mouse events can be differentiated by touch_id == 0. +// return kFlutterPointerDeviceKindTouch; +// } +// return kFlutterPointerDeviceKindTouch; +// } #ifdef TV_PROFILE time_t GetBootTimeEpoch() { @@ -167,7 +183,7 @@ TizenWindowEcoreWl2::TizenWindowEcoreWl2(TizenGeometry geometry, RegisterEventHandlers(); PrepareInputMethod(); Show(); -} // namespace flutter +} TizenWindowEcoreWl2::~TizenWindowEcoreWl2() { UnregisterEventHandlers(); @@ -175,22 +191,41 @@ TizenWindowEcoreWl2::~TizenWindowEcoreWl2() { } bool TizenWindowEcoreWl2::CreateWindow(void* window_handle) { - if (!ecore_wl2_init()) { - FT_LOG(Error) << "Could not initialize Ecore Wl2."; + FT_LOG(Error) << "tizen core wl init()!!!!!!! "; + + if (tizen_core_wl_init() != TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Could not initialize tizen core wl."; return false; } - ecore_wl2_display_ = ecore_wl2_display_connect(nullptr); - if (!ecore_wl2_display_) { - FT_LOG(Error) << "Ecore Wl2 display not found."; + if (tizen_core_wl_display_create(&tcore_wl_display_) != + TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Could not create tizen core wl display."; return false; } - wl2_display_ = ecore_wl2_display_get(ecore_wl2_display_); - ecore_wl2_sync(); + if (tizen_core_wl_display_connect(tcore_wl_display_, nullptr) != + TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Tizen core wl display not found."; + return false; + } + + tizen_core_wl_display_private_get_wl_display(tcore_wl_display_, + &wl2_display_); + + tizen_core_wl_display_sync(tcore_wl_display_); - int32_t width, height; - ecore_wl2_display_screen_size_get(ecore_wl2_display_, &width, &height); + tizen_core_wl_display_get_event(tcore_wl_display_, &tcore_wl_event_); + + int32_t width = 0, height = 0; + GList* output_list = nullptr; + tizen_core_wl_display_get_output_device_list(tcore_wl_display_, &output_list); + if (output_list) { + tizen_core_wl_output_h output = + static_cast(output_list->data); + tizen_core_wl_output_device_get_geometry(output, &width, &height); + g_list_free(output_list); + } if (width == 0 || height == 0) { FT_LOG(Error) << "Invalid screen size: " << width << " x " << height; return false; @@ -204,79 +239,72 @@ bool TizenWindowEcoreWl2::CreateWindow(void* window_handle) { } if (window_handle == nullptr) { - ecore_wl2_window_ = - ecore_wl2_window_new(ecore_wl2_display_, nullptr, - initial_geometry_.left, initial_geometry_.top, - initial_geometry_.width, initial_geometry_.height); + if (tizen_core_wl_create_window( + tcore_wl_display_, nullptr, initial_geometry_.left, + initial_geometry_.top, initial_geometry_.width, + initial_geometry_.height, + &tcore_wl_window_) != TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Could not create tizen core wl window."; + return false; + } } else { - ecore_wl2_window_ = static_cast(window_handle); + tcore_wl_window_ = static_cast(window_handle); } if (is_vulkan_) { - wl2_surface_ = ecore_wl2_window_surface_get(ecore_wl2_window_); + tizen_core_wl_window_private_get_wl_surface(tcore_wl_window_, + &wl2_surface_); return wl2_surface_ && wl2_display_; } else { - ecore_wl2_egl_window_ = ecore_wl2_egl_window_create( - ecore_wl2_window_, initial_geometry_.width, initial_geometry_.height); - return ecore_wl2_egl_window_ && wl2_display_; + if (tizen_core_wl_create_egl_window( + tcore_wl_window_, initial_geometry_.width, initial_geometry_.height, + &tcore_wl_egl_window_) != TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Could not create tizen core wl egl window."; + return false; + } + return tcore_wl_egl_window_ && wl2_display_; } } void TizenWindowEcoreWl2::SetWindowOptions() { - // Change the window type to use the tizen policy for notification window - // according to top_level_. - // Note: ECORE_WL2_WINDOW_TYPE_TOPLEVEL is similar to "ELM_WIN_BASIC" and it - // does not mean that the window always will be overlaid on other apps :( - ecore_wl2_window_type_set(ecore_wl2_window_, - top_level_ ? ECORE_WL2_WINDOW_TYPE_NOTIFICATION - : ECORE_WL2_WINDOW_TYPE_TOPLEVEL); + tizen_core_wl_window_set_type( + tcore_wl_window_, top_level_ ? TIZEN_CORE_WL_WINDOW_TYPE_NOTIFICATION + : TIZEN_CORE_WL_WINDOW_TYPE_TOPLEVEL); if (top_level_) { - SetTizenPolicyNotificationLevel(TIZEN_POLICY_LEVEL_TOP); + SetNotificationLevel(TIZEN_CORE_WL_NOTIFICATION_LEVEL_TOP); } - ecore_wl2_window_position_set(ecore_wl2_window_, initial_geometry_.left, - initial_geometry_.top); - ecore_wl2_window_aux_hint_add(ecore_wl2_window_, 0, - "wm.policy.win.user.geometry", "1"); + tizen_core_wl_window_set_position(tcore_wl_window_, initial_geometry_.left, + initial_geometry_.top); + tizen_core_wl_window_set_aux_hint(tcore_wl_window_, + "wm.policy.win.user.geometry", "1"); - if (transparent_) { - ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_TRUE); - } else { - ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_FALSE); - } + tizen_core_wl_window_set_alpha(tcore_wl_window_, transparent_); if (!focusable_) { - ecore_wl2_window_focus_skip_set(ecore_wl2_window_, EINA_TRUE); + tizen_core_wl_window_set_focus_skip(tcore_wl_window_, true); } - ecore_wl2_window_indicator_state_set(ecore_wl2_window_, - ECORE_WL2_INDICATOR_STATE_ON); - ecore_wl2_window_indicator_opacity_set(ecore_wl2_window_, - ECORE_WL2_INDICATOR_OPAQUE); - ecore_wl2_indicator_visible_type_set(ecore_wl2_window_, - ECORE_WL2_INDICATOR_VISIBLE_TYPE_SHOWN); - #ifdef TV_PROFILE - int rotations[1] = {0}; // Default is only landscape. + tizen_core_wl_window_angle_e rotations[1] = {TIZEN_CORE_WL_WINDOW_ANGLE_0}; #else - int rotations[4] = {0, 90, 180, 270}; + tizen_core_wl_window_angle_e rotations[4] = { + TIZEN_CORE_WL_WINDOW_ANGLE_0, TIZEN_CORE_WL_WINDOW_ANGLE_90, + TIZEN_CORE_WL_WINDOW_ANGLE_180, TIZEN_CORE_WL_WINDOW_ANGLE_270}; #endif - ecore_wl2_window_available_rotations_set(ecore_wl2_window_, rotations, - sizeof(rotations) / sizeof(int)); + tizen_core_wl_window_set_available_rotation_angle_list( + tcore_wl_window_, rotations, sizeof(rotations) / sizeof(rotations[0])); EnableCursor(); } void TizenWindowEcoreWl2::EnableCursor() { #ifdef TV_PROFILE - // dlopen is used here because the TV-specific library libvd-win-util.so - // and the relevant headers are not present in the rootstrap. void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); if (!handle) { FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; return; } - // These functions are defined in vd-win-util's cursor_module.h. int (*CursorModule_Initialize)(wl_display* display, wl_registry* registry, wl_seat* seat, unsigned int id); int (*Cursor_Set_Config)(wl_surface* surface, uint32_t config_type, @@ -294,34 +322,41 @@ void TizenWindowEcoreWl2::EnableCursor() { return; } - wl_registry* registry = ecore_wl2_display_registry_get(ecore_wl2_display_); - wl_seat* seat = ecore_wl2_input_seat_get( - ecore_wl2_input_default_input_get(ecore_wl2_display_)); - if (!registry || !seat) { - FT_LOG(Error) - << "Could not retreive wl_registry or wl_seat from the display."; + tizen_core_wl_seat_h default_seat = nullptr; + tizen_core_wl_display_get_default_seat(tcore_wl_display_, &default_seat); + if (!default_seat) { + FT_LOG(Error) << "Could not get default seat."; + dlclose(handle); + return; + } + struct wl_seat* seat = nullptr; + tizen_core_wl_seat_private_get_wl_seat(default_seat, &seat); + if (!seat) { + FT_LOG(Error) << "Could not get wl_seat from the default seat."; dlclose(handle); return; } - Eina_Iterator* iter = ecore_wl2_display_globals_get(ecore_wl2_display_); - Ecore_Wl2_Global* global = nullptr; - - EINA_ITERATOR_FOREACH(iter, global) { - if (strcmp(global->interface, "tizen_cursor") == 0) { - if (!CursorModule_Initialize(wl2_display_, registry, seat, global->id)) { + int cursor_global_id = 0; + if (tizen_core_wl_display_private_get_global_id( + tcore_wl_display_, "tizen_cursor", &cursor_global_id) == + TIZEN_CORE_WL_ERROR_NONE && + cursor_global_id > 0) { + struct wl_registry* registry = wl_display_get_registry(wl2_display_); + if (registry) { + if (!CursorModule_Initialize(wl2_display_, registry, seat, + cursor_global_id)) { FT_LOG(Error) << "Failed to initialize the cursor module."; } + wl_registry_destroy(registry); } } - eina_iterator_free(iter); - ecore_wl2_sync(); + tizen_core_wl_display_sync(tcore_wl_display_); - wl_surface* surface = ecore_wl2_window_surface_get(ecore_wl2_window_); - // The config_type 1 refers to TIZEN_CURSOR_CONFIG_CURSOR_AVAILABLE - // defined in the TV extension protocol tizen-extension-tv.xml. - if (!Cursor_Set_Config(surface, 1, nullptr)) { + struct wl_surface* surface = nullptr; + tizen_core_wl_window_private_get_wl_surface(tcore_wl_window_, &surface); + if (surface && !Cursor_Set_Config(surface, 1, nullptr)) { FT_LOG(Error) << "Failed to set a cursor config value."; } @@ -335,16 +370,13 @@ typedef enum _MouseSupport { DISABLE = 0, ENABLE } MouseSupport; typedef enum _Device_Type { MOUSE_DEVICE = 3, TOUCH_DEVICE } Device_Type; void TizenWindowEcoreWl2::SetPointingDeviceSupport() { - // dlopen is used here because the TV-specific library libvd-win-util.so - // and the relevant headers are not present in the rootstrap. void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); if (!handle) { FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; return; } - // These functions are defined in vd-win-util's cursor_module.h. - int (*Mouse_Pointer_Support)(MouseSupport type, void* ecore_wl2_win); + int (*Mouse_Pointer_Support)(MouseSupport type, void* win); *(void**)(&Mouse_Pointer_Support) = dlsym(handle, "Mouse_Pointer_Support"); if (!Mouse_Pointer_Support) { @@ -354,21 +386,18 @@ void TizenWindowEcoreWl2::SetPointingDeviceSupport() { } Mouse_Pointer_Support(pointing_device_support_ ? ENABLE : DISABLE, - ecore_wl2_window_); + tcore_wl_window_); dlclose(handle); } void TizenWindowEcoreWl2::SetFloatingMenuSupport() { - // dlopen is used here because the TV-specific library libvd-win-util.so - // and the relevant headers are not present in the rootstrap. void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); if (!handle) { FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; return; } - // These functions are defined in vd-win-util's cursor_module.h. - int (*Mouse_Pointer_Not_Allow)(int enable, void* ecore_wl2_win); + int (*Mouse_Pointer_Not_Allow)(int enable, void* win); *(void**)(&Mouse_Pointer_Not_Allow) = dlsym(handle, "Mouse_Pointer_Not_Allow"); @@ -378,22 +407,19 @@ void TizenWindowEcoreWl2::SetFloatingMenuSupport() { return; } - Mouse_Pointer_Not_Allow(!floating_menu_support_, ecore_wl2_window_); + Mouse_Pointer_Not_Allow(!floating_menu_support_, tcore_wl_window_); dlclose(handle); } void TizenWindowEcoreWl2::ShowUnsupportedToast() { - // dlopen is used here because the TV-specific library libvd-win-util.so - // and the relevant headers are not present in the rootstrap. void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); if (!handle) { FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; return; } - // These functions are defined in vd-win-util's cursor_module.h. void (*Unsupported_Toast_Launch)(Device_Type type, int show, int enable, - void* ecore_wl2_win); + void* win); *(void**)(&Unsupported_Toast_Launch) = dlsym(handle, "Unsupported_Toast_Launch"); @@ -403,60 +429,75 @@ void TizenWindowEcoreWl2::ShowUnsupportedToast() { return; } - Unsupported_Toast_Launch(MOUSE_DEVICE, 1, 1, ecore_wl2_window_); + Unsupported_Toast_Launch(MOUSE_DEVICE, 1, 1, tcore_wl_window_); dlclose(handle); } #endif void TizenWindowEcoreWl2::RegisterEventHandlers() { - ecore_event_handlers_.push_back(ecore_event_handler_add( - ECORE_WL2_EVENT_WINDOW_ROTATE, - [](void* data, int type, void* event) -> Eina_Bool { + tizen_core_wl_event_listener_h listener = nullptr; + + // Window rotation event. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_WINDOW_ROTATION, + [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { - auto* rotation_event = - reinterpret_cast(event); - if (rotation_event->win == self->GetWindowId()) { - int32_t degree = rotation_event->angle; + auto* base_event = + static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_window_base_get_window(base_event, &event_window); + if (event_window == self->tcore_wl_window_) { + tizen_core_wl_event_window_rotation_h rot_event = nullptr; + tizen_core_wl_event_window_base_to_window_rotation(base_event, + &rot_event); + tizen_core_wl_window_angle_e angle = TIZEN_CORE_WL_WINDOW_ANGLE_0; + tizen_core_wl_event_window_rotation_get_angle(rot_event, &angle); + int degree = static_cast(angle); self->view_delegate_->OnRotate(degree); - TizenGeometry geometry = self->GetGeometry(); - ecore_wl2_window_rotation_set(self->ecore_wl2_window_, degree); - ecore_wl2_window_rotation_change_done_send( - self->ecore_wl2_window_, rotation_event->rotation, - geometry.width, geometry.height); - return ECORE_CALLBACK_DONE; + tizen_core_wl_window_set_rotation_angle( + self->tcore_wl_window_, + static_cast(degree)); + tizen_core_wl_window_send_rotation_change_done( + self->tcore_wl_window_, degree); } } - return ECORE_CALLBACK_PASS_ON; }, - this)); + this, &listener); + tcore_event_listeners_.push_back(listener); + + // Window configure event. if (!is_vulkan_) { - ecore_event_handlers_.push_back(ecore_event_handler_add( - ECORE_WL2_EVENT_WINDOW_CONFIGURE, - [](void* data, int type, void* event) -> Eina_Bool { + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_WINDOW_CONFIGURE_COMPLETE, + [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { - auto* configure_event = - reinterpret_cast(event); - if (configure_event->win == self->GetWindowId()) { - ecore_wl2_egl_window_resize_with_rotation( - self->ecore_wl2_egl_window_, configure_event->x, - configure_event->y, configure_event->w, configure_event->h, - self->GetRotation()); - - self->view_delegate_->OnResize( - configure_event->x, configure_event->y, configure_event->w, - configure_event->h); - return ECORE_CALLBACK_DONE; + auto* base_event = + static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_window_base_get_window(base_event, + &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0, w = 0, h = 0; + tizen_core_wl_window_get_geometry(self->tcore_wl_window_, &x, &y, + &w, &h); + int32_t rotation = self->GetRotation(); + tizen_core_wl_egl_window_resize(self->tcore_wl_egl_window_, w, h); + tizen_core_wl_egl_window_set_window_transform( + self->tcore_wl_egl_window_, rotation / 90); + self->view_delegate_->OnResize(x, y, w, h); } } - return ECORE_CALLBACK_PASS_ON; }, - this)); + this, &listener); + tcore_event_listeners_.push_back(listener); } - ecore_event_handlers_.push_back(ecore_event_handler_add( - ECORE_EVENT_MOUSE_BUTTON_DOWN, - [](void* data, int type, void* event) -> Eina_Bool { + + // Mouse button down. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_DOWN, + [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); #ifdef TV_PROFILE if ((!self->pointing_device_support_ || @@ -467,7 +508,6 @@ void TizenWindowEcoreWl2::RegisterEventHandlers() { self->SetFloatingMenuSupport(); } if (!shown) { - // Toast popup should be called first to set up D-PAD. self->ShowUnsupportedToast(); SetPointingDevicePreference(); } @@ -475,282 +515,458 @@ void TizenWindowEcoreWl2::RegisterEventHandlers() { if (self->floating_menu_support_ && !self->pointing_device_support_) { self->SetPointingDeviceSupport(); } - return ECORE_CALLBACK_PASS_ON; + return; } #endif - if (self->view_delegate_) { - auto* button_event = - reinterpret_cast(event); - if (button_event->window == self->GetWindowId()) { + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0; + tizen_core_wl_event_mouse_button_get_position(ev, &x, &y); + unsigned int buttons = 0; + tizen_core_wl_event_mouse_button_get_buttons(ev, &buttons); + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + unsigned int touch_id = 0; + tizen_core_wl_event_mouse_button_get_touch_id(ev, &touch_id); self->view_delegate_->OnPointerDown( - button_event->x, button_event->y, - ToFlutterPointerButton(button_event->buttons), - button_event->timestamp, ToFlutterDeviceKind(button_event->dev), - button_event->multi.device); - return ECORE_CALLBACK_DONE; + x, y, ToFlutterPointerButton(buttons), timestamp, + touch_id == 0 ? kFlutterPointerDeviceKindMouse + : kFlutterPointerDeviceKindTouch, + touch_id); } } - return ECORE_CALLBACK_PASS_ON; }, - this)); + this, &listener); + tcore_event_listeners_.push_back(listener); - ecore_event_handlers_.push_back(ecore_event_handler_add( - ECORE_EVENT_MOUSE_BUTTON_UP, - [](void* data, int type, void* event) -> Eina_Bool { + // Mouse button up. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_UP, + [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { - auto* button_event = - reinterpret_cast(event); - if (button_event->window == self->GetWindowId()) { + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0; + tizen_core_wl_event_mouse_button_get_position(ev, &x, &y); + unsigned int buttons = 0; + tizen_core_wl_event_mouse_button_get_buttons(ev, &buttons); + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + unsigned int touch_id = 0; + tizen_core_wl_event_mouse_button_get_touch_id(ev, &touch_id); self->view_delegate_->OnPointerUp( - button_event->x, button_event->y, - ToFlutterPointerButton(button_event->buttons), - button_event->timestamp, ToFlutterDeviceKind(button_event->dev), - button_event->multi.device); - return ECORE_CALLBACK_DONE; + x, y, ToFlutterPointerButton(buttons), timestamp, + touch_id == 0 ? kFlutterPointerDeviceKindMouse + : kFlutterPointerDeviceKindTouch, + touch_id); } } - return ECORE_CALLBACK_PASS_ON; }, - this)); + this, &listener); + tcore_event_listeners_.push_back(listener); - ecore_event_handlers_.push_back(ecore_event_handler_add( - ECORE_EVENT_MOUSE_MOVE, - [](void* data, int type, void* event) -> Eina_Bool { + // Mouse move. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_MOVE, + [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { - auto* move_event = reinterpret_cast(event); - if (move_event->window == self->GetWindowId()) { + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0; + tizen_core_wl_event_mouse_move_get_position(ev, &x, &y); + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + unsigned int touch_id = 0; + tizen_core_wl_event_mouse_move_get_touch_id(ev, &touch_id); self->view_delegate_->OnPointerMove( - move_event->x, move_event->y, move_event->timestamp, - ToFlutterDeviceKind(move_event->dev), move_event->multi.device); - return ECORE_CALLBACK_DONE; + x, y, timestamp, + touch_id == 0 ? kFlutterPointerDeviceKindMouse + : kFlutterPointerDeviceKindTouch, + touch_id); } } - return ECORE_CALLBACK_PASS_ON; }, - this)); + this, &listener); + tcore_event_listeners_.push_back(listener); - ecore_event_handlers_.push_back(ecore_event_handler_add( - ECORE_EVENT_MOUSE_WHEEL, - [](void* data, int type, void* event) -> Eina_Bool { + // Mouse wheel. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_WHEEL, + [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { - auto* wheel_event = reinterpret_cast(event); - if (wheel_event->window == self->GetWindowId()) { + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0; + tizen_core_wl_event_mouse_wheel_get_position(ev, &x, &y); + int direction = 0; + tizen_core_wl_event_mouse_wheel_get_direction(ev, &direction); + int z = 0; + tizen_core_wl_event_mouse_wheel_get_z(ev, &z); + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + double delta_x = 0.0; double delta_y = 0.0; - - if (wheel_event->direction == kScrollDirectionVertical) { - delta_y += wheel_event->z; - } else if (wheel_event->direction == kScrollDirectionHorizontal) { - delta_x += wheel_event->z; + if (direction == kScrollDirectionVertical) { + delta_y += z; + } else if (direction == kScrollDirectionHorizontal) { + delta_x += z; } - self->view_delegate_->OnScroll( - wheel_event->x, wheel_event->y, delta_x, delta_y, - wheel_event->timestamp, ToFlutterDeviceKind(wheel_event->dev), - 0); - return ECORE_CALLBACK_DONE; + self->view_delegate_->OnScroll(x, y, delta_x, delta_y, timestamp, + kFlutterPointerDeviceKindMouse, 0); } } - return ECORE_CALLBACK_PASS_ON; }, - this)); + this, &listener); + tcore_event_listeners_.push_back(listener); - ecore_event_handlers_.push_back(ecore_event_handler_add( - ECORE_EVENT_KEY_DOWN, - [](void* data, int type, void* event) -> Eina_Bool { + // Key down. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_DOWN, + [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [1] entered, view_delegate_=" + << (self->view_delegate_ ? "set" : "null") + << ", event=" << event; if (self->view_delegate_) { - auto* key_event = reinterpret_cast(event); - if (key_event->window == self->GetWindowId()) { + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [2] casting event to base"; + auto* ev = static_cast(event); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [3] ev=" << ev; + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [4] getting event window"; + tizen_core_wl_window_h event_window = nullptr; + int ret_get_window = + tizen_core_wl_event_input_base_get_window(ev, &event_window); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [5] get_window ret=" + << ret_get_window << ", event_window=" << event_window + << ", self_window=" << self->tcore_wl_window_; + + if (event_window == self->tcore_wl_window_) { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [6] window matched, extracting key info"; + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [7] getting keyname"; + char* keyname = nullptr; + tizen_core_wl_event_key_get_keyname(ev, &keyname); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [8] keyname=" + << (keyname ? keyname : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [9] getting keysymbol"; + char* keysymbol = nullptr; + tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [10] keysymbol=" + << (keysymbol ? keysymbol : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [11] getting compose"; + char* compose = nullptr; + tizen_core_wl_event_key_get_compose(ev, &compose); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [12] compose=" + << (compose ? compose : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [13] getting modifiers"; + unsigned int modifiers = 0; + tizen_core_wl_event_key_get_modifiers(ev, &modifiers); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [14] modifiers=" << modifiers; + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [15] getting keycode"; + unsigned int keycode = 0; + tizen_core_wl_event_key_get_keycode(ev, &keycode); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [16] keycode=" << keycode; + + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [17] getting device_identifier"; + char* dev_identifier = nullptr; + tizen_core_wl_event_input_base_get_device_identifier( + ev, &dev_identifier); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [18] dev_identifier=" + << (dev_identifier ? dev_identifier : "null"); + + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [19] checking input_method_context_=" + << (self->input_method_context_ ? "set" : "null"); bool handled = false; - if (self->input_method_context_->IsInputPanelShown()) { - handled = self->input_method_context_->HandleEcoreEventKey( - key_event, true); + if (self->input_method_context_) { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [20] calling IsInputPanelShown"; + bool panel_shown = + self->input_method_context_->IsInputPanelShown(); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [21] IsInputPanelShown=" + << panel_shown; + if (panel_shown) { + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [22] input panel shown, " + "calling HandleTcoreWlEventKey"; + handled = self->input_method_context_->HandleTcoreWlEventKey( + event, true); + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [23] IMF handled=" << handled; + } else { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [24] input panel NOT shown"; + } + } else { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [25] input_method_context_ is null"; } if (!handled) { - self->view_delegate_->OnKey( - key_event->key, key_event->string, key_event->compose, - key_event->modifiers, key_event->keycode, - ecore_device_name_get(key_event->dev), true); + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [26] calling view_delegate_->OnKey"; + self->view_delegate_->OnKey(keyname, keysymbol, compose, + modifiers, keycode, dev_identifier, + true); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [27] OnKey returned"; } - return ECORE_CALLBACK_DONE; + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [28] freeing keyname"; + free(keyname); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [29] freeing keysymbol"; + free(keysymbol); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [30] freeing compose"; + free(compose); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [31] freeing dev_identifier"; + free(dev_identifier); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [32] done"; + } else { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: event window mismatch, ignoring"; } } - return ECORE_CALLBACK_PASS_ON; }, - this)); + this, &listener); + tcore_event_listeners_.push_back(listener); - ecore_event_handlers_.push_back(ecore_event_handler_add( - ECORE_EVENT_KEY_UP, - [](void* data, int type, void* event) -> Eina_Bool { + // Key up. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_UP, + [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [1] entered, view_delegate_=" + << (self->view_delegate_ ? "set" : "null") + << ", event=" << event; if (self->view_delegate_) { - auto* key_event = reinterpret_cast(event); - if (key_event->window == self->GetWindowId()) { + FT_LOG(Error) << "WL_EVENT_KEY_UP: [2] casting event to base"; + auto* ev = static_cast(event); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [3] ev=" << ev; + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [4] getting event window"; + tizen_core_wl_window_h event_window = nullptr; + int ret_get_window = + tizen_core_wl_event_input_base_get_window(ev, &event_window); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [5] get_window ret=" + << ret_get_window << ", event_window=" << event_window + << ", self_window=" << self->tcore_wl_window_; + + if (event_window == self->tcore_wl_window_) { + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [6] window matched, extracting key info"; + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [7] getting keyname"; + char* keyname = nullptr; + tizen_core_wl_event_key_get_keyname(ev, &keyname); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [8] keyname=" + << (keyname ? keyname : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [9] getting keysymbol"; + char* keysymbol = nullptr; + tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [10] keysymbol=" + << (keysymbol ? keysymbol : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [11] getting compose"; + char* compose = nullptr; + tizen_core_wl_event_key_get_compose(ev, &compose); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [12] compose=" + << (compose ? compose : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [13] getting modifiers"; + unsigned int modifiers = 0; + tizen_core_wl_event_key_get_modifiers(ev, &modifiers); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [14] modifiers=" << modifiers; + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [15] getting keycode"; + unsigned int keycode = 0; + tizen_core_wl_event_key_get_keycode(ev, &keycode); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [16] keycode=" << keycode; + + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [17] checking input_method_context_=" + << (self->input_method_context_ ? "set" : "null"); bool handled = false; - if (self->input_method_context_->IsInputPanelShown()) { - handled = self->input_method_context_->HandleEcoreEventKey( - key_event, false); + if (self->input_method_context_) { + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [18] calling IsInputPanelShown"; + bool panel_shown = + self->input_method_context_->IsInputPanelShown(); + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [19] IsInputPanelShown=" << panel_shown; + if (panel_shown) { + FT_LOG(Error) << "WL_EVENT_KEY_UP: [20] input panel shown, " + "calling HandleTcoreWlEventKey"; + handled = self->input_method_context_->HandleTcoreWlEventKey( + event, false); + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [21] IMF handled=" << handled; + } else { + FT_LOG(Error) << "WL_EVENT_KEY_UP: [22] input panel NOT shown"; + } + } else { + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [23] input_method_context_ is null"; } if (!handled) { - self->view_delegate_->OnKey( - key_event->key, key_event->string, key_event->compose, - key_event->modifiers, key_event->keycode, nullptr, false); + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [24] calling view_delegate_->OnKey"; + self->view_delegate_->OnKey(keyname, keysymbol, compose, + modifiers, keycode, nullptr, false); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [25] OnKey returned"; } - return ECORE_CALLBACK_DONE; + FT_LOG(Error) << "WL_EVENT_KEY_UP: [26] freeing keyname"; + free(keyname); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [27] freeing keysymbol"; + free(keysymbol); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [28] freeing compose"; + free(compose); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [29] done"; + } else { + FT_LOG(Error) << "WL_EVENT_KEY_UP: event window mismatch, ignoring"; } } - return ECORE_CALLBACK_PASS_ON; }, - this)); + this, &listener); + tcore_event_listeners_.push_back(listener); } void TizenWindowEcoreWl2::UnregisterEventHandlers() { - for (Ecore_Event_Handler* handler : ecore_event_handlers_) { - ecore_event_handler_del(handler); + for (tizen_core_wl_event_listener_h listener : tcore_event_listeners_) { + tizen_core_wl_event_remove_listener(tcore_wl_event_, listener); } - ecore_event_handlers_.clear(); + tcore_event_listeners_.clear(); } void TizenWindowEcoreWl2::DestroyWindow() { - if (ecore_wl2_egl_window_) { - ecore_wl2_egl_window_destroy(ecore_wl2_egl_window_); - ecore_wl2_egl_window_ = nullptr; + if (tcore_wl_egl_window_) { + tizen_core_wl_egl_window_destroy(tcore_wl_egl_window_); + tcore_wl_egl_window_ = nullptr; } - if (ecore_wl2_window_) { - ecore_wl2_window_free(ecore_wl2_window_); - ecore_wl2_window_ = nullptr; + if (tcore_wl_window_) { + tizen_core_wl_window_destroy(tcore_wl_window_); + tcore_wl_window_ = nullptr; } - if (ecore_wl2_display_) { - ecore_wl2_display_disconnect(ecore_wl2_display_); - ecore_wl2_display_ = nullptr; + if (tcore_wl_display_) { + tizen_core_wl_display_disconnect(tcore_wl_display_); + tizen_core_wl_display_destroy(tcore_wl_display_); + tcore_wl_display_ = nullptr; } - ecore_wl2_shutdown(); + tizen_core_wl_shutdown(); } TizenGeometry TizenWindowEcoreWl2::GetGeometry() { TizenGeometry result; - ecore_wl2_window_geometry_get(ecore_wl2_window_, &result.left, &result.top, - &result.width, &result.height); + tizen_core_wl_window_get_geometry(tcore_wl_window_, &result.left, &result.top, + &result.width, &result.height); return result; } bool TizenWindowEcoreWl2::SetGeometry(TizenGeometry geometry) { - ecore_wl2_window_rotation_geometry_set(ecore_wl2_window_, GetRotation(), - geometry.left, geometry.top, - geometry.width, geometry.height); - // FIXME: The changes set in `ecore_wl2_window_geometry_set` seems to apply - // only after calling `ecore_wl2_window_position_set`. Call a more - // appropriate API that flushes geometry settings to the compositor. - ecore_wl2_window_position_set(ecore_wl2_window_, geometry.left, geometry.top); + tizen_core_wl_window_set_geometry(tcore_wl_window_, geometry.left, + geometry.top, geometry.width, + geometry.height); + tizen_core_wl_window_set_position(tcore_wl_window_, geometry.left, + geometry.top); return true; } TizenGeometry TizenWindowEcoreWl2::GetScreenGeometry() { TizenGeometry result = {}; - ecore_wl2_display_screen_size_get(ecore_wl2_display_, &result.width, - &result.height); + GList* output_list = nullptr; + tizen_core_wl_display_get_output_device_list(tcore_wl_display_, &output_list); + if (output_list) { + tizen_core_wl_output_h output = + static_cast(output_list->data); + tizen_core_wl_output_device_get_geometry(output, &result.width, + &result.height); + g_list_free(output_list); + } return result; } int32_t TizenWindowEcoreWl2::GetRotation() { - return ecore_wl2_window_rotation_get(ecore_wl2_window_); + tizen_core_wl_window_angle_e angle = TIZEN_CORE_WL_WINDOW_ANGLE_0; + tizen_core_wl_window_get_rotation_angle(tcore_wl_window_, &angle); + return static_cast(angle); } int32_t TizenWindowEcoreWl2::GetDpi() { - Ecore_Wl2_Output* output = ecore_wl2_window_output_find(ecore_wl2_window_); - if (!output) { - FT_LOG(Error) << "Could not find an output associated with the window."; + GList* output_list = nullptr; + tizen_core_wl_display_get_output_device_list(tcore_wl_display_, &output_list); + if (!output_list) { + FT_LOG(Error) << "Could not find an output device."; return 0; } - return ecore_wl2_output_dpi_get(output); + tizen_core_wl_output_h output = + static_cast(output_list->data); + g_list_free(output_list); + int dpi = 0; + tizen_core_wl_output_device_get_dpi(output, &dpi); + return dpi; } uintptr_t TizenWindowEcoreWl2::GetWindowId() { - return ecore_wl2_window_id_get(ecore_wl2_window_); -} - -void HandleResourceId(void* data, tizen_resource* tizen_resource, uint32_t id) { - if (data) { - *reinterpret_cast(data) = id; - } + return reinterpret_cast(tcore_wl_window_); } uint32_t TizenWindowEcoreWl2::GetResourceId() { if (resource_id_ > 0) { return resource_id_; } - struct wl_registry* registry = - ecore_wl2_display_registry_get(ecore_wl2_display_); - if (!registry) { - FT_LOG(Error) << "Could not retreive wl_registry from the display."; - return 0; - } - static const struct tizen_resource_listener tz_resource_listener = { - HandleResourceId}; - Eina_Iterator* iter = ecore_wl2_display_globals_get(ecore_wl2_display_); - Ecore_Wl2_Global* global = nullptr; - struct tizen_surface* surface = nullptr; - EINA_ITERATOR_FOREACH(iter, global) { - if (strcmp(global->interface, "tizen_surface") == 0) { - surface = static_cast(wl_registry_bind( - registry, global->id, &tizen_surface_interface, global->version)); - break; - } - } - eina_iterator_free(iter); - if (!surface) { - FT_LOG(Error) << "Failed to initialize the tizen surface."; - return 0; - } - - struct tizen_resource* resource = tizen_surface_get_tizen_resource( - surface, ecore_wl2_window_surface_get(ecore_wl2_window_)); - - if (!resource) { - FT_LOG(Error) << "Failed to get tizen resource."; - tizen_surface_destroy(surface); - return 0; - } - - struct wl_event_queue* event_queue = wl_display_create_queue(wl2_display_); - if (!event_queue) { - FT_LOG(Error) << "Failed to create wl_event_queue."; - tizen_resource_destroy(resource); - tizen_surface_destroy(surface); - return 0; + unsigned int res_id = 0; + if (tizen_core_wl_window_private_get_resource_id(tcore_wl_window_, &res_id) == + TIZEN_CORE_WL_ERROR_NONE) { + resource_id_ = res_id; } - wl_proxy_set_queue(reinterpret_cast(resource), event_queue); - tizen_resource_add_listener(resource, &tz_resource_listener, &resource_id_); - wl_display_roundtrip_queue(wl2_display_, event_queue); - tizen_resource_destroy(resource); - tizen_surface_destroy(surface); - wl_event_queue_destroy(event_queue); return resource_id_; } void TizenWindowEcoreWl2::SetPreferredOrientations( const std::vector& rotations) { - ecore_wl2_window_available_rotations_set(ecore_wl2_window_, rotations.data(), - rotations.size()); + std::vector angles; + for (int rot : rotations) { + angles.push_back(static_cast(rot)); + } + tizen_core_wl_window_set_available_rotation_angle_list( + tcore_wl_window_, angles.data(), angles.size()); } void TizenWindowEcoreWl2::BindKeys(const std::vector& keys) { for (const std::string& key : keys) { - ecore_wl2_window_keygrab_set(ecore_wl2_window_, key.c_str(), 0, 0, 0, - ECORE_WL2_WINDOW_KEYGRAB_TOPMOST); + tizen_core_wl_keygrab_info_h info = nullptr; + tizen_core_wl_keygrab_info_create(key.c_str(), + TIZEN_CORE_WL_KEYGRAB_TOPMOST, &info); + if (info) { + GList* list = g_list_append(nullptr, info); + tizen_core_wl_window_set_keygrab_list(tcore_wl_window_, list); + g_list_free(list); + tizen_core_wl_keygrab_info_destroy(info); + } } } void TizenWindowEcoreWl2::Show() { - ecore_wl2_window_show(ecore_wl2_window_); + tizen_core_wl_window_show(tcore_wl_window_); } void TizenWindowEcoreWl2::UpdateFlutterCursor(const std::string& kind) { @@ -762,31 +978,31 @@ void TizenWindowEcoreWl2::UpdateFlutterCursor(const std::string& kind) { std::string cursor_name = "normal_default"; if (kind == "basic") { - if (pointer_size == 0) { // Large. + if (pointer_size == 0) { cursor_name = "large_normal"; - } else if (pointer_size == 1) { // Medium. + } else if (pointer_size == 1) { cursor_name = "medium_normal"; - } else if (pointer_size == 2) { // Small. + } else if (pointer_size == 2) { cursor_name = "small_normal"; } else { cursor_name = "normal_default"; } } else if (kind == "click") { - if (pointer_size == 0) { // Large. + if (pointer_size == 0) { cursor_name = "large_normal_pnh"; - } else if (pointer_size == 1) { // Medium. + } else if (pointer_size == 1) { cursor_name = "medium_normal_pnh"; - } else if (pointer_size == 2) { // Small. + } else if (pointer_size == 2) { cursor_name = "small_normal_pnh"; } else { cursor_name = "normal_pnh"; } } else if (kind == "text") { - if (pointer_size == 0) { // Large. + if (pointer_size == 0) { cursor_name = "large_normal_input_field"; - } else if (pointer_size == 1) { // Medium. + } else if (pointer_size == 1) { cursor_name = "medium_normal_input_field"; - } else if (pointer_size == 2) { // Small. + } else if (pointer_size == 2) { cursor_name = "small_normal_input_field"; } else { cursor_name = "normal_input_field"; @@ -796,53 +1012,36 @@ void TizenWindowEcoreWl2::UpdateFlutterCursor(const std::string& kind) { } else { FT_LOG(Info) << kind << " cursor is not supported."; } - ecore_wl2_input_cursor_theme_name_set( - ecore_wl2_input_default_input_get(ecore_wl2_display_), - kEcoreWL2InputCursorThemeName); - ecore_wl2_input_cursor_from_name_set( - ecore_wl2_input_default_input_get(ecore_wl2_display_), - cursor_name.c_str()); + tizen_core_wl_seat_h default_seat = nullptr; + tizen_core_wl_display_get_default_seat(tcore_wl_display_, &default_seat); + if (default_seat) { + tizen_core_wl_seat_set_cursor_theme(default_seat, + kTcoreWlInputCursorThemeName); + tizen_core_wl_seat_set_cursor_name(default_seat, cursor_name.c_str()); + } else { + tizen_core_wl_seat_set_cursor_theme(default_seat, "default"); + tizen_core_wl_seat_set_cursor_name(default_seat, "left_ptr"); + } #else + tizen_core_wl_seat_h default_seat = nullptr; + tizen_core_wl_display_get_default_seat(tcore_wl_display_, &default_seat); + if (default_seat) { + tizen_core_wl_seat_set_cursor_theme(default_seat, "default"); + tizen_core_wl_seat_set_cursor_name(default_seat, "left_ptr"); + } FT_LOG(Info) << "UpdateFlutterCursor is not supported."; #endif } -void TizenWindowEcoreWl2::SetTizenPolicyNotificationLevel(int level) { - wl_registry* registry = ecore_wl2_display_registry_get(ecore_wl2_display_); - if (!registry) { - FT_LOG(Error) << "Could not retreive wl_registry from the display."; - return; - } - - Eina_Iterator* iter = ecore_wl2_display_globals_get(ecore_wl2_display_); - Ecore_Wl2_Global* global = nullptr; - - // Retrieve global objects to bind a tizen policy. - EINA_ITERATOR_FOREACH(iter, global) { - if (strcmp(global->interface, tizen_policy_interface.name) == 0) { - tizen_policy_ = static_cast( - wl_registry_bind(registry, global->id, &tizen_policy_interface, 1)); - break; - } - } - eina_iterator_free(iter); - - if (!tizen_policy_) { - FT_LOG(Error) - << "Failed to initialize the tizen policy handle, the top_level " - "attribute is ignored."; - return; - } - - tizen_policy_set_notification_level( - tizen_policy_, ecore_wl2_window_surface_get(ecore_wl2_window_), level); +void TizenWindowEcoreWl2::SetNotificationLevel(int level) { + tizen_core_wl_notification_set_level( + tcore_wl_window_, static_cast(level)); } void TizenWindowEcoreWl2::PrepareInputMethod() { input_method_context_ = std::make_unique(GetWindowId()); - // Set input method callbacks. input_method_context_->SetOnPreeditStart( [this]() { view_delegate_->OnComposeBegin(); }); input_method_context_->SetOnPreeditChanged( @@ -859,20 +1058,20 @@ void* TizenWindowEcoreWl2::GetRenderTarget() { if (is_vulkan_) { return wl2_surface_; } else { - return ecore_wl2_egl_window_; + return tcore_wl_egl_window_; } } void TizenWindowEcoreWl2::ActivateWindow() { - ecore_wl2_window_activate(ecore_wl2_window_); + tizen_core_wl_window_activate(tcore_wl_window_); } void TizenWindowEcoreWl2::RaiseWindow() { - ecore_wl2_window_raise(ecore_wl2_window_); + tizen_core_wl_window_raise(tcore_wl_window_); } void TizenWindowEcoreWl2::LowerWindow() { - ecore_wl2_window_lower(ecore_wl2_window_); + tizen_core_wl_window_lower(tcore_wl_window_); } } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.h b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.h index 3cc1a9d0..4ab113f2 100644 --- a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.h +++ b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.h @@ -5,8 +5,8 @@ #ifndef EMBEDDER_TIZEN_WINDOW_ECORE_WL2_H_ #define EMBEDDER_TIZEN_WINDOW_ECORE_WL2_H_ -#define EFL_BETA_API_SUPPORT -#include +#include +#include #include #include @@ -40,7 +40,7 @@ class TizenWindowEcoreWl2 : public TizenWindow { void* GetRenderTargetDisplay() override { return wl2_display_; } - void* GetNativeHandle() override { return ecore_wl2_window_; } + void* GetNativeHandle() override { return tcore_wl_window_; } int32_t GetRotation() override; @@ -85,17 +85,17 @@ class TizenWindowEcoreWl2 : public TizenWindow { void UnregisterEventHandlers(); - void SetTizenPolicyNotificationLevel(int level); + void SetNotificationLevel(int level); void PrepareInputMethod(); - Ecore_Wl2_Display* ecore_wl2_display_ = nullptr; - Ecore_Wl2_Window* ecore_wl2_window_ = nullptr; - Ecore_Wl2_Egl_Window* ecore_wl2_egl_window_ = nullptr; + tizen_core_wl_display_h tcore_wl_display_ = nullptr; + tizen_core_wl_window_h tcore_wl_window_ = nullptr; + tizen_core_wl_egl_window_h tcore_wl_egl_window_ = nullptr; + tizen_core_event_h tcore_wl_event_ = nullptr; wl_display* wl2_display_ = nullptr; wl_surface* wl2_surface_ = nullptr; - std::vector ecore_event_handlers_; - tizen_policy* tizen_policy_ = nullptr; + std::vector tcore_event_listeners_; uint32_t resource_id_ = 0; #ifdef TV_PROFILE diff --git a/flutter/third_party/accessibility/ax/ax_active_popup.h b/flutter/third_party/accessibility/ax/ax_active_popup.h index 39b8beda..94f15c66 100644 --- a/flutter/third_party/accessibility/ax/ax_active_popup.h +++ b/flutter/third_party/accessibility/ax/ax_active_popup.h @@ -5,6 +5,7 @@ #ifndef UI_ACCESSIBILITY_AX_ACTIVE_POPUP_H_ #define UI_ACCESSIBILITY_AX_ACTIVE_POPUP_H_ +#include #include #include "ax/ax_export.h" diff --git a/flutter/third_party/accessibility/ax/ax_event_generator.h b/flutter/third_party/accessibility/ax/ax_event_generator.h index 688cffcd..f66e5f0c 100644 --- a/flutter/third_party/accessibility/ax/ax_event_generator.h +++ b/flutter/third_party/accessibility/ax/ax_event_generator.h @@ -125,9 +125,13 @@ class AX_EXPORT AXEventGenerator : public AXTreeObserver { const EventParams& event_params; }; - class AX_EXPORT Iterator - : public std::iterator { + class AX_EXPORT Iterator { public: + using iterator_category = std::input_iterator_tag; + using value_type = TargetedEvent; + using difference_type = std::ptrdiff_t; + using pointer = TargetedEvent*; + using reference = TargetedEvent&; Iterator( const std::map>& map, const std::map>::const_iterator& head); diff --git a/tools/generate_sysroot.py b/tools/generate_sysroot.py index 8b036cd2..097c9fae 100755 --- a/tools/generate_sysroot.py +++ b/tools/generate_sysroot.py @@ -109,6 +109,14 @@ 'dali2-integration-devel', 'dali2-adaptor-integration-devel', 'dali2-toolkit-integration-devel', + 'tizen-core', + 'tizen-core-devel', + 'tizen-core-imf', + 'tizen-core-imf-devel', + 'tizen-core-wl', + 'tizen-core-wl-devel', + 'libwayland-egl-tizen', + 'libwayland-egl-tizen-devel', ] def generate_sysroot(sysroot: Path, api_version: float, arch: str, quiet=False): From 2dda99a9a026a49b549afd8fe72836b5085f0018 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Fri, 15 May 2026 16:32:46 +0900 Subject: [PATCH 02/11] Add --use-tcore option for tizen-core-wl API support This commit adds support for building with either ecore or tizen-core-wl API: - Add --use-tcore option to tools/gn script - Add use_tcore variable to BUILDCONFIG.gn - Split window implementation into: - tizen_window_ecore_wl2.cc/h (ecore version) - tizen_window_tcore_wl.cc/h (tcore version) - Split input method context into: - tizen_input_method_context.cc/h (ecore version) - tizen_input_method_context_tcore.cc/h (tcore version) - Add conditional compilation in flutter_tizen.cc and tizen_view_base.h - Add conditional include paths and libraries in BUILD.gn Usage: # Build with ecore (default) ./tools/gn --target-cpu arm64 --api-version 6.0 --target-toolchain /usr/lib/llvm-17 # Build with tcore ./tools/gn --target-cpu arm64 --api-version 6.0 --use-tcore --target-toolchain /usr/lib/llvm-17 --- build/config/BUILDCONFIG.gn | 3 + flutter/shell/platform/tizen/BUILD.gn | 65 +- flutter/shell/platform/tizen/flutter_tizen.cc | 13 + .../tizen/tizen_input_method_context.cc | 464 ++++--- .../tizen/tizen_input_method_context.h | 19 +- .../tizen/tizen_input_method_context_tcore.cc | 464 +++++++ .../tizen/tizen_input_method_context_tcore.h | 104 ++ .../platform/tizen/tizen_renderer_egl.cc | 7 +- .../shell/platform/tizen/tizen_view_base.h | 4 + .../platform/tizen/tizen_window_ecore_wl2.cc | 893 ++++++-------- .../platform/tizen/tizen_window_ecore_wl2.h | 18 +- .../platform/tizen/tizen_window_tcore_wl.cc | 1077 +++++++++++++++++ .../platform/tizen/tizen_window_tcore_wl.h | 111 ++ tools/gn | 6 + 14 files changed, 2428 insertions(+), 820 deletions(-) create mode 100644 flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc create mode 100644 flutter/shell/platform/tizen/tizen_input_method_context_tcore.h create mode 100644 flutter/shell/platform/tizen/tizen_window_tcore_wl.cc create mode 100644 flutter/shell/platform/tizen/tizen_window_tcore_wl.h diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 65876b36..baea25a7 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -31,6 +31,9 @@ declare_args() { # Use the system libstdc++ without building third_party/libcxx from source. use_system_cxx = false + + # Use tizen-core-wl API instead of ecore. + use_tcore = false } _default_configs = [ diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index 5fba7c67..c3fe2cd0 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -19,9 +19,6 @@ config("flutter_tizen_config") { "${sysroot_path}/usr/include/dlog", "${sysroot_path}/usr/include/feedback", "${sysroot_path}/usr/include/system", - "${sysroot_path}/usr/include/tizen-core", - "${sysroot_path}/usr/include/tizen-core-imf", - "${sysroot_path}/usr/include/tizen-core-wl", "${sysroot_path}/usr/include/tzsh", "${sysroot_path}/usr/include/vconf", "${sysroot_path}/usr/include/wayland-extension", @@ -29,6 +26,28 @@ config("flutter_tizen_config") { "${sysroot_path}/usr/lib/glib-2.0/include", ] + # tcore-specific includes + if (use_tcore) { + include_dirs += [ + "${sysroot_path}/usr/include/tizen-core", + "${sysroot_path}/usr/include/tizen-core-imf", + "${sysroot_path}/usr/include/tizen-core-wl", + ] + } else { + # ecore-specific includes + include_dirs += [ + "${sysroot_path}/usr/include/ecore-1", + "${sysroot_path}/usr/include/ecore-imf-1", + "${sysroot_path}/usr/include/ecore-input-1", + "${sysroot_path}/usr/include/ecore-wayland-1", + "${sysroot_path}/usr/include/ecore-wl2-1", + "${sysroot_path}/usr/include/efl-1", + "${sysroot_path}/usr/include/eina-1", + "${sysroot_path}/usr/include/eina-1/eina", + "${sysroot_path}/usr/include/eo-1", + ] + } + cflags_cc = [ "-Wno-newline-eof", "-Wno-macro-redefined", @@ -87,14 +106,25 @@ template("embedder") { "logger.cc", "system_utils.cc", "tizen_event_loop.cc", - "tizen_input_method_context.cc", "tizen_renderer.cc", "tizen_renderer_egl.cc", "tizen_renderer_gl.cc", "tizen_vsync_waiter.cc", - "tizen_window_ecore_wl2.cc", ] + # Select window implementation based on use_tcore + if (use_tcore) { + sources += [ + "tizen_window_tcore_wl.cc", + "tizen_input_method_context_tcore.cc", + ] + } else { + sources += [ + "tizen_window_ecore_wl2.cc", + "tizen_input_method_context.cc", + ] + } + lib_dirs = [ "//engine/${target_cpu}" ] libs = [ @@ -107,9 +137,6 @@ template("embedder") { "capi-system-info", "capi-system-system-settings", "dlog", - "tizen-core", - "tizen-core-imf", - "tizen-core-wl", "glib-2.0", "gio-2.0", "feedback", @@ -123,6 +150,23 @@ template("embedder") { "GLESv2", ] + # tcore-specific or ecore-specific libraries + if (use_tcore) { + libs += [ + "tizen-core", + "tizen-core-imf", + "tizen-core-wl", + ] + } else { + libs += [ + "ecore", + "ecore_imf", + "ecore_input", + "ecore_wl2", + "eina", + ] + } + if (target_name == "flutter_tizen_common" || target_name == "flutter_tizen_common_experimental") { sources += [ "channels/tizen_shell.cc" ] @@ -136,6 +180,11 @@ template("embedder") { defines += invoker.defines defines += [ "FLUTTER_ENGINE_NO_PROTOTYPES" ] + # Add USE_TCORE_WL define when using tcore + if (use_tcore) { + defines += [ "USE_TCORE_WL" ] + } + if (target_name == "flutter_tizen_mobile_experimental" || target_name == "flutter_tizen_tv_experimental" || target_name == "flutter_tizen_common_experimental") { diff --git a/flutter/shell/platform/tizen/flutter_tizen.cc b/flutter/shell/platform/tizen/flutter_tizen.cc index 9615b111..c87e3732 100644 --- a/flutter/shell/platform/tizen/flutter_tizen.cc +++ b/flutter/shell/platform/tizen/flutter_tizen.cc @@ -20,7 +20,11 @@ #include "flutter/shell/platform/tizen/tizen_view_nui.h" #endif #include "flutter/shell/platform/tizen/tizen_window.h" +#ifdef USE_TCORE_WL +#include "flutter/shell/platform/tizen/tizen_window_tcore_wl.h" +#else #include "flutter/shell/platform/tizen/tizen_window_ecore_wl2.h" +#endif namespace { @@ -201,12 +205,21 @@ FlutterDesktopViewRef FlutterDesktopViewCreateFromNewWindow( std::unique_ptr window; +#ifdef USE_TCORE_WL + window = std::make_unique( + window_geometry, window_properties.transparent, + window_properties.focusable, window_properties.top_level, + window_properties.pointing_device_support, + window_properties.floating_menu_support, window_properties.window_handle, + window_properties.renderer_type == kEVulkan); +#else window = std::make_unique( window_geometry, window_properties.transparent, window_properties.focusable, window_properties.top_level, window_properties.pointing_device_support, window_properties.floating_menu_support, window_properties.window_handle, window_properties.renderer_type == kEVulkan); +#endif auto view = std::make_unique( flutter::kImplicitViewId, std::move(window), diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index 6b70a558..869d2c03 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -8,120 +8,111 @@ namespace { -tizen_core_imf_input_panel_layout_e TextInputTypeToImfInputPanelLayout( +const char* GetEcoreImfContextAvailableId() { + Eina_List* modules; + + modules = ecore_imf_context_available_ids_get(); + if (modules) { + void* module; + EINA_LIST_FREE(modules, module) { + return static_cast(module); + } + } + return nullptr; +} + +Ecore_IMF_Input_Panel_Layout TextInputTypeToEcoreImfInputPanelLayout( const std::string& text_input_type) { if (text_input_type == "TextInputType.text" || text_input_type == "TextInputType.multiline") { - return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; + return ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; } else if (text_input_type == "TextInputType.number") { - return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY; + return ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY; } else if (text_input_type == "TextInputType.phone") { - return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER; + return ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER; } else if (text_input_type == "TextInputType.datetime") { - return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_DATETIME; + return ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME; } else if (text_input_type == "TextInputType.emailAddress" || text_input_type == "TextInputType.twitter") { - return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_EMAIL; + return ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL; } else if (text_input_type == "TextInputType.url" || text_input_type == "TextInputType.webSearch") { - return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_URL; + return ECORE_IMF_INPUT_PANEL_LAYOUT_URL; } else if (text_input_type == "TextInputType.visiblePassword") { - return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD; + return ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD; } else { FT_LOG(Warn) << "The requested input type " << text_input_type << " is not supported."; - return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; + return ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; } } -tizen_core_imf_keyboard_modifiers_e ModifiersToImfModifiers( - unsigned int modifiers) { - unsigned int imf_modifiers = TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_NONE; - if (modifiers & TIZEN_CORE_WL_MODIFIER_SHIFT) { - imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_SHIFT; +Ecore_IMF_Keyboard_Modifiers EcoreInputModifiersToEcoreImfModifiers( + unsigned int ecore_modifiers) { + unsigned int modifiers(ECORE_IMF_KEYBOARD_MODIFIER_NONE); + if (ecore_modifiers & ECORE_EVENT_MODIFIER_SHIFT) { + modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT; } - if (modifiers & TIZEN_CORE_WL_MODIFIER_ALT) { - imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_ALT; + if (ecore_modifiers & ECORE_EVENT_MODIFIER_ALT) { + modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_ALT; } - if (modifiers & TIZEN_CORE_WL_MODIFIER_CTRL) { - imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_CTRL; + if (ecore_modifiers & ECORE_EVENT_MODIFIER_CTRL) { + modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL; } - if (modifiers & TIZEN_CORE_WL_MODIFIER_WIN) { - imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_WIN; + if (ecore_modifiers & ECORE_EVENT_MODIFIER_WIN) { + modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_WIN; } - if (modifiers & TIZEN_CORE_WL_MODIFIER_ALTGR) { - imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_ALTGR; + if (ecore_modifiers & ECORE_EVENT_MODIFIER_ALTGR) { + modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR; } - return static_cast(imf_modifiers); + return static_cast(modifiers); } -tizen_core_imf_keyboard_locks_e ModifiersToImfLocks(unsigned int modifiers) { - unsigned int locks = TIZEN_CORE_IMF_KEYBOARD_LOCKS_NONE; - if (modifiers & TIZEN_CORE_WL_MODIFIER_NUM) { - locks |= TIZEN_CORE_IMF_KEYBOARD_LOCKS_NUM; +Ecore_IMF_Keyboard_Locks EcoreInputModifiersToEcoreImfLocks( + unsigned int modifiers) { + // If no other matches, returns NONE. + unsigned int locks(ECORE_IMF_KEYBOARD_LOCK_NONE); + if (modifiers & ECORE_EVENT_LOCK_NUM) { + locks |= ECORE_IMF_KEYBOARD_LOCK_NUM; } - if (modifiers & TIZEN_CORE_WL_MODIFIER_CAPS) { - locks |= TIZEN_CORE_IMF_KEYBOARD_LOCKS_CAPS; + if (modifiers & ECORE_EVENT_LOCK_CAPS) { + locks |= ECORE_IMF_KEYBOARD_LOCK_CAPS; } - if (modifiers & TIZEN_CORE_WL_MODIFIER_SCROLL) { - locks |= TIZEN_CORE_IMF_KEYBOARD_LOCKS_SCROLL; + if (modifiers & ECORE_EVENT_LOCK_SCROLL) { + locks |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; } - return static_cast(locks); + return static_cast(locks); } -tizen_core_imf_event_key_h CreateImfKeyEventFromTcoreWlEvent(void* event) { - auto* ev = static_cast(event); - - tizen_core_imf_event_key_h imf_key = nullptr; - tizen_core_imf_event_key_create(&imf_key); - if (!imf_key) { - return nullptr; - } - - char* keyname = nullptr; - tizen_core_wl_event_key_get_keyname(ev, &keyname); - if (keyname) { - tizen_core_imf_event_key_set_keyname(imf_key, keyname); - tizen_core_imf_event_key_set_key(imf_key, keyname); - free(keyname); - } - - char* keysymbol = nullptr; - tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); - if (keysymbol) { - tizen_core_imf_event_key_set_string(imf_key, keysymbol); - free(keysymbol); - } - - char* compose = nullptr; - tizen_core_wl_event_key_get_compose(ev, &compose); - if (compose) { - tizen_core_imf_event_key_set_compose(imf_key, compose); - free(compose); - } - - unsigned int keycode = 0; - tizen_core_wl_event_key_get_keycode(ev, &keycode); - tizen_core_imf_event_key_set_keycode(imf_key, keycode); - - unsigned int modifiers = 0; - tizen_core_wl_event_key_get_modifiers(ev, &modifiers); - tizen_core_imf_event_key_set_modifiers(imf_key, - ModifiersToImfModifiers(modifiers)); - tizen_core_imf_event_key_set_locks(imf_key, ModifiersToImfLocks(modifiers)); - - uint32_t timestamp = 0; - tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); - tizen_core_imf_event_key_set_timestamp(imf_key, timestamp); - - char* dev_identifier = nullptr; - tizen_core_wl_event_input_base_get_device_identifier(ev, &dev_identifier); - if (dev_identifier) { - tizen_core_imf_event_key_set_device_name(imf_key, dev_identifier); - free(dev_identifier); +template +T EcoreEventKeyToEcoreImfEvent(Ecore_Event_Key* event) { + T imf_event; + + imf_event.keyname = event->keyname; + imf_event.key = event->key; + imf_event.string = event->string; + imf_event.compose = event->compose; + imf_event.timestamp = event->timestamp; + imf_event.keycode = event->keycode; + + imf_event.modifiers = + EcoreInputModifiersToEcoreImfModifiers(event->modifiers); + imf_event.locks = EcoreInputModifiersToEcoreImfLocks(event->modifiers); + + if (event->dev) { + const char* device_name = ecore_device_name_get(event->dev); + imf_event.dev_name = device_name ? device_name : ""; + imf_event.dev_class = + static_cast(ecore_device_class_get(event->dev)); + imf_event.dev_subclass = static_cast( + ecore_device_subclass_get(event->dev)); + } else { + imf_event.dev_name = ""; + imf_event.dev_class = ECORE_IMF_DEVICE_CLASS_NONE; + imf_event.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE; } - return imf_key; + return imf_event; } } // namespace @@ -129,16 +120,26 @@ tizen_core_imf_event_key_h CreateImfKeyEventFromTcoreWlEvent(void* event) { namespace flutter { TizenInputMethodContext::TizenInputMethodContext(uintptr_t window_id) { - tizen_core_imf_init(); + ecore_imf_init(); + + const char* imf_id = ecore_imf_context_default_id_get(); + if (imf_id == nullptr) { + // Try to get a fallback ID. + imf_id = GetEcoreImfContextAvailableId(); + } + if (imf_id == nullptr) { + FT_LOG(Error) << "Failed to get an IMF context ID."; + return; + } - if (tizen_core_imf_context_create(&imf_context_) != - TIZEN_CORE_IMF_ERROR_NONE) { - FT_LOG(Error) << "Failed to create tizen_core_imf_context."; + imf_context_ = ecore_imf_context_add(imf_id); + if (imf_context_ == nullptr) { + FT_LOG(Error) << "Failed to create Ecore_IMF_Context."; return; } - tizen_core_imf_context_set_client_window(imf_context_, - reinterpret_cast(window_id)); + ecore_imf_context_client_window_set(imf_context_, + reinterpret_cast(window_id)); SetContextOptions(); SetInputPanelOptions(); RegisterEventCallbacks(); @@ -149,35 +150,36 @@ TizenInputMethodContext::~TizenInputMethodContext() { UnregisterInputPanelEventCallback(); UnregisterEventCallbacks(); +#ifdef NUI_SUPPORT + if (ecore_device_) { + ecore_device_del(ecore_device_); + } +#endif + if (imf_context_) { - tizen_core_imf_context_destroy(imf_context_); + ecore_imf_context_del(imf_context_); } - tizen_core_imf_shutdown(); + ecore_imf_shutdown(); } -bool TizenInputMethodContext::HandleTcoreWlEventKey(void* event, bool is_down) { +bool TizenInputMethodContext::HandleEcoreEventKey(Ecore_Event_Key* event, + bool is_down) { FT_ASSERT(imf_context_); FT_ASSERT(event); - FT_LOG(Error) << "HandleTcoreWlEventKey: is_down=" << is_down; - - tizen_core_imf_event_key_h imf_key = CreateImfKeyEventFromTcoreWlEvent(event); - if (!imf_key) { - FT_LOG(Error) << "HandleTcoreWlEventKey: failed to create imf_key event"; - return false; + Ecore_IMF_Event imf_event; + if (is_down) { + imf_event.key_down = + EcoreEventKeyToEcoreImfEvent(event); + return ecore_imf_context_filter_event(imf_context_, + ECORE_IMF_EVENT_KEY_DOWN, &imf_event); + } else { + imf_event.key_up = + EcoreEventKeyToEcoreImfEvent(event); + return ecore_imf_context_filter_event(imf_context_, ECORE_IMF_EVENT_KEY_UP, + &imf_event); } - - bool filter_result = false; - int ret = tizen_core_imf_context_filter_event( - imf_context_, - is_down ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN - : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, - imf_key, &filter_result); - FT_LOG(Error) << "HandleTcoreWlEventKey: filter_event ret=" << ret - << ", filter_result=" << filter_result; - tizen_core_imf_event_key_destroy(imf_key); - return filter_result; } #ifdef NUI_SUPPORT @@ -190,245 +192,219 @@ bool TizenInputMethodContext::HandleNuiKeyEvent(const char* device_name, uint32_t scan_code, size_t timestamp, bool is_down) { - FT_LOG(Error) << "HandleNuiKeyEvent: key=" << (key ? key : "null") - << ", string=" << (string ? string : "null") - << ", modifiers=" << modifiers << ", scan_code=" << scan_code - << ", is_down=" << is_down; - - tizen_core_imf_event_key_h imf_key = nullptr; - tizen_core_imf_event_key_create(&imf_key); - if (!imf_key) { - FT_LOG(Error) << "HandleNuiKeyEvent: failed to create imf_key event"; - return false; - } - - if (key) { - tizen_core_imf_event_key_set_keyname(imf_key, key); - tizen_core_imf_event_key_set_key(imf_key, key); - } - if (string) { - tizen_core_imf_event_key_set_string(imf_key, string); + Ecore_Event_Key event; + event.keyname = event.key = key ? key : ""; + event.string = string ? string : ""; + event.modifiers = modifiers; + event.keycode = scan_code; + event.timestamp = timestamp; + if (device_name) { + if (!ecore_device_) { + ecore_device_ = ecore_device_add(); + } + + event.dev = ecore_device_; + ecore_device_name_set(event.dev, device_name); + ecore_device_class_set(event.dev, + static_cast(device_class)); + ecore_device_subclass_set( + event.dev, static_cast(device_subclass)); } - tizen_core_imf_event_key_set_modifiers(imf_key, - ModifiersToImfModifiers(modifiers)); - tizen_core_imf_event_key_set_locks(imf_key, ModifiersToImfLocks(modifiers)); - tizen_core_imf_event_key_set_keycode(imf_key, scan_code); - tizen_core_imf_event_key_set_timestamp(imf_key, timestamp); - - if (device_name) { - tizen_core_imf_event_key_set_device_name(imf_key, device_name); + Ecore_IMF_Event imf_event; + if (is_down) { + imf_event.key_down = + EcoreEventKeyToEcoreImfEvent(&event); + return ecore_imf_context_filter_event(imf_context_, + ECORE_IMF_EVENT_KEY_DOWN, &imf_event); + } else { + imf_event.key_up = + EcoreEventKeyToEcoreImfEvent(&event); + return ecore_imf_context_filter_event(imf_context_, ECORE_IMF_EVENT_KEY_UP, + &imf_event); } - tizen_core_imf_event_key_set_device_class( - imf_key, static_cast(device_class)); - tizen_core_imf_event_key_set_device_subclass( - imf_key, static_cast(device_subclass)); - - bool filter_result = false; - int ret = tizen_core_imf_context_filter_event( - imf_context_, - is_down ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN - : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, - imf_key, &filter_result); - FT_LOG(Error) << "HandleNuiKeyEvent: filter_event ret=" << ret - << ", filter_result=" << filter_result; - tizen_core_imf_event_key_destroy(imf_key); - return filter_result; } #endif InputPanelGeometry TizenInputMethodContext::GetInputPanelGeometry() { FT_ASSERT(imf_context_); InputPanelGeometry geometry; - tizen_core_imf_context_get_input_panel_geometry( + ecore_imf_context_input_panel_geometry_get( imf_context_, &geometry.x, &geometry.y, &geometry.w, &geometry.h); return geometry; } void TizenInputMethodContext::ResetInputMethodContext() { FT_ASSERT(imf_context_); - tizen_core_imf_context_reset(imf_context_); + ecore_imf_context_reset(imf_context_); } void TizenInputMethodContext::ShowInputPanel() { FT_ASSERT(imf_context_); - FT_LOG(Error) << "ShowInputPanel: called"; - tizen_core_imf_context_input_panel_show(imf_context_); - tizen_core_imf_context_focus_in(imf_context_); + ecore_imf_context_input_panel_show(imf_context_); + ecore_imf_context_focus_in(imf_context_); } void TizenInputMethodContext::HideInputPanel() { FT_ASSERT(imf_context_); - FT_LOG(Error) << "HideInputPanel: called"; - tizen_core_imf_context_focus_out(imf_context_); - tizen_core_imf_context_input_panel_hide(imf_context_); + ecore_imf_context_focus_out(imf_context_); + ecore_imf_context_input_panel_hide(imf_context_); } bool TizenInputMethodContext::IsInputPanelShown() { - tizen_core_imf_input_panel_state_e state; - int ret = tizen_core_imf_context_get_input_panel_state(imf_context_, &state); - FT_LOG(Error) << "IsInputPanelShown: ret=" << ret << ", state=" << state; - return state == TIZEN_CORE_IMF_INPUT_PANEL_STATE_SHOW; + Ecore_IMF_Input_Panel_State state = + ecore_imf_context_input_panel_state_get(imf_context_); + return state == ECORE_IMF_INPUT_PANEL_STATE_SHOW; } void TizenInputMethodContext::SetInputPanelLayout( const std::string& input_type) { FT_ASSERT(imf_context_); - tizen_core_imf_input_panel_layout_e panel_layout = - TextInputTypeToImfInputPanelLayout(input_type); - tizen_core_imf_context_set_input_panel_layout(imf_context_, panel_layout); + Ecore_IMF_Input_Panel_Layout panel_layout = + TextInputTypeToEcoreImfInputPanelLayout(input_type); + ecore_imf_context_input_panel_layout_set(imf_context_, panel_layout); } void TizenInputMethodContext::SetInputPanelLayoutVariation(bool is_signed, bool is_decimal) { - tizen_core_imf_layout_numberonly_variation_e variation; + Ecore_IMF_Input_Panel_Layout_Numberonly_Variation variation; if (is_signed && is_decimal) { - variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL; + variation = + ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL; } else if (is_signed) { - variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_SIGNED; + variation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED; } else if (is_decimal) { - variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_DECIMAL; + variation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_DECIMAL; } else { - variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_NORMAL; + variation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_NORMAL; } - tizen_core_imf_context_set_input_panel_layout_variation(imf_context_, - variation); + ecore_imf_context_input_panel_layout_variation_set(imf_context_, variation); } void TizenInputMethodContext::SetAutocapitalType(const std::string& type) { - tizen_core_imf_autocapital_type_e autocapital_type = - TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_NONE; + Ecore_IMF_Autocapital_Type autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE; if (type == "TextCapitalization.characters") { - autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER; + autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER; } else if (type == "TextCapitalization.words") { - autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_WORD; + autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_WORD; } else if (type == "TextCapitalization.sentences") { - autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_SENTENCE; + autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE; } else if (type == "TextCapitalization.none") { - autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_NONE; + autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE; } - tizen_core_imf_context_set_autocapital_type(imf_context_, autocapital_type); + ecore_imf_context_autocapital_type_set(imf_context_, autocapital_type); } void TizenInputMethodContext::RegisterEventCallbacks() { FT_ASSERT(imf_context_); // commit callback - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_COMMIT] = - [](tizen_core_imf_context_h ctx, void* event_info, void* data) { + event_callbacks_[ECORE_IMF_CALLBACK_COMMIT] = + [](void* data, Ecore_IMF_Context* ctx, void* event_info) { auto* self = static_cast(data); char* str = static_cast(event_info); - FT_LOG(Error) << "IMF_CALLBACK_COMMIT: str=" << (str ? str : "null") - << ", on_commit_=" << (self->on_commit_ ? "set" : "null"); if (self->on_commit_) { self->on_commit_(str); } }; - tizen_core_imf_context_add_event_callback( - imf_context_, TIZEN_CORE_IMF_CALLBACK_COMMIT, - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_COMMIT], this); + ecore_imf_context_event_callback_add( + imf_context_, ECORE_IMF_CALLBACK_COMMIT, + event_callbacks_[ECORE_IMF_CALLBACK_COMMIT], this); // pre-edit start callback - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START] = - [](tizen_core_imf_context_h ctx, void* event_info, void* data) { + event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_START] = + [](void* data, Ecore_IMF_Context* ctx, void* event_info) { auto* self = static_cast(data); - FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_START: on_preedit_start_=" - << (self->on_preedit_start_ ? "set" : "null"); if (self->on_preedit_start_) { self->on_preedit_start_(); } }; - tizen_core_imf_context_add_event_callback( - imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_START, - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START], this); + ecore_imf_context_event_callback_add( + imf_context_, ECORE_IMF_CALLBACK_PREEDIT_START, + event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_START], this); // pre-edit end callback - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END] = - [](tizen_core_imf_context_h ctx, void* event_info, void* data) { + event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_END] = + [](void* data, Ecore_IMF_Context* ctx, void* event_info) { auto* self = static_cast(data); - FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_END: on_preedit_end_=" - << (self->on_preedit_end_ ? "set" : "null"); if (self->on_preedit_end_) { self->on_preedit_end_(); } }; - tizen_core_imf_context_add_event_callback( - imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_END, - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END], this); + ecore_imf_context_event_callback_add( + imf_context_, ECORE_IMF_CALLBACK_PREEDIT_END, + event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_END], this); // pre-edit changed callback - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED] = - [](tizen_core_imf_context_h ctx, void* event_info, void* data) { + event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_CHANGED] = + [](void* data, Ecore_IMF_Context* ctx, void* event_info) { auto* self = static_cast(data); - FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_CHANGED: on_preedit_changed_=" - << (self->on_preedit_changed_ ? "set" : "null"); if (self->on_preedit_changed_) { char* str = nullptr; int cursor_pos = 0; - tizen_core_imf_context_get_preedit_string(ctx, &str, nullptr, nullptr, - &cursor_pos); - FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_CHANGED: str=" - << (str ? str : "null") - << ", cursor_pos=" << cursor_pos; + ecore_imf_context_preedit_string_get(ctx, &str, &cursor_pos); if (str) { self->on_preedit_changed_(str, cursor_pos); free(str); } } }; - tizen_core_imf_context_add_event_callback( - imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED, - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED], this); + ecore_imf_context_event_callback_add( + imf_context_, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, + event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_CHANGED], this); } void TizenInputMethodContext::UnregisterEventCallbacks() { FT_ASSERT(imf_context_); - tizen_core_imf_context_del_event_callback( - imf_context_, TIZEN_CORE_IMF_CALLBACK_COMMIT, - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_COMMIT]); - tizen_core_imf_context_del_event_callback( - imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED, - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED]); - tizen_core_imf_context_del_event_callback( - imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_START, - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START]); - tizen_core_imf_context_del_event_callback( - imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_END, - event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END]); + ecore_imf_context_event_callback_del( + imf_context_, ECORE_IMF_CALLBACK_COMMIT, + event_callbacks_[ECORE_IMF_CALLBACK_COMMIT]); + ecore_imf_context_event_callback_del( + imf_context_, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, + event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_CHANGED]); + ecore_imf_context_event_callback_del( + imf_context_, ECORE_IMF_CALLBACK_PREEDIT_START, + event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_START]); + ecore_imf_context_event_callback_del( + imf_context_, ECORE_IMF_CALLBACK_PREEDIT_END, + event_callbacks_[ECORE_IMF_CALLBACK_PREEDIT_END]); } void TizenInputMethodContext::SetContextOptions() { FT_ASSERT(imf_context_); - tizen_core_imf_context_set_autocapital_type( - imf_context_, TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_NONE); + ecore_imf_context_autocapital_type_set(imf_context_, + ECORE_IMF_AUTOCAPITAL_TYPE_NONE); + ecore_imf_context_prediction_allow_set(imf_context_, EINA_FALSE); } void TizenInputMethodContext::SetInputPanelOptions() { FT_ASSERT(imf_context_); - tizen_core_imf_context_set_input_panel_layout( - imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); - tizen_core_imf_context_set_input_panel_return_key_type( - imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT); + ecore_imf_context_input_panel_layout_set(imf_context_, + ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); + ecore_imf_context_input_panel_return_key_type_set( + imf_context_, ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT); + ecore_imf_context_input_panel_language_set( + imf_context_, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC); } void TizenInputMethodContext::InputPanelStateChangedCallback( - tizen_core_imf_context_h ctx, - int value, - void* data) { + void* data, + Ecore_IMF_Context* ctx, + int value) { auto* self = static_cast(data); - tizen_core_imf_input_panel_state_e state = - static_cast(value); + Ecore_IMF_Input_Panel_State state = + static_cast(value); std::string state_str; switch (state) { - case TIZEN_CORE_IMF_INPUT_PANEL_STATE_SHOW: + case ECORE_IMF_INPUT_PANEL_STATE_SHOW: state_str = "show"; break; - case TIZEN_CORE_IMF_INPUT_PANEL_STATE_HIDE: + case ECORE_IMF_INPUT_PANEL_STATE_HIDE: state_str = "hide"; break; - case TIZEN_CORE_IMF_INPUT_PANEL_STATE_WILL_SHOW: + case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW: state_str = "will_show"; break; default: @@ -436,10 +412,6 @@ void TizenInputMethodContext::InputPanelStateChangedCallback( break; } - FT_LOG(Error) << "InputPanelStateChangedCallback: state=" << state_str - << ", on_input_panel_state_changed_=" - << (self->on_input_panel_state_changed_ ? "set" : "null"); - if (self->on_input_panel_state_changed_) { self->on_input_panel_state_changed_(state_str); } @@ -448,16 +420,16 @@ void TizenInputMethodContext::InputPanelStateChangedCallback( void TizenInputMethodContext::RegisterInputPanelEventCallback() { FT_ASSERT(imf_context_); - tizen_core_imf_context_add_input_panel_event_callback( - imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_EVENT_STATE, + ecore_imf_context_input_panel_event_callback_add( + imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangedCallback, this); } void TizenInputMethodContext::UnregisterInputPanelEventCallback() { FT_ASSERT(imf_context_); - tizen_core_imf_context_del_input_panel_event_callback( - imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_EVENT_STATE, + ecore_imf_context_input_panel_event_callback_del( + imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangedCallback); } diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index f0a0314d..6915dd51 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -5,8 +5,8 @@ #ifndef EMBEDDER_TIZEN_INPUT_METHOD_CONTEXT_H_ #define EMBEDDER_TIZEN_INPUT_METHOD_CONTEXT_H_ -#include -#include +#include +#include #include #include @@ -29,7 +29,7 @@ class TizenInputMethodContext { TizenInputMethodContext(uintptr_t window_id); ~TizenInputMethodContext(); - bool HandleTcoreWlEventKey(void* event, bool is_down); + bool HandleEcoreEventKey(Ecore_Event_Key* event, bool is_down); #ifdef NUI_SUPPORT bool HandleNuiKeyEvent(const char* device_name, @@ -79,9 +79,9 @@ class TizenInputMethodContext { void UnregisterInputPanelEventCallback(); private: - static void InputPanelStateChangedCallback(tizen_core_imf_context_h ctx, - int value, - void* data); + static void InputPanelStateChangedCallback(void* data, + Ecore_IMF_Context* ctx, + int value); void RegisterEventCallbacks(); void UnregisterEventCallbacks(); @@ -89,13 +89,16 @@ class TizenInputMethodContext { void SetContextOptions(); void SetInputPanelOptions(); - tizen_core_imf_context_h imf_context_ = nullptr; +#ifdef NUI_SUPPORT + Ecore_Device* ecore_device_ = nullptr; +#endif + Ecore_IMF_Context* imf_context_ = nullptr; OnCommit on_commit_; OnPreeditChanged on_preedit_changed_; OnPreeditStart on_preedit_start_; OnPreeditEnd on_preedit_end_; OnInputPanelStateChanged on_input_panel_state_changed_; - std::unordered_map + std::unordered_map event_callbacks_; }; diff --git a/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc new file mode 100644 index 00000000..6b70a558 --- /dev/null +++ b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc @@ -0,0 +1,464 @@ +// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tizen_input_method_context.h" + +#include "flutter/shell/platform/tizen/logger.h" + +namespace { + +tizen_core_imf_input_panel_layout_e TextInputTypeToImfInputPanelLayout( + const std::string& text_input_type) { + if (text_input_type == "TextInputType.text" || + text_input_type == "TextInputType.multiline") { + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; + } else if (text_input_type == "TextInputType.number") { + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY; + } else if (text_input_type == "TextInputType.phone") { + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER; + } else if (text_input_type == "TextInputType.datetime") { + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_DATETIME; + } else if (text_input_type == "TextInputType.emailAddress" || + text_input_type == "TextInputType.twitter") { + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_EMAIL; + } else if (text_input_type == "TextInputType.url" || + text_input_type == "TextInputType.webSearch") { + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_URL; + } else if (text_input_type == "TextInputType.visiblePassword") { + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD; + } else { + FT_LOG(Warn) << "The requested input type " << text_input_type + << " is not supported."; + return TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; + } +} + +tizen_core_imf_keyboard_modifiers_e ModifiersToImfModifiers( + unsigned int modifiers) { + unsigned int imf_modifiers = TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_NONE; + if (modifiers & TIZEN_CORE_WL_MODIFIER_SHIFT) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_SHIFT; + } + if (modifiers & TIZEN_CORE_WL_MODIFIER_ALT) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_ALT; + } + if (modifiers & TIZEN_CORE_WL_MODIFIER_CTRL) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_CTRL; + } + if (modifiers & TIZEN_CORE_WL_MODIFIER_WIN) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_WIN; + } + if (modifiers & TIZEN_CORE_WL_MODIFIER_ALTGR) { + imf_modifiers |= TIZEN_CORE_IMF_KEYBOARD_MODIFIERS_ALTGR; + } + return static_cast(imf_modifiers); +} + +tizen_core_imf_keyboard_locks_e ModifiersToImfLocks(unsigned int modifiers) { + unsigned int locks = TIZEN_CORE_IMF_KEYBOARD_LOCKS_NONE; + if (modifiers & TIZEN_CORE_WL_MODIFIER_NUM) { + locks |= TIZEN_CORE_IMF_KEYBOARD_LOCKS_NUM; + } + if (modifiers & TIZEN_CORE_WL_MODIFIER_CAPS) { + locks |= TIZEN_CORE_IMF_KEYBOARD_LOCKS_CAPS; + } + if (modifiers & TIZEN_CORE_WL_MODIFIER_SCROLL) { + locks |= TIZEN_CORE_IMF_KEYBOARD_LOCKS_SCROLL; + } + return static_cast(locks); +} + +tizen_core_imf_event_key_h CreateImfKeyEventFromTcoreWlEvent(void* event) { + auto* ev = static_cast(event); + + tizen_core_imf_event_key_h imf_key = nullptr; + tizen_core_imf_event_key_create(&imf_key); + if (!imf_key) { + return nullptr; + } + + char* keyname = nullptr; + tizen_core_wl_event_key_get_keyname(ev, &keyname); + if (keyname) { + tizen_core_imf_event_key_set_keyname(imf_key, keyname); + tizen_core_imf_event_key_set_key(imf_key, keyname); + free(keyname); + } + + char* keysymbol = nullptr; + tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); + if (keysymbol) { + tizen_core_imf_event_key_set_string(imf_key, keysymbol); + free(keysymbol); + } + + char* compose = nullptr; + tizen_core_wl_event_key_get_compose(ev, &compose); + if (compose) { + tizen_core_imf_event_key_set_compose(imf_key, compose); + free(compose); + } + + unsigned int keycode = 0; + tizen_core_wl_event_key_get_keycode(ev, &keycode); + tizen_core_imf_event_key_set_keycode(imf_key, keycode); + + unsigned int modifiers = 0; + tizen_core_wl_event_key_get_modifiers(ev, &modifiers); + tizen_core_imf_event_key_set_modifiers(imf_key, + ModifiersToImfModifiers(modifiers)); + tizen_core_imf_event_key_set_locks(imf_key, ModifiersToImfLocks(modifiers)); + + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + tizen_core_imf_event_key_set_timestamp(imf_key, timestamp); + + char* dev_identifier = nullptr; + tizen_core_wl_event_input_base_get_device_identifier(ev, &dev_identifier); + if (dev_identifier) { + tizen_core_imf_event_key_set_device_name(imf_key, dev_identifier); + free(dev_identifier); + } + + return imf_key; +} + +} // namespace + +namespace flutter { + +TizenInputMethodContext::TizenInputMethodContext(uintptr_t window_id) { + tizen_core_imf_init(); + + if (tizen_core_imf_context_create(&imf_context_) != + TIZEN_CORE_IMF_ERROR_NONE) { + FT_LOG(Error) << "Failed to create tizen_core_imf_context."; + return; + } + + tizen_core_imf_context_set_client_window(imf_context_, + reinterpret_cast(window_id)); + SetContextOptions(); + SetInputPanelOptions(); + RegisterEventCallbacks(); + RegisterInputPanelEventCallback(); +} + +TizenInputMethodContext::~TizenInputMethodContext() { + UnregisterInputPanelEventCallback(); + UnregisterEventCallbacks(); + + if (imf_context_) { + tizen_core_imf_context_destroy(imf_context_); + } + + tizen_core_imf_shutdown(); +} + +bool TizenInputMethodContext::HandleTcoreWlEventKey(void* event, bool is_down) { + FT_ASSERT(imf_context_); + FT_ASSERT(event); + + FT_LOG(Error) << "HandleTcoreWlEventKey: is_down=" << is_down; + + tizen_core_imf_event_key_h imf_key = CreateImfKeyEventFromTcoreWlEvent(event); + if (!imf_key) { + FT_LOG(Error) << "HandleTcoreWlEventKey: failed to create imf_key event"; + return false; + } + + bool filter_result = false; + int ret = tizen_core_imf_context_filter_event( + imf_context_, + is_down ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN + : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, + imf_key, &filter_result); + FT_LOG(Error) << "HandleTcoreWlEventKey: filter_event ret=" << ret + << ", filter_result=" << filter_result; + tizen_core_imf_event_key_destroy(imf_key); + return filter_result; +} + +#ifdef NUI_SUPPORT +bool TizenInputMethodContext::HandleNuiKeyEvent(const char* device_name, + uint32_t device_class, + uint32_t device_subclass, + const char* key, + const char* string, + uint32_t modifiers, + uint32_t scan_code, + size_t timestamp, + bool is_down) { + FT_LOG(Error) << "HandleNuiKeyEvent: key=" << (key ? key : "null") + << ", string=" << (string ? string : "null") + << ", modifiers=" << modifiers << ", scan_code=" << scan_code + << ", is_down=" << is_down; + + tizen_core_imf_event_key_h imf_key = nullptr; + tizen_core_imf_event_key_create(&imf_key); + if (!imf_key) { + FT_LOG(Error) << "HandleNuiKeyEvent: failed to create imf_key event"; + return false; + } + + if (key) { + tizen_core_imf_event_key_set_keyname(imf_key, key); + tizen_core_imf_event_key_set_key(imf_key, key); + } + if (string) { + tizen_core_imf_event_key_set_string(imf_key, string); + } + + tizen_core_imf_event_key_set_modifiers(imf_key, + ModifiersToImfModifiers(modifiers)); + tizen_core_imf_event_key_set_locks(imf_key, ModifiersToImfLocks(modifiers)); + tizen_core_imf_event_key_set_keycode(imf_key, scan_code); + tizen_core_imf_event_key_set_timestamp(imf_key, timestamp); + + if (device_name) { + tizen_core_imf_event_key_set_device_name(imf_key, device_name); + } + tizen_core_imf_event_key_set_device_class( + imf_key, static_cast(device_class)); + tizen_core_imf_event_key_set_device_subclass( + imf_key, static_cast(device_subclass)); + + bool filter_result = false; + int ret = tizen_core_imf_context_filter_event( + imf_context_, + is_down ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN + : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, + imf_key, &filter_result); + FT_LOG(Error) << "HandleNuiKeyEvent: filter_event ret=" << ret + << ", filter_result=" << filter_result; + tizen_core_imf_event_key_destroy(imf_key); + return filter_result; +} +#endif + +InputPanelGeometry TizenInputMethodContext::GetInputPanelGeometry() { + FT_ASSERT(imf_context_); + InputPanelGeometry geometry; + tizen_core_imf_context_get_input_panel_geometry( + imf_context_, &geometry.x, &geometry.y, &geometry.w, &geometry.h); + return geometry; +} + +void TizenInputMethodContext::ResetInputMethodContext() { + FT_ASSERT(imf_context_); + tizen_core_imf_context_reset(imf_context_); +} + +void TizenInputMethodContext::ShowInputPanel() { + FT_ASSERT(imf_context_); + FT_LOG(Error) << "ShowInputPanel: called"; + tizen_core_imf_context_input_panel_show(imf_context_); + tizen_core_imf_context_focus_in(imf_context_); +} + +void TizenInputMethodContext::HideInputPanel() { + FT_ASSERT(imf_context_); + FT_LOG(Error) << "HideInputPanel: called"; + tizen_core_imf_context_focus_out(imf_context_); + tizen_core_imf_context_input_panel_hide(imf_context_); +} + +bool TizenInputMethodContext::IsInputPanelShown() { + tizen_core_imf_input_panel_state_e state; + int ret = tizen_core_imf_context_get_input_panel_state(imf_context_, &state); + FT_LOG(Error) << "IsInputPanelShown: ret=" << ret << ", state=" << state; + return state == TIZEN_CORE_IMF_INPUT_PANEL_STATE_SHOW; +} + +void TizenInputMethodContext::SetInputPanelLayout( + const std::string& input_type) { + FT_ASSERT(imf_context_); + tizen_core_imf_input_panel_layout_e panel_layout = + TextInputTypeToImfInputPanelLayout(input_type); + tizen_core_imf_context_set_input_panel_layout(imf_context_, panel_layout); +} + +void TizenInputMethodContext::SetInputPanelLayoutVariation(bool is_signed, + bool is_decimal) { + tizen_core_imf_layout_numberonly_variation_e variation; + if (is_signed && is_decimal) { + variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL; + } else if (is_signed) { + variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_SIGNED; + } else if (is_decimal) { + variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_DECIMAL; + } else { + variation = TIZEN_CORE_IMF_LAYOUT_NUMBERONLY_VARIATION_NORMAL; + } + tizen_core_imf_context_set_input_panel_layout_variation(imf_context_, + variation); +} + +void TizenInputMethodContext::SetAutocapitalType(const std::string& type) { + tizen_core_imf_autocapital_type_e autocapital_type = + TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_NONE; + + if (type == "TextCapitalization.characters") { + autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER; + } else if (type == "TextCapitalization.words") { + autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_WORD; + } else if (type == "TextCapitalization.sentences") { + autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_SENTENCE; + } else if (type == "TextCapitalization.none") { + autocapital_type = TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_NONE; + } + tizen_core_imf_context_set_autocapital_type(imf_context_, autocapital_type); +} + +void TizenInputMethodContext::RegisterEventCallbacks() { + FT_ASSERT(imf_context_); + + // commit callback + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_COMMIT] = + [](tizen_core_imf_context_h ctx, void* event_info, void* data) { + auto* self = static_cast(data); + char* str = static_cast(event_info); + FT_LOG(Error) << "IMF_CALLBACK_COMMIT: str=" << (str ? str : "null") + << ", on_commit_=" << (self->on_commit_ ? "set" : "null"); + if (self->on_commit_) { + self->on_commit_(str); + } + }; + tizen_core_imf_context_add_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_COMMIT, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_COMMIT], this); + + // pre-edit start callback + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START] = + [](tizen_core_imf_context_h ctx, void* event_info, void* data) { + auto* self = static_cast(data); + FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_START: on_preedit_start_=" + << (self->on_preedit_start_ ? "set" : "null"); + if (self->on_preedit_start_) { + self->on_preedit_start_(); + } + }; + tizen_core_imf_context_add_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_START, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START], this); + + // pre-edit end callback + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END] = + [](tizen_core_imf_context_h ctx, void* event_info, void* data) { + auto* self = static_cast(data); + FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_END: on_preedit_end_=" + << (self->on_preedit_end_ ? "set" : "null"); + if (self->on_preedit_end_) { + self->on_preedit_end_(); + } + }; + tizen_core_imf_context_add_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_END, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END], this); + + // pre-edit changed callback + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED] = + [](tizen_core_imf_context_h ctx, void* event_info, void* data) { + auto* self = static_cast(data); + FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_CHANGED: on_preedit_changed_=" + << (self->on_preedit_changed_ ? "set" : "null"); + if (self->on_preedit_changed_) { + char* str = nullptr; + int cursor_pos = 0; + tizen_core_imf_context_get_preedit_string(ctx, &str, nullptr, nullptr, + &cursor_pos); + FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_CHANGED: str=" + << (str ? str : "null") + << ", cursor_pos=" << cursor_pos; + if (str) { + self->on_preedit_changed_(str, cursor_pos); + free(str); + } + } + }; + tizen_core_imf_context_add_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED], this); +} + +void TizenInputMethodContext::UnregisterEventCallbacks() { + FT_ASSERT(imf_context_); + tizen_core_imf_context_del_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_COMMIT, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_COMMIT]); + tizen_core_imf_context_del_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED]); + tizen_core_imf_context_del_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_START, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START]); + tizen_core_imf_context_del_event_callback( + imf_context_, TIZEN_CORE_IMF_CALLBACK_PREEDIT_END, + event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END]); +} + +void TizenInputMethodContext::SetContextOptions() { + FT_ASSERT(imf_context_); + tizen_core_imf_context_set_autocapital_type( + imf_context_, TIZEN_CORE_IMF_AUTOCAPITAL_TYPE_NONE); +} + +void TizenInputMethodContext::SetInputPanelOptions() { + FT_ASSERT(imf_context_); + tizen_core_imf_context_set_input_panel_layout( + imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); + tizen_core_imf_context_set_input_panel_return_key_type( + imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT); +} + +void TizenInputMethodContext::InputPanelStateChangedCallback( + tizen_core_imf_context_h ctx, + int value, + void* data) { + auto* self = static_cast(data); + tizen_core_imf_input_panel_state_e state = + static_cast(value); + + std::string state_str; + switch (state) { + case TIZEN_CORE_IMF_INPUT_PANEL_STATE_SHOW: + state_str = "show"; + break; + case TIZEN_CORE_IMF_INPUT_PANEL_STATE_HIDE: + state_str = "hide"; + break; + case TIZEN_CORE_IMF_INPUT_PANEL_STATE_WILL_SHOW: + state_str = "will_show"; + break; + default: + state_str = "unknown"; + break; + } + + FT_LOG(Error) << "InputPanelStateChangedCallback: state=" << state_str + << ", on_input_panel_state_changed_=" + << (self->on_input_panel_state_changed_ ? "set" : "null"); + + if (self->on_input_panel_state_changed_) { + self->on_input_panel_state_changed_(state_str); + } +} + +void TizenInputMethodContext::RegisterInputPanelEventCallback() { + FT_ASSERT(imf_context_); + + tizen_core_imf_context_add_input_panel_event_callback( + imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_EVENT_STATE, + InputPanelStateChangedCallback, this); +} + +void TizenInputMethodContext::UnregisterInputPanelEventCallback() { + FT_ASSERT(imf_context_); + + tizen_core_imf_context_del_input_panel_event_callback( + imf_context_, TIZEN_CORE_IMF_INPUT_PANEL_EVENT_STATE, + InputPanelStateChangedCallback); +} + +} // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_input_method_context_tcore.h b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.h new file mode 100644 index 00000000..f0a0314d --- /dev/null +++ b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.h @@ -0,0 +1,104 @@ +// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EMBEDDER_TIZEN_INPUT_METHOD_CONTEXT_H_ +#define EMBEDDER_TIZEN_INPUT_METHOD_CONTEXT_H_ + +#include +#include + +#include +#include +#include + +namespace flutter { + +using OnCommit = std::function; +using OnPreeditChanged = std::function; +using OnPreeditStart = std::function; +using OnPreeditEnd = std::function; +using OnInputPanelStateChanged = std::function; + +struct InputPanelGeometry { + int32_t x = 0, y = 0, w = 0, h = 0; +}; + +class TizenInputMethodContext { + public: + TizenInputMethodContext(uintptr_t window_id); + ~TizenInputMethodContext(); + + bool HandleTcoreWlEventKey(void* event, bool is_down); + +#ifdef NUI_SUPPORT + bool HandleNuiKeyEvent(const char* device_name, + uint32_t device_class, + uint32_t device_subclass, + const char* key, + const char* string, + uint32_t modifiers, + uint32_t scan_code, + size_t timestamp, + bool is_down); +#endif + + InputPanelGeometry GetInputPanelGeometry(); + + void ResetInputMethodContext(); + + void ShowInputPanel(); + + void HideInputPanel(); + + bool IsInputPanelShown(); + + void SetInputPanelLayout(const std::string& layout); + + void SetInputPanelLayoutVariation(bool is_signed, bool is_decimal); + + void SetAutocapitalType(const std::string& type); + + void SetOnCommit(OnCommit callback) { on_commit_ = callback; } + + void SetOnPreeditChanged(OnPreeditChanged callback) { + on_preedit_changed_ = callback; + } + + void SetOnPreeditStart(OnPreeditStart callback) { + on_preedit_start_ = callback; + } + + void SetOnPreeditEnd(OnPreeditEnd callback) { on_preedit_end_ = callback; } + + void SetOnInputPanelStateChanged(OnInputPanelStateChanged callback) { + on_input_panel_state_changed_ = callback; + } + + void RegisterInputPanelEventCallback(); + void UnregisterInputPanelEventCallback(); + + private: + static void InputPanelStateChangedCallback(tizen_core_imf_context_h ctx, + int value, + void* data); + + void RegisterEventCallbacks(); + void UnregisterEventCallbacks(); + + void SetContextOptions(); + void SetInputPanelOptions(); + + tizen_core_imf_context_h imf_context_ = nullptr; + OnCommit on_commit_; + OnPreeditChanged on_preedit_changed_; + OnPreeditStart on_preedit_start_; + OnPreeditEnd on_preedit_end_; + OnInputPanelStateChanged on_input_panel_state_changed_; + std::unordered_map + event_callbacks_; +}; + +} // namespace flutter + +#endif // EMBEDDER_TIZEN_INPUT_METHOD_CONTEXT_H_ diff --git a/flutter/shell/platform/tizen/tizen_renderer_egl.cc b/flutter/shell/platform/tizen/tizen_renderer_egl.cc index ad103cab..d618943c 100644 --- a/flutter/shell/platform/tizen/tizen_renderer_egl.cc +++ b/flutter/shell/platform/tizen/tizen_renderer_egl.cc @@ -4,7 +4,8 @@ #include "flutter/shell/platform/tizen/tizen_renderer_egl.h" -#include +#define EFL_BETA_API_SUPPORT +#include #include #include #ifdef NUI_SUPPORT @@ -93,8 +94,8 @@ bool TizenRendererEgl::CreateSurface(void* render_target, const EGLint attribs[] = {EGL_NONE}; if (render_target_display) { - const auto egl_window = tizen_core_wl_egl_window_native_get( - static_cast(render_target)); + const auto egl_window = ecore_wl2_egl_window_native_get( + static_cast(render_target)); egl_surface_ = eglCreateWindowSurface( egl_display_, egl_config_, reinterpret_cast(egl_window), attribs); diff --git a/flutter/shell/platform/tizen/tizen_view_base.h b/flutter/shell/platform/tizen/tizen_view_base.h index 40a1b8f9..9354dd4a 100644 --- a/flutter/shell/platform/tizen/tizen_view_base.h +++ b/flutter/shell/platform/tizen/tizen_view_base.h @@ -10,7 +10,11 @@ #include #include +#ifdef USE_TCORE_WL +#include "flutter/shell/platform/tizen/tizen_input_method_context_tcore.h" +#else #include "flutter/shell/platform/tizen/tizen_input_method_context.h" +#endif #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" namespace flutter { diff --git a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc index f3514873..41d16b9d 100644 --- a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc +++ b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc @@ -17,21 +17,6 @@ #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" -// Forward declarations for rotation APIs that exist in the library -// but are not yet declared in the public header. -extern "C" { -tizen_core_wl_error_e tizen_core_wl_window_set_rotation_angle( - tizen_core_wl_window_h window, - tizen_core_wl_window_angle_e angle); -tizen_core_wl_error_e tizen_core_wl_window_get_rotation_angle( - tizen_core_wl_window_h window, - tizen_core_wl_window_angle_e* angle); -tizen_core_wl_error_e tizen_core_wl_window_set_available_rotation_angle_list( - tizen_core_wl_window_h window, - tizen_core_wl_window_angle_e* available_angles, - size_t available_angle_count); -} - namespace flutter { namespace { @@ -44,7 +29,7 @@ constexpr char kSysMouseCursorPointerSizeVConfKey[] = "db/menu/system/mouse-pointer-size"; constexpr char kSysPointingDeviceSupportToastSharedPreferenceKey[] = "flutter-tizen/preference/pointing-device-support-toast"; -constexpr char kTcoreWlInputCursorThemeName[] = "vd-cursors"; +constexpr char kEcoreWL2InputCursorThemeName[] = "vd-cursors"; #endif FlutterPointerMouseButtons ToFlutterPointerButton(int32_t button) { @@ -57,17 +42,16 @@ FlutterPointerMouseButtons ToFlutterPointerButton(int32_t button) { } } -// FlutterPointerDeviceKind GetDeviceKindFromEventType(int event_type) { -// if (event_type == TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_DOWN || -// event_type == TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_UP || -// event_type == TIZEN_CORE_WL_EVENT_MOUSE_MOVE || -// event_type == TIZEN_CORE_WL_EVENT_MOUSE_WHEEL) { -// // The event system doesn't distinguish mouse vs touch at event level. -// // Default to touch; mouse events can be differentiated by touch_id == 0. -// return kFlutterPointerDeviceKindTouch; -// } -// return kFlutterPointerDeviceKindTouch; -// } +FlutterPointerDeviceKind ToFlutterDeviceKind(const Ecore_Device* dev) { + Ecore_Device_Class device_class = ecore_device_class_get(dev); + if (device_class == ECORE_DEVICE_CLASS_MOUSE) { + return kFlutterPointerDeviceKindMouse; + } else if (device_class == ECORE_DEVICE_CLASS_PEN) { + return kFlutterPointerDeviceKindStylus; + } else { + return kFlutterPointerDeviceKindTouch; + } +} #ifdef TV_PROFILE time_t GetBootTimeEpoch() { @@ -183,7 +167,7 @@ TizenWindowEcoreWl2::TizenWindowEcoreWl2(TizenGeometry geometry, RegisterEventHandlers(); PrepareInputMethod(); Show(); -} +} // namespace flutter TizenWindowEcoreWl2::~TizenWindowEcoreWl2() { UnregisterEventHandlers(); @@ -191,41 +175,22 @@ TizenWindowEcoreWl2::~TizenWindowEcoreWl2() { } bool TizenWindowEcoreWl2::CreateWindow(void* window_handle) { - FT_LOG(Error) << "tizen core wl init()!!!!!!! "; - - if (tizen_core_wl_init() != TIZEN_CORE_WL_ERROR_NONE) { - FT_LOG(Error) << "Could not initialize tizen core wl."; + if (!ecore_wl2_init()) { + FT_LOG(Error) << "Could not initialize Ecore Wl2."; return false; } - if (tizen_core_wl_display_create(&tcore_wl_display_) != - TIZEN_CORE_WL_ERROR_NONE) { - FT_LOG(Error) << "Could not create tizen core wl display."; + ecore_wl2_display_ = ecore_wl2_display_connect(nullptr); + if (!ecore_wl2_display_) { + FT_LOG(Error) << "Ecore Wl2 display not found."; return false; } + wl2_display_ = ecore_wl2_display_get(ecore_wl2_display_); - if (tizen_core_wl_display_connect(tcore_wl_display_, nullptr) != - TIZEN_CORE_WL_ERROR_NONE) { - FT_LOG(Error) << "Tizen core wl display not found."; - return false; - } - - tizen_core_wl_display_private_get_wl_display(tcore_wl_display_, - &wl2_display_); - - tizen_core_wl_display_sync(tcore_wl_display_); + ecore_wl2_sync(); - tizen_core_wl_display_get_event(tcore_wl_display_, &tcore_wl_event_); - - int32_t width = 0, height = 0; - GList* output_list = nullptr; - tizen_core_wl_display_get_output_device_list(tcore_wl_display_, &output_list); - if (output_list) { - tizen_core_wl_output_h output = - static_cast(output_list->data); - tizen_core_wl_output_device_get_geometry(output, &width, &height); - g_list_free(output_list); - } + int32_t width, height; + ecore_wl2_display_screen_size_get(ecore_wl2_display_, &width, &height); if (width == 0 || height == 0) { FT_LOG(Error) << "Invalid screen size: " << width << " x " << height; return false; @@ -239,72 +204,79 @@ bool TizenWindowEcoreWl2::CreateWindow(void* window_handle) { } if (window_handle == nullptr) { - if (tizen_core_wl_create_window( - tcore_wl_display_, nullptr, initial_geometry_.left, - initial_geometry_.top, initial_geometry_.width, - initial_geometry_.height, - &tcore_wl_window_) != TIZEN_CORE_WL_ERROR_NONE) { - FT_LOG(Error) << "Could not create tizen core wl window."; - return false; - } + ecore_wl2_window_ = + ecore_wl2_window_new(ecore_wl2_display_, nullptr, + initial_geometry_.left, initial_geometry_.top, + initial_geometry_.width, initial_geometry_.height); } else { - tcore_wl_window_ = static_cast(window_handle); + ecore_wl2_window_ = static_cast(window_handle); } if (is_vulkan_) { - tizen_core_wl_window_private_get_wl_surface(tcore_wl_window_, - &wl2_surface_); + wl2_surface_ = ecore_wl2_window_surface_get(ecore_wl2_window_); return wl2_surface_ && wl2_display_; } else { - if (tizen_core_wl_create_egl_window( - tcore_wl_window_, initial_geometry_.width, initial_geometry_.height, - &tcore_wl_egl_window_) != TIZEN_CORE_WL_ERROR_NONE) { - FT_LOG(Error) << "Could not create tizen core wl egl window."; - return false; - } - return tcore_wl_egl_window_ && wl2_display_; + ecore_wl2_egl_window_ = ecore_wl2_egl_window_create( + ecore_wl2_window_, initial_geometry_.width, initial_geometry_.height); + return ecore_wl2_egl_window_ && wl2_display_; } } void TizenWindowEcoreWl2::SetWindowOptions() { - tizen_core_wl_window_set_type( - tcore_wl_window_, top_level_ ? TIZEN_CORE_WL_WINDOW_TYPE_NOTIFICATION - : TIZEN_CORE_WL_WINDOW_TYPE_TOPLEVEL); + // Change the window type to use the tizen policy for notification window + // according to top_level_. + // Note: ECORE_WL2_WINDOW_TYPE_TOPLEVEL is similar to "ELM_WIN_BASIC" and it + // does not mean that the window always will be overlaid on other apps :( + ecore_wl2_window_type_set(ecore_wl2_window_, + top_level_ ? ECORE_WL2_WINDOW_TYPE_NOTIFICATION + : ECORE_WL2_WINDOW_TYPE_TOPLEVEL); if (top_level_) { - SetNotificationLevel(TIZEN_CORE_WL_NOTIFICATION_LEVEL_TOP); + SetTizenPolicyNotificationLevel(TIZEN_POLICY_LEVEL_TOP); } - tizen_core_wl_window_set_position(tcore_wl_window_, initial_geometry_.left, - initial_geometry_.top); - tizen_core_wl_window_set_aux_hint(tcore_wl_window_, - "wm.policy.win.user.geometry", "1"); + ecore_wl2_window_position_set(ecore_wl2_window_, initial_geometry_.left, + initial_geometry_.top); + ecore_wl2_window_aux_hint_add(ecore_wl2_window_, 0, + "wm.policy.win.user.geometry", "1"); - tizen_core_wl_window_set_alpha(tcore_wl_window_, transparent_); + if (transparent_) { + ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_TRUE); + } else { + ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_FALSE); + } if (!focusable_) { - tizen_core_wl_window_set_focus_skip(tcore_wl_window_, true); + ecore_wl2_window_focus_skip_set(ecore_wl2_window_, EINA_TRUE); } + ecore_wl2_window_indicator_state_set(ecore_wl2_window_, + ECORE_WL2_INDICATOR_STATE_ON); + ecore_wl2_window_indicator_opacity_set(ecore_wl2_window_, + ECORE_WL2_INDICATOR_OPAQUE); + ecore_wl2_indicator_visible_type_set(ecore_wl2_window_, + ECORE_WL2_INDICATOR_VISIBLE_TYPE_SHOWN); + #ifdef TV_PROFILE - tizen_core_wl_window_angle_e rotations[1] = {TIZEN_CORE_WL_WINDOW_ANGLE_0}; + int rotations[1] = {0}; // Default is only landscape. #else - tizen_core_wl_window_angle_e rotations[4] = { - TIZEN_CORE_WL_WINDOW_ANGLE_0, TIZEN_CORE_WL_WINDOW_ANGLE_90, - TIZEN_CORE_WL_WINDOW_ANGLE_180, TIZEN_CORE_WL_WINDOW_ANGLE_270}; + int rotations[4] = {0, 90, 180, 270}; #endif - tizen_core_wl_window_set_available_rotation_angle_list( - tcore_wl_window_, rotations, sizeof(rotations) / sizeof(rotations[0])); + ecore_wl2_window_available_rotations_set(ecore_wl2_window_, rotations, + sizeof(rotations) / sizeof(int)); EnableCursor(); } void TizenWindowEcoreWl2::EnableCursor() { #ifdef TV_PROFILE + // dlopen is used here because the TV-specific library libvd-win-util.so + // and the relevant headers are not present in the rootstrap. void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); if (!handle) { FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; return; } + // These functions are defined in vd-win-util's cursor_module.h. int (*CursorModule_Initialize)(wl_display* display, wl_registry* registry, wl_seat* seat, unsigned int id); int (*Cursor_Set_Config)(wl_surface* surface, uint32_t config_type, @@ -322,41 +294,34 @@ void TizenWindowEcoreWl2::EnableCursor() { return; } - tizen_core_wl_seat_h default_seat = nullptr; - tizen_core_wl_display_get_default_seat(tcore_wl_display_, &default_seat); - if (!default_seat) { - FT_LOG(Error) << "Could not get default seat."; - dlclose(handle); - return; - } - struct wl_seat* seat = nullptr; - tizen_core_wl_seat_private_get_wl_seat(default_seat, &seat); - if (!seat) { - FT_LOG(Error) << "Could not get wl_seat from the default seat."; + wl_registry* registry = ecore_wl2_display_registry_get(ecore_wl2_display_); + wl_seat* seat = ecore_wl2_input_seat_get( + ecore_wl2_input_default_input_get(ecore_wl2_display_)); + if (!registry || !seat) { + FT_LOG(Error) + << "Could not retreive wl_registry or wl_seat from the display."; dlclose(handle); return; } - int cursor_global_id = 0; - if (tizen_core_wl_display_private_get_global_id( - tcore_wl_display_, "tizen_cursor", &cursor_global_id) == - TIZEN_CORE_WL_ERROR_NONE && - cursor_global_id > 0) { - struct wl_registry* registry = wl_display_get_registry(wl2_display_); - if (registry) { - if (!CursorModule_Initialize(wl2_display_, registry, seat, - cursor_global_id)) { + Eina_Iterator* iter = ecore_wl2_display_globals_get(ecore_wl2_display_); + Ecore_Wl2_Global* global = nullptr; + + EINA_ITERATOR_FOREACH(iter, global) { + if (strcmp(global->interface, "tizen_cursor") == 0) { + if (!CursorModule_Initialize(wl2_display_, registry, seat, global->id)) { FT_LOG(Error) << "Failed to initialize the cursor module."; } - wl_registry_destroy(registry); } } + eina_iterator_free(iter); - tizen_core_wl_display_sync(tcore_wl_display_); + ecore_wl2_sync(); - struct wl_surface* surface = nullptr; - tizen_core_wl_window_private_get_wl_surface(tcore_wl_window_, &surface); - if (surface && !Cursor_Set_Config(surface, 1, nullptr)) { + wl_surface* surface = ecore_wl2_window_surface_get(ecore_wl2_window_); + // The config_type 1 refers to TIZEN_CURSOR_CONFIG_CURSOR_AVAILABLE + // defined in the TV extension protocol tizen-extension-tv.xml. + if (!Cursor_Set_Config(surface, 1, nullptr)) { FT_LOG(Error) << "Failed to set a cursor config value."; } @@ -370,13 +335,16 @@ typedef enum _MouseSupport { DISABLE = 0, ENABLE } MouseSupport; typedef enum _Device_Type { MOUSE_DEVICE = 3, TOUCH_DEVICE } Device_Type; void TizenWindowEcoreWl2::SetPointingDeviceSupport() { + // dlopen is used here because the TV-specific library libvd-win-util.so + // and the relevant headers are not present in the rootstrap. void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); if (!handle) { FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; return; } - int (*Mouse_Pointer_Support)(MouseSupport type, void* win); + // These functions are defined in vd-win-util's cursor_module.h. + int (*Mouse_Pointer_Support)(MouseSupport type, void* ecore_wl2_win); *(void**)(&Mouse_Pointer_Support) = dlsym(handle, "Mouse_Pointer_Support"); if (!Mouse_Pointer_Support) { @@ -386,18 +354,21 @@ void TizenWindowEcoreWl2::SetPointingDeviceSupport() { } Mouse_Pointer_Support(pointing_device_support_ ? ENABLE : DISABLE, - tcore_wl_window_); + ecore_wl2_window_); dlclose(handle); } void TizenWindowEcoreWl2::SetFloatingMenuSupport() { + // dlopen is used here because the TV-specific library libvd-win-util.so + // and the relevant headers are not present in the rootstrap. void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); if (!handle) { FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; return; } - int (*Mouse_Pointer_Not_Allow)(int enable, void* win); + // These functions are defined in vd-win-util's cursor_module.h. + int (*Mouse_Pointer_Not_Allow)(int enable, void* ecore_wl2_win); *(void**)(&Mouse_Pointer_Not_Allow) = dlsym(handle, "Mouse_Pointer_Not_Allow"); @@ -407,19 +378,22 @@ void TizenWindowEcoreWl2::SetFloatingMenuSupport() { return; } - Mouse_Pointer_Not_Allow(!floating_menu_support_, tcore_wl_window_); + Mouse_Pointer_Not_Allow(!floating_menu_support_, ecore_wl2_window_); dlclose(handle); } void TizenWindowEcoreWl2::ShowUnsupportedToast() { + // dlopen is used here because the TV-specific library libvd-win-util.so + // and the relevant headers are not present in the rootstrap. void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); if (!handle) { FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; return; } + // These functions are defined in vd-win-util's cursor_module.h. void (*Unsupported_Toast_Launch)(Device_Type type, int show, int enable, - void* win); + void* ecore_wl2_win); *(void**)(&Unsupported_Toast_Launch) = dlsym(handle, "Unsupported_Toast_Launch"); @@ -429,75 +403,60 @@ void TizenWindowEcoreWl2::ShowUnsupportedToast() { return; } - Unsupported_Toast_Launch(MOUSE_DEVICE, 1, 1, tcore_wl_window_); + Unsupported_Toast_Launch(MOUSE_DEVICE, 1, 1, ecore_wl2_window_); dlclose(handle); } #endif void TizenWindowEcoreWl2::RegisterEventHandlers() { - tizen_core_wl_event_listener_h listener = nullptr; - - // Window rotation event. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_WINDOW_ROTATION, - [](void* event, tizen_core_wl_event_type_e type, void* data) { + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_WL2_EVENT_WINDOW_ROTATE, + [](void* data, int type, void* event) -> Eina_Bool { auto* self = static_cast(data); if (self->view_delegate_) { - auto* base_event = - static_cast(event); - tizen_core_wl_window_h event_window = nullptr; - tizen_core_wl_event_window_base_get_window(base_event, &event_window); - if (event_window == self->tcore_wl_window_) { - tizen_core_wl_event_window_rotation_h rot_event = nullptr; - tizen_core_wl_event_window_base_to_window_rotation(base_event, - &rot_event); - tizen_core_wl_window_angle_e angle = TIZEN_CORE_WL_WINDOW_ANGLE_0; - tizen_core_wl_event_window_rotation_get_angle(rot_event, &angle); - int degree = static_cast(angle); + auto* rotation_event = + reinterpret_cast(event); + if (rotation_event->win == self->GetWindowId()) { + int32_t degree = rotation_event->angle; self->view_delegate_->OnRotate(degree); - tizen_core_wl_window_set_rotation_angle( - self->tcore_wl_window_, - static_cast(degree)); - tizen_core_wl_window_send_rotation_change_done( - self->tcore_wl_window_, degree); + TizenGeometry geometry = self->GetGeometry(); + ecore_wl2_window_rotation_set(self->ecore_wl2_window_, degree); + ecore_wl2_window_rotation_change_done_send( + self->ecore_wl2_window_, rotation_event->rotation, + geometry.width, geometry.height); + return ECORE_CALLBACK_DONE; } } + return ECORE_CALLBACK_PASS_ON; }, - this, &listener); - tcore_event_listeners_.push_back(listener); - - // Window configure event. + this)); if (!is_vulkan_) { - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_WINDOW_CONFIGURE_COMPLETE, - [](void* event, tizen_core_wl_event_type_e type, void* data) { + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_WL2_EVENT_WINDOW_CONFIGURE, + [](void* data, int type, void* event) -> Eina_Bool { auto* self = static_cast(data); if (self->view_delegate_) { - auto* base_event = - static_cast(event); - tizen_core_wl_window_h event_window = nullptr; - tizen_core_wl_event_window_base_get_window(base_event, - &event_window); - if (event_window == self->tcore_wl_window_) { - int x = 0, y = 0, w = 0, h = 0; - tizen_core_wl_window_get_geometry(self->tcore_wl_window_, &x, &y, - &w, &h); - int32_t rotation = self->GetRotation(); - tizen_core_wl_egl_window_resize(self->tcore_wl_egl_window_, w, h); - tizen_core_wl_egl_window_set_window_transform( - self->tcore_wl_egl_window_, rotation / 90); - self->view_delegate_->OnResize(x, y, w, h); + auto* configure_event = + reinterpret_cast(event); + if (configure_event->win == self->GetWindowId()) { + ecore_wl2_egl_window_resize_with_rotation( + self->ecore_wl2_egl_window_, configure_event->x, + configure_event->y, configure_event->w, configure_event->h, + self->GetRotation()); + + self->view_delegate_->OnResize( + configure_event->x, configure_event->y, configure_event->w, + configure_event->h); + return ECORE_CALLBACK_DONE; } } + return ECORE_CALLBACK_PASS_ON; }, - this, &listener); - tcore_event_listeners_.push_back(listener); + this)); } - - // Mouse button down. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_DOWN, - [](void* event, tizen_core_wl_event_type_e type, void* data) { + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_MOUSE_BUTTON_DOWN, + [](void* data, int type, void* event) -> Eina_Bool { auto* self = static_cast(data); #ifdef TV_PROFILE if ((!self->pointing_device_support_ || @@ -508,6 +467,7 @@ void TizenWindowEcoreWl2::RegisterEventHandlers() { self->SetFloatingMenuSupport(); } if (!shown) { + // Toast popup should be called first to set up D-PAD. self->ShowUnsupportedToast(); SetPointingDevicePreference(); } @@ -515,458 +475,282 @@ void TizenWindowEcoreWl2::RegisterEventHandlers() { if (self->floating_menu_support_ && !self->pointing_device_support_) { self->SetPointingDeviceSupport(); } - return; + return ECORE_CALLBACK_PASS_ON; } #endif + if (self->view_delegate_) { - auto* ev = static_cast(event); - tizen_core_wl_window_h event_window = nullptr; - tizen_core_wl_event_input_base_get_window(ev, &event_window); - if (event_window == self->tcore_wl_window_) { - int x = 0, y = 0; - tizen_core_wl_event_mouse_button_get_position(ev, &x, &y); - unsigned int buttons = 0; - tizen_core_wl_event_mouse_button_get_buttons(ev, &buttons); - uint32_t timestamp = 0; - tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); - unsigned int touch_id = 0; - tizen_core_wl_event_mouse_button_get_touch_id(ev, &touch_id); + auto* button_event = + reinterpret_cast(event); + if (button_event->window == self->GetWindowId()) { self->view_delegate_->OnPointerDown( - x, y, ToFlutterPointerButton(buttons), timestamp, - touch_id == 0 ? kFlutterPointerDeviceKindMouse - : kFlutterPointerDeviceKindTouch, - touch_id); + button_event->x, button_event->y, + ToFlutterPointerButton(button_event->buttons), + button_event->timestamp, ToFlutterDeviceKind(button_event->dev), + button_event->multi.device); + return ECORE_CALLBACK_DONE; } } + return ECORE_CALLBACK_PASS_ON; }, - this, &listener); - tcore_event_listeners_.push_back(listener); + this)); - // Mouse button up. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_UP, - [](void* event, tizen_core_wl_event_type_e type, void* data) { + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_MOUSE_BUTTON_UP, + [](void* data, int type, void* event) -> Eina_Bool { auto* self = static_cast(data); if (self->view_delegate_) { - auto* ev = static_cast(event); - tizen_core_wl_window_h event_window = nullptr; - tizen_core_wl_event_input_base_get_window(ev, &event_window); - if (event_window == self->tcore_wl_window_) { - int x = 0, y = 0; - tizen_core_wl_event_mouse_button_get_position(ev, &x, &y); - unsigned int buttons = 0; - tizen_core_wl_event_mouse_button_get_buttons(ev, &buttons); - uint32_t timestamp = 0; - tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); - unsigned int touch_id = 0; - tizen_core_wl_event_mouse_button_get_touch_id(ev, &touch_id); + auto* button_event = + reinterpret_cast(event); + if (button_event->window == self->GetWindowId()) { self->view_delegate_->OnPointerUp( - x, y, ToFlutterPointerButton(buttons), timestamp, - touch_id == 0 ? kFlutterPointerDeviceKindMouse - : kFlutterPointerDeviceKindTouch, - touch_id); + button_event->x, button_event->y, + ToFlutterPointerButton(button_event->buttons), + button_event->timestamp, ToFlutterDeviceKind(button_event->dev), + button_event->multi.device); + return ECORE_CALLBACK_DONE; } } + return ECORE_CALLBACK_PASS_ON; }, - this, &listener); - tcore_event_listeners_.push_back(listener); + this)); - // Mouse move. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_MOVE, - [](void* event, tizen_core_wl_event_type_e type, void* data) { + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_MOUSE_MOVE, + [](void* data, int type, void* event) -> Eina_Bool { auto* self = static_cast(data); if (self->view_delegate_) { - auto* ev = static_cast(event); - tizen_core_wl_window_h event_window = nullptr; - tizen_core_wl_event_input_base_get_window(ev, &event_window); - if (event_window == self->tcore_wl_window_) { - int x = 0, y = 0; - tizen_core_wl_event_mouse_move_get_position(ev, &x, &y); - uint32_t timestamp = 0; - tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); - unsigned int touch_id = 0; - tizen_core_wl_event_mouse_move_get_touch_id(ev, &touch_id); + auto* move_event = reinterpret_cast(event); + if (move_event->window == self->GetWindowId()) { self->view_delegate_->OnPointerMove( - x, y, timestamp, - touch_id == 0 ? kFlutterPointerDeviceKindMouse - : kFlutterPointerDeviceKindTouch, - touch_id); + move_event->x, move_event->y, move_event->timestamp, + ToFlutterDeviceKind(move_event->dev), move_event->multi.device); + return ECORE_CALLBACK_DONE; } } + return ECORE_CALLBACK_PASS_ON; }, - this, &listener); - tcore_event_listeners_.push_back(listener); + this)); - // Mouse wheel. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_WHEEL, - [](void* event, tizen_core_wl_event_type_e type, void* data) { + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_MOUSE_WHEEL, + [](void* data, int type, void* event) -> Eina_Bool { auto* self = static_cast(data); if (self->view_delegate_) { - auto* ev = static_cast(event); - tizen_core_wl_window_h event_window = nullptr; - tizen_core_wl_event_input_base_get_window(ev, &event_window); - if (event_window == self->tcore_wl_window_) { - int x = 0, y = 0; - tizen_core_wl_event_mouse_wheel_get_position(ev, &x, &y); - int direction = 0; - tizen_core_wl_event_mouse_wheel_get_direction(ev, &direction); - int z = 0; - tizen_core_wl_event_mouse_wheel_get_z(ev, &z); - uint32_t timestamp = 0; - tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); - + auto* wheel_event = reinterpret_cast(event); + if (wheel_event->window == self->GetWindowId()) { double delta_x = 0.0; double delta_y = 0.0; - if (direction == kScrollDirectionVertical) { - delta_y += z; - } else if (direction == kScrollDirectionHorizontal) { - delta_x += z; + + if (wheel_event->direction == kScrollDirectionVertical) { + delta_y += wheel_event->z; + } else if (wheel_event->direction == kScrollDirectionHorizontal) { + delta_x += wheel_event->z; } - self->view_delegate_->OnScroll(x, y, delta_x, delta_y, timestamp, - kFlutterPointerDeviceKindMouse, 0); + self->view_delegate_->OnScroll( + wheel_event->x, wheel_event->y, delta_x, delta_y, + wheel_event->timestamp, ToFlutterDeviceKind(wheel_event->dev), + 0); + return ECORE_CALLBACK_DONE; } } + return ECORE_CALLBACK_PASS_ON; }, - this, &listener); - tcore_event_listeners_.push_back(listener); + this)); - // Key down. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_DOWN, - [](void* event, tizen_core_wl_event_type_e type, void* data) { + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_KEY_DOWN, + [](void* data, int type, void* event) -> Eina_Bool { auto* self = static_cast(data); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [1] entered, view_delegate_=" - << (self->view_delegate_ ? "set" : "null") - << ", event=" << event; if (self->view_delegate_) { - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [2] casting event to base"; - auto* ev = static_cast(event); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [3] ev=" << ev; - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [4] getting event window"; - tizen_core_wl_window_h event_window = nullptr; - int ret_get_window = - tizen_core_wl_event_input_base_get_window(ev, &event_window); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [5] get_window ret=" - << ret_get_window << ", event_window=" << event_window - << ", self_window=" << self->tcore_wl_window_; - - if (event_window == self->tcore_wl_window_) { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [6] window matched, extracting key info"; - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [7] getting keyname"; - char* keyname = nullptr; - tizen_core_wl_event_key_get_keyname(ev, &keyname); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [8] keyname=" - << (keyname ? keyname : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [9] getting keysymbol"; - char* keysymbol = nullptr; - tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [10] keysymbol=" - << (keysymbol ? keysymbol : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [11] getting compose"; - char* compose = nullptr; - tizen_core_wl_event_key_get_compose(ev, &compose); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [12] compose=" - << (compose ? compose : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [13] getting modifiers"; - unsigned int modifiers = 0; - tizen_core_wl_event_key_get_modifiers(ev, &modifiers); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [14] modifiers=" << modifiers; - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [15] getting keycode"; - unsigned int keycode = 0; - tizen_core_wl_event_key_get_keycode(ev, &keycode); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [16] keycode=" << keycode; - - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [17] getting device_identifier"; - char* dev_identifier = nullptr; - tizen_core_wl_event_input_base_get_device_identifier( - ev, &dev_identifier); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [18] dev_identifier=" - << (dev_identifier ? dev_identifier : "null"); - - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [19] checking input_method_context_=" - << (self->input_method_context_ ? "set" : "null"); + auto* key_event = reinterpret_cast(event); + if (key_event->window == self->GetWindowId()) { bool handled = false; - if (self->input_method_context_) { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [20] calling IsInputPanelShown"; - bool panel_shown = - self->input_method_context_->IsInputPanelShown(); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [21] IsInputPanelShown=" - << panel_shown; - if (panel_shown) { - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [22] input panel shown, " - "calling HandleTcoreWlEventKey"; - handled = self->input_method_context_->HandleTcoreWlEventKey( - event, true); - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [23] IMF handled=" << handled; - } else { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [24] input panel NOT shown"; - } - } else { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [25] input_method_context_ is null"; + if (self->input_method_context_->IsInputPanelShown()) { + handled = self->input_method_context_->HandleEcoreEventKey( + key_event, true); } if (!handled) { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [26] calling view_delegate_->OnKey"; - self->view_delegate_->OnKey(keyname, keysymbol, compose, - modifiers, keycode, dev_identifier, - true); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [27] OnKey returned"; + self->view_delegate_->OnKey( + key_event->key, key_event->string, key_event->compose, + key_event->modifiers, key_event->keycode, + ecore_device_name_get(key_event->dev), true); } - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [28] freeing keyname"; - free(keyname); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [29] freeing keysymbol"; - free(keysymbol); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [30] freeing compose"; - free(compose); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [31] freeing dev_identifier"; - free(dev_identifier); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [32] done"; - } else { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: event window mismatch, ignoring"; + return ECORE_CALLBACK_DONE; } } + return ECORE_CALLBACK_PASS_ON; }, - this, &listener); - tcore_event_listeners_.push_back(listener); + this)); - // Key up. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_UP, - [](void* event, tizen_core_wl_event_type_e type, void* data) { + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_KEY_UP, + [](void* data, int type, void* event) -> Eina_Bool { auto* self = static_cast(data); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [1] entered, view_delegate_=" - << (self->view_delegate_ ? "set" : "null") - << ", event=" << event; if (self->view_delegate_) { - FT_LOG(Error) << "WL_EVENT_KEY_UP: [2] casting event to base"; - auto* ev = static_cast(event); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [3] ev=" << ev; - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [4] getting event window"; - tizen_core_wl_window_h event_window = nullptr; - int ret_get_window = - tizen_core_wl_event_input_base_get_window(ev, &event_window); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [5] get_window ret=" - << ret_get_window << ", event_window=" << event_window - << ", self_window=" << self->tcore_wl_window_; - - if (event_window == self->tcore_wl_window_) { - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [6] window matched, extracting key info"; - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [7] getting keyname"; - char* keyname = nullptr; - tizen_core_wl_event_key_get_keyname(ev, &keyname); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [8] keyname=" - << (keyname ? keyname : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [9] getting keysymbol"; - char* keysymbol = nullptr; - tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [10] keysymbol=" - << (keysymbol ? keysymbol : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [11] getting compose"; - char* compose = nullptr; - tizen_core_wl_event_key_get_compose(ev, &compose); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [12] compose=" - << (compose ? compose : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [13] getting modifiers"; - unsigned int modifiers = 0; - tizen_core_wl_event_key_get_modifiers(ev, &modifiers); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [14] modifiers=" << modifiers; - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [15] getting keycode"; - unsigned int keycode = 0; - tizen_core_wl_event_key_get_keycode(ev, &keycode); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [16] keycode=" << keycode; - - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [17] checking input_method_context_=" - << (self->input_method_context_ ? "set" : "null"); + auto* key_event = reinterpret_cast(event); + if (key_event->window == self->GetWindowId()) { bool handled = false; - if (self->input_method_context_) { - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [18] calling IsInputPanelShown"; - bool panel_shown = - self->input_method_context_->IsInputPanelShown(); - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [19] IsInputPanelShown=" << panel_shown; - if (panel_shown) { - FT_LOG(Error) << "WL_EVENT_KEY_UP: [20] input panel shown, " - "calling HandleTcoreWlEventKey"; - handled = self->input_method_context_->HandleTcoreWlEventKey( - event, false); - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [21] IMF handled=" << handled; - } else { - FT_LOG(Error) << "WL_EVENT_KEY_UP: [22] input panel NOT shown"; - } - } else { - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [23] input_method_context_ is null"; + if (self->input_method_context_->IsInputPanelShown()) { + handled = self->input_method_context_->HandleEcoreEventKey( + key_event, false); } if (!handled) { - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [24] calling view_delegate_->OnKey"; - self->view_delegate_->OnKey(keyname, keysymbol, compose, - modifiers, keycode, nullptr, false); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [25] OnKey returned"; + self->view_delegate_->OnKey( + key_event->key, key_event->string, key_event->compose, + key_event->modifiers, key_event->keycode, nullptr, false); } - FT_LOG(Error) << "WL_EVENT_KEY_UP: [26] freeing keyname"; - free(keyname); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [27] freeing keysymbol"; - free(keysymbol); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [28] freeing compose"; - free(compose); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [29] done"; - } else { - FT_LOG(Error) << "WL_EVENT_KEY_UP: event window mismatch, ignoring"; + return ECORE_CALLBACK_DONE; } } + return ECORE_CALLBACK_PASS_ON; }, - this, &listener); - tcore_event_listeners_.push_back(listener); + this)); } void TizenWindowEcoreWl2::UnregisterEventHandlers() { - for (tizen_core_wl_event_listener_h listener : tcore_event_listeners_) { - tizen_core_wl_event_remove_listener(tcore_wl_event_, listener); + for (Ecore_Event_Handler* handler : ecore_event_handlers_) { + ecore_event_handler_del(handler); } - tcore_event_listeners_.clear(); + ecore_event_handlers_.clear(); } void TizenWindowEcoreWl2::DestroyWindow() { - if (tcore_wl_egl_window_) { - tizen_core_wl_egl_window_destroy(tcore_wl_egl_window_); - tcore_wl_egl_window_ = nullptr; + if (ecore_wl2_egl_window_) { + ecore_wl2_egl_window_destroy(ecore_wl2_egl_window_); + ecore_wl2_egl_window_ = nullptr; } - if (tcore_wl_window_) { - tizen_core_wl_window_destroy(tcore_wl_window_); - tcore_wl_window_ = nullptr; + if (ecore_wl2_window_) { + ecore_wl2_window_free(ecore_wl2_window_); + ecore_wl2_window_ = nullptr; } - if (tcore_wl_display_) { - tizen_core_wl_display_disconnect(tcore_wl_display_); - tizen_core_wl_display_destroy(tcore_wl_display_); - tcore_wl_display_ = nullptr; + if (ecore_wl2_display_) { + ecore_wl2_display_disconnect(ecore_wl2_display_); + ecore_wl2_display_ = nullptr; } - tizen_core_wl_shutdown(); + ecore_wl2_shutdown(); } TizenGeometry TizenWindowEcoreWl2::GetGeometry() { TizenGeometry result; - tizen_core_wl_window_get_geometry(tcore_wl_window_, &result.left, &result.top, - &result.width, &result.height); + ecore_wl2_window_geometry_get(ecore_wl2_window_, &result.left, &result.top, + &result.width, &result.height); return result; } bool TizenWindowEcoreWl2::SetGeometry(TizenGeometry geometry) { - tizen_core_wl_window_set_geometry(tcore_wl_window_, geometry.left, - geometry.top, geometry.width, - geometry.height); - tizen_core_wl_window_set_position(tcore_wl_window_, geometry.left, - geometry.top); + ecore_wl2_window_rotation_geometry_set(ecore_wl2_window_, GetRotation(), + geometry.left, geometry.top, + geometry.width, geometry.height); + // FIXME: The changes set in `ecore_wl2_window_geometry_set` seems to apply + // only after calling `ecore_wl2_window_position_set`. Call a more + // appropriate API that flushes geometry settings to the compositor. + ecore_wl2_window_position_set(ecore_wl2_window_, geometry.left, geometry.top); return true; } TizenGeometry TizenWindowEcoreWl2::GetScreenGeometry() { TizenGeometry result = {}; - GList* output_list = nullptr; - tizen_core_wl_display_get_output_device_list(tcore_wl_display_, &output_list); - if (output_list) { - tizen_core_wl_output_h output = - static_cast(output_list->data); - tizen_core_wl_output_device_get_geometry(output, &result.width, - &result.height); - g_list_free(output_list); - } + ecore_wl2_display_screen_size_get(ecore_wl2_display_, &result.width, + &result.height); return result; } int32_t TizenWindowEcoreWl2::GetRotation() { - tizen_core_wl_window_angle_e angle = TIZEN_CORE_WL_WINDOW_ANGLE_0; - tizen_core_wl_window_get_rotation_angle(tcore_wl_window_, &angle); - return static_cast(angle); + return ecore_wl2_window_rotation_get(ecore_wl2_window_); } int32_t TizenWindowEcoreWl2::GetDpi() { - GList* output_list = nullptr; - tizen_core_wl_display_get_output_device_list(tcore_wl_display_, &output_list); - if (!output_list) { - FT_LOG(Error) << "Could not find an output device."; + Ecore_Wl2_Output* output = ecore_wl2_window_output_find(ecore_wl2_window_); + if (!output) { + FT_LOG(Error) << "Could not find an output associated with the window."; return 0; } - tizen_core_wl_output_h output = - static_cast(output_list->data); - g_list_free(output_list); - int dpi = 0; - tizen_core_wl_output_device_get_dpi(output, &dpi); - return dpi; + return ecore_wl2_output_dpi_get(output); } uintptr_t TizenWindowEcoreWl2::GetWindowId() { - return reinterpret_cast(tcore_wl_window_); + return ecore_wl2_window_id_get(ecore_wl2_window_); +} + +void HandleResourceId(void* data, tizen_resource* tizen_resource, uint32_t id) { + if (data) { + *reinterpret_cast(data) = id; + } } uint32_t TizenWindowEcoreWl2::GetResourceId() { if (resource_id_ > 0) { return resource_id_; } + struct wl_registry* registry = + ecore_wl2_display_registry_get(ecore_wl2_display_); + if (!registry) { + FT_LOG(Error) << "Could not retreive wl_registry from the display."; + return 0; + } - unsigned int res_id = 0; - if (tizen_core_wl_window_private_get_resource_id(tcore_wl_window_, &res_id) == - TIZEN_CORE_WL_ERROR_NONE) { - resource_id_ = res_id; + static const struct tizen_resource_listener tz_resource_listener = { + HandleResourceId}; + Eina_Iterator* iter = ecore_wl2_display_globals_get(ecore_wl2_display_); + Ecore_Wl2_Global* global = nullptr; + struct tizen_surface* surface = nullptr; + EINA_ITERATOR_FOREACH(iter, global) { + if (strcmp(global->interface, "tizen_surface") == 0) { + surface = static_cast(wl_registry_bind( + registry, global->id, &tizen_surface_interface, global->version)); + break; + } + } + eina_iterator_free(iter); + if (!surface) { + FT_LOG(Error) << "Failed to initialize the tizen surface."; + return 0; + } + + struct tizen_resource* resource = tizen_surface_get_tizen_resource( + surface, ecore_wl2_window_surface_get(ecore_wl2_window_)); + + if (!resource) { + FT_LOG(Error) << "Failed to get tizen resource."; + tizen_surface_destroy(surface); + return 0; + } + + struct wl_event_queue* event_queue = wl_display_create_queue(wl2_display_); + if (!event_queue) { + FT_LOG(Error) << "Failed to create wl_event_queue."; + tizen_resource_destroy(resource); + tizen_surface_destroy(surface); + return 0; } + wl_proxy_set_queue(reinterpret_cast(resource), event_queue); + tizen_resource_add_listener(resource, &tz_resource_listener, &resource_id_); + wl_display_roundtrip_queue(wl2_display_, event_queue); + tizen_resource_destroy(resource); + tizen_surface_destroy(surface); + wl_event_queue_destroy(event_queue); return resource_id_; } void TizenWindowEcoreWl2::SetPreferredOrientations( const std::vector& rotations) { - std::vector angles; - for (int rot : rotations) { - angles.push_back(static_cast(rot)); - } - tizen_core_wl_window_set_available_rotation_angle_list( - tcore_wl_window_, angles.data(), angles.size()); + ecore_wl2_window_available_rotations_set(ecore_wl2_window_, rotations.data(), + rotations.size()); } void TizenWindowEcoreWl2::BindKeys(const std::vector& keys) { for (const std::string& key : keys) { - tizen_core_wl_keygrab_info_h info = nullptr; - tizen_core_wl_keygrab_info_create(key.c_str(), - TIZEN_CORE_WL_KEYGRAB_TOPMOST, &info); - if (info) { - GList* list = g_list_append(nullptr, info); - tizen_core_wl_window_set_keygrab_list(tcore_wl_window_, list); - g_list_free(list); - tizen_core_wl_keygrab_info_destroy(info); - } + ecore_wl2_window_keygrab_set(ecore_wl2_window_, key.c_str(), 0, 0, 0, + ECORE_WL2_WINDOW_KEYGRAB_TOPMOST); } } void TizenWindowEcoreWl2::Show() { - tizen_core_wl_window_show(tcore_wl_window_); + ecore_wl2_window_show(ecore_wl2_window_); } void TizenWindowEcoreWl2::UpdateFlutterCursor(const std::string& kind) { @@ -978,31 +762,31 @@ void TizenWindowEcoreWl2::UpdateFlutterCursor(const std::string& kind) { std::string cursor_name = "normal_default"; if (kind == "basic") { - if (pointer_size == 0) { + if (pointer_size == 0) { // Large. cursor_name = "large_normal"; - } else if (pointer_size == 1) { + } else if (pointer_size == 1) { // Medium. cursor_name = "medium_normal"; - } else if (pointer_size == 2) { + } else if (pointer_size == 2) { // Small. cursor_name = "small_normal"; } else { cursor_name = "normal_default"; } } else if (kind == "click") { - if (pointer_size == 0) { + if (pointer_size == 0) { // Large. cursor_name = "large_normal_pnh"; - } else if (pointer_size == 1) { + } else if (pointer_size == 1) { // Medium. cursor_name = "medium_normal_pnh"; - } else if (pointer_size == 2) { + } else if (pointer_size == 2) { // Small. cursor_name = "small_normal_pnh"; } else { cursor_name = "normal_pnh"; } } else if (kind == "text") { - if (pointer_size == 0) { + if (pointer_size == 0) { // Large. cursor_name = "large_normal_input_field"; - } else if (pointer_size == 1) { + } else if (pointer_size == 1) { // Medium. cursor_name = "medium_normal_input_field"; - } else if (pointer_size == 2) { + } else if (pointer_size == 2) { // Small. cursor_name = "small_normal_input_field"; } else { cursor_name = "normal_input_field"; @@ -1012,36 +796,53 @@ void TizenWindowEcoreWl2::UpdateFlutterCursor(const std::string& kind) { } else { FT_LOG(Info) << kind << " cursor is not supported."; } - tizen_core_wl_seat_h default_seat = nullptr; - tizen_core_wl_display_get_default_seat(tcore_wl_display_, &default_seat); - if (default_seat) { - tizen_core_wl_seat_set_cursor_theme(default_seat, - kTcoreWlInputCursorThemeName); - tizen_core_wl_seat_set_cursor_name(default_seat, cursor_name.c_str()); - } else { - tizen_core_wl_seat_set_cursor_theme(default_seat, "default"); - tizen_core_wl_seat_set_cursor_name(default_seat, "left_ptr"); - } + ecore_wl2_input_cursor_theme_name_set( + ecore_wl2_input_default_input_get(ecore_wl2_display_), + kEcoreWL2InputCursorThemeName); + ecore_wl2_input_cursor_from_name_set( + ecore_wl2_input_default_input_get(ecore_wl2_display_), + cursor_name.c_str()); #else - tizen_core_wl_seat_h default_seat = nullptr; - tizen_core_wl_display_get_default_seat(tcore_wl_display_, &default_seat); - if (default_seat) { - tizen_core_wl_seat_set_cursor_theme(default_seat, "default"); - tizen_core_wl_seat_set_cursor_name(default_seat, "left_ptr"); - } FT_LOG(Info) << "UpdateFlutterCursor is not supported."; #endif } -void TizenWindowEcoreWl2::SetNotificationLevel(int level) { - tizen_core_wl_notification_set_level( - tcore_wl_window_, static_cast(level)); +void TizenWindowEcoreWl2::SetTizenPolicyNotificationLevel(int level) { + wl_registry* registry = ecore_wl2_display_registry_get(ecore_wl2_display_); + if (!registry) { + FT_LOG(Error) << "Could not retreive wl_registry from the display."; + return; + } + + Eina_Iterator* iter = ecore_wl2_display_globals_get(ecore_wl2_display_); + Ecore_Wl2_Global* global = nullptr; + + // Retrieve global objects to bind a tizen policy. + EINA_ITERATOR_FOREACH(iter, global) { + if (strcmp(global->interface, tizen_policy_interface.name) == 0) { + tizen_policy_ = static_cast( + wl_registry_bind(registry, global->id, &tizen_policy_interface, 1)); + break; + } + } + eina_iterator_free(iter); + + if (!tizen_policy_) { + FT_LOG(Error) + << "Failed to initialize the tizen policy handle, the top_level " + "attribute is ignored."; + return; + } + + tizen_policy_set_notification_level( + tizen_policy_, ecore_wl2_window_surface_get(ecore_wl2_window_), level); } void TizenWindowEcoreWl2::PrepareInputMethod() { input_method_context_ = std::make_unique(GetWindowId()); + // Set input method callbacks. input_method_context_->SetOnPreeditStart( [this]() { view_delegate_->OnComposeBegin(); }); input_method_context_->SetOnPreeditChanged( @@ -1058,20 +859,20 @@ void* TizenWindowEcoreWl2::GetRenderTarget() { if (is_vulkan_) { return wl2_surface_; } else { - return tcore_wl_egl_window_; + return ecore_wl2_egl_window_; } } void TizenWindowEcoreWl2::ActivateWindow() { - tizen_core_wl_window_activate(tcore_wl_window_); + ecore_wl2_window_activate(ecore_wl2_window_); } void TizenWindowEcoreWl2::RaiseWindow() { - tizen_core_wl_window_raise(tcore_wl_window_); + ecore_wl2_window_raise(ecore_wl2_window_); } void TizenWindowEcoreWl2::LowerWindow() { - tizen_core_wl_window_lower(tcore_wl_window_); + ecore_wl2_window_lower(ecore_wl2_window_); } } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.h b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.h index 4ab113f2..3cc1a9d0 100644 --- a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.h +++ b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.h @@ -5,8 +5,8 @@ #ifndef EMBEDDER_TIZEN_WINDOW_ECORE_WL2_H_ #define EMBEDDER_TIZEN_WINDOW_ECORE_WL2_H_ -#include -#include +#define EFL_BETA_API_SUPPORT +#include #include #include @@ -40,7 +40,7 @@ class TizenWindowEcoreWl2 : public TizenWindow { void* GetRenderTargetDisplay() override { return wl2_display_; } - void* GetNativeHandle() override { return tcore_wl_window_; } + void* GetNativeHandle() override { return ecore_wl2_window_; } int32_t GetRotation() override; @@ -85,17 +85,17 @@ class TizenWindowEcoreWl2 : public TizenWindow { void UnregisterEventHandlers(); - void SetNotificationLevel(int level); + void SetTizenPolicyNotificationLevel(int level); void PrepareInputMethod(); - tizen_core_wl_display_h tcore_wl_display_ = nullptr; - tizen_core_wl_window_h tcore_wl_window_ = nullptr; - tizen_core_wl_egl_window_h tcore_wl_egl_window_ = nullptr; - tizen_core_event_h tcore_wl_event_ = nullptr; + Ecore_Wl2_Display* ecore_wl2_display_ = nullptr; + Ecore_Wl2_Window* ecore_wl2_window_ = nullptr; + Ecore_Wl2_Egl_Window* ecore_wl2_egl_window_ = nullptr; wl_display* wl2_display_ = nullptr; wl_surface* wl2_surface_ = nullptr; - std::vector tcore_event_listeners_; + std::vector ecore_event_handlers_; + tizen_policy* tizen_policy_ = nullptr; uint32_t resource_id_ = 0; #ifdef TV_PROFILE diff --git a/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc new file mode 100644 index 00000000..593fef2e --- /dev/null +++ b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc @@ -0,0 +1,1077 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tizen_window_tcore_wl.h" + +#ifdef TV_PROFILE +#include +#include +#include +#include +#include +#include +#endif + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" + +// Forward declarations for rotation APIs that exist in the library +// but are not yet declared in the public header. +extern "C" { +tizen_core_wl_error_e tizen_core_wl_window_set_rotation_angle( + tizen_core_wl_window_h window, + tizen_core_wl_window_angle_e angle); +tizen_core_wl_error_e tizen_core_wl_window_get_rotation_angle( + tizen_core_wl_window_h window, + tizen_core_wl_window_angle_e* angle); +tizen_core_wl_error_e tizen_core_wl_window_set_available_rotation_angle_list( + tizen_core_wl_window_h window, + tizen_core_wl_window_angle_e* available_angles, + size_t available_angle_count); +} + +namespace flutter { + +namespace { + +constexpr int kScrollDirectionVertical = 0; +constexpr int kScrollDirectionHorizontal = 1; + +#ifdef TV_PROFILE +constexpr char kSysMouseCursorPointerSizeVConfKey[] = + "db/menu/system/mouse-pointer-size"; +constexpr char kSysPointingDeviceSupportToastSharedPreferenceKey[] = + "flutter-tizen/preference/pointing-device-support-toast"; +constexpr char kTcoreWlInputCursorThemeName[] = "vd-cursors"; +#endif + +FlutterPointerMouseButtons ToFlutterPointerButton(int32_t button) { + if (button == 2) { + return kFlutterPointerButtonMouseMiddle; + } else if (button == 3) { + return kFlutterPointerButtonMouseSecondary; + } else { + return kFlutterPointerButtonMousePrimary; + } +} + +// FlutterPointerDeviceKind GetDeviceKindFromEventType(int event_type) { +// if (event_type == TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_DOWN || +// event_type == TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_UP || +// event_type == TIZEN_CORE_WL_EVENT_MOUSE_MOVE || +// event_type == TIZEN_CORE_WL_EVENT_MOUSE_WHEEL) { +// // The event system doesn't distinguish mouse vs touch at event level. +// // Default to touch; mouse events can be differentiated by touch_id == 0. +// return kFlutterPointerDeviceKindTouch; +// } +// return kFlutterPointerDeviceKindTouch; +// } + +#ifdef TV_PROFILE +time_t GetBootTimeEpoch() { + struct timespec now, boot_time; + if (clock_gettime(CLOCK_REALTIME, &now) != 0) { + FT_LOG(Error) << "Fail to get clock_gettime(CLOCK_REALTIME)."; + return -1; + } + if (clock_gettime(CLOCK_BOOTTIME, &boot_time) != 0) { + FT_LOG(Error) << "Fail to get clock_gettime(CLOCK_BOOTTIME)."; + return -1; + } + time_t boot_time_epoch = now.tv_sec - boot_time.tv_sec; + return (boot_time_epoch / 10) * 10; +} + +bool PreferenceItemCallback(const char* key, void* user_data) { + char* app_id = (char*)user_data; + if (!app_id || !key) { + return true; + } + + std::string preference_key = + std::string(kSysPointingDeviceSupportToastSharedPreferenceKey) + "/" + + app_id; + if (!strncmp(key, preference_key.c_str(), preference_key.length())) { + preference_remove(key); + } + return true; +} + +std::string GetPreferenceKey(bool clear_exist_key) { + time_t boot_time = GetBootTimeEpoch(); + if (boot_time == -1) { + return ""; + } + + char* id = nullptr; + int ret = app_get_id(&id); + if (ret != APP_CONTROL_ERROR_NONE || !id) { + FT_LOG(Error) << "Fail to get app id."; + return std::string(); + } + + std::string app_id = id; + free(id); + + std::ostringstream boot_time_buffer; + boot_time_buffer << boot_time; + + std::string preference_key = + std::string(kSysPointingDeviceSupportToastSharedPreferenceKey) + "/" + + app_id + "/" + boot_time_buffer.str(); + + if (clear_exist_key) { + preference_foreach_item(PreferenceItemCallback, (void*)app_id.c_str()); + } + return preference_key; +} + +bool GetPointingDeviceToastPreference() { + bool show_unsupported_toast = false; + std::string preference_key = GetPreferenceKey(false); + if (preference_key.empty()) { + return false; + } + + int ret = + preference_get_boolean(preference_key.c_str(), &show_unsupported_toast); + if (ret != PREFERENCE_ERROR_NONE) { + return false; + } + return show_unsupported_toast; +} + +void SetPointingDevicePreference() { + std::string preference_key = GetPreferenceKey(true); + if (preference_key.empty()) { + return; + } + + int ret = preference_set_boolean(preference_key.c_str(), true); + if (ret != PREFERENCE_ERROR_NONE) { + FT_LOG(Error) << "Fail to set toasted preference."; + } +} +#endif + +} // namespace + +TizenWindowTcoreWl::TizenWindowTcoreWl(TizenGeometry geometry, + bool transparent, + bool focusable, + bool top_level, + bool pointing_device_support, + bool floating_menu_support, + void* window_handle = nullptr, + bool is_vulkan = false) + : TizenWindow(geometry, transparent, focusable, top_level) +#ifdef TV_PROFILE + , + pointing_device_support_(pointing_device_support), + floating_menu_support_(floating_menu_support) +#endif + , + is_vulkan_(is_vulkan) { + if (!CreateWindow(window_handle)) { + FT_LOG(Error) << "Failed to create a platform window."; + return; + } + + SetWindowOptions(); + RegisterEventHandlers(); + PrepareInputMethod(); + Show(); +} + +TizenWindowTcoreWl::~TizenWindowTcoreWl() { + UnregisterEventHandlers(); + DestroyWindow(); +} + +bool TizenWindowTcoreWl::CreateWindow(void* window_handle) { + FT_LOG(Error) << "tizen core wl init()!!!!!!! "; + + if (tizen_core_wl_init() != TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Could not initialize tizen core wl."; + return false; + } + + if (tizen_core_wl_display_create(&tcore_wl_display_) != + TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Could not create tizen core wl display."; + return false; + } + + if (tizen_core_wl_display_connect(tcore_wl_display_, nullptr) != + TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Tizen core wl display not found."; + return false; + } + + tizen_core_wl_display_private_get_wl_display(tcore_wl_display_, + &wl2_display_); + + tizen_core_wl_display_sync(tcore_wl_display_); + + tizen_core_wl_display_get_event(tcore_wl_display_, &tcore_wl_event_); + + int32_t width = 0, height = 0; + GList* output_list = nullptr; + tizen_core_wl_display_get_output_device_list(tcore_wl_display_, &output_list); + if (output_list) { + tizen_core_wl_output_h output = + static_cast(output_list->data); + tizen_core_wl_output_device_get_geometry(output, &width, &height); + g_list_free(output_list); + } + if (width == 0 || height == 0) { + FT_LOG(Error) << "Invalid screen size: " << width << " x " << height; + return false; + } + + if (initial_geometry_.width == 0) { + initial_geometry_.width = width; + } + if (initial_geometry_.height == 0) { + initial_geometry_.height = height; + } + + if (window_handle == nullptr) { + if (tizen_core_wl_create_window( + tcore_wl_display_, nullptr, initial_geometry_.left, + initial_geometry_.top, initial_geometry_.width, + initial_geometry_.height, + &tcore_wl_window_) != TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Could not create tizen core wl window."; + return false; + } + } else { + tcore_wl_window_ = static_cast(window_handle); + } + + if (is_vulkan_) { + tizen_core_wl_window_private_get_wl_surface(tcore_wl_window_, + &wl2_surface_); + return wl2_surface_ && wl2_display_; + } else { + if (tizen_core_wl_create_egl_window( + tcore_wl_window_, initial_geometry_.width, initial_geometry_.height, + &tcore_wl_egl_window_) != TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Could not create tizen core wl egl window."; + return false; + } + return tcore_wl_egl_window_ && wl2_display_; + } +} + +void TizenWindowTcoreWl::SetWindowOptions() { + tizen_core_wl_window_set_type( + tcore_wl_window_, top_level_ ? TIZEN_CORE_WL_WINDOW_TYPE_NOTIFICATION + : TIZEN_CORE_WL_WINDOW_TYPE_TOPLEVEL); + if (top_level_) { + SetNotificationLevel(TIZEN_CORE_WL_NOTIFICATION_LEVEL_TOP); + } + + tizen_core_wl_window_set_position(tcore_wl_window_, initial_geometry_.left, + initial_geometry_.top); + tizen_core_wl_window_set_aux_hint(tcore_wl_window_, + "wm.policy.win.user.geometry", "1"); + + tizen_core_wl_window_set_alpha(tcore_wl_window_, transparent_); + + if (!focusable_) { + tizen_core_wl_window_set_focus_skip(tcore_wl_window_, true); + } + +#ifdef TV_PROFILE + tizen_core_wl_window_angle_e rotations[1] = {TIZEN_CORE_WL_WINDOW_ANGLE_0}; +#else + tizen_core_wl_window_angle_e rotations[4] = { + TIZEN_CORE_WL_WINDOW_ANGLE_0, TIZEN_CORE_WL_WINDOW_ANGLE_90, + TIZEN_CORE_WL_WINDOW_ANGLE_180, TIZEN_CORE_WL_WINDOW_ANGLE_270}; +#endif + tizen_core_wl_window_set_available_rotation_angle_list( + tcore_wl_window_, rotations, sizeof(rotations) / sizeof(rotations[0])); + EnableCursor(); +} + +void TizenWindowTcoreWl::EnableCursor() { +#ifdef TV_PROFILE + void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); + if (!handle) { + FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; + return; + } + + int (*CursorModule_Initialize)(wl_display* display, wl_registry* registry, + wl_seat* seat, unsigned int id); + int (*Cursor_Set_Config)(wl_surface* surface, uint32_t config_type, + void* data); + void (*CursorModule_Finalize)(void); + *(void**)(&CursorModule_Initialize) = + dlsym(handle, "CursorModule_Initialize"); + *(void**)(&Cursor_Set_Config) = dlsym(handle, "Cursor_Set_Config"); + *(void**)(&CursorModule_Finalize) = dlsym(handle, "CursorModule_Finalize"); + + if (!CursorModule_Initialize || !Cursor_Set_Config || + !CursorModule_Finalize) { + FT_LOG(Error) << "Could not load symbols from the library."; + dlclose(handle); + return; + } + + tizen_core_wl_seat_h default_seat = nullptr; + tizen_core_wl_display_get_default_seat(tcore_wl_display_, &default_seat); + if (!default_seat) { + FT_LOG(Error) << "Could not get default seat."; + dlclose(handle); + return; + } + struct wl_seat* seat = nullptr; + tizen_core_wl_seat_private_get_wl_seat(default_seat, &seat); + if (!seat) { + FT_LOG(Error) << "Could not get wl_seat from the default seat."; + dlclose(handle); + return; + } + + int cursor_global_id = 0; + if (tizen_core_wl_display_private_get_global_id( + tcore_wl_display_, "tizen_cursor", &cursor_global_id) == + TIZEN_CORE_WL_ERROR_NONE && + cursor_global_id > 0) { + struct wl_registry* registry = wl_display_get_registry(wl2_display_); + if (registry) { + if (!CursorModule_Initialize(wl2_display_, registry, seat, + cursor_global_id)) { + FT_LOG(Error) << "Failed to initialize the cursor module."; + } + wl_registry_destroy(registry); + } + } + + tizen_core_wl_display_sync(tcore_wl_display_); + + struct wl_surface* surface = nullptr; + tizen_core_wl_window_private_get_wl_surface(tcore_wl_window_, &surface); + if (surface && !Cursor_Set_Config(surface, 1, nullptr)) { + FT_LOG(Error) << "Failed to set a cursor config value."; + } + + CursorModule_Finalize(); + dlclose(handle); +#endif +} + +#ifdef TV_PROFILE +typedef enum _MouseSupport { DISABLE = 0, ENABLE } MouseSupport; +typedef enum _Device_Type { MOUSE_DEVICE = 3, TOUCH_DEVICE } Device_Type; + +void TizenWindowTcoreWl::SetPointingDeviceSupport() { + void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); + if (!handle) { + FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; + return; + } + + int (*Mouse_Pointer_Support)(MouseSupport type, void* win); + *(void**)(&Mouse_Pointer_Support) = dlsym(handle, "Mouse_Pointer_Support"); + + if (!Mouse_Pointer_Support) { + FT_LOG(Error) << "Could not load symbols from the library."; + dlclose(handle); + return; + } + + Mouse_Pointer_Support(pointing_device_support_ ? ENABLE : DISABLE, + tcore_wl_window_); + dlclose(handle); +} + +void TizenWindowTcoreWl::SetFloatingMenuSupport() { + void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); + if (!handle) { + FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; + return; + } + + int (*Mouse_Pointer_Not_Allow)(int enable, void* win); + *(void**)(&Mouse_Pointer_Not_Allow) = + dlsym(handle, "Mouse_Pointer_Not_Allow"); + + if (!Mouse_Pointer_Not_Allow) { + FT_LOG(Error) << "Could not load symbols from the library."; + dlclose(handle); + return; + } + + Mouse_Pointer_Not_Allow(!floating_menu_support_, tcore_wl_window_); + dlclose(handle); +} + +void TizenWindowTcoreWl::ShowUnsupportedToast() { + void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); + if (!handle) { + FT_LOG(Error) << "Could not open a shared library libvd-win-util.so."; + return; + } + + void (*Unsupported_Toast_Launch)(Device_Type type, int show, int enable, + void* win); + *(void**)(&Unsupported_Toast_Launch) = + dlsym(handle, "Unsupported_Toast_Launch"); + + if (!Unsupported_Toast_Launch) { + FT_LOG(Error) << "Could not load symbols from the library."; + dlclose(handle); + return; + } + + Unsupported_Toast_Launch(MOUSE_DEVICE, 1, 1, tcore_wl_window_); + dlclose(handle); +} +#endif + +void TizenWindowTcoreWl::RegisterEventHandlers() { + tizen_core_wl_event_listener_h listener = nullptr; + + // Window rotation event. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_WINDOW_ROTATION, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); + if (self->view_delegate_) { + auto* base_event = + static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_window_base_get_window(base_event, &event_window); + if (event_window == self->tcore_wl_window_) { + tizen_core_wl_event_window_rotation_h rot_event = nullptr; + tizen_core_wl_event_window_base_to_window_rotation(base_event, + &rot_event); + tizen_core_wl_window_angle_e angle = TIZEN_CORE_WL_WINDOW_ANGLE_0; + tizen_core_wl_event_window_rotation_get_angle(rot_event, &angle); + int degree = static_cast(angle); + self->view_delegate_->OnRotate(degree); + tizen_core_wl_window_set_rotation_angle( + self->tcore_wl_window_, + static_cast(degree)); + tizen_core_wl_window_send_rotation_change_done( + self->tcore_wl_window_, degree); + } + } + }, + this, &listener); + tcore_event_listeners_.push_back(listener); + + // Window configure event. + if (!is_vulkan_) { + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_WINDOW_CONFIGURE_COMPLETE, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); + if (self->view_delegate_) { + auto* base_event = + static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_window_base_get_window(base_event, + &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0, w = 0, h = 0; + tizen_core_wl_window_get_geometry(self->tcore_wl_window_, &x, &y, + &w, &h); + int32_t rotation = self->GetRotation(); + tizen_core_wl_egl_window_resize(self->tcore_wl_egl_window_, w, h); + tizen_core_wl_egl_window_set_window_transform( + self->tcore_wl_egl_window_, rotation / 90); + self->view_delegate_->OnResize(x, y, w, h); + } + } + }, + this, &listener); + tcore_event_listeners_.push_back(listener); + } + + // Mouse button down. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_DOWN, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); +#ifdef TV_PROFILE + if ((!self->pointing_device_support_ || + !self->floating_menu_support_) && + !self->show_unsupported_toast_) { + bool shown = GetPointingDeviceToastPreference(); + if (!self->floating_menu_support_) { + self->SetFloatingMenuSupport(); + } + if (!shown) { + self->ShowUnsupportedToast(); + SetPointingDevicePreference(); + } + self->show_unsupported_toast_ = true; + if (self->floating_menu_support_ && !self->pointing_device_support_) { + self->SetPointingDeviceSupport(); + } + return; + } +#endif + if (self->view_delegate_) { + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0; + tizen_core_wl_event_mouse_button_get_position(ev, &x, &y); + unsigned int buttons = 0; + tizen_core_wl_event_mouse_button_get_buttons(ev, &buttons); + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + unsigned int touch_id = 0; + tizen_core_wl_event_mouse_button_get_touch_id(ev, &touch_id); + self->view_delegate_->OnPointerDown( + x, y, ToFlutterPointerButton(buttons), timestamp, + touch_id == 0 ? kFlutterPointerDeviceKindMouse + : kFlutterPointerDeviceKindTouch, + touch_id); + } + } + }, + this, &listener); + tcore_event_listeners_.push_back(listener); + + // Mouse button up. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_UP, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); + if (self->view_delegate_) { + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0; + tizen_core_wl_event_mouse_button_get_position(ev, &x, &y); + unsigned int buttons = 0; + tizen_core_wl_event_mouse_button_get_buttons(ev, &buttons); + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + unsigned int touch_id = 0; + tizen_core_wl_event_mouse_button_get_touch_id(ev, &touch_id); + self->view_delegate_->OnPointerUp( + x, y, ToFlutterPointerButton(buttons), timestamp, + touch_id == 0 ? kFlutterPointerDeviceKindMouse + : kFlutterPointerDeviceKindTouch, + touch_id); + } + } + }, + this, &listener); + tcore_event_listeners_.push_back(listener); + + // Mouse move. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_MOVE, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); + if (self->view_delegate_) { + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0; + tizen_core_wl_event_mouse_move_get_position(ev, &x, &y); + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + unsigned int touch_id = 0; + tizen_core_wl_event_mouse_move_get_touch_id(ev, &touch_id); + self->view_delegate_->OnPointerMove( + x, y, timestamp, + touch_id == 0 ? kFlutterPointerDeviceKindMouse + : kFlutterPointerDeviceKindTouch, + touch_id); + } + } + }, + this, &listener); + tcore_event_listeners_.push_back(listener); + + // Mouse wheel. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_WHEEL, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); + if (self->view_delegate_) { + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window == self->tcore_wl_window_) { + int x = 0, y = 0; + tizen_core_wl_event_mouse_wheel_get_position(ev, &x, &y); + int direction = 0; + tizen_core_wl_event_mouse_wheel_get_direction(ev, &direction); + int z = 0; + tizen_core_wl_event_mouse_wheel_get_z(ev, &z); + uint32_t timestamp = 0; + tizen_core_wl_event_input_base_get_timestamp(ev, ×tamp); + + double delta_x = 0.0; + double delta_y = 0.0; + if (direction == kScrollDirectionVertical) { + delta_y += z; + } else if (direction == kScrollDirectionHorizontal) { + delta_x += z; + } + + self->view_delegate_->OnScroll(x, y, delta_x, delta_y, timestamp, + kFlutterPointerDeviceKindMouse, 0); + } + } + }, + this, &listener); + tcore_event_listeners_.push_back(listener); + + // Key down. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_DOWN, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [1] entered, view_delegate_=" + << (self->view_delegate_ ? "set" : "null") + << ", event=" << event; + if (self->view_delegate_) { + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [2] casting event to base"; + auto* ev = static_cast(event); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [3] ev=" << ev; + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [4] getting event window"; + tizen_core_wl_window_h event_window = nullptr; + int ret_get_window = + tizen_core_wl_event_input_base_get_window(ev, &event_window); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [5] get_window ret=" + << ret_get_window << ", event_window=" << event_window + << ", self_window=" << self->tcore_wl_window_; + + if (event_window == self->tcore_wl_window_) { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [6] window matched, extracting key info"; + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [7] getting keyname"; + char* keyname = nullptr; + tizen_core_wl_event_key_get_keyname(ev, &keyname); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [8] keyname=" + << (keyname ? keyname : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [9] getting keysymbol"; + char* keysymbol = nullptr; + tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [10] keysymbol=" + << (keysymbol ? keysymbol : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [11] getting compose"; + char* compose = nullptr; + tizen_core_wl_event_key_get_compose(ev, &compose); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [12] compose=" + << (compose ? compose : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [13] getting modifiers"; + unsigned int modifiers = 0; + tizen_core_wl_event_key_get_modifiers(ev, &modifiers); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [14] modifiers=" << modifiers; + + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [15] getting keycode"; + unsigned int keycode = 0; + tizen_core_wl_event_key_get_keycode(ev, &keycode); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [16] keycode=" << keycode; + + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [17] getting device_identifier"; + char* dev_identifier = nullptr; + tizen_core_wl_event_input_base_get_device_identifier( + ev, &dev_identifier); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [18] dev_identifier=" + << (dev_identifier ? dev_identifier : "null"); + + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [19] checking input_method_context_=" + << (self->input_method_context_ ? "set" : "null"); + bool handled = false; + if (self->input_method_context_) { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [20] calling IsInputPanelShown"; + bool panel_shown = + self->input_method_context_->IsInputPanelShown(); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [21] IsInputPanelShown=" + << panel_shown; + if (panel_shown) { + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [22] input panel shown, " + "calling HandleTcoreWlEventKey"; + handled = self->input_method_context_->HandleTcoreWlEventKey( + event, true); + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [23] IMF handled=" << handled; + } else { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [24] input panel NOT shown"; + } + } else { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [25] input_method_context_ is null"; + } + if (!handled) { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: [26] calling view_delegate_->OnKey"; + self->view_delegate_->OnKey(keyname, keysymbol, compose, + modifiers, keycode, dev_identifier, + true); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [27] OnKey returned"; + } + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [28] freeing keyname"; + free(keyname); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [29] freeing keysymbol"; + free(keysymbol); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [30] freeing compose"; + free(compose); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [31] freeing dev_identifier"; + free(dev_identifier); + FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [32] done"; + } else { + FT_LOG(Error) + << "WL_EVENT_KEY_DOWN: event window mismatch, ignoring"; + } + } + }, + this, &listener); + tcore_event_listeners_.push_back(listener); + + // Key up. + tizen_core_wl_event_add_listener( + tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_UP, + [](void* event, tizen_core_wl_event_type_e type, void* data) { + auto* self = static_cast(data); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [1] entered, view_delegate_=" + << (self->view_delegate_ ? "set" : "null") + << ", event=" << event; + if (self->view_delegate_) { + FT_LOG(Error) << "WL_EVENT_KEY_UP: [2] casting event to base"; + auto* ev = static_cast(event); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [3] ev=" << ev; + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [4] getting event window"; + tizen_core_wl_window_h event_window = nullptr; + int ret_get_window = + tizen_core_wl_event_input_base_get_window(ev, &event_window); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [5] get_window ret=" + << ret_get_window << ", event_window=" << event_window + << ", self_window=" << self->tcore_wl_window_; + + if (event_window == self->tcore_wl_window_) { + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [6] window matched, extracting key info"; + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [7] getting keyname"; + char* keyname = nullptr; + tizen_core_wl_event_key_get_keyname(ev, &keyname); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [8] keyname=" + << (keyname ? keyname : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [9] getting keysymbol"; + char* keysymbol = nullptr; + tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [10] keysymbol=" + << (keysymbol ? keysymbol : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [11] getting compose"; + char* compose = nullptr; + tizen_core_wl_event_key_get_compose(ev, &compose); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [12] compose=" + << (compose ? compose : "null"); + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [13] getting modifiers"; + unsigned int modifiers = 0; + tizen_core_wl_event_key_get_modifiers(ev, &modifiers); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [14] modifiers=" << modifiers; + + FT_LOG(Error) << "WL_EVENT_KEY_UP: [15] getting keycode"; + unsigned int keycode = 0; + tizen_core_wl_event_key_get_keycode(ev, &keycode); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [16] keycode=" << keycode; + + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [17] checking input_method_context_=" + << (self->input_method_context_ ? "set" : "null"); + bool handled = false; + if (self->input_method_context_) { + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [18] calling IsInputPanelShown"; + bool panel_shown = + self->input_method_context_->IsInputPanelShown(); + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [19] IsInputPanelShown=" << panel_shown; + if (panel_shown) { + FT_LOG(Error) << "WL_EVENT_KEY_UP: [20] input panel shown, " + "calling HandleTcoreWlEventKey"; + handled = self->input_method_context_->HandleTcoreWlEventKey( + event, false); + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [21] IMF handled=" << handled; + } else { + FT_LOG(Error) << "WL_EVENT_KEY_UP: [22] input panel NOT shown"; + } + } else { + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [23] input_method_context_ is null"; + } + if (!handled) { + FT_LOG(Error) + << "WL_EVENT_KEY_UP: [24] calling view_delegate_->OnKey"; + self->view_delegate_->OnKey(keyname, keysymbol, compose, + modifiers, keycode, nullptr, false); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [25] OnKey returned"; + } + FT_LOG(Error) << "WL_EVENT_KEY_UP: [26] freeing keyname"; + free(keyname); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [27] freeing keysymbol"; + free(keysymbol); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [28] freeing compose"; + free(compose); + FT_LOG(Error) << "WL_EVENT_KEY_UP: [29] done"; + } else { + FT_LOG(Error) << "WL_EVENT_KEY_UP: event window mismatch, ignoring"; + } + } + }, + this, &listener); + tcore_event_listeners_.push_back(listener); +} + +void TizenWindowTcoreWl::UnregisterEventHandlers() { + for (tizen_core_wl_event_listener_h listener : tcore_event_listeners_) { + tizen_core_wl_event_remove_listener(tcore_wl_event_, listener); + } + tcore_event_listeners_.clear(); +} + +void TizenWindowTcoreWl::DestroyWindow() { + if (tcore_wl_egl_window_) { + tizen_core_wl_egl_window_destroy(tcore_wl_egl_window_); + tcore_wl_egl_window_ = nullptr; + } + + if (tcore_wl_window_) { + tizen_core_wl_window_destroy(tcore_wl_window_); + tcore_wl_window_ = nullptr; + } + + if (tcore_wl_display_) { + tizen_core_wl_display_disconnect(tcore_wl_display_); + tizen_core_wl_display_destroy(tcore_wl_display_); + tcore_wl_display_ = nullptr; + } + tizen_core_wl_shutdown(); +} + +TizenGeometry TizenWindowTcoreWl::GetGeometry() { + TizenGeometry result; + tizen_core_wl_window_get_geometry(tcore_wl_window_, &result.left, &result.top, + &result.width, &result.height); + return result; +} + +bool TizenWindowTcoreWl::SetGeometry(TizenGeometry geometry) { + tizen_core_wl_window_set_geometry(tcore_wl_window_, geometry.left, + geometry.top, geometry.width, + geometry.height); + tizen_core_wl_window_set_position(tcore_wl_window_, geometry.left, + geometry.top); + return true; +} + +TizenGeometry TizenWindowTcoreWl::GetScreenGeometry() { + TizenGeometry result = {}; + GList* output_list = nullptr; + tizen_core_wl_display_get_output_device_list(tcore_wl_display_, &output_list); + if (output_list) { + tizen_core_wl_output_h output = + static_cast(output_list->data); + tizen_core_wl_output_device_get_geometry(output, &result.width, + &result.height); + g_list_free(output_list); + } + return result; +} + +int32_t TizenWindowTcoreWl::GetRotation() { + tizen_core_wl_window_angle_e angle = TIZEN_CORE_WL_WINDOW_ANGLE_0; + tizen_core_wl_window_get_rotation_angle(tcore_wl_window_, &angle); + return static_cast(angle); +} + +int32_t TizenWindowTcoreWl::GetDpi() { + GList* output_list = nullptr; + tizen_core_wl_display_get_output_device_list(tcore_wl_display_, &output_list); + if (!output_list) { + FT_LOG(Error) << "Could not find an output device."; + return 0; + } + tizen_core_wl_output_h output = + static_cast(output_list->data); + g_list_free(output_list); + int dpi = 0; + tizen_core_wl_output_device_get_dpi(output, &dpi); + return dpi; +} + +uintptr_t TizenWindowTcoreWl::GetWindowId() { + return reinterpret_cast(tcore_wl_window_); +} + +uint32_t TizenWindowTcoreWl::GetResourceId() { + if (resource_id_ > 0) { + return resource_id_; + } + + unsigned int res_id = 0; + if (tizen_core_wl_window_private_get_resource_id(tcore_wl_window_, &res_id) == + TIZEN_CORE_WL_ERROR_NONE) { + resource_id_ = res_id; + } + return resource_id_; +} + +void TizenWindowTcoreWl::SetPreferredOrientations( + const std::vector& rotations) { + std::vector angles; + for (int rot : rotations) { + angles.push_back(static_cast(rot)); + } + tizen_core_wl_window_set_available_rotation_angle_list( + tcore_wl_window_, angles.data(), angles.size()); +} + +void TizenWindowTcoreWl::BindKeys(const std::vector& keys) { + for (const std::string& key : keys) { + tizen_core_wl_keygrab_info_h info = nullptr; + tizen_core_wl_keygrab_info_create(key.c_str(), + TIZEN_CORE_WL_KEYGRAB_TOPMOST, &info); + if (info) { + GList* list = g_list_append(nullptr, info); + tizen_core_wl_window_set_keygrab_list(tcore_wl_window_, list); + g_list_free(list); + tizen_core_wl_keygrab_info_destroy(info); + } + } +} + +void TizenWindowTcoreWl::Show() { + tizen_core_wl_window_show(tcore_wl_window_); +} + +void TizenWindowTcoreWl::UpdateFlutterCursor(const std::string& kind) { +#ifdef TV_PROFILE + int pointer_size = -1; + if (vconf_get_int(kSysMouseCursorPointerSizeVConfKey, &pointer_size) < 0) { + FT_LOG(Info) << "Failed to load cursor size."; + } + + std::string cursor_name = "normal_default"; + if (kind == "basic") { + if (pointer_size == 0) { + cursor_name = "large_normal"; + } else if (pointer_size == 1) { + cursor_name = "medium_normal"; + } else if (pointer_size == 2) { + cursor_name = "small_normal"; + } else { + cursor_name = "normal_default"; + } + } else if (kind == "click") { + if (pointer_size == 0) { + cursor_name = "large_normal_pnh"; + } else if (pointer_size == 1) { + cursor_name = "medium_normal_pnh"; + } else if (pointer_size == 2) { + cursor_name = "small_normal_pnh"; + } else { + cursor_name = "normal_pnh"; + } + } else if (kind == "text") { + if (pointer_size == 0) { + cursor_name = "large_normal_input_field"; + } else if (pointer_size == 1) { + cursor_name = "medium_normal_input_field"; + } else if (pointer_size == 2) { + cursor_name = "small_normal_input_field"; + } else { + cursor_name = "normal_input_field"; + } + } else if (kind == "none") { + cursor_name = "normal_transparent"; + } else { + FT_LOG(Info) << kind << " cursor is not supported."; + } + tizen_core_wl_seat_h default_seat = nullptr; + tizen_core_wl_display_get_default_seat(tcore_wl_display_, &default_seat); + if (default_seat) { + tizen_core_wl_seat_set_cursor_theme(default_seat, + kTcoreWlInputCursorThemeName); + tizen_core_wl_seat_set_cursor_name(default_seat, cursor_name.c_str()); + } else { + tizen_core_wl_seat_set_cursor_theme(default_seat, "default"); + tizen_core_wl_seat_set_cursor_name(default_seat, "left_ptr"); + } +#else + tizen_core_wl_seat_h default_seat = nullptr; + tizen_core_wl_display_get_default_seat(tcore_wl_display_, &default_seat); + if (default_seat) { + tizen_core_wl_seat_set_cursor_theme(default_seat, "default"); + tizen_core_wl_seat_set_cursor_name(default_seat, "left_ptr"); + } + FT_LOG(Info) << "UpdateFlutterCursor is not supported."; +#endif +} + +void TizenWindowTcoreWl::SetNotificationLevel(int level) { + tizen_core_wl_notification_set_level( + tcore_wl_window_, static_cast(level)); +} + +void TizenWindowTcoreWl::PrepareInputMethod() { + input_method_context_ = + std::make_unique(GetWindowId()); + + input_method_context_->SetOnPreeditStart( + [this]() { view_delegate_->OnComposeBegin(); }); + input_method_context_->SetOnPreeditChanged( + [this](std::string str, int cursor_pos) { + view_delegate_->OnComposeChange(str, cursor_pos); + }); + input_method_context_->SetOnPreeditEnd( + [this]() { view_delegate_->OnComposeEnd(); }); + input_method_context_->SetOnCommit( + [this](std::string str) { view_delegate_->OnCommit(str); }); +} + +void* TizenWindowTcoreWl::GetRenderTarget() { + if (is_vulkan_) { + return wl2_surface_; + } else { + return tcore_wl_egl_window_; + } +} + +void TizenWindowTcoreWl::ActivateWindow() { + tizen_core_wl_window_activate(tcore_wl_window_); +} + +void TizenWindowTcoreWl::RaiseWindow() { + tizen_core_wl_window_raise(tcore_wl_window_); +} + +void TizenWindowTcoreWl::LowerWindow() { + tizen_core_wl_window_lower(tcore_wl_window_); +} + +} // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_window_tcore_wl.h b/flutter/shell/platform/tizen/tizen_window_tcore_wl.h new file mode 100644 index 00000000..82153ffd --- /dev/null +++ b/flutter/shell/platform/tizen/tizen_window_tcore_wl.h @@ -0,0 +1,111 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EMBEDDER_TIZEN_WINDOW_TCORE_WL_H_ +#define EMBEDDER_TIZEN_WINDOW_TCORE_WL_H_ + +#include +#include +#include + +#include +#include +#include + +#include "flutter/shell/platform/tizen/tizen_window.h" + +namespace flutter { + +class TizenWindowTcoreWl : public TizenWindow { + public: + TizenWindowTcoreWl(TizenGeometry geometry, + bool transparent, + bool focusable, + bool top_level, + bool pointing_device_support, + bool floating_menu_support, + void* window_handle, + bool is_vulkan); + + ~TizenWindowTcoreWl(); + + TizenGeometry GetGeometry() override; + + bool SetGeometry(TizenGeometry geometry) override; + + TizenGeometry GetScreenGeometry() override; + + void* GetRenderTarget() override; + + void* GetRenderTargetDisplay() override { return wl2_display_; } + + void* GetNativeHandle() override { return tcore_wl_window_; } + + int32_t GetRotation() override; + + int32_t GetDpi() override; + + uintptr_t GetWindowId() override; + + uint32_t GetResourceId() override; + + void SetPreferredOrientations(const std::vector& rotations) override; + + void BindKeys(const std::vector& keys) override; + + void Show() override; + + void UpdateFlutterCursor(const std::string& kind) override; + + void ActivateWindow() override; + + void RaiseWindow() override; + + void LowerWindow() override; + + private: + bool CreateWindow(void* window_handle); + + void DestroyWindow(); + + void SetWindowOptions(); + + void EnableCursor(); + +#ifdef TV_PROFILE + void SetPointingDeviceSupport(); + + void SetFloatingMenuSupport(); + + void ShowUnsupportedToast(); +#endif + + void RegisterEventHandlers(); + + void UnregisterEventHandlers(); + + void SetNotificationLevel(int level); + + void PrepareInputMethod(); + + tizen_core_wl_display_h tcore_wl_display_ = nullptr; + tizen_core_wl_window_h tcore_wl_window_ = nullptr; + tizen_core_wl_egl_window_h tcore_wl_egl_window_ = nullptr; + tizen_core_event_h tcore_wl_event_ = nullptr; + wl_display* wl2_display_ = nullptr; + wl_surface* wl2_surface_ = nullptr; + std::vector tcore_event_listeners_; + uint32_t resource_id_ = 0; + +#ifdef TV_PROFILE + bool pointing_device_support_ = true; + bool floating_menu_support_ = true; + bool show_unsupported_toast_ = false; +#endif + bool is_vulkan_ = false; +}; + +} // namespace flutter + +#endif // EMBEDDER_TIZEN_WINDOW_TCORE_WL_H_ diff --git a/tools/gn b/tools/gn index 7038677f..6e20600b 100755 --- a/tools/gn +++ b/tools/gn @@ -14,6 +14,9 @@ from pathlib import Path def get_out_dir(args): target_dir = ['tizen', args.target_cpu] + if args.use_tcore: + target_dir.append('tcore') + if args.unoptimized: target_dir.append('unopt') @@ -78,6 +81,7 @@ def to_gn_args(args): gn_args['clang_version'] = get_clang_version(args.target_toolchain) gn_args['api_version'] = args.api_version gn_args['use_system_cxx'] = not args.no_system_cxx + gn_args['use_tcore'] = args.use_tcore for key, val in gn_args.items(): if isinstance(val, bool): @@ -104,6 +108,8 @@ def parse_args(args): parser.add_argument('--api-version', default='6.0', type=str) parser.add_argument('--no-system-cxx', default=False, action='store_true') + parser.add_argument('--use-tcore', default=False, action='store_true', + help='Use tizen-core-wl API instead of ecore') parser.add_argument('--target-dir', type=str) parser.add_argument('--verbose', default=False, action='store_true') From 19351ed89d0b8049e57893baa5cc5fc946429750 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 18 May 2026 20:05:55 +0900 Subject: [PATCH 03/11] Fix clang-format violations in tizen_window_tcore_wl Resolves the format CI failure: indent of constructor parameter lists and reorder of include block per .clang-format (Chromium, SortIncludes). --- .../platform/tizen/tizen_window_tcore_wl.cc | 14 +++++++------- .../shell/platform/tizen/tizen_window_tcore_wl.h | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc index 593fef2e..5489172e 100644 --- a/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc +++ b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc @@ -159,13 +159,13 @@ void SetPointingDevicePreference() { } // namespace TizenWindowTcoreWl::TizenWindowTcoreWl(TizenGeometry geometry, - bool transparent, - bool focusable, - bool top_level, - bool pointing_device_support, - bool floating_menu_support, - void* window_handle = nullptr, - bool is_vulkan = false) + bool transparent, + bool focusable, + bool top_level, + bool pointing_device_support, + bool floating_menu_support, + void* window_handle = nullptr, + bool is_vulkan = false) : TizenWindow(geometry, transparent, focusable, top_level) #ifdef TV_PROFILE , diff --git a/flutter/shell/platform/tizen/tizen_window_tcore_wl.h b/flutter/shell/platform/tizen/tizen_window_tcore_wl.h index 82153ffd..d099d0ae 100644 --- a/flutter/shell/platform/tizen/tizen_window_tcore_wl.h +++ b/flutter/shell/platform/tizen/tizen_window_tcore_wl.h @@ -5,9 +5,9 @@ #ifndef EMBEDDER_TIZEN_WINDOW_TCORE_WL_H_ #define EMBEDDER_TIZEN_WINDOW_TCORE_WL_H_ +#include #include #include -#include #include #include @@ -20,13 +20,13 @@ namespace flutter { class TizenWindowTcoreWl : public TizenWindow { public: TizenWindowTcoreWl(TizenGeometry geometry, - bool transparent, - bool focusable, - bool top_level, - bool pointing_device_support, - bool floating_menu_support, - void* window_handle, - bool is_vulkan); + bool transparent, + bool focusable, + bool top_level, + bool pointing_device_support, + bool floating_menu_support, + void* window_handle, + bool is_vulkan); ~TizenWindowTcoreWl(); From f54fe013bf6b26ea8831e1ca004fb72cebfa499c Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 18 May 2026 20:06:23 +0900 Subject: [PATCH 04/11] Gate tizen_clipboard on USE_TCORE_WL for ecore builds The previous commit replaced tizen_clipboard with a tcore_wl-only implementation, which broke all ecore builds because tizen_clipboard.h is pulled in unconditionally through platform_channel.h and is not available on sysroots that don't have tizen-core packages. Wrap both the header and the implementation in `#ifdef USE_TCORE_WL` so ecore builds get the restored Ecore_Wl2 version, while tcore builds keep the new tizen_core_wl one. Also fix the build by referencing TizenWindowTcoreWl in the tcore branch instead of TizenWindowEcoreWl2. --- .../shell/platform/tizen/tizen_clipboard.cc | 200 +++++++++++++++++- .../shell/platform/tizen/tizen_clipboard.h | 12 ++ 2 files changed, 203 insertions(+), 9 deletions(-) diff --git a/flutter/shell/platform/tizen/tizen_clipboard.cc b/flutter/shell/platform/tizen/tizen_clipboard.cc index 1c381cfa..120d5875 100644 --- a/flutter/shell/platform/tizen/tizen_clipboard.cc +++ b/flutter/shell/platform/tizen/tizen_clipboard.cc @@ -8,7 +8,12 @@ #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_window.h" + +#ifdef USE_TCORE_WL +#include "flutter/shell/platform/tizen/tizen_window_tcore_wl.h" +#else #include "flutter/shell/platform/tizen/tizen_window_ecore_wl2.h" +#endif namespace flutter { @@ -18,13 +23,15 @@ constexpr char kMimeTypeTextPlain[] = "text/plain;charset=utf-8"; } // namespace +#ifdef USE_TCORE_WL + TizenClipboard::TizenClipboard(TizenViewBase* view) { - if (auto* window = dynamic_cast(view)) { + if (auto* window = dynamic_cast(view)) { tizen_core_wl_window_h tcore_window = static_cast(window->GetNativeHandle()); tizen_core_wl_window_get_display(tcore_window, &display_); } else { - // tizen_core_wl_get_connected_display() will deprecated. + // TODO(jsuya): tizen_core_wl_get_connected_display() will be deprecated. tizen_core_wl_get_connected_display(nullptr, &display_); } @@ -153,6 +160,11 @@ void TizenClipboard::SetData(const std::string& data) { const char* mime_types[3]; mime_types[0] = kMimeTypeTextPlain; + // TODO(jsuya): There is an issue where ECORE_WL2_EVENT_DATA_SOURCE_SEND event + // does not work properly even if ecore_wl2_dnd_selection_set() is called in + // Tizen 6.5 or lower. Therefore, add empty mimetype for event call from the + // cbhm module. Since it works normally from Tizen 8.0, this part may be + // modified in the future. mime_types[1] = ""; mime_types[2] = nullptr; @@ -230,16 +242,186 @@ bool TizenClipboard::HasStrings() { int mime_count = 0; tizen_core_wl_data_get_mimes(selection_offer_, &mimes, &mime_count); - if (mimes) { - for (int i = 0; i < mime_count; ++i) { - if (mimes[i] && !strcmp(kMimeTypeTextPlain, mimes[i])) { - free(mimes); - return true; - } + if (!mimes) { + return false; + } + + bool found = false; + for (int i = 0; i < mime_count; ++i) { + if (mimes[i] && !strcmp(kMimeTypeTextPlain, mimes[i])) { + found = true; + break; + } + } + free(mimes); + return found; +} + +#else // USE_TCORE_WL + +TizenClipboard::TizenClipboard(TizenViewBase* view) { + if (auto* window = dynamic_cast(view)) { + auto* ecore_wl2_window = + static_cast(window->GetNativeHandle()); + display_ = ecore_wl2_window_display_get(ecore_wl2_window); + } else { + display_ = ecore_wl2_connected_display_get(NULL); + } + + send_handler = ecore_event_handler_add( + ECORE_WL2_EVENT_DATA_SOURCE_SEND, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + self->SendData(event); + return ECORE_CALLBACK_PASS_ON; + }, + this); + receive_handler = ecore_event_handler_add( + ECORE_WL2_EVENT_OFFER_DATA_READY, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + self->ReceiveData(event); + return ECORE_CALLBACK_PASS_ON; + }, + this); +} + +TizenClipboard::~TizenClipboard() { + on_data_callback_ = nullptr; + + ecore_event_handler_del(send_handler); + ecore_event_handler_del(receive_handler); +} + +void TizenClipboard::SendData(void* event) { + if (!event) { + return; + } + auto* send_event = reinterpret_cast(event); + + // TODO(jsuya): If the type of Ecore_Wl2_Event_Data_Source_Send is empty, it + // is assumed to be "text/plain". + if (!send_event->type || (strlen(send_event->type) != 0 && + strcmp(send_event->type, kMimeTypeTextPlain))) { + FT_LOG(Error) << "Invaild mime type(" + << (send_event->type ? send_event->type : "null") << ")."; + if (send_event->fd >= 0) { + close(send_event->fd); + } + return; + } + + if (send_event->serial != selection_serial_) { + FT_LOG(Error) << "The serial doesn't match."; + if (send_event->fd >= 0) { + close(send_event->fd); + } + return; + } + + write(send_event->fd, data_.c_str(), data_.length()); + close(send_event->fd); +} + +void TizenClipboard::ReceiveData(void* event) { + if (!event) { + return; + } + auto* ready_event = + reinterpret_cast(event); + if (ready_event->data == nullptr || ready_event->len < 1) { + FT_LOG(Info) << "No data available."; + if (on_data_callback_) { + on_data_callback_(""); + on_data_callback_ = nullptr; + } + return; + } + + if (ready_event->offer != selection_offer_) { + FT_LOG(Error) << "The offer doesn't match."; + if (on_data_callback_) { + on_data_callback_(std::nullopt); + on_data_callback_ = nullptr; + } + return; + } + + size_t data_length = strlen(ready_event->data); + size_t buffer_size = ready_event->len; + std::string content; + + if (data_length < buffer_size) { + content.append(ready_event->data, data_length); + } else { + content.append(ready_event->data, buffer_size); + } + + if (on_data_callback_) { + on_data_callback_(content); + on_data_callback_ = nullptr; + } +} + +void TizenClipboard::SetData(const std::string& data) { + data_ = data; + + const char* mime_types[3]; + mime_types[0] = kMimeTypeTextPlain; + // TODO(jsuya): There is an issue where ECORE_WL2_EVENT_DATA_SOURCE_SEND event + // does not work properly even if ecore_wl2_dnd_selection_set() is called in + // Tizen 6.5 or lower. Therefore, add empty mimetype for event call from the + // cbhm module. Since it works normally from Tizen 8.0, this part may be + // modified in the future. + mime_types[1] = ""; + mime_types[2] = nullptr; + + Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display_); + selection_serial_ = ecore_wl2_dnd_selection_set(input, mime_types); + ecore_wl2_display_flush(display_); +} + +bool TizenClipboard::GetData(ClipboardCallback on_data_callback) { + on_data_callback_ = std::move(on_data_callback); + + Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display_); + selection_offer_ = ecore_wl2_dnd_selection_get(input); + + if (!selection_offer_) { + FT_LOG(Error) << "ecore_wl2_dnd_selection_get() failed."; + + if (on_data_callback_) { + on_data_callback_ = nullptr; + } + return false; + } + + ecore_wl2_offer_receive(selection_offer_, + const_cast(kMimeTypeTextPlain)); + return true; +} + +bool TizenClipboard::HasStrings() { + Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display_); + selection_offer_ = ecore_wl2_dnd_selection_get(input); + + if (!selection_offer_) { + return false; + } + + Eina_Array* available_types = ecore_wl2_offer_mimes_get(selection_offer_); + unsigned int type_count = eina_array_count(available_types); + + for (unsigned int i = 0; i < type_count; ++i) { + auto* available_type = + static_cast(eina_array_data_get(available_types, i)); + if (!strcmp(kMimeTypeTextPlain, available_type)) { + return true; } - free(mimes); } return false; } +#endif // USE_TCORE_WL + } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_clipboard.h b/flutter/shell/platform/tizen/tizen_clipboard.h index 2583f307..35d5c007 100644 --- a/flutter/shell/platform/tizen/tizen_clipboard.h +++ b/flutter/shell/platform/tizen/tizen_clipboard.h @@ -5,7 +5,12 @@ #ifndef EMBEDDER_TIZEN_CLIPBOARD_H_ #define EMBEDDER_TIZEN_CLIPBOARD_H_ +#ifdef USE_TCORE_WL #include +#else +#define EFL_BETA_API_SUPPORT +#include +#endif #include #include @@ -34,11 +39,18 @@ class TizenClipboard { std::string data_; ClipboardCallback on_data_callback_; uint32_t selection_serial_ = 0; +#ifdef USE_TCORE_WL tizen_core_wl_data_offer_h selection_offer_ = nullptr; tizen_core_wl_display_h display_ = nullptr; tizen_core_event_h tcore_wl_event_ = nullptr; tizen_core_wl_event_listener_h send_listener_ = nullptr; tizen_core_wl_event_listener_h receive_listener_ = nullptr; +#else + Ecore_Wl2_Offer* selection_offer_ = nullptr; + Ecore_Wl2_Display* display_ = nullptr; + Ecore_Event_Handler* send_handler = nullptr; + Ecore_Event_Handler* receive_handler = nullptr; +#endif }; } // namespace flutter From 77758fb4693e46b514c49432da849ef970324317 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 18 May 2026 20:30:39 +0900 Subject: [PATCH 05/11] Address Gemini code review feedback Apply the changes requested in the Gemini code review on flutter-tizen/embedder#170: - Remove temporary FT_LOG(Error) debug breadcrumbs added throughout the key-event path (tizen_window_tcore_wl, tizen_view_nui, flutter_tizen_view, channels/keyboard_channel, channels/text_input_channel, tizen_input_method_context_tcore). Error level was being used for trace logging, which made real errors hard to find. Genuine error paths (initialization failures, out-of-order events, dlopen/dlsym failures) keep their FT_LOG(Error) calls. - flutter_tizen_display_monitor: add a TODO explaining that refresh_rate = 60.0 is a fallback until tizen-core (or another public Tizen API) exposes a way to query the actual rate, since ecore_animator_frametime_get() is gone. - tizen_window_tcore_wl: document that the TV cursor / pointer / floating-menu helpers depend on libvd-win-util.so, a private Samsung TV library, and that dlopen/dlsym lookups must be treated as best-effort. - Fix wrong header include in tizen_input_method_context_tcore.cc (was including the ecore version's header). --- .../tizen/channels/keyboard_channel.cc | 35 --- .../tizen/channels/text_input_channel.cc | 46 +-- .../tizen/flutter_tizen_display_monitor.cc | 6 +- .../platform/tizen/flutter_tizen_view.cc | 30 -- .../tizen/tizen_input_method_context_tcore.cc | 55 +--- .../shell/platform/tizen/tizen_view_nui.cc | 15 - .../platform/tizen/tizen_window_tcore_wl.cc | 268 +++++------------- 7 files changed, 92 insertions(+), 363 deletions(-) diff --git a/flutter/shell/platform/tizen/channels/keyboard_channel.cc b/flutter/shell/platform/tizen/channels/keyboard_channel.cc index 37b351ea..8b6e32cb 100644 --- a/flutter/shell/platform/tizen/channels/keyboard_channel.cc +++ b/flutter/shell/platform/tizen/channels/keyboard_channel.cc @@ -119,12 +119,6 @@ void KeyboardChannel::SendKey(const char* key, uint32_t scan_code, bool is_down, std::function callback) { - FT_LOG(Error) << "KeyboardChannel::SendKey: key=" << (key ? key : "null") - << ", string=" << (string ? string : "null") - << ", compose=" << (compose ? compose : "null") - << ", modifiers=" << modifiers << ", scan_code=" << scan_code - << ", is_down=" << is_down; - uint64_t sequence_id = last_sequence_id_++; PendingEvent pending; @@ -145,14 +139,8 @@ void KeyboardChannel::SendKey(const char* key, if (scan_code == 0) { scan_code = GetFallbackScanCodeFromKey(key); - FT_LOG(Error) - << "KeyboardChannel::SendKey: scan_code was 0, fallback scan_code=" - << scan_code; } - FT_LOG(Error) << "KeyboardChannel::SendKey: sending embedder+channel events, " - "sequence_id=" - << sequence_id; SendEmbedderEvent(key, string, compose, modifiers, scan_code, is_down, sequence_id); // The channel-based API (RawKeyEvent) is deprecated and |SendChannelEvent| @@ -222,12 +210,6 @@ void KeyboardChannel::SendEmbedderEvent(const char* key, uint64_t logical_key = GetLogicalKey(key); const char* character = is_down ? string : nullptr; - FT_LOG(Error) << "KeyboardChannel::SendEmbedderEvent: key=" - << (key ? key : "null") << ", physical_key=" << physical_key - << ", logical_key=" << logical_key - << ", scan_code=" << scan_code << ", is_down=" << is_down - << ", sequence_id=" << sequence_id; - uint64_t last_logical_record = 0; auto iter = pressing_records_.find(physical_key); if (iter != pressing_records_.end()) { @@ -249,8 +231,6 @@ void KeyboardChannel::SendEmbedderEvent(const char* key, // The physical key has been released before. It might indicate a missed // event due to loss of focus, or multiple keyboards pressed keys with the // same physical key. Ignore the up event. - FT_LOG(Error) << "KeyboardChannel::SendEmbedderEvent: key up without " - "prior key down, synthesizing empty event"; FlutterKeyEvent empty_event = { .struct_size = sizeof(FlutterKeyEvent), .timestamp = static_cast( @@ -284,12 +264,6 @@ void KeyboardChannel::SendEmbedderEvent(const char* key, event.character = character; event.synthesized = false; - FT_LOG(Error) - << "KeyboardChannel::SendEmbedderEvent: sending FlutterKeyEvent, type=" - << static_cast(type) << ", physical=" << event.physical - << ", logical=" << event.logical - << ", character=" << (event.character ? event.character : "null"); - send_event_( event, [](bool handled, void* user_data) { @@ -303,28 +277,19 @@ void KeyboardChannel::SendEmbedderEvent(const char* key, } void KeyboardChannel::ResolvePendingEvent(uint64_t sequence_id, bool handled) { - FT_LOG(Error) << "KeyboardChannel::ResolvePendingEvent: sequence_id=" - << sequence_id << ", handled=" << handled; auto iter = pending_events_.find(sequence_id); if (iter != pending_events_.end()) { PendingEvent* event = iter->second.get(); event->any_handled = event->any_handled || handled; event->unreplied -= 1; - FT_LOG(Error) << "KeyboardChannel::ResolvePendingEvent: unreplied=" - << event->unreplied << ", any_handled=" << event->any_handled; // If all handlers have replied, report if any of them handled the event. if (event->unreplied == 0) { - FT_LOG(Error) << "KeyboardChannel::ResolvePendingEvent: all handlers " - "replied, calling callback"; event->callback(event->any_handled); pending_events_.erase(iter); } return; } // The pending event should always be found. - FT_LOG(Error) << "KeyboardChannel::ResolvePendingEvent: pending event NOT " - "found for sequence_id=" - << sequence_id; FT_ASSERT_NOT_REACHED(); } diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index b373b79a..b986f57e 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -66,29 +66,18 @@ TextInputChannel::TextInputChannel( TextInputChannel::~TextInputChannel() {} void TextInputChannel::OnComposeBegin() { - FT_LOG(Error) << "TextInputChannel::OnComposeBegin: active_model_=" - << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { - FT_LOG(Error) - << "TextInputChannel::OnComposeBegin: active_model_ is null, returning"; return; } active_model_->BeginComposing(); } void TextInputChannel::OnComposeChange(const std::string& str, int cursor_pos) { - FT_LOG(Error) << "TextInputChannel::OnComposeChange: str=" << str - << ", cursor_pos=" << cursor_pos - << ", active_model_=" << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { - FT_LOG(Error) << "TextInputChannel::OnComposeChange: active_model_ is " - "null, returning"; return; } if (str == "") { // Enter pre-edit end stage. - FT_LOG(Error) << "TextInputChannel::OnComposeChange: empty str, entering " - "pre-edit end stage"; return; } active_model_->UpdateComposingText(str); @@ -96,17 +85,12 @@ void TextInputChannel::OnComposeChange(const std::string& str, int cursor_pos) { } void TextInputChannel::OnComposeEnd() { - FT_LOG(Error) << "TextInputChannel::OnComposeEnd: active_model_=" - << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { - FT_LOG(Error) - << "TextInputChannel::OnComposeEnd: active_model_ is null, returning"; return; } // Delete preedit-string, it will be committed. int count = active_model_->composing_range().extent() - active_model_->composing_range().base(); - FT_LOG(Error) << "TextInputChannel::OnComposeEnd: composing count=" << count; active_model_->CommitComposing(); active_model_->EndComposing(); @@ -115,16 +99,11 @@ void TextInputChannel::OnComposeEnd() { } void TextInputChannel::OnCommit(const std::string& str) { - FT_LOG(Error) << "TextInputChannel::OnCommit: str=" << str - << ", active_model_=" << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { - FT_LOG(Error) - << "TextInputChannel::OnCommit: active_model_ is null, returning"; return; } active_model_->AddText(str); if (active_model_->composing()) { - FT_LOG(Error) << "TextInputChannel::OnCommit: committing composing text"; active_model_->CommitComposing(); active_model_->EndComposing(); } @@ -137,22 +116,12 @@ bool TextInputChannel::SendKey(const char* key, uint32_t modifiers, uint32_t scan_code, bool is_down) { - FT_LOG(Error) << "TextInputChannel::SendKey: key=" << (key ? key : "null") - << ", string=" << (string ? string : "null") - << ", compose=" << (compose ? compose : "null") - << ", modifiers=" << modifiers << ", scan_code=" << scan_code - << ", is_down=" << is_down - << ", active_model_=" << (active_model_ ? "set" : "null"); if (active_model_ == nullptr) { - FT_LOG(Error) - << "TextInputChannel::SendKey: active_model_ is null, returning false"; return false; } if (is_down) { - bool result = HandleKey(key, string, modifiers); - FT_LOG(Error) << "TextInputChannel::SendKey: HandleKey result=" << result; - return result; + return HandleKey(key, string, modifiers); } return false; @@ -350,32 +319,22 @@ void TextInputChannel::SendStateUpdate() { bool TextInputChannel::HandleKey(const char* key, const char* string, uint32_t modifires) { - FT_LOG(Error) << "TextInputChannel::HandleKey: key=" << (key ? key : "null") - << ", string=" << (string ? string : "null") - << ", modifiers=" << modifires; bool needs_update = false; std::string key_str = key; if (string && strlen(string) == 1 && IsAsciiPrintableKey(string[0])) { // This is a fallback for printable keys not handled by IMF. - FT_LOG(Error) - << "TextInputChannel::HandleKey: printable key fallback, char=" - << string[0]; active_model_->AddCodePoint(string[0]); needs_update = true; } else if (key_str == "Return") { - FT_LOG(Error) << "TextInputChannel::HandleKey: Return key pressed"; EnterPressed(); return true; #ifdef TV_PROFILE } else if (key_str == "Select") { - FT_LOG(Error) << "TextInputChannel::HandleKey: Select key pressed"; SelectPressed(); return true; #endif } else { - FT_LOG(Error) << "TextInputChannel::HandleKey: key[" << key - << "] is unhandled."; return false; } @@ -386,9 +345,6 @@ bool TextInputChannel::HandleKey(const char* key, } void TextInputChannel::EnterPressed() { - FT_LOG(Error) << "TextInputChannel::EnterPressed: input_type_=" << input_type_ - << ", input_action_=" << input_action_ - << ", client_id_=" << client_id_; if (input_type_ == kMultilineInputType) { active_model_->AddCodePoint('\n'); SendStateUpdate(); diff --git a/flutter/shell/platform/tizen/flutter_tizen_display_monitor.cc b/flutter/shell/platform/tizen/flutter_tizen_display_monitor.cc index d9141772..7cf67d42 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_display_monitor.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_display_monitor.cc @@ -28,8 +28,10 @@ void FlutterTizenDisplayMonitor::UpdateDisplays() { display.display_id = 0; display.single_display = true; - // Default to 60Hz refresh rate since the Tizen platform does not - // provide a direct API to query the display refresh rate. + // TODO(jsuya): Default to 60Hz refresh rate. The previous implementation + // used ecore_animator_frametime_get(), which is no longer available after + // dropping the Ecore dependency. Replace this once tizen-core (or another + // public Tizen API) exposes a way to query the display refresh rate. display.refresh_rate = 60.0; int32_t width = 0, height = 0, dpi = 0; diff --git a/flutter/shell/platform/tizen/flutter_tizen_view.cc b/flutter/shell/platform/tizen/flutter_tizen_view.cc index 5b4102cb..8e665707 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_view.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_view.cc @@ -250,13 +250,6 @@ void FlutterTizenView::OnKey(const char* key, uint32_t scan_code, const char* device_name, bool is_down) { - FT_LOG(Error) << "OnKey: key=" << (key ? key : "null") - << ", string=" << (string ? string : "null") - << ", compose=" << (compose ? compose : "null") - << ", modifiers=" << modifiers << ", scan_code=" << scan_code - << ", device_name=" << (device_name ? device_name : "null") - << ", is_down=" << is_down; - if (is_down) { FT_LOG(Info) << "Key symbol: " << key << ", code: 0x" << std::setw(8) << std::setfill('0') << std::right << std::hex << scan_code; @@ -264,7 +257,6 @@ void FlutterTizenView::OnKey(const char* key, // Do not handle the TV system menu key. if (strcmp(key, kSysMenuKey) == 0) { - FT_LOG(Error) << "OnKey: ignoring system menu key"; return; } @@ -274,36 +266,25 @@ void FlutterTizenView::OnKey(const char* key, } if (text_input_channel_) { - FT_LOG(Error) << "OnKey: sending to text_input_channel_"; if (text_input_channel_->SendKey(key, string, compose, modifiers, scan_code, is_down)) { - FT_LOG(Error) << "OnKey: handled by text_input_channel_"; return; } - FT_LOG(Error) << "OnKey: not handled by text_input_channel_"; - } else { - FT_LOG(Error) << "OnKey: text_input_channel_ is null"; } if (platform_view_channel_) { - FT_LOG(Error) << "OnKey: sending to platform_view_channel_"; if (platform_view_channel_->SendKey(key, string, compose, modifiers, scan_code, is_down)) { - FT_LOG(Error) << "OnKey: handled by platform_view_channel_"; return; } - FT_LOG(Error) << "OnKey: not handled by platform_view_channel_"; } if (engine_->keyboard_channel()) { - FT_LOG(Error) << "OnKey: sending to keyboard_channel_"; bool& backkey_handled = backkey_handled_; engine_->keyboard_channel()->SendKey( key, string, compose, modifiers, scan_code, is_down, [engine = engine_.get(), symbol = std::string(key), is_down, &backkey_handled](bool handled) { - FT_LOG(Error) << "OnKey: keyboard_channel_ callback, handled=" - << handled << ", symbol=" << symbol; // If System's back key is handled in key-down, it should be // handled so that "popRoute" is not called in key-up. if (symbol == kBackKey) { @@ -325,33 +306,22 @@ void FlutterTizenView::OnKey(const char* key, ui_app_exit(); } }); - } else { - FT_LOG(Error) << "OnKey: keyboard_channel_ is null"; } } void FlutterTizenView::OnComposeBegin() { - FT_LOG(Error) << "OnComposeBegin: text_input_channel_=" - << (text_input_channel_ ? "set" : "null"); text_input_channel_->OnComposeBegin(); } void FlutterTizenView::OnComposeChange(const std::string& str, int cursor_pos) { - FT_LOG(Error) << "OnComposeChange: str=" << str - << ", cursor_pos=" << cursor_pos << ", text_input_channel_=" - << (text_input_channel_ ? "set" : "null"); text_input_channel_->OnComposeChange(str, cursor_pos); } void FlutterTizenView::OnComposeEnd() { - FT_LOG(Error) << "OnComposeEnd: text_input_channel_=" - << (text_input_channel_ ? "set" : "null"); text_input_channel_->OnComposeEnd(); } void FlutterTizenView::OnCommit(const std::string& str) { - FT_LOG(Error) << "OnCommit: str=" << str << ", text_input_channel_=" - << (text_input_channel_ ? "set" : "null"); text_input_channel_->OnCommit(str); } diff --git a/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc index 6b70a558..619d2061 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "tizen_input_method_context.h" +#include "tizen_input_method_context_tcore.h" #include "flutter/shell/platform/tizen/logger.h" @@ -160,22 +160,17 @@ bool TizenInputMethodContext::HandleTcoreWlEventKey(void* event, bool is_down) { FT_ASSERT(imf_context_); FT_ASSERT(event); - FT_LOG(Error) << "HandleTcoreWlEventKey: is_down=" << is_down; - tizen_core_imf_event_key_h imf_key = CreateImfKeyEventFromTcoreWlEvent(event); if (!imf_key) { - FT_LOG(Error) << "HandleTcoreWlEventKey: failed to create imf_key event"; return false; } bool filter_result = false; - int ret = tizen_core_imf_context_filter_event( - imf_context_, - is_down ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN - : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, - imf_key, &filter_result); - FT_LOG(Error) << "HandleTcoreWlEventKey: filter_event ret=" << ret - << ", filter_result=" << filter_result; + tizen_core_imf_context_filter_event(imf_context_, + is_down + ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN + : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, + imf_key, &filter_result); tizen_core_imf_event_key_destroy(imf_key); return filter_result; } @@ -190,15 +185,9 @@ bool TizenInputMethodContext::HandleNuiKeyEvent(const char* device_name, uint32_t scan_code, size_t timestamp, bool is_down) { - FT_LOG(Error) << "HandleNuiKeyEvent: key=" << (key ? key : "null") - << ", string=" << (string ? string : "null") - << ", modifiers=" << modifiers << ", scan_code=" << scan_code - << ", is_down=" << is_down; - tizen_core_imf_event_key_h imf_key = nullptr; tizen_core_imf_event_key_create(&imf_key); if (!imf_key) { - FT_LOG(Error) << "HandleNuiKeyEvent: failed to create imf_key event"; return false; } @@ -225,13 +214,11 @@ bool TizenInputMethodContext::HandleNuiKeyEvent(const char* device_name, imf_key, static_cast(device_subclass)); bool filter_result = false; - int ret = tizen_core_imf_context_filter_event( - imf_context_, - is_down ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN - : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, - imf_key, &filter_result); - FT_LOG(Error) << "HandleNuiKeyEvent: filter_event ret=" << ret - << ", filter_result=" << filter_result; + tizen_core_imf_context_filter_event(imf_context_, + is_down + ? TIZEN_CORE_IMF_EVENT_TYPE_KEY_DOWN + : TIZEN_CORE_IMF_EVENT_TYPE_KEY_UP, + imf_key, &filter_result); tizen_core_imf_event_key_destroy(imf_key); return filter_result; } @@ -252,22 +239,19 @@ void TizenInputMethodContext::ResetInputMethodContext() { void TizenInputMethodContext::ShowInputPanel() { FT_ASSERT(imf_context_); - FT_LOG(Error) << "ShowInputPanel: called"; tizen_core_imf_context_input_panel_show(imf_context_); tizen_core_imf_context_focus_in(imf_context_); } void TizenInputMethodContext::HideInputPanel() { FT_ASSERT(imf_context_); - FT_LOG(Error) << "HideInputPanel: called"; tizen_core_imf_context_focus_out(imf_context_); tizen_core_imf_context_input_panel_hide(imf_context_); } bool TizenInputMethodContext::IsInputPanelShown() { tizen_core_imf_input_panel_state_e state; - int ret = tizen_core_imf_context_get_input_panel_state(imf_context_, &state); - FT_LOG(Error) << "IsInputPanelShown: ret=" << ret << ", state=" << state; + tizen_core_imf_context_get_input_panel_state(imf_context_, &state); return state == TIZEN_CORE_IMF_INPUT_PANEL_STATE_SHOW; } @@ -319,8 +303,6 @@ void TizenInputMethodContext::RegisterEventCallbacks() { [](tizen_core_imf_context_h ctx, void* event_info, void* data) { auto* self = static_cast(data); char* str = static_cast(event_info); - FT_LOG(Error) << "IMF_CALLBACK_COMMIT: str=" << (str ? str : "null") - << ", on_commit_=" << (self->on_commit_ ? "set" : "null"); if (self->on_commit_) { self->on_commit_(str); } @@ -333,8 +315,6 @@ void TizenInputMethodContext::RegisterEventCallbacks() { event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_START] = [](tizen_core_imf_context_h ctx, void* event_info, void* data) { auto* self = static_cast(data); - FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_START: on_preedit_start_=" - << (self->on_preedit_start_ ? "set" : "null"); if (self->on_preedit_start_) { self->on_preedit_start_(); } @@ -347,8 +327,6 @@ void TizenInputMethodContext::RegisterEventCallbacks() { event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_END] = [](tizen_core_imf_context_h ctx, void* event_info, void* data) { auto* self = static_cast(data); - FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_END: on_preedit_end_=" - << (self->on_preedit_end_ ? "set" : "null"); if (self->on_preedit_end_) { self->on_preedit_end_(); } @@ -361,16 +339,11 @@ void TizenInputMethodContext::RegisterEventCallbacks() { event_callbacks_[TIZEN_CORE_IMF_CALLBACK_PREEDIT_CHANGED] = [](tizen_core_imf_context_h ctx, void* event_info, void* data) { auto* self = static_cast(data); - FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_CHANGED: on_preedit_changed_=" - << (self->on_preedit_changed_ ? "set" : "null"); if (self->on_preedit_changed_) { char* str = nullptr; int cursor_pos = 0; tizen_core_imf_context_get_preedit_string(ctx, &str, nullptr, nullptr, &cursor_pos); - FT_LOG(Error) << "IMF_CALLBACK_PREEDIT_CHANGED: str=" - << (str ? str : "null") - << ", cursor_pos=" << cursor_pos; if (str) { self->on_preedit_changed_(str, cursor_pos); free(str); @@ -436,10 +409,6 @@ void TizenInputMethodContext::InputPanelStateChangedCallback( break; } - FT_LOG(Error) << "InputPanelStateChangedCallback: state=" << state_str - << ", on_input_panel_state_changed_=" - << (self->on_input_panel_state_changed_ ? "set" : "null"); - if (self->on_input_panel_state_changed_) { self->on_input_panel_state_changed_(state_str); } diff --git a/flutter/shell/platform/tizen/tizen_view_nui.cc b/flutter/shell/platform/tizen/tizen_view_nui.cc index e4355560..f3b93477 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.cc +++ b/flutter/shell/platform/tizen/tizen_view_nui.cc @@ -88,30 +88,15 @@ void TizenViewNui::OnKey(const char* device_name, uint32_t scan_code, size_t timestamp, bool is_down) { - FT_LOG(Error) << "TizenViewNui::OnKey: key=" << (key ? key : "null") - << ", string=" << (string ? string : "null") - << ", compose=" << (compose ? compose : "null") - << ", modifiers=" << modifiers << ", scan_code=" << scan_code - << ", device_name=" << (device_name ? device_name : "null") - << ", device_class=" << device_class - << ", device_subclass=" << device_subclass - << ", timestamp=" << timestamp << ", is_down=" << is_down; - bool handled = false; if (input_method_context_->IsInputPanelShown()) { - FT_LOG(Error) << "TizenViewNui::OnKey: input panel shown, passing to " - "HandleNuiKeyEvent"; handled = input_method_context_->HandleNuiKeyEvent( device_name, device_class, device_subclass, key, string, modifiers, scan_code, timestamp, is_down); - FT_LOG(Error) << "TizenViewNui::OnKey: IMF handled=" << handled; - } else { - FT_LOG(Error) << "TizenViewNui::OnKey: input panel NOT shown"; } if (!handled) { - FT_LOG(Error) << "TizenViewNui::OnKey: forwarding to view_delegate_->OnKey"; view_delegate_->OnKey(key, string, compose, modifiers, scan_code, device_name, is_down); } diff --git a/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc index 5489172e..6589305c 100644 --- a/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc +++ b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc @@ -191,8 +191,6 @@ TizenWindowTcoreWl::~TizenWindowTcoreWl() { } bool TizenWindowTcoreWl::CreateWindow(void* window_handle) { - FT_LOG(Error) << "tizen core wl init()!!!!!!! "; - if (tizen_core_wl_init() != TIZEN_CORE_WL_ERROR_NONE) { FT_LOG(Error) << "Could not initialize tizen core wl."; return false; @@ -297,6 +295,13 @@ void TizenWindowTcoreWl::SetWindowOptions() { EnableCursor(); } +// NOTE: The TV profile cursor / mouse-pointer / floating-menu helpers below +// depend on libvd-win-util.so, which is an internal Samsung TV library and +// not part of the public Tizen API. Symbols are looked up via dlopen/dlsym +// so the embedder still builds on devices where the library is missing, but +// these symbols may be renamed or removed in future TV platform releases. +// All call sites must handle the "library or symbol not available" case +// gracefully (by bailing out and leaving the corresponding feature disabled). void TizenWindowTcoreWl::EnableCursor() { #ifdef TV_PROFILE void* handle = dlopen("libvd-win-util.so", RTLD_LAZY); @@ -638,110 +643,44 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_DOWN, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [1] entered, view_delegate_=" - << (self->view_delegate_ ? "set" : "null") - << ", event=" << event; - if (self->view_delegate_) { - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [2] casting event to base"; - auto* ev = static_cast(event); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [3] ev=" << ev; - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [4] getting event window"; - tizen_core_wl_window_h event_window = nullptr; - int ret_get_window = - tizen_core_wl_event_input_base_get_window(ev, &event_window); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [5] get_window ret=" - << ret_get_window << ", event_window=" << event_window - << ", self_window=" << self->tcore_wl_window_; + if (!self->view_delegate_) { + return; + } + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window != self->tcore_wl_window_) { + return; + } - if (event_window == self->tcore_wl_window_) { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [6] window matched, extracting key info"; - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [7] getting keyname"; - char* keyname = nullptr; - tizen_core_wl_event_key_get_keyname(ev, &keyname); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [8] keyname=" - << (keyname ? keyname : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [9] getting keysymbol"; - char* keysymbol = nullptr; - tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [10] keysymbol=" - << (keysymbol ? keysymbol : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [11] getting compose"; - char* compose = nullptr; - tizen_core_wl_event_key_get_compose(ev, &compose); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [12] compose=" - << (compose ? compose : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [13] getting modifiers"; - unsigned int modifiers = 0; - tizen_core_wl_event_key_get_modifiers(ev, &modifiers); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [14] modifiers=" << modifiers; - - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [15] getting keycode"; - unsigned int keycode = 0; - tizen_core_wl_event_key_get_keycode(ev, &keycode); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [16] keycode=" << keycode; - - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [17] getting device_identifier"; - char* dev_identifier = nullptr; - tizen_core_wl_event_input_base_get_device_identifier( - ev, &dev_identifier); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [18] dev_identifier=" - << (dev_identifier ? dev_identifier : "null"); - - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [19] checking input_method_context_=" - << (self->input_method_context_ ? "set" : "null"); - bool handled = false; - if (self->input_method_context_) { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [20] calling IsInputPanelShown"; - bool panel_shown = - self->input_method_context_->IsInputPanelShown(); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [21] IsInputPanelShown=" - << panel_shown; - if (panel_shown) { - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [22] input panel shown, " - "calling HandleTcoreWlEventKey"; - handled = self->input_method_context_->HandleTcoreWlEventKey( - event, true); - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [23] IMF handled=" << handled; - } else { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [24] input panel NOT shown"; - } - } else { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [25] input_method_context_ is null"; - } - if (!handled) { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: [26] calling view_delegate_->OnKey"; - self->view_delegate_->OnKey(keyname, keysymbol, compose, - modifiers, keycode, dev_identifier, - true); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [27] OnKey returned"; - } - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [28] freeing keyname"; - free(keyname); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [29] freeing keysymbol"; - free(keysymbol); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [30] freeing compose"; - free(compose); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [31] freeing dev_identifier"; - free(dev_identifier); - FT_LOG(Error) << "WL_EVENT_KEY_DOWN: [32] done"; - } else { - FT_LOG(Error) - << "WL_EVENT_KEY_DOWN: event window mismatch, ignoring"; - } + char* keyname = nullptr; + tizen_core_wl_event_key_get_keyname(ev, &keyname); + char* keysymbol = nullptr; + tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); + char* compose = nullptr; + tizen_core_wl_event_key_get_compose(ev, &compose); + unsigned int modifiers = 0; + tizen_core_wl_event_key_get_modifiers(ev, &modifiers); + unsigned int keycode = 0; + tizen_core_wl_event_key_get_keycode(ev, &keycode); + char* dev_identifier = nullptr; + tizen_core_wl_event_input_base_get_device_identifier(ev, + &dev_identifier); + + bool handled = false; + if (self->input_method_context_ && + self->input_method_context_->IsInputPanelShown()) { + handled = + self->input_method_context_->HandleTcoreWlEventKey(event, true); + } + if (!handled) { + self->view_delegate_->OnKey(keyname, keysymbol, compose, modifiers, + keycode, dev_identifier, true); } + free(keyname); + free(keysymbol); + free(compose); + free(dev_identifier); }, this, &listener); tcore_event_listeners_.push_back(listener); @@ -751,97 +690,40 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_UP, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [1] entered, view_delegate_=" - << (self->view_delegate_ ? "set" : "null") - << ", event=" << event; - if (self->view_delegate_) { - FT_LOG(Error) << "WL_EVENT_KEY_UP: [2] casting event to base"; - auto* ev = static_cast(event); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [3] ev=" << ev; - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [4] getting event window"; - tizen_core_wl_window_h event_window = nullptr; - int ret_get_window = - tizen_core_wl_event_input_base_get_window(ev, &event_window); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [5] get_window ret=" - << ret_get_window << ", event_window=" << event_window - << ", self_window=" << self->tcore_wl_window_; + if (!self->view_delegate_) { + return; + } + auto* ev = static_cast(event); + tizen_core_wl_window_h event_window = nullptr; + tizen_core_wl_event_input_base_get_window(ev, &event_window); + if (event_window != self->tcore_wl_window_) { + return; + } - if (event_window == self->tcore_wl_window_) { - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [6] window matched, extracting key info"; - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [7] getting keyname"; - char* keyname = nullptr; - tizen_core_wl_event_key_get_keyname(ev, &keyname); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [8] keyname=" - << (keyname ? keyname : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [9] getting keysymbol"; - char* keysymbol = nullptr; - tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [10] keysymbol=" - << (keysymbol ? keysymbol : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [11] getting compose"; - char* compose = nullptr; - tizen_core_wl_event_key_get_compose(ev, &compose); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [12] compose=" - << (compose ? compose : "null"); - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [13] getting modifiers"; - unsigned int modifiers = 0; - tizen_core_wl_event_key_get_modifiers(ev, &modifiers); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [14] modifiers=" << modifiers; - - FT_LOG(Error) << "WL_EVENT_KEY_UP: [15] getting keycode"; - unsigned int keycode = 0; - tizen_core_wl_event_key_get_keycode(ev, &keycode); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [16] keycode=" << keycode; - - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [17] checking input_method_context_=" - << (self->input_method_context_ ? "set" : "null"); - bool handled = false; - if (self->input_method_context_) { - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [18] calling IsInputPanelShown"; - bool panel_shown = - self->input_method_context_->IsInputPanelShown(); - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [19] IsInputPanelShown=" << panel_shown; - if (panel_shown) { - FT_LOG(Error) << "WL_EVENT_KEY_UP: [20] input panel shown, " - "calling HandleTcoreWlEventKey"; - handled = self->input_method_context_->HandleTcoreWlEventKey( - event, false); - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [21] IMF handled=" << handled; - } else { - FT_LOG(Error) << "WL_EVENT_KEY_UP: [22] input panel NOT shown"; - } - } else { - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [23] input_method_context_ is null"; - } - if (!handled) { - FT_LOG(Error) - << "WL_EVENT_KEY_UP: [24] calling view_delegate_->OnKey"; - self->view_delegate_->OnKey(keyname, keysymbol, compose, - modifiers, keycode, nullptr, false); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [25] OnKey returned"; - } - FT_LOG(Error) << "WL_EVENT_KEY_UP: [26] freeing keyname"; - free(keyname); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [27] freeing keysymbol"; - free(keysymbol); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [28] freeing compose"; - free(compose); - FT_LOG(Error) << "WL_EVENT_KEY_UP: [29] done"; - } else { - FT_LOG(Error) << "WL_EVENT_KEY_UP: event window mismatch, ignoring"; - } + char* keyname = nullptr; + tizen_core_wl_event_key_get_keyname(ev, &keyname); + char* keysymbol = nullptr; + tizen_core_wl_event_key_get_keysymbol(ev, &keysymbol); + char* compose = nullptr; + tizen_core_wl_event_key_get_compose(ev, &compose); + unsigned int modifiers = 0; + tizen_core_wl_event_key_get_modifiers(ev, &modifiers); + unsigned int keycode = 0; + tizen_core_wl_event_key_get_keycode(ev, &keycode); + + bool handled = false; + if (self->input_method_context_ && + self->input_method_context_->IsInputPanelShown()) { + handled = + self->input_method_context_->HandleTcoreWlEventKey(event, false); + } + if (!handled) { + self->view_delegate_->OnKey(keyname, keysymbol, compose, modifiers, + keycode, nullptr, false); } + free(keyname); + free(keysymbol); + free(compose); }, this, &listener); tcore_event_listeners_.push_back(listener); From 1203622d157376b0737f677abc9e7f101ec9fdc2 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 18 May 2026 20:30:54 +0900 Subject: [PATCH 06/11] Gate remaining ecore-only includes on USE_TCORE_WL The prior commit that introduced --use-tcore split the window and input-method implementations into ecore_wl2 / tcore_wl variants, but several callers and the EGL renderer still pulled in the ecore_wl2 headers unconditionally. As a result, a tcore build fails to compile because and are not in the include path and the ecore_wl2_* APIs are not available. Add #ifdef USE_TCORE_WL gates and tcore code paths in: - channels/text_input_channel.h - channels/input_panel_channel.cc - channels/window_channel.cc - flutter_tizen_engine.cc - tizen_renderer_egl.cc (also use tizen_core_wl_egl_window_native_get instead of ecore_wl2_egl_window_native_get when use_tcore is set) After this commit, both ecore and tcore variants build cleanly. --- .../shell/platform/tizen/channels/input_panel_channel.cc | 4 ++++ .../shell/platform/tizen/channels/text_input_channel.h | 4 ++++ flutter/shell/platform/tizen/channels/window_channel.cc | 4 ++++ flutter/shell/platform/tizen/flutter_tizen_engine.cc | 4 ++++ flutter/shell/platform/tizen/tizen_renderer_egl.cc | 9 +++++++++ 5 files changed, 25 insertions(+) diff --git a/flutter/shell/platform/tizen/channels/input_panel_channel.cc b/flutter/shell/platform/tizen/channels/input_panel_channel.cc index c2af019c..d6c6150b 100644 --- a/flutter/shell/platform/tizen/channels/input_panel_channel.cc +++ b/flutter/shell/platform/tizen/channels/input_panel_channel.cc @@ -7,7 +7,11 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/event_stream_handler_functions.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h" #include "flutter/shell/platform/tizen/logger.h" +#ifdef USE_TCORE_WL +#include "flutter/shell/platform/tizen/tizen_input_method_context_tcore.h" +#else #include "flutter/shell/platform/tizen/tizen_input_method_context.h" +#endif namespace { diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.h b/flutter/shell/platform/tizen/channels/text_input_channel.h index 11d3aa35..91c2a68a 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.h +++ b/flutter/shell/platform/tizen/channels/text_input_channel.h @@ -11,7 +11,11 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/method_channel.h" #include "flutter/shell/platform/common/text_input_model.h" +#ifdef USE_TCORE_WL +#include "flutter/shell/platform/tizen/tizen_input_method_context_tcore.h" +#else #include "flutter/shell/platform/tizen/tizen_input_method_context.h" +#endif #include "rapidjson/document.h" namespace flutter { diff --git a/flutter/shell/platform/tizen/channels/window_channel.cc b/flutter/shell/platform/tizen/channels/window_channel.cc index 5e618e55..4f4d825f 100644 --- a/flutter/shell/platform/tizen/channels/window_channel.cc +++ b/flutter/shell/platform/tizen/channels/window_channel.cc @@ -8,7 +8,11 @@ #include "flutter/shell/platform/tizen/channels/encodable_value_holder.h" #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_window.h" +#ifdef USE_TCORE_WL +#include "flutter/shell/platform/tizen/tizen_window_tcore_wl.h" +#else #include "flutter/shell/platform/tizen/tizen_window_ecore_wl2.h" +#endif namespace flutter { diff --git a/flutter/shell/platform/tizen/flutter_tizen_engine.cc b/flutter/shell/platform/tizen/flutter_tizen_engine.cc index acfb334d..05cc468a 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_engine.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_engine.cc @@ -15,7 +15,11 @@ #include "flutter/shell/platform/tizen/flutter_tizen_view.h" #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/system_utils.h" +#ifdef USE_TCORE_WL +#include "flutter/shell/platform/tizen/tizen_input_method_context_tcore.h" +#else #include "flutter/shell/platform/tizen/tizen_input_method_context.h" +#endif #include "flutter/shell/platform/tizen/tizen_renderer_egl.h" #ifdef FLUTTER_TIZEN_EXPERIMENTAL diff --git a/flutter/shell/platform/tizen/tizen_renderer_egl.cc b/flutter/shell/platform/tizen/tizen_renderer_egl.cc index d618943c..53a622cd 100644 --- a/flutter/shell/platform/tizen/tizen_renderer_egl.cc +++ b/flutter/shell/platform/tizen/tizen_renderer_egl.cc @@ -4,8 +4,12 @@ #include "flutter/shell/platform/tizen/tizen_renderer_egl.h" +#ifdef USE_TCORE_WL +#include +#else #define EFL_BETA_API_SUPPORT #include +#endif #include #include #ifdef NUI_SUPPORT @@ -94,8 +98,13 @@ bool TizenRendererEgl::CreateSurface(void* render_target, const EGLint attribs[] = {EGL_NONE}; if (render_target_display) { +#ifdef USE_TCORE_WL + void* egl_window = tizen_core_wl_egl_window_native_get( + static_cast(render_target)); +#else const auto egl_window = ecore_wl2_egl_window_native_get( static_cast(render_target)); +#endif egl_surface_ = eglCreateWindowSurface( egl_display_, egl_config_, reinterpret_cast(egl_window), attribs); From c8fe16ad31d9dbc4336295338b13b8f303c1f272 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 19 May 2026 09:53:53 +0900 Subject: [PATCH 07/11] Gate unittests on USE_TCORE_WL too The unittests cc files unconditionally include and call tizen_core_wl_init(), which breaks ecore builds because the header is not in the include path on non-tcore sysroots. Conversely, the flutter_tizen_unittests executable target was not getting the USE_TCORE_WL define, so a tcore build was pulling in flutter_tizen_engine.h -> tizen_view_base.h -> the ecore input-method header. - Add #ifdef USE_TCORE_WL gates in flutter_tizen_engine_unittest.cc and flutter_tizen_texture_registrar_unittests.cc so each variant uses the matching init call (tizen_core_wl_init / ecore_init). - Propagate USE_TCORE_WL to the flutter_tizen_unittests target in BUILD.gn when use_tcore is set. --- flutter/shell/platform/tizen/BUILD.gn | 4 ++++ .../platform/tizen/flutter_tizen_engine_unittest.cc | 12 +++++++++++- .../flutter_tizen_texture_registrar_unittests.cc | 12 +++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index c3fe2cd0..8df1b196 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -297,6 +297,10 @@ executable("flutter_tizen_unittests") { ldflags = [ "-Wl,--unresolved-symbols=ignore-in-shared-libs" ] + if (use_tcore) { + defines = [ "USE_TCORE_WL" ] + } + configs += [ ":flutter_tizen_config" ] deps += [ diff --git a/flutter/shell/platform/tizen/flutter_tizen_engine_unittest.cc b/flutter/shell/platform/tizen/flutter_tizen_engine_unittest.cc index 0633bf92..bd441be7 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_engine_unittest.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_engine_unittest.cc @@ -4,7 +4,11 @@ #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" +#ifdef USE_TCORE_WL #include +#else +#include +#endif #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" #include "flutter/shell/platform/tizen/testing/engine_modifier.h" @@ -15,7 +19,13 @@ namespace testing { class FlutterTizenEngineTest : public ::testing::Test { public: - FlutterTizenEngineTest() { tizen_core_wl_init(); } + FlutterTizenEngineTest() { +#ifdef USE_TCORE_WL + tizen_core_wl_init(); +#else + ecore_init(); +#endif + } protected: void SetUp() { diff --git a/flutter/shell/platform/tizen/flutter_tizen_texture_registrar_unittests.cc b/flutter/shell/platform/tizen/flutter_tizen_texture_registrar_unittests.cc index 1ab256c4..3432e714 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_texture_registrar_unittests.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_texture_registrar_unittests.cc @@ -4,7 +4,11 @@ #include "flutter/shell/platform/tizen/flutter_tizen_texture_registrar.h" +#ifdef USE_TCORE_WL #include +#else +#include +#endif #include @@ -18,7 +22,13 @@ namespace testing { class FlutterTizenTextureRegistrarTest : public ::testing::Test { public: - FlutterTizenTextureRegistrarTest() { tizen_core_wl_init(); } + FlutterTizenTextureRegistrarTest() { +#ifdef USE_TCORE_WL + tizen_core_wl_init(); +#else + ecore_init(); +#endif + } protected: void SetUp() { From c5cdbebd3552b14b6eb470cd8da8011513f0b3d7 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 19 May 2026 10:17:47 +0900 Subject: [PATCH 08/11] Reject --use-tcore on Tizen <10 and fix transitive includes Three independent fixes that surfaced when somebody tried 'tools/gn --use-tcore --api-version 6.5': 1. tools/gn now rejects --use-tcore for api_version < 10.0 with a clear error message. The tizen-core / tizen-core-imf / tizen-core-wl packages are only published in the Tizen 11+ repository, so building the use_tcore variant against a 6.5/8.0 sysroot can never succeed. 2. Move '#include ' from tizen_input_method_context_tcore.h to the .cc. The public interface only exposes tizen_core_imf_* types (events go through void*), so the .h does not need the wl header. This also stops the header from blowing up earlier-than-necessary when somebody mis-configures the build. 3. external_texture_surface_vulkan_buffer_dma.cc: add explicit '#include ' for close(). The Tizen 11 gcc 14 stdlib no longer pulls it in transitively, so the experimental Vulkan target failed to compile against sysroot-11.0. --- .../external_texture_surface_vulkan_buffer_dma.cc | 3 +++ .../platform/tizen/tizen_input_method_context_tcore.cc | 2 ++ .../platform/tizen/tizen_input_method_context_tcore.h | 1 - tools/gn | 10 ++++++++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/flutter/shell/platform/tizen/external_texture_surface_vulkan_buffer_dma.cc b/flutter/shell/platform/tizen/external_texture_surface_vulkan_buffer_dma.cc index d422d522..511bc03f 100644 --- a/flutter/shell/platform/tizen/external_texture_surface_vulkan_buffer_dma.cc +++ b/flutter/shell/platform/tizen/external_texture_surface_vulkan_buffer_dma.cc @@ -3,6 +3,9 @@ // found in the LICENSE file. #include "flutter/shell/platform/tizen/external_texture_surface_vulkan_buffer_dma.h" + +#include + #include "flutter/shell/platform/tizen/logger.h" namespace flutter { diff --git a/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc index 619d2061..aa25a520 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.cc @@ -4,6 +4,8 @@ #include "tizen_input_method_context_tcore.h" +#include + #include "flutter/shell/platform/tizen/logger.h" namespace { diff --git a/flutter/shell/platform/tizen/tizen_input_method_context_tcore.h b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.h index f0a0314d..c62dd20a 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context_tcore.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context_tcore.h @@ -6,7 +6,6 @@ #define EMBEDDER_TIZEN_INPUT_METHOD_CONTEXT_H_ #include -#include #include #include diff --git a/tools/gn b/tools/gn index 6e20600b..aba985c7 100755 --- a/tools/gn +++ b/tools/gn @@ -120,6 +120,16 @@ def parse_args(args): def main(): args = parse_args(sys.argv) + if args.use_tcore: + try: + api_value = float(args.api_version) + except ValueError: + api_value = 0.0 + if api_value < 10.0: + sys.exit('--use-tcore requires --api-version 10.0 or higher ' + '(tizen-core packages are only published for Tizen 11+). ' + 'Got --api-version {}.'.format(args.api_version)) + root_dir = Path(__file__).parent.parent.resolve() gn = root_dir / 'third_party' / 'gn' / 'gn' command = [gn, 'gen', '--check', '--export-compile-commands'] From dd4fa872622d4fd8b0e1c5c4b89850ba61964123 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 19 May 2026 11:27:32 +0900 Subject: [PATCH 09/11] Fix non-letter key input in tcore mode The TIZEN_CORE_WL_EVENT_KEY_DOWN/UP listeners in TizenWindowTcoreWl::RegisterEventHandlers were passing the wrong strings into view_delegate_->OnKey(), so punctuation keys (period, minus, equal, etc.) silently dropped when the IME panel was hidden. OnKey's signature is (key, string, compose, ...) where 'string' is expected to be the printable character produced by the key. TextInputChannel::HandleKey relies on `strlen(string) == 1 && IsAsciiPrintableKey(string[0])` to forward the character to the active TextInputModel. The ecore_wl2 handler maps: key <- key_event->key (XKB symbol, e.g. "period") string <- key_event->string (composed char, e.g. ".") compose <- key_event->compose The tcore handler was passing: key <- keyname (key name, often == keysymbol) string <- keysymbol (XKB symbol "period", strlen != 1) compose <- compose For alphanumeric keys keysymbol is a single character ("a", "1"), so the fallback in HandleKey() happened to fire. For punctuation keys keysymbol is the symbol name ("period", "minus", "equal"), strlen > 1, and the printable-fallback branch is skipped, so nothing ever reaches the engine. Pass keysymbol as 'key' and compose (the composed UTF-8 result) as 'string', matching the ecore_wl2 contract. The IME path keeps working independently because tizen_core_imf_context_filter_event does its own keysym -> UTF-8 translation internally. --- .../shell/platform/tizen/tizen_window_tcore_wl.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc index 6589305c..32df8ede 100644 --- a/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc +++ b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc @@ -674,7 +674,15 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { self->input_method_context_->HandleTcoreWlEventKey(event, true); } if (!handled) { - self->view_delegate_->OnKey(keyname, keysymbol, compose, modifiers, + // Match TizenWindowEcoreWl2 OnKey arg semantics: + // param 1 (key) = XKB key symbol name (e.g. "period") + // param 2 (string) = composed printable string (e.g. ".") + // tcore's keysymbol corresponds to ecore's key_event->key, and + // tcore's compose corresponds to ecore's key_event->string. + // Passing keysymbol as `string` breaks the printable-key fallback + // in TextInputChannel::HandleKey() for keys whose symbol name is + // multi-char ("period", "minus", "equal", ...). + self->view_delegate_->OnKey(keysymbol, compose, compose, modifiers, keycode, dev_identifier, true); } free(keyname); @@ -718,7 +726,8 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { self->input_method_context_->HandleTcoreWlEventKey(event, false); } if (!handled) { - self->view_delegate_->OnKey(keyname, keysymbol, compose, modifiers, + // See key-down handler for the keysymbol vs compose rationale. + self->view_delegate_->OnKey(keysymbol, compose, compose, modifiers, keycode, nullptr, false); } free(keyname); From 02d7fa61beb1db0eee89794418ab2f49b74b10be Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 19 May 2026 11:36:56 +0900 Subject: [PATCH 10/11] Fix gn format --- flutter/shell/platform/tizen/BUILD.gn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index 8df1b196..e902416e 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -115,13 +115,13 @@ template("embedder") { # Select window implementation based on use_tcore if (use_tcore) { sources += [ - "tizen_window_tcore_wl.cc", "tizen_input_method_context_tcore.cc", + "tizen_window_tcore_wl.cc", ] } else { sources += [ - "tizen_window_ecore_wl2.cc", "tizen_input_method_context.cc", + "tizen_window_ecore_wl2.cc", ] } From 70d310b950ebdd39cbdd63ee63e81d7354f4ff8f Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 15 Jun 2026 14:06:30 +0900 Subject: [PATCH 11/11] Adapt tcore window/clipboard to tizen-core-wl 0.1.34 and harden init tizen_core_wl_get_connected_display() was removed in tizen-core-wl 0.1.34. The clipboard view-mode path now opens its own display connection via display_create()/display_connect() (display cache shares the same core, so it is equivalent), tracks ownership, and disconnects/destroys/shuts down the connection it owns. This also fixes a pre-existing leak on that path. Fix several robustness issues surfaced in review: - TizenClipboard::SendData(): loop write() to handle partial writes and EINTR instead of dropping clipboard data on short writes. - CreateWindow(): check tizen_core_wl_display_sync()/get_event() return values and bail out instead of proceeding with an invalid event handle. - UpdateFlutterCursor(): drop the TV_PROFILE branch that called the seat cursor setters with a null seat handle. - Route all event-listener registration through an AddEventListener() helper that checks the return value and stores the handle, removing the reused-listener variable that could double-push a stale handle on failure. Verified: builds for arm/arm64 Tizen 11 (--use-tcore) and runs on a Tizen 11 arm64 device (window creation, input, and listeners confirmed via dlog). --- .../shell/platform/tizen/tizen_clipboard.cc | 41 ++++++++- .../shell/platform/tizen/tizen_clipboard.h | 1 + .../platform/tizen/tizen_window_tcore_wl.cc | 90 +++++++++---------- .../platform/tizen/tizen_window_tcore_wl.h | 3 + 4 files changed, 86 insertions(+), 49 deletions(-) diff --git a/flutter/shell/platform/tizen/tizen_clipboard.cc b/flutter/shell/platform/tizen/tizen_clipboard.cc index 120d5875..8b85c067 100644 --- a/flutter/shell/platform/tizen/tizen_clipboard.cc +++ b/flutter/shell/platform/tizen/tizen_clipboard.cc @@ -6,6 +6,9 @@ #include +#include +#include + #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_window.h" @@ -31,11 +34,22 @@ TizenClipboard::TizenClipboard(TizenViewBase* view) { static_cast(window->GetNativeHandle()); tizen_core_wl_window_get_display(tcore_window, &display_); } else { - // TODO(jsuya): tizen_core_wl_get_connected_display() will be deprecated. - tizen_core_wl_get_connected_display(nullptr, &display_); + if (tizen_core_wl_init() != TIZEN_CORE_WL_ERROR_NONE || + tizen_core_wl_display_create(&display_) != TIZEN_CORE_WL_ERROR_NONE || + tizen_core_wl_display_connect(display_, nullptr) != + TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Failed to connect display for clipboard."; + display_ = nullptr; + return; + } + owns_display_ = true; } - tizen_core_wl_display_get_event(display_, &tcore_wl_event_); + if (tizen_core_wl_display_get_event(display_, &tcore_wl_event_) != + TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Failed to get event handle for clipboard."; + return; + } tizen_core_wl_event_add_listener( tcore_wl_event_, TIZEN_CORE_WL_EVENT_DATA_SOURCE_SEND, @@ -63,6 +77,12 @@ TizenClipboard::~TizenClipboard() { if (receive_listener_) { tizen_core_wl_event_remove_listener(tcore_wl_event_, receive_listener_); } + + if (owns_display_ && display_) { + tizen_core_wl_display_disconnect(display_); + tizen_core_wl_display_destroy(display_); + tizen_core_wl_shutdown(); + } } void TizenClipboard::SendData(void* event) { @@ -101,7 +121,20 @@ void TizenClipboard::SendData(void* event) { return; } - write(fd, data_.c_str(), data_.length()); + const char* buffer = data_.c_str(); + size_t remaining = data_.length(); + while (remaining > 0) { + ssize_t written = write(fd, buffer, remaining); + if (written < 0) { + if (errno == EINTR) { + continue; + } + FT_LOG(Error) << "Failed to write clipboard data: " << strerror(errno); + break; + } + buffer += written; + remaining -= written; + } close(fd); } diff --git a/flutter/shell/platform/tizen/tizen_clipboard.h b/flutter/shell/platform/tizen/tizen_clipboard.h index 35d5c007..df8d70c9 100644 --- a/flutter/shell/platform/tizen/tizen_clipboard.h +++ b/flutter/shell/platform/tizen/tizen_clipboard.h @@ -42,6 +42,7 @@ class TizenClipboard { #ifdef USE_TCORE_WL tizen_core_wl_data_offer_h selection_offer_ = nullptr; tizen_core_wl_display_h display_ = nullptr; + bool owns_display_ = false; tizen_core_event_h tcore_wl_event_ = nullptr; tizen_core_wl_event_listener_h send_listener_ = nullptr; tizen_core_wl_event_listener_h receive_listener_ = nullptr; diff --git a/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc index 32df8ede..b2744e13 100644 --- a/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc +++ b/flutter/shell/platform/tizen/tizen_window_tcore_wl.cc @@ -211,9 +211,17 @@ bool TizenWindowTcoreWl::CreateWindow(void* window_handle) { tizen_core_wl_display_private_get_wl_display(tcore_wl_display_, &wl2_display_); - tizen_core_wl_display_sync(tcore_wl_display_); + if (tizen_core_wl_display_sync(tcore_wl_display_) != + TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Failed to sync tizen core wl display."; + return false; + } - tizen_core_wl_display_get_event(tcore_wl_display_, &tcore_wl_event_); + if (tizen_core_wl_display_get_event(tcore_wl_display_, &tcore_wl_event_) != + TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Could not get tizen core wl event handle."; + return false; + } int32_t width = 0, height = 0; GList* output_list = nullptr; @@ -439,12 +447,21 @@ void TizenWindowTcoreWl::ShowUnsupportedToast() { } #endif -void TizenWindowTcoreWl::RegisterEventHandlers() { +void TizenWindowTcoreWl::AddEventListener(tizen_core_wl_event_type_e type, + tizen_core_wl_event_cb callback) { tizen_core_wl_event_listener_h listener = nullptr; + if (tizen_core_wl_event_add_listener(tcore_wl_event_, type, callback, this, + &listener) != TIZEN_CORE_WL_ERROR_NONE) { + FT_LOG(Error) << "Failed to add tizen core wl event listener."; + return; + } + tcore_event_listeners_.push_back(listener); +} +void TizenWindowTcoreWl::RegisterEventHandlers() { // Window rotation event. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_WINDOW_ROTATION, + AddEventListener( + TIZEN_CORE_WL_EVENT_WINDOW_ROTATION, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { @@ -467,14 +484,12 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { self->tcore_wl_window_, degree); } } - }, - this, &listener); - tcore_event_listeners_.push_back(listener); + }); // Window configure event. if (!is_vulkan_) { - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_WINDOW_CONFIGURE_COMPLETE, + AddEventListener( + TIZEN_CORE_WL_EVENT_WINDOW_CONFIGURE_COMPLETE, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { @@ -494,14 +509,12 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { self->view_delegate_->OnResize(x, y, w, h); } } - }, - this, &listener); - tcore_event_listeners_.push_back(listener); + }); } // Mouse button down. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_DOWN, + AddEventListener( + TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_DOWN, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); #ifdef TV_PROFILE @@ -543,13 +556,11 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { touch_id); } } - }, - this, &listener); - tcore_event_listeners_.push_back(listener); + }); // Mouse button up. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_UP, + AddEventListener( + TIZEN_CORE_WL_EVENT_MOUSE_BUTTON_UP, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { @@ -572,13 +583,11 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { touch_id); } } - }, - this, &listener); - tcore_event_listeners_.push_back(listener); + }); // Mouse move. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_MOVE, + AddEventListener( + TIZEN_CORE_WL_EVENT_MOUSE_MOVE, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { @@ -599,13 +608,11 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { touch_id); } } - }, - this, &listener); - tcore_event_listeners_.push_back(listener); + }); // Mouse wheel. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_MOUSE_WHEEL, + AddEventListener( + TIZEN_CORE_WL_EVENT_MOUSE_WHEEL, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (self->view_delegate_) { @@ -634,13 +641,11 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { kFlutterPointerDeviceKindMouse, 0); } } - }, - this, &listener); - tcore_event_listeners_.push_back(listener); + }); // Key down. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_DOWN, + AddEventListener( + TIZEN_CORE_WL_EVENT_KEY_DOWN, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (!self->view_delegate_) { @@ -689,13 +694,11 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { free(keysymbol); free(compose); free(dev_identifier); - }, - this, &listener); - tcore_event_listeners_.push_back(listener); + }); // Key up. - tizen_core_wl_event_add_listener( - tcore_wl_event_, TIZEN_CORE_WL_EVENT_KEY_UP, + AddEventListener( + TIZEN_CORE_WL_EVENT_KEY_UP, [](void* event, tizen_core_wl_event_type_e type, void* data) { auto* self = static_cast(data); if (!self->view_delegate_) { @@ -733,9 +736,7 @@ void TizenWindowTcoreWl::RegisterEventHandlers() { free(keyname); free(keysymbol); free(compose); - }, - this, &listener); - tcore_event_listeners_.push_back(listener); + }); } void TizenWindowTcoreWl::UnregisterEventHandlers() { @@ -910,8 +911,7 @@ void TizenWindowTcoreWl::UpdateFlutterCursor(const std::string& kind) { kTcoreWlInputCursorThemeName); tizen_core_wl_seat_set_cursor_name(default_seat, cursor_name.c_str()); } else { - tizen_core_wl_seat_set_cursor_theme(default_seat, "default"); - tizen_core_wl_seat_set_cursor_name(default_seat, "left_ptr"); + FT_LOG(Error) << "Failed to get default seat; cannot update cursor."; } #else tizen_core_wl_seat_h default_seat = nullptr; diff --git a/flutter/shell/platform/tizen/tizen_window_tcore_wl.h b/flutter/shell/platform/tizen/tizen_window_tcore_wl.h index d099d0ae..2ced4ddc 100644 --- a/flutter/shell/platform/tizen/tizen_window_tcore_wl.h +++ b/flutter/shell/platform/tizen/tizen_window_tcore_wl.h @@ -83,6 +83,9 @@ class TizenWindowTcoreWl : public TizenWindow { void RegisterEventHandlers(); + void AddEventListener(tizen_core_wl_event_type_e type, + tizen_core_wl_event_cb callback); + void UnregisterEventHandlers(); void SetNotificationLevel(int level);