[Tizen] Add Finalize api for imf-manager
[platform/core/uifw/dali-adaptor.git] / adaptors / x11 / imf-manager-impl-x.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <imf-manager-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/events/key-event.h>
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/integration-api/debug.h>
25
26 // INTERNAL INCLUDES
27 #include <adaptor.h>
28 #include <window-render-surface.h>
29 #include <adaptor-impl.h>
30 #include <locale-utils.h>
31 #include <singleton-service-impl.h>
32 #include <virtual-keyboard-impl.h>
33 // Ecore is littered with C style cast
34 #pragma GCC diagnostic push
35 #pragma GCC diagnostic ignored "-Wold-style-cast"
36 #include "ecore-virtual-keyboard.h"
37
38 namespace Dali
39 {
40
41 namespace Internal
42 {
43
44 namespace Adaptor
45 {
46
47 namespace
48 {
49 #if defined(DEBUG_ENABLED)
50 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_IMF_MANAGER");
51 #endif
52
53 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
54 size_t Utf8SequenceLength(const unsigned char leadByte)
55 {
56   size_t length = 0;
57
58   if ((leadByte & 0x80) == 0 )          //ASCII character (lead bit zero)
59   {
60     length = 1;
61   }
62   else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
63   {
64     length = 2;
65   }
66   else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
67   {
68     length = 3;
69   }
70   else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
71   {
72     length = 4;
73   }
74
75   return length;
76 }
77
78 // Static function calls used by ecore 'c' style callback registration
79 void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
80 {
81   if ( data )
82   {
83     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
84     imfManager->CommitReceived( data, imfContext, event_info );
85   }
86 }
87
88 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
89 {
90   if ( data )
91   {
92     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
93     imfManager->PreEditChanged( data, imfContext, event_info );
94   }
95 }
96
97 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
98 {
99   if ( data )
100   {
101     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
102     return imfManager->RetrieveSurrounding( data, imfContext, text, cursorPosition );
103   }
104   else
105   {
106     return false;
107   }
108 }
109
110 /**
111  * Called when an IMF delete surrounding event is received.
112  * Here we tell the application that it should delete a certain range.
113  */
114 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
115 {
116   if ( data )
117   {
118     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
119     imfManager->DeleteSurrounding( data, imfContext, event_info );
120   }
121 }
122
123 } // unnamed namespace
124
125 void ImfManager::Finalize()
126 {
127   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Finalize\n" );
128   if ( mInited )
129   {
130     VirtualKeyboard::DisconnectCallbacks( mIMFContext );
131     DisconnectCallbacks();
132     DeleteContext();
133     ecore_imf_shutdown();
134     mInited = false;
135   }
136 }
137
138 bool ImfManager::IsAvailable()
139 {
140   bool available( false );
141
142   Dali::SingletonService service( SingletonService::Get() );
143   if ( service )
144   {
145     available = service.GetSingleton( typeid( Dali::ImfManager ) );
146   }
147
148   return available;
149 }
150
151 Dali::ImfManager ImfManager::Get()
152 {
153   Dali::ImfManager manager;
154   ImfManager *imfManager = NULL;
155
156   Dali::SingletonService service( SingletonService::Get() );
157   if ( service )
158   {
159     // Check whether the singleton is already created
160     Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ImfManager ) );
161     if( handle )
162     {
163       // If so, downcast the handle
164       imfManager = dynamic_cast< ImfManager* >( handle.GetObjectPtr() );
165       manager = Dali::ImfManager( imfManager );
166     }
167     else if ( Adaptor::IsAvailable() )
168     {
169       // Create instance and register singleton only if the adaptor is available
170
171       Adaptor& adaptorImpl( Adaptor::GetImplementation( Adaptor::Get() ) );
172       Any nativeWindow = adaptorImpl.GetNativeWindowHandle();
173
174       // The Ecore_X_Window needs to use the ImfManager.
175       // Only when the render surface is window, we can get the Ecore_X_Window.
176       Ecore_X_Window *ecoreXwin( AnyCast< Ecore_X_Window* >( nativeWindow ) );
177       if ( ecoreXwin )
178       {
179         // If we fail to get Ecore_X_Window, we can't use the ImfManager correctly.
180         // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
181         // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
182         imfManager = new ImfManager( ecoreXwin );
183         manager = Dali::ImfManager( imfManager );
184         service.Register( typeid( manager ), manager );
185       }
186       else
187       {
188         DALI_LOG_ERROR("Failed to get native window handle\n");
189       }
190     }
191   }
192
193   if ( ( imfManager != NULL ) !imfManager->mInited )
194   {
195     ecore_imf_init();
196     imfManager->CreateContext( imfManager->mEcoreXWin );
197
198     imfManager->ConnectCallbacks();
199     VirtualKeyboard::ConnectCallbacks( mIMFContext );
200     imfManager->mInited = true;
201   }
202
203   return manager;
204 }
205
206 ImfManager::ImfManager( Ecore_X_Window* ecoreXwin )
207 : mIMFContext(),
208   mEcoreXWin( ecoreXwin ),
209   mIMFCursorPosition( 0 ),
210   mSurroundingText(),
211   mInited( false ),
212   mRestoreAfterFocusLost( false ),
213   mIdleCallbackConnected( false )
214 {
215 }
216
217 ImfManager::~ImfManager()
218 {
219   Finalize();
220 }
221
222 void ImfManager::CreateContext( Ecore_X_Window* ecoreXwin )
223 {
224   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::CreateContext\n" );
225
226   const char *contextId = ecore_imf_context_default_id_get();
227   if( contextId )
228   {
229     mIMFContext = ecore_imf_context_add( contextId );
230
231     if( mIMFContext )
232     {
233       if( ecoreXwin )
234       {
235         ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast<void*>( ecoreXwin ) );
236       }
237     }
238     else
239     {
240       DALI_LOG_INFO( gLogFilter, Debug::General, "IMF Unable to get IMF Context\n");
241     }
242   }
243   else
244   {
245     DALI_LOG_INFO( gLogFilter, Debug::General, "IMF Unable to get IMF Context\n");
246   }
247 }
248
249 void ImfManager::DeleteContext()
250 {
251   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteContext\n" );
252
253   if ( mIMFContext )
254   {
255     ecore_imf_context_del( mIMFContext );
256     mIMFContext = NULL;
257   }
258 }
259
260 // Callbacks for predicitive text support.
261 void ImfManager::ConnectCallbacks()
262 {
263   if ( mIMFContext )
264   {
265     DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::ConnectCallbacks\n" );
266
267     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit,    this );
268     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit,     this );
269     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
270
271     ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
272   }
273 }
274
275 void ImfManager::DisconnectCallbacks()
276 {
277   if ( mIMFContext )
278   {
279     DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DisconnectCallbacks\n" );
280
281     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit );
282     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit );
283     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
284
285     // We do not need to unset the retrieve surrounding callback.
286   }
287 }
288
289 void ImfManager::Activate()
290 {
291   // Reset mIdleCallbackConnected
292   mIdleCallbackConnected = false;
293
294   if ( mIMFContext )
295   {
296     DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Activate\n" );
297
298     ecore_imf_context_focus_in( mIMFContext );
299
300     // emit keyboard activated signal
301     Dali::ImfManager handle( this );
302     mActivatedSignal.Emit( handle );
303   }
304 }
305
306 void ImfManager::Deactivate()
307 {
308   if( mIMFContext )
309   {
310     DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Deactivate\n" );
311
312     Reset();
313     ecore_imf_context_focus_out( mIMFContext );
314   }
315
316   // Reset mIdleCallbackConnected
317   mIdleCallbackConnected = false;
318 }
319
320 void ImfManager::Reset()
321 {
322   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Reset\n" );
323
324   if ( mIMFContext )
325   {
326     ecore_imf_context_reset( mIMFContext );
327   }
328 }
329
330 Ecore_IMF_Context* ImfManager::GetContext()
331 {
332   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetContext\n" );
333
334   return mIMFContext;
335 }
336
337 bool ImfManager::RestoreAfterFocusLost() const
338 {
339   return mRestoreAfterFocusLost;
340 }
341
342 void ImfManager::SetRestoreAfterFocusLost( bool toggle )
343 {
344   mRestoreAfterFocusLost = toggle;
345 }
346
347 /**
348  * Called when an IMF Pre-Edit changed event is received.
349  * We are still predicting what the user is typing.  The latest string is what the IMF module thinks
350  * the user wants to type.
351  */
352 void ImfManager::PreEditChanged( void*, Ecore_IMF_Context* imfContext, void* event_info )
353 {
354   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::PreEditChanged\n" );
355
356   char* preEditString( NULL );
357   int cursorPosition( 0 );
358   Eina_List* attrs = NULL;
359   Eina_List* l = NULL;
360
361   Ecore_IMF_Preedit_Attr* attr;
362
363   // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
364   // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
365   ecore_imf_context_preedit_string_with_attributes_get( imfContext, &preEditString, &attrs, &cursorPosition );
366
367   if ( attrs )
368   {
369     // iterate through the list of attributes getting the type, start and end position.
370     for ( l = attrs, (attr =  static_cast<Ecore_IMF_Preedit_Attr*>( eina_list_data_get(l) ) ); l; l = eina_list_next(l), ( attr = static_cast<Ecore_IMF_Preedit_Attr*>( eina_list_data_get(l) ) ))
371     {
372 #ifdef DALI_PROFILE_UBUNTU
373       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
374 #else // DALI_PROFILE_UBUNTU
375       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
376 #endif // DALI_PROFILE_UBUNTU
377       {
378         // check first byte so know how many bytes a character is represented by as keyboard returns cursor position in bytes. Which is different for some languages.
379
380         size_t visualCharacterIndex = 0;
381         size_t byteIndex = 0;
382
383         // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
384         const char leadByte = preEditString[byteIndex];
385         while( leadByte != '\0' )
386         {
387           // attr->end_index is provided as a byte position not character and we need to know the character position.
388           const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
389           if ( byteIndex == attr->end_index )
390           {
391             cursorPosition = visualCharacterIndex;
392             break;
393             // end loop as found cursor position that matches byte position
394           }
395           else
396           {
397             byteIndex += currentSequenceLength; // jump to next character
398             visualCharacterIndex++;  // increment character count so we know our position for when we get a match
399           }
400
401           DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
402         }
403       }
404     }
405   }
406
407   if ( Dali::Adaptor::IsAvailable() )
408   {
409     Dali::ImfManager handle( this );
410     Dali::ImfManager::ImfEventData imfEventData( Dali::ImfManager::PREEDIT, preEditString, cursorPosition, 0 );
411     Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
412
413     if( callbackData.update )
414     {
415       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
416
417       NotifyCursorPosition();
418     }
419
420     if( callbackData.preeditResetRequired )
421     {
422       Reset();
423     }
424   }
425   free( preEditString );
426 }
427
428 void ImfManager::CommitReceived( void*, Ecore_IMF_Context* imfContext, void* event_info )
429 {
430   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::CommitReceived\n" );
431
432   if ( Dali::Adaptor::IsAvailable() )
433   {
434     const std::string keyString( static_cast<char*>( event_info ) );
435
436     Dali::ImfManager handle( this );
437     Dali::ImfManager::ImfEventData imfEventData( Dali::ImfManager::COMMIT, keyString, 0, 0 );
438     Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
439
440     if( callbackData.update )
441     {
442       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
443
444       NotifyCursorPosition();
445     }
446   }
447 }
448
449 /**
450  * Called when an IMF retrieve surround event is received.
451  * Here the IMF module wishes to know the string we are working with and where within the string the cursor is
452  * We need to signal the application to tell us this information.
453  */
454 Eina_Bool ImfManager::RetrieveSurrounding( void* data, Ecore_IMF_Context* imfContext, char** text, int* cursorPosition )
455 {
456   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::RetrieveSurrounding\n" );
457
458   Dali::ImfManager::ImfEventData imfData( Dali::ImfManager::GETSURROUNDING, std::string(), 0, 0 );
459   Dali::ImfManager handle( this );
460   Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfData );
461
462   if( callbackData.update )
463   {
464     if( text )
465     {
466       *text = strdup( callbackData.currentText.c_str() );
467     }
468
469     if( cursorPosition )
470     {
471       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
472       *cursorPosition = mIMFCursorPosition;
473     }
474   }
475
476   return EINA_TRUE;
477 }
478
479 /**
480  * Called when an IMF delete surrounding event is received.
481  * Here we tell the application that it should delete a certain range.
482  */
483 void ImfManager::DeleteSurrounding( void* data, Ecore_IMF_Context* imfContext, void* event_info )
484 {
485   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteSurrounding\n" );
486
487   if( Dali::Adaptor::IsAvailable() )
488   {
489     Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( event_info );
490
491     Dali::ImfManager::ImfEventData imfData( Dali::ImfManager::DELETESURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
492     Dali::ImfManager handle( this );
493     Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfData );
494
495     if( callbackData.update )
496     {
497       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
498
499       NotifyCursorPosition();
500     }
501   }
502 }
503
504 void ImfManager::NotifyCursorPosition()
505 {
506   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::NotifyCursorPosition\n" );
507
508   if( mIMFContext )
509   {
510     ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
511   }
512 }
513
514 void ImfManager::SetCursorPosition( unsigned int cursorPosition )
515 {
516   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetCursorPosition\n" );
517
518   mIMFCursorPosition = static_cast<int>( cursorPosition );
519 }
520
521 unsigned int ImfManager::GetCursorPosition() const
522 {
523   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetCursorPosition\n" );
524
525   return static_cast<unsigned int>( mIMFCursorPosition );
526 }
527
528 void ImfManager::SetSurroundingText( const std::string& text )
529 {
530   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetSurroundingText\n" );
531
532   mSurroundingText = text;
533 }
534
535 const std::string& ImfManager::GetSurroundingText() const
536 {
537   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetSurroundingText\n" );
538
539   return mSurroundingText;
540 }
541
542 void ImfManager::NotifyTextInputMultiLine( bool multiLine )
543 {
544 }
545
546 Dali::ImfManager::TextDirection ImfManager::GetTextDirection()
547 {
548   Dali::ImfManager::TextDirection direction ( Dali::ImfManager::LeftToRight );
549
550   if ( ImfManager::IsAvailable() /* We do not want to create an instance of ImfManager */ )
551   {
552     if ( mIMFContext )
553     {
554       char* locale( NULL );
555       ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
556
557       if ( locale )
558       {
559         direction = static_cast< Dali::ImfManager::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
560         free( locale );
561       }
562     }
563   }
564   return direction;
565 }
566
567 Rect<int> ImfManager::GetInputMethodArea()
568 {
569   int xPos, yPos, width, height;
570
571   width = height = xPos = yPos = 0;
572
573   if( mIMFContext )
574   {
575     ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
576   }
577   else
578   {
579     DALI_LOG_WARNING("VKB Unable to get IMF Context so GetSize unavailable\n");
580   }
581
582   return Rect<int>(xPos,yPos,width,height);
583 }
584
585 void ImfManager::ApplyOptions( const InputMethodOptions& options )
586 {
587   using namespace Dali::InputMethod::Category;
588
589   int index;
590
591   if (mIMFContext == NULL)
592   {
593     DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
594     return;
595   }
596
597   if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
598   {
599   }
600   if ( mOptions.CompareAndSet(AUTO_CAPITALISE, options, index) )
601   {
602   }
603   if ( mOptions.CompareAndSet(ACTION_BUTTON_TITLE, options, index) )
604   {
605   }
606   if ( mOptions.CompareAndSet(VARIATION, options, index) )
607   {
608   }
609 }
610
611 void ImfManager::SetInputPanelUserData( const std::string& data )
612 {
613   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetInputPanelUserData\n" );
614
615   if( mIMFContext )
616   {
617     int length = data.length();
618     ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
619   }
620 }
621
622 void ImfManager::GetInputPanelUserData( std::string& data )
623 {
624   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetInputPanelUserData\n" );
625
626   if( mIMFContext )
627   {
628     int length = 256;
629     char* buffer = reinterpret_cast< char* >( calloc ( 1, length * sizeof ( char ) ) );
630     if( buffer != NULL )
631     {
632       ecore_imf_context_input_panel_imdata_get( mIMFContext, buffer, &length );
633       data = buffer;
634       free( buffer );
635     }
636   }
637 }
638
639 Dali::ImfManager::State ImfManager::GetInputPanelState()
640 {
641   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetInputPanelState\n" );
642
643   if( mIMFContext )
644   {
645     int value;
646     value = ecore_imf_context_input_panel_state_get( mIMFContext );
647
648     switch (value)
649     {
650       case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
651       {
652         return Dali::ImfManager::SHOW;
653         break;
654       }
655
656       case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
657       {
658         return Dali::ImfManager::HIDE;
659         break;
660       }
661
662       case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
663       {
664         return Dali::ImfManager::WILL_SHOW;
665         break;
666       }
667
668       default:
669       {
670         return Dali::ImfManager::DEFAULT;
671       }
672     }
673   }
674   return Dali::ImfManager::DEFAULT;
675 }
676
677 void ImfManager::SetReturnKeyState( bool visible )
678 {
679   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetReturnKeyState\n" );
680
681   if( mIMFContext )
682   {
683     ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
684   }
685 }
686
687 void ImfManager::AutoEnableInputPanel( bool enabled )
688 {
689   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::AutoEnableInputPanel\n" );
690
691   if( mIMFContext )
692   {
693     ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
694   }
695 }
696
697 void ImfManager::ShowInputPanel()
698 {
699   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::ShowInputPanel\n" );
700
701   if( mIMFContext )
702   {
703     ecore_imf_context_input_panel_show( mIMFContext );
704   }
705 }
706
707 void ImfManager::HideInputPanel()
708 {
709   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::HideInputPanel\n" );
710
711   if( mIMFContext )
712   {
713     ecore_imf_context_input_panel_hide( mIMFContext );
714   }
715 }
716
717 Dali::ImfManager::KeyboardType ImfManager::GetKeyboardType()
718 {
719   return Dali::ImfManager::KeyboardType::SOFTWARE_KEYBOARD;
720 }
721
722 std::string ImfManager::GetInputPanelLocale()
723 {
724   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetInputPanelLocale\n" );
725
726   std::string locale = "";
727
728   if( mIMFContext )
729   {
730     char* value = NULL;
731     ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
732
733     if( value )
734     {
735       std::string valueCopy( value );
736       locale = valueCopy;
737
738       // The locale string retrieved must be freed with free().
739       free( value );
740     }
741   }
742   return locale;
743 }
744
745 } // Adaptor
746
747 } // Internal
748
749 } // Dali
750
751 #pragma GCC diagnostic pop