[4.0] 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       // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
467       *text = strdup( callbackData.currentText.c_str() );
468     }
469
470     if( cursorPosition )
471     {
472       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
473       *cursorPosition = mIMFCursorPosition;
474     }
475   }
476
477   return EINA_TRUE;
478 }
479
480 /**
481  * Called when an IMF delete surrounding event is received.
482  * Here we tell the application that it should delete a certain range.
483  */
484 void ImfManager::DeleteSurrounding( void* data, Ecore_IMF_Context* imfContext, void* event_info )
485 {
486   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteSurrounding\n" );
487
488   if( Dali::Adaptor::IsAvailable() )
489   {
490     Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( event_info );
491
492     Dali::ImfManager::ImfEventData imfData( Dali::ImfManager::DELETESURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
493     Dali::ImfManager handle( this );
494     Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfData );
495
496     if( callbackData.update )
497     {
498       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
499
500       NotifyCursorPosition();
501     }
502   }
503 }
504
505 void ImfManager::NotifyCursorPosition()
506 {
507   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::NotifyCursorPosition\n" );
508
509   if( mIMFContext )
510   {
511     ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
512   }
513 }
514
515 void ImfManager::SetCursorPosition( unsigned int cursorPosition )
516 {
517   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetCursorPosition\n" );
518
519   mIMFCursorPosition = static_cast<int>( cursorPosition );
520 }
521
522 unsigned int ImfManager::GetCursorPosition() const
523 {
524   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetCursorPosition\n" );
525
526   return static_cast<unsigned int>( mIMFCursorPosition );
527 }
528
529 void ImfManager::SetSurroundingText( const std::string& text )
530 {
531   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetSurroundingText\n" );
532
533   mSurroundingText = text;
534 }
535
536 const std::string& ImfManager::GetSurroundingText() const
537 {
538   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetSurroundingText\n" );
539
540   return mSurroundingText;
541 }
542
543 void ImfManager::NotifyTextInputMultiLine( bool multiLine )
544 {
545 }
546
547 Dali::ImfManager::TextDirection ImfManager::GetTextDirection()
548 {
549   Dali::ImfManager::TextDirection direction ( Dali::ImfManager::LeftToRight );
550
551   if ( ImfManager::IsAvailable() /* We do not want to create an instance of ImfManager */ )
552   {
553     if ( mIMFContext )
554     {
555       char* locale( NULL );
556       ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
557
558       if ( locale )
559       {
560         direction = static_cast< Dali::ImfManager::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
561         free( locale );
562       }
563     }
564   }
565   return direction;
566 }
567
568 Rect<int> ImfManager::GetInputMethodArea()
569 {
570   int xPos, yPos, width, height;
571
572   width = height = xPos = yPos = 0;
573
574   if( mIMFContext )
575   {
576     ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
577   }
578   else
579   {
580     DALI_LOG_WARNING("VKB Unable to get IMF Context so GetSize unavailable\n");
581   }
582
583   return Rect<int>(xPos,yPos,width,height);
584 }
585
586 void ImfManager::ApplyOptions( const InputMethodOptions& options )
587 {
588   using namespace Dali::InputMethod::Category;
589
590   int index;
591
592   if (mIMFContext == NULL)
593   {
594     DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
595     return;
596   }
597
598   if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
599   {
600   }
601   if ( mOptions.CompareAndSet(AUTO_CAPITALISE, options, index) )
602   {
603   }
604   if ( mOptions.CompareAndSet(ACTION_BUTTON_TITLE, options, index) )
605   {
606   }
607   if ( mOptions.CompareAndSet(VARIATION, options, index) )
608   {
609   }
610 }
611
612 void ImfManager::SetInputPanelData( const std::string& data )
613 {
614   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetInputPanelData\n" );
615
616   if( mIMFContext )
617   {
618     int length = data.length();
619     ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
620   }
621 }
622
623 void ImfManager::GetInputPanelData( std::string& data )
624 {
625   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetInputPanelData\n" );
626
627   if( mIMFContext )
628   {
629     int length = 4096; // The max length is 4096 bytes
630     Dali::Vector< char > buffer;
631     buffer.Resize( length );
632     ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
633     data = std::string( buffer.Begin(), buffer.End() );
634   }
635 }
636
637 Dali::ImfManager::State ImfManager::GetInputPanelState()
638 {
639   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetInputPanelState\n" );
640
641   if( mIMFContext )
642   {
643     int value;
644     value = ecore_imf_context_input_panel_state_get( mIMFContext );
645
646     switch (value)
647     {
648       case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
649       {
650         return Dali::ImfManager::SHOW;
651         break;
652       }
653
654       case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
655       {
656         return Dali::ImfManager::HIDE;
657         break;
658       }
659
660       case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
661       {
662         return Dali::ImfManager::WILL_SHOW;
663         break;
664       }
665
666       default:
667       {
668         return Dali::ImfManager::DEFAULT;
669       }
670     }
671   }
672   return Dali::ImfManager::DEFAULT;
673 }
674
675 void ImfManager::SetReturnKeyState( bool visible )
676 {
677   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetReturnKeyState\n" );
678
679   if( mIMFContext )
680   {
681     ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
682   }
683 }
684
685 void ImfManager::AutoEnableInputPanel( bool enabled )
686 {
687   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::AutoEnableInputPanel\n" );
688
689   if( mIMFContext )
690   {
691     ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
692   }
693 }
694
695 void ImfManager::ShowInputPanel()
696 {
697   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::ShowInputPanel\n" );
698
699   if( mIMFContext )
700   {
701     ecore_imf_context_input_panel_show( mIMFContext );
702   }
703 }
704
705 void ImfManager::HideInputPanel()
706 {
707   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::HideInputPanel\n" );
708
709   if( mIMFContext )
710   {
711     ecore_imf_context_input_panel_hide( mIMFContext );
712   }
713 }
714
715 Dali::ImfManager::KeyboardType ImfManager::GetKeyboardType()
716 {
717   return Dali::ImfManager::KeyboardType::SOFTWARE_KEYBOARD;
718 }
719
720 std::string ImfManager::GetInputPanelLocale()
721 {
722   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetInputPanelLocale\n" );
723
724   std::string locale = "";
725
726   if( mIMFContext )
727   {
728     char* value = NULL;
729     ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
730
731     if( value )
732     {
733       std::string valueCopy( value );
734       locale = valueCopy;
735
736       // The locale string retrieved must be freed with free().
737       free( value );
738     }
739   }
740   return locale;
741 }
742
743 } // Adaptor
744
745 } // Internal
746
747 } // Dali
748
749 #pragma GCC diagnostic pop