Upload initial version
[platform/core/uifw/libscl-ui-nui.git] / scl / sclkeyfocushandler.cpp
1 /*
2  * Copyright (c) 2012 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
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 #include "sclkeyfocushandler.h"
18 #include <Elementary.h>
19 #include <Evas.h>
20 #include <dlog.h>
21 #ifndef WAYLAND
22 #include <Ecore_X.h>
23 #endif
24 #include "sclres_type.h"
25 #include "scldebug.h"
26 #include "sclcontext.h"
27 #include "sclresourcecache.h"
28 #include "sclwindows.h"
29 #include "scleventhandler.h"
30 #include "sclres_manager.h"
31 #include "sclanimator.h"
32
33 using namespace scl;
34
35 /**
36  * Constructor
37  */
38 CSCLKeyFocusHandler::CSCLKeyFocusHandler()
39 {
40     SCL_DEBUG();
41 #ifdef USING_KEY_GRAB
42     m_keyboard_grabbed = FALSE;
43 #endif
44     m_focus_key = NOT_USED;
45     m_focus_window = SCLWINDOW_INVALID;
46
47 #ifdef TARGET_EMULATOR
48     create_sniffer_window();
49 #endif
50 }
51
52 /**
53  * Destructor
54  */
55 CSCLKeyFocusHandler::~CSCLKeyFocusHandler()
56 {
57     SCL_DEBUG();
58 }
59
60 CSCLKeyFocusHandler*
61 CSCLKeyFocusHandler::get_instance()
62 {
63     static CSCLKeyFocusHandler instance;
64     return &instance;
65 }
66
67 #ifdef USING_KEY_GRAB
68 /**
69  * Grabs the navigation and Return keys
70  */
71 bool
72 CSCLKeyFocusHandler::grab_keyboard(const sclwindow parent)
73 {
74 #ifndef WAYLAND
75     Evas_Object *window = (Evas_Object *)parent;
76     Ecore_X_Window x_window = elm_win_xwindow_get(window);
77
78     Display *x_display = (Display *)ecore_x_display_get();
79     int grab_result;
80
81     grab_result = utilx_grab_key(x_display, x_window, "Return", EXCLUSIVE_GRAB);
82     if (0 == grab_result) {
83         LOGD("Return Key Grabbed successfully\n");
84     } else if (EXCLUSIVE_GRABBED_ALREADY == grab_result) {
85         LOGD("Return Key already grabbed in Exclusiv mode\n");
86     } else {
87         LOGD("Failed to Grab Return key\n");
88     }
89 #endif
90     m_keyboard_grabbed = TRUE;
91     return TRUE;
92 }
93
94 /**
95  * UnGrabs the navigation and Return keys
96  */
97 void
98 CSCLKeyFocusHandler::ungrab_keyboard(const sclwindow parent)
99 {
100 #ifndef WAYLAND
101     Evas_Object *window = (Evas_Object *)parent;
102     Ecore_X_Window x_window = elm_win_xwindow_get(window);
103     Display *x_display = (Display *)ecore_x_display_get();
104     int grab_result;
105     grab_result = utilx_ungrab_key(x_display, x_window, "Return");
106     if (0 == grab_result) {
107         LOGD("Return Key UnGrabbed successfully\n");
108     } else {
109         LOGD("Failed to UnGrab Return key\n");
110     }
111 #endif
112     m_keyboard_grabbed = FALSE;
113 }
114
115 #endif /*USING_KEY_GRAB*/
116
117
118 void
119 CSCLKeyFocusHandler::popup_opened(sclwindow window)
120 {
121 }
122
123 void
124 CSCLKeyFocusHandler::popup_closed(sclwindow window)
125 {
126     sclshort layout = NOT_USED;
127     CSCLContext *context = CSCLContext::get_instance();
128     CSCLWindows *windows = CSCLWindows::get_instance();
129     SclResParserManager *sclres_manager = SclResParserManager::get_instance();
130     PSclLayoutKeyCoordinatePointerTable sclres_layout_key_coordinate_pointer_frame = NULL;
131
132     if (context && windows && sclres_manager) {
133         sclres_layout_key_coordinate_pointer_frame = sclres_manager->get_key_coordinate_pointer_frame();
134         layout = context->get_popup_layout(m_focus_window);
135     }
136     if (windows && sclres_layout_key_coordinate_pointer_frame &&
137         scl_check_arrindex(layout, MAX_SCL_LAYOUT) && scl_check_arrindex(m_focus_key, MAX_KEY)) {
138             SclLayoutKeyCoordinatePointer cur = sclres_layout_key_coordinate_pointer_frame[layout][m_focus_key];
139             SclWindowContext *window_context = windows->get_window_context(m_focus_window);
140             SclRectangle cur_key_coordinate = {0, 0, 0, 0};
141             if (window_context) {
142                 cur_key_coordinate.x = cur->x + window_context->geometry.x;
143                 cur_key_coordinate.y = cur->y + window_context->geometry.y;
144                 cur_key_coordinate.width = cur->width;
145                 cur_key_coordinate.height = cur->height;
146             }
147
148             m_focus_window = windows->get_base_window();
149             m_focus_key = get_next_candidate_key(HIGHLIGHT_NAVIGATE_NONE, cur_key_coordinate, windows->get_base_window()).candidate;
150     }
151 }
152
153 /**
154  * Resets the navigation info
155  */
156 void
157 CSCLKeyFocusHandler::reset_key_navigation_info(sclwindow window)
158 {
159     CSCLWindows *windows = CSCLWindows::get_instance();
160     if (windows) {
161         if (windows->is_base_window(window)) {
162             m_focus_window = window;
163             m_focus_key = 0;
164         }
165     }
166 }
167
168 /**
169  * Compares the sub-layout values
170  */
171 inline bool
172 CSCLKeyFocusHandler::sub_layout_match(sclchar *layout1, sclchar *layout2)
173 {
174     if (layout1) {
175         if (layout2) {
176             if (strcmp(layout1, layout2) == 0) {
177                 return TRUE;
178             }
179         }
180     } else if (layout2) {
181         return FALSE;
182     } else {
183         return TRUE;
184     }
185     return FALSE;
186 }
187
188 /**
189  * Builds the key navigation info
190  */
191 void
192 CSCLKeyFocusHandler::update_key_navigation_info(sclwindow window, scl8 index, SclLayoutKeyCoordinatePointer p_next_key)
193 {
194 }
195
196 /**
197  * Finalize the navigation info
198  */
199 void
200 CSCLKeyFocusHandler::finalize_key_navigation_info(sclwindow window)
201 {
202 }
203
204 /**
205  * Initializes the key index to first key of first row
206  */
207 void
208 CSCLKeyFocusHandler::init_key_index()
209 {
210 }
211
212 /**
213  * Returns the currently focused key index
214  */
215 scl8
216 CSCLKeyFocusHandler::get_current_focus_key(void)
217 {
218     return m_focus_key;
219 }
220
221 /**
222  * Returns the currently focused window
223  */
224 sclwindow
225 CSCLKeyFocusHandler::get_current_focus_window(void)
226 {
227     return m_focus_window;
228 }
229
230 #ifndef min
231 #define min(a, b)    (((a) < (b)) ? (a) : (b))
232 #endif
233 #ifndef max
234 #define max(a, b)    (((a) > (b)) ? (a) : (b))
235 #endif
236 /* If 2 lines overlap, this will return minus value of overlapping length,
237     and return positive distance value otherwise */
238 int calculate_distance(int start_1, int end_1, int start_2, int end_2)
239 {
240     return -1 * (min(end_1, end_2) - max(start_1, start_2));
241 }
242
243 /**
244  * Computes and Returns the key index for next focussed key depending upon the navigation direction
245  */
246 NEXT_CANDIDATE_INFO
247 CSCLKeyFocusHandler::get_next_candidate_key(SCLHighlightNavigationDirection direction, SclRectangle cur, sclwindow window)
248 {
249     NEXT_CANDIDATE_INFO ret;
250     ret.candidate = NOT_USED;
251     ret.candidate_otherside = NOT_USED;
252
253     int candidate = NOT_USED;
254     int candidate_distance_x = INT_MAX;
255     int candidate_distance_y = INT_MAX;
256     int startpos_identical = FALSE;
257
258     int otherside_candidate = NOT_USED;
259
260     sclshort layout = NOT_USED;
261
262     CSCLContext *context = CSCLContext::get_instance();
263     CSCLWindows *windows = CSCLWindows::get_instance();
264     CSCLResourceCache *cache = CSCLResourceCache::get_instance();
265
266     SclResParserManager *sclres_manager = SclResParserManager::get_instance();
267     PSclLayoutKeyCoordinatePointerTable sclres_layout_key_coordinate_pointer_frame = NULL;
268
269     if (context && windows && sclres_manager) {
270         sclres_layout_key_coordinate_pointer_frame = sclres_manager->get_key_coordinate_pointer_frame();
271
272         if (windows->is_base_window(window)) {
273             layout = context->get_base_layout();
274         } else {
275             layout = context->get_popup_layout(window);
276         }
277     }
278
279     if (windows && cache && context &&
280         sclres_layout_key_coordinate_pointer_frame && scl_check_arrindex(layout, MAX_SCL_LAYOUT)) {
281         for (sclint loop = 0;loop < MAX_KEY; loop++) {
282             SclLayoutKeyCoordinatePointer p = sclres_layout_key_coordinate_pointer_frame[layout][loop];
283             if (p && (loop != m_focus_key || window != m_focus_window)) {
284                 if (p->sub_layout && context->get_cur_sublayout()) {
285                     if (!sub_layout_match(p->sub_layout, context->get_cur_sublayout())) {
286                         continue;
287                     }
288                 }
289                 SclWindowContext *window_context = windows->get_window_context(window);
290                 SclRectangle btn = {0, 0, 0, 0};
291                 if (window_context) {
292                     btn.x = p->x + window_context->geometry.x;
293                     btn.y = p->y + window_context->geometry.y;
294                     btn.width = p->width;
295                     btn.height = p->height;
296                 }
297                 if (windows->is_base_window(window)) {
298                     btn.x += cache->get_custom_starting_coordinates().x;
299                     btn.y += cache->get_custom_starting_coordinates().y;
300                 }
301
302                 int temp_distance_x;
303                 int temp_distance_y;
304
305                 switch (direction) {
306                     case HIGHLIGHT_NAVIGATE_LEFT:
307                         temp_distance_y = calculate_distance(btn.y, btn.y + btn.height, cur.y, cur.y + cur.height);
308                         //if (temp_distance_y <= candidate_distance_y) {
309                         if (temp_distance_y <= candidate_distance_y && temp_distance_y < 0) {
310                             /* If the button is closer in Y axis, consider this to be the closer regardless of X */
311                             if (temp_distance_y < candidate_distance_y) {
312                                 /* Only if the ypos were not the same */
313                                 if (!startpos_identical) {
314                                     candidate_distance_x = INT_MAX;
315                                 }
316                             }
317                             /* Save for otherside */
318                             otherside_candidate = loop;
319                             temp_distance_x = calculate_distance(btn.x, btn.x + btn.width, cur.x, cur.x + cur.width);
320                             if (temp_distance_x < candidate_distance_x) {
321                                 if (btn.x < cur.x) {
322                                     candidate = loop;
323                                     candidate_distance_x = temp_distance_x;
324                                     candidate_distance_y = temp_distance_y;
325                                     startpos_identical = (btn.y == cur.y);
326                                 }
327                             }
328                         }
329                         break;
330                     case HIGHLIGHT_NAVIGATE_RIGHT:
331                         temp_distance_y = calculate_distance(btn.y, btn.y + btn.height, cur.y, cur.y + cur.height);
332                         //if (temp_distance_y <= candidate_distance_y) {
333                         if (temp_distance_y <= candidate_distance_y && temp_distance_y < 0) {
334                             /* If the button is closer in Y axis, consider this to be the closer regardless of X */
335                             if (temp_distance_y < candidate_distance_y) {
336                                 /* Only if the ypos were not the same */
337                                 if (!startpos_identical) {
338                                     candidate_distance_x = INT_MAX;
339                                 }
340                             }
341                             /* Save for otherside */
342                             if (otherside_candidate == NOT_USED) {
343                                 otherside_candidate = loop;
344                             }
345                             temp_distance_x = calculate_distance(btn.x, btn.x + btn.width, cur.x, cur.x + cur.width);
346                             if (temp_distance_x < candidate_distance_x) {
347                                 if (btn.x > cur.x) {
348                                     candidate = loop;
349                                     candidate_distance_x = temp_distance_x;
350                                     candidate_distance_y = temp_distance_y;
351                                     startpos_identical = (btn.y == cur.y);
352                                 }
353                             }
354                         }
355                         break;
356                     case HIGHLIGHT_NAVIGATE_UP:
357                         temp_distance_x = calculate_distance(btn.x, btn.x + btn.width, cur.x, cur.x + cur.width);
358                         if (temp_distance_x <= candidate_distance_x) {
359                             /* If the button is closer in X axis, consider this to be the closer regardless of Y */
360                             if (temp_distance_x < candidate_distance_x) {
361                                 /* Only if the xpos were not the same */
362                                 if (!startpos_identical) {
363                                     candidate_distance_y = INT_MAX;
364                                 }
365                             }
366                             temp_distance_y = calculate_distance(btn.y, btn.y + btn.height, cur.y, cur.y + cur.height);
367                             if (temp_distance_y < candidate_distance_y) {
368                                 if (btn.y < cur.y) {
369                                     candidate = loop;
370                                     candidate_distance_x = temp_distance_x;
371                                     candidate_distance_y = temp_distance_y;
372                                     startpos_identical = (btn.x == cur.x);
373                                 }
374                             }
375                         }
376                         break;
377                     case HIGHLIGHT_NAVIGATE_DOWN:
378                         temp_distance_x = calculate_distance(btn.x, btn.x + btn.width, cur.x, cur.x + cur.width);
379                         if (temp_distance_x <= candidate_distance_x) {
380                             /* If the button is closer in X axis, consider this to be the closer regardless of Y */
381                             if (temp_distance_x < candidate_distance_x) {
382                                 /* Only if the xpos were not the same */
383                                 if (!startpos_identical) {
384                                     candidate_distance_y = INT_MAX;
385                                 }
386                             }
387                             temp_distance_y = calculate_distance(btn.y, btn.y + btn.height, cur.y, cur.y + cur.height);
388                             if (temp_distance_y < candidate_distance_y) {
389                                 if (btn.y > cur.y) {
390                                     candidate = loop;
391                                     candidate_distance_x = temp_distance_x;
392                                     candidate_distance_y = temp_distance_y;
393                                     startpos_identical = (btn.x == cur.x);
394                                 }
395                             }
396                         }
397                         break;
398                     default:
399                         temp_distance_y = calculate_distance(btn.y, btn.y + btn.height, cur.y, cur.y + cur.height);
400                         if (temp_distance_y <= candidate_distance_y) {
401                             temp_distance_x = calculate_distance(btn.x, btn.x + btn.width, cur.x, cur.x + cur.width);
402                             if (temp_distance_x <= candidate_distance_x) {
403                                 candidate = loop;
404                                 candidate_distance_x = temp_distance_x;
405                                 candidate_distance_y = temp_distance_y;
406                             }
407                         }
408                         break;
409                 }
410             }
411         }
412
413         ret.candidate = candidate;
414         ret.candidate_otherside = otherside_candidate;
415     }
416
417     return ret;
418 }
419
420 static void copy_rectangle(SclLayoutKeyCoordinatePointer src, SclRectangle *dest)
421 {
422     if (src && dest) {
423         (dest)->x = (src)->x;
424         (dest)->y = (src)->y;
425         (dest)->width = (src)->width;
426         (dest)->height = (src)->height;
427     }
428 }
429
430 void
431 CSCLKeyFocusHandler::process_navigation(SCLHighlightNavigationDirection direction)
432 {
433     CSCLContext *context = CSCLContext::get_instance();
434     CSCLWindows *windows = CSCLWindows::get_instance();
435     CSCLEventHandler *handler = CSCLEventHandler::get_instance();
436     CSCLResourceCache *cache = CSCLResourceCache::get_instance();
437     SclResParserManager *sclres_manager = SclResParserManager::get_instance();
438
439     if (!context || !windows || !handler || !cache || !sclres_manager) return;
440
441     sclshort layout = NOT_USED;
442
443     sclwindow prev_window = m_focus_window;
444     scl8 prev_key = m_focus_key;
445     sclwindow next_window = m_focus_window;
446     scl8 next_key = m_focus_key;
447
448     PSclLayoutKeyCoordinatePointerTable sclres_layout_key_coordinate_pointer_frame = NULL;
449
450     if (context && windows && handler && sclres_manager) {
451         sclres_layout_key_coordinate_pointer_frame = sclres_manager->get_key_coordinate_pointer_frame();
452
453         if (windows->is_base_window(m_focus_window)) {
454             layout = context->get_base_layout();
455         } else {
456             layout = context->get_popup_layout(m_focus_window);
457         }
458     }
459
460     if (sclres_layout_key_coordinate_pointer_frame && context->get_highlight_ui_enabled() &&
461         scl_check_arrindex(layout, MAX_SCL_LAYOUT) && scl_check_arrindex(m_focus_key, MAX_KEY)) {
462         SclLayoutKeyCoordinatePointer cur = sclres_layout_key_coordinate_pointer_frame[layout][m_focus_key];
463
464         /* To compare with buttons in popup window, let's convert to global coordinates */
465         SclWindowContext *window_context = windows->get_window_context(m_focus_window);
466         SclRectangle cur_key_coordinate = {0, 0, 0, 0};
467         if (window_context && cur && cache) {
468             cur_key_coordinate.x = cur->x + window_context->geometry.x;
469             cur_key_coordinate.y = cur->y + window_context->geometry.y;
470             cur_key_coordinate.width = cur->width;
471             cur_key_coordinate.height = cur->height;
472
473             if (windows->is_base_window(m_focus_window)) {
474                 cur_key_coordinate.x += cache->get_custom_starting_coordinates().x;
475                 cur_key_coordinate.y += cache->get_custom_starting_coordinates().y;
476             }
477         }
478
479         NEXT_CANDIDATE_INFO base_candidate;
480         base_candidate.candidate = base_candidate.candidate_otherside = NOT_USED;
481         NEXT_CANDIDATE_INFO popup_candidate;
482         popup_candidate.candidate = popup_candidate.candidate_otherside = NOT_USED;
483         sclboolean search_in_base_window = TRUE;
484         sclboolean exclude_popup_covered_area = FALSE;
485
486         if (windows && !windows->is_base_window(windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP))) {
487             if (cache && window_context && scl_check_arrindex(window_context->inputmode, MAX_SCL_INPUT_MODE)) {
488                 const SclLayout *cur_layout =
489                     cache->get_cur_layout(windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP));
490                 if (cur_layout) {
491                     if (!(cur_layout->use_sw_background) || cur_layout->bg_color.a != 0) {
492                         const PSclInputModeConfigure sclres_input_mode_configure =
493                             sclres_manager->get_input_mode_configure_table();
494                         if (sclres_input_mode_configure && sclres_input_mode_configure[window_context->inputmode].use_dim_window) {
495                             search_in_base_window = FALSE;
496                         } else {
497                             exclude_popup_covered_area = TRUE;
498                         }
499                     }
500                 }
501             }
502             popup_candidate = get_next_candidate_key(direction, cur_key_coordinate,
503                 windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP));
504         }
505         /* Now search buttons in base window */
506         if (search_in_base_window && windows) {
507             base_candidate = get_next_candidate_key(direction, cur_key_coordinate, windows->get_base_window());
508         }
509
510         if (popup_candidate.candidate == NOT_USED && base_candidate.candidate != NOT_USED) {
511             next_window = windows->get_base_window();
512             next_key = base_candidate.candidate;
513         } else if (popup_candidate.candidate != NOT_USED && base_candidate.candidate == NOT_USED) {
514             next_window = windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP);
515             next_key = popup_candidate.candidate;
516         } else if (popup_candidate.candidate == NOT_USED && base_candidate.candidate == NOT_USED) {
517             if (base_candidate.candidate_otherside != NOT_USED) {
518                 next_window = windows->get_base_window();
519                 next_key = base_candidate.candidate_otherside;
520             } else if (popup_candidate.candidate_otherside != NOT_USED) {
521                 next_window = windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP);
522                 next_key = popup_candidate.candidate_otherside;
523             }
524         } else {
525             /* Compare those 2 candidates */
526             sclwindow popup_window = windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP);
527             sclshort base_layout = context->get_base_layout();
528             sclshort popup_layout = context->get_popup_layout(popup_window);
529
530             SclLayoutKeyCoordinatePointer base_key = NULL;
531             SclLayoutKeyCoordinatePointer popup_key = NULL;
532             SclWindowContext *base_window_context = NULL;
533             SclWindowContext *popup_window_context = NULL;
534
535             if (scl_check_arrindex(base_layout, MAX_SCL_LAYOUT) && scl_check_arrindex(popup_layout, MAX_SCL_LAYOUT)) {
536                 base_key = sclres_layout_key_coordinate_pointer_frame[base_layout][base_candidate.candidate];
537                 popup_key = sclres_layout_key_coordinate_pointer_frame[popup_layout][popup_candidate.candidate];
538                 base_window_context = windows->get_window_context(windows->get_base_window());
539                 popup_window_context = windows->get_window_context(popup_window);
540             }
541
542             SclRectangle base_key_coordinate = {0, 0, 0, 0};
543             if (base_window_context) {
544                 base_key_coordinate.x = base_key->x + base_window_context->geometry.x;
545                 base_key_coordinate.y = base_key->y + base_window_context->geometry.y;
546                 base_key_coordinate.width = base_key->width;
547                 base_key_coordinate.height = base_key->height;
548
549                 base_key_coordinate.x += cache->get_custom_starting_coordinates().x;
550                 base_key_coordinate.y += cache->get_custom_starting_coordinates().y;
551             }
552
553             SclRectangle popup_key_coordinate = {0, 0, 0, 0};
554             if (popup_window_context) {
555                 popup_key_coordinate.x = popup_key->x + popup_window_context->geometry.x;
556                 popup_key_coordinate.y = popup_key->y + popup_window_context->geometry.y;
557                 popup_key_coordinate.width = popup_key->width;
558                 popup_key_coordinate.height = popup_key->height;
559             }
560
561             if (exclude_popup_covered_area) {
562                 CSCLUtils *utils = CSCLUtils::get_instance();
563                 if (utils && popup_window_context) {
564                     /* If the base candidate key is covered by popup window, do not choose it */
565                     if (utils->is_rect_overlap(base_key_coordinate, popup_window_context->geometry)) {
566                         base_candidate.candidate = NOT_USED;
567                     }
568                 }
569             }
570             /* If the base candidate key wasn't excluded */
571             if (base_candidate.candidate != NOT_USED) {
572                 int base_distance_x = INT_MAX;
573                 int base_distance_y = INT_MAX;
574                 int popup_distance_x = INT_MAX;
575                 int popup_distance_y = INT_MAX;
576
577                 base_distance_x = calculate_distance(
578                     cur_key_coordinate.x, cur_key_coordinate.x + cur_key_coordinate.width,
579                     base_key_coordinate.x, base_key_coordinate.x + base_key_coordinate.width);
580                 base_distance_y = calculate_distance(
581                     cur_key_coordinate.y, cur_key_coordinate.y + cur_key_coordinate.height,
582                     base_key_coordinate.y, base_key_coordinate.y + base_key_coordinate.height);
583
584                 popup_distance_x = calculate_distance(
585                     cur_key_coordinate.x, cur_key_coordinate.x + cur_key_coordinate.width,
586                     popup_key_coordinate.x, popup_key_coordinate.x + popup_key_coordinate.width);
587                 popup_distance_y = calculate_distance(
588                     cur_key_coordinate.y, cur_key_coordinate.y + cur_key_coordinate.height,
589                     popup_key_coordinate.y, popup_key_coordinate.y + popup_key_coordinate.height);
590
591                 if (direction == HIGHLIGHT_NAVIGATE_LEFT || direction == HIGHLIGHT_NAVIGATE_RIGHT) {
592                     int minimum_distance = -1 * (cur_key_coordinate.height / 3);
593                     if (base_distance_y > minimum_distance && popup_distance_y > minimum_distance) {
594                         minimum_distance = 0;
595                     }
596                     if (base_distance_y < minimum_distance && popup_distance_y < minimum_distance) {
597                         if (base_distance_x < popup_distance_x) {
598                             next_window = windows->get_base_window();
599                             next_key = base_candidate.candidate;
600                         } else {
601                             next_window = windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP);
602                             next_key = popup_candidate.candidate;
603                         }
604                     } else if (base_distance_y < minimum_distance) {
605                         next_window = windows->get_base_window();
606                         next_key = base_candidate.candidate;
607                     } else {
608                         next_window = windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP);
609                         next_key = popup_candidate.candidate;
610                     }
611                 } else if (direction == HIGHLIGHT_NAVIGATE_UP || direction == HIGHLIGHT_NAVIGATE_DOWN) {
612                     int minimum_distance = -1 * (cur_key_coordinate.width / 3);
613                     if (base_distance_x > minimum_distance && popup_distance_x > minimum_distance) {
614                         minimum_distance = 0;
615                     }
616                     if (base_distance_x < minimum_distance && popup_distance_x < minimum_distance) {
617                         if (base_distance_y < popup_distance_y) {
618                             next_window = windows->get_base_window();
619                             next_key = base_candidate.candidate;
620                         } else {
621                             next_window = windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP);
622                             next_key = popup_candidate.candidate;
623                         }
624                     } else if (base_distance_x < minimum_distance) {
625                         next_window = windows->get_base_window();
626                         next_key = base_candidate.candidate;
627                     } else {
628                         next_window = windows->get_nth_window_in_Z_order_list(SCL_WINDOW_Z_TOP);
629                         next_key = popup_candidate.candidate;
630                     }
631                 }
632             }
633         }
634
635         SclNotiHighlightNavigateDesc desc;
636         desc.direction = direction;
637         desc.window_from = prev_window;
638         desc.key_from = prev_key;
639         desc.window_to = next_window;
640         desc.key_to = next_key;
641         if (SCL_EVENT_PASS_ON == handler->on_event_notification(SCL_UINOTITYPE_HIGHLIGHT_NAVIGATE, &desc)) {
642             CSCLAnimator *animator = CSCLAnimator::get_instance();
643             if (animator) {
644                 sclboolean start_animation = FALSE;
645                 if (windows->is_base_window(desc.window_to) && windows->is_base_window(desc.window_from)) {
646                     if (desc.key_to != desc.key_from) {
647                         start_animation = TRUE;
648                     }
649                 } else {
650                     SclWindowContext *window_context_from = windows->get_window_context(desc.window_from);
651                     SclWindowContext *window_context_to = windows->get_window_context(desc.window_to);
652                     if (window_context_from && window_context_to) {
653                         if ((windows->is_base_window(desc.window_from) || window_context_from->is_virtual) &&
654                             (windows->is_base_window(desc.window_to) || window_context_to->is_virtual)) {
655                                 start_animation = TRUE;
656                         }
657                     }
658                 }
659                 sclshort layout_from = NOT_USED;
660                 sclshort layout_to = NOT_USED;
661                 if (windows->is_base_window(desc.window_from)) {
662                     layout_from = context->get_base_layout();
663                 } else {
664                     layout_from = context->get_popup_layout(desc.window_from);
665                 }
666                 if (windows->is_base_window(desc.window_to)) {
667                     layout_to = context->get_base_layout();
668                 } else {
669                     layout_to = context->get_popup_layout(desc.window_to);
670                 }
671                 if (!scl_check_arrindex(desc.key_from, MAX_KEY) || !scl_check_arrindex(desc.key_to, MAX_KEY) ||
672                     !scl_check_arrindex(layout_from, MAX_SCL_LAYOUT) || !scl_check_arrindex(layout_to, MAX_SCL_LAYOUT)) {
673                     start_animation = FALSE;
674                 }
675                 if (start_animation &&
676                     context->get_highlight_ui_enabled() &&
677                     context->get_highlight_ui_animation_enabled() &&
678                     animator->check_animation_supported()) {
679                         SclLayoutKeyCoordinatePointer prev_coordinate =
680                             sclres_layout_key_coordinate_pointer_frame[layout_from][desc.key_from];
681                         SclLayoutKeyCoordinatePointer next_coordinate =
682                             sclres_layout_key_coordinate_pointer_frame[layout_to][desc.key_to];
683
684                         SclRectangle prev_rect;
685                         SclRectangle next_rect;
686                         copy_rectangle(prev_coordinate, &(prev_rect));
687                         copy_rectangle(next_coordinate, &(next_rect));
688
689                         if (windows->is_base_window(desc.window_from)) {
690                             prev_rect.x += cache->get_custom_starting_coordinates().x;
691                             prev_rect.y += cache->get_custom_starting_coordinates().y;
692                         } else {
693                             /* Convert popup window coordinates relative to base window */
694                             SclWindowContext *base_window_context =
695                                 windows->get_window_context(windows->get_base_window());
696                             SclWindowContext *prev_window_context =
697                                 windows->get_window_context(desc.window_from);
698                             if (base_window_context && prev_window_context) {
699                                 prev_rect.x += (prev_window_context->geometry.x - base_window_context->geometry.x);
700                                 prev_rect.y += (prev_window_context->geometry.y - base_window_context->geometry.y);
701                             }
702                         }
703                         if (windows->is_base_window(desc.window_to)) {
704                             next_rect.x += cache->get_custom_starting_coordinates().x;
705                             next_rect.y += cache->get_custom_starting_coordinates().y;
706                         } else {
707                             /* Convert popup window coordinates relative to base window */
708                             SclWindowContext *base_window_context =
709                                 windows->get_window_context(windows->get_base_window());
710                             SclWindowContext *next_window_context =
711                                 windows->get_window_context(desc.window_to);
712                             if (base_window_context && next_window_context) {
713                                 next_rect.x += (next_window_context->geometry.x - base_window_context->geometry.x);
714                                 next_rect.y += (next_window_context->geometry.y - base_window_context->geometry.y);
715                             }
716                         }
717                         /* Let's check if the navigation animation should be in circular movement */
718                         sclboolean circular = FALSE;
719                         /* If our 2 buttons overlap in Y axis */
720                         if (calculate_distance(
721                             prev_rect.y, prev_rect.y + prev_rect.height,
722                             next_rect.y, next_rect.y + next_rect.height) < 0) {
723                                 /* And if those 2 buttons are side buttons, let's run the animation in circular mode */
724                                 if (prev_coordinate->is_side_button && next_coordinate->is_side_button) {
725                                     circular = TRUE;
726                                 }
727                         }
728
729                         sclint id = animator->find_animator_by_type(ANIMATION_TYPE_HIGHLIGHT_UI);
730                         if (id == NOT_USED) {
731                             SclAnimationDesc animdesc;
732                             animdesc.type = ANIMATION_TYPE_HIGHLIGHT_UI;
733                             animdesc.length = SCL_ANIMATION_TIME;
734
735                             animdesc.rect_from = prev_rect;
736                             animdesc.rect_to = next_rect;
737
738                             animdesc.window_from = desc.window_from;
739                             animdesc.window_to = desc.window_to;
740                             animdesc.circular = circular;
741
742                             id = animator->create_animator(&animdesc);
743                             animator->start_animator(id);
744                         } else {
745                             SclAnimationState *state = animator->get_animation_state(id);
746                             if (state) {
747                                 if (state->active) {
748                                     /* FIXME : When we have time later,
749                                         let's use the currect rect so that the animation starts from the current position,
750                                         considering the circular movement case */
751                                     //state->desc.rect_from = state->rect_cur;
752                                     state->desc.rect_from = prev_rect;
753                                 } else {
754                                     state->active = TRUE;
755                                     state->desc.rect_from = prev_rect;
756                                 }
757                                 state->step = 0;
758                                 state->desc.circular = circular;
759
760                                 state->desc.rect_to = next_rect;
761
762                                 state->desc.window_from = desc.window_from;
763                                 state->desc.window_to = desc.window_to;
764                             }
765                             animator->start_animator(id);
766                         }
767                 }
768             }
769             m_focus_window = desc.window_to;
770             m_focus_key = desc.key_to;
771         }
772     }
773 }
774
775 void
776 CSCLKeyFocusHandler::set_current_focus(sclwindow window, scl8 index)
777 {
778     m_focus_window = window;
779     m_focus_key = index;
780 }
781
782 #ifdef TARGET_EMULATOR
783
784 /**
785  * callback for window show event (sniffer window)
786  */
787 static void sniffer_window_show_cb(void *data, Evas *e, Evas_Object *obj, void *event)
788 {
789     LOGD("INSIDE =-=-=-=- x_event_sniffer_window_show_cb, Trying to Grab Key Board : \n");
790 #ifndef WAYLAND
791     Eina_Bool ret = ecore_x_keyboard_grab(x_window);
792
793     if (EINA_TRUE == ret) {
794         LOGD("Keyboard Grabbed successfully by sniffer\n");
795     } else {
796         LOGD("Failed to Grab keyboard by sniffer\n");
797     }
798 #endif
799 }
800
801 /**
802  * sniffer window creation function, the keyboard would be grabbed by this window in case of Tizen Emulator
803  */
804 void
805 CSCLKeyFocusHandler::create_sniffer_window(void)
806 {
807     LOGD("CSCLKeyFocusHandler : INSIDE =-=-=-=- create_sniffer_window : \n");
808     Evas_Object *win = NULL;
809
810     win = elm_win_add(NULL, "KEY_SNIFFER", ELM_WIN_UTILITY);
811
812     elm_win_borderless_set(win, EINA_TRUE);
813     elm_win_alpha_set(win, EINA_FALSE);
814     elm_win_title_set(win, "KEY_SNIFFER");
815     elm_win_fullscreen_set(win, EINA_FALSE);
816     set_window_accepts_focus(win, FALSE);
817     evas_object_show(win);
818     evas_object_resize(win, 100, 100);
819     m_sniffer = win;
820
821     evas_object_event_callback_add(win, EVAS_CALLBACK_SHOW, sniffer_window_show_cb, NULL);
822 }
823
824 void
825 CSCLKeyFocusHandler::set_window_accepts_focus(const sclwindow window, sclboolean acceptable)
826 {
827     elm_win_prop_focus_skip_set(static_cast<Evas_Object*>(window), !acceptable);
828 }
829
830
831 #endif
832
833