1c47e09ad5888ef49fd4f861295fbc6dcc1d52ae
[platform/upstream/enlightenment.git] / src / bin / e_focus_policy_topmost.c
1 #include "e_focus_policy_iface.h"
2 #include "e_zone_intern.h"
3 #include "e_client_intern.h"
4 #include "e_desk_intern.h"
5 #include "e_config_intern.h"
6
7 typedef struct _E_Focus_Policy_Topmost_Impl E_Focus_Policy_Topmost;
8 typedef struct _E_Focus_Policy_Topmost_Client E_Focus_Policy_Topmost_Client;
9
10 struct _E_Focus_Policy_Topmost_Impl
11 {
12    E_Zone   *zone;
13    E_Client *focused_ec;
14
15    struct
16      {
17         struct wl_signal focused_ec_changed;
18      } events;
19
20    struct wl_listener zone_client_add;
21    struct wl_listener zone_client_remove;
22    struct wl_listener zone_focus_clear;
23 };
24
25 struct _E_Focus_Policy_Topmost_Client
26 {
27    E_Client *ec;
28    E_Focus_Policy_Topmost *topmost_policy;
29
30    struct wl_listener client_destroy;
31    struct wl_listener client_mouse_in;
32    struct wl_listener client_mouse_out;
33    struct wl_listener client_mouse_down;
34    struct wl_listener client_focus_set;
35    struct wl_listener client_focus_unset;
36    struct wl_listener client_lower;
37    struct wl_listener client_move;
38    struct wl_listener client_eval_end;
39 };
40
41 // Trace the focus topmost
42 //#define FOCUS_TOPMOST_TRACE
43 #ifdef FOCUS_TOPMOST_TRACE
44 #define E_FOCUS_TOPMOST_TRACE(topmost_policy, ec) \
45   do \
46     { \
47        ELOGF( \
48              "FOCUS_TOPMOST", "[FOCUS][Trace][%s]:(%p, %d) focused_ec:%p", ec, \
49              __FUNCTION__, topmost_policy, topmost_policy->zone->id, topmost_policy->focused_ec)\
50             ); \
51     } \
52   while (0)
53 #else
54 #define E_FOCUS_TOPMOST_TRACE(topmost_policy, ec)
55 #endif
56
57 static Eina_Bool
58 _e_focus_policy_topmost_focus_can_take_by_vis_obscured(E_Client *ec)
59 {
60    switch (e_client_visibility_get(ec))
61      {
62        case E_VISIBILITY_UNKNOWN:
63        case E_VISIBILITY_FULLY_OBSCURED:
64            if (e_client_check_really_iconified(ec))
65              return EINA_FALSE;
66            break;
67        case E_VISIBILITY_UNOBSCURED:
68        case E_VISIBILITY_PARTIALLY_OBSCURED:
69        case E_VISIBILITY_PRE_UNOBSCURED:
70        default:
71            break;
72      }
73    return EINA_TRUE;
74 }
75
76 static Eina_Bool
77 _e_focus_policy_topmost_focus_can_take(E_Client *ec)
78 {
79    E_Zone *zone;
80    E_Client *child_ec, *above_ec;
81    int x = 0, y = 0, w = 0, h = 0;
82
83    if (!ec) return EINA_FALSE;
84    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
85    if (e_client_util_ignored_get(ec)) return EINA_FALSE;
86
87    if (!(ec->icccm.accepts_focus || ec->icccm.take_focus)) return EINA_FALSE;
88    if (ec->lock_focus_in || ec->lock_focus_out) return EINA_FALSE;
89
90    if (!ec->visible) return EINA_FALSE;
91    if (ec->bg_state) return EINA_FALSE;
92    if (ec->visibility.force_obscured) return EINA_FALSE;
93    if (!_e_focus_policy_topmost_focus_can_take_by_vis_obscured(ec)) return EINA_FALSE;
94
95    zone = e_comp_zone_find_by_ec(ec);
96    if (zone)
97      {
98         e_client_geometry_get(ec, &x, &y, &w, &h);
99         if (!E_INTERSECTS(zone->x, zone->y, zone->w, zone->h, x, y, w, h))
100           return EINA_FALSE;
101      }
102
103    above_ec = e_client_check_fully_contain_by_above(ec, EINA_FALSE);
104    if (above_ec)
105      {
106          if (!evas_object_visible_get(above_ec->frame))
107            return EINA_TRUE;
108
109         child_ec = e_client_check_obscured_by_children_group(ec);
110         if (!child_ec) return EINA_FALSE;
111         if (above_ec != child_ec) return EINA_FALSE;
112
113         if (_e_focus_policy_topmost_focus_can_take(child_ec))
114           return EINA_FALSE;
115         else if (e_client_check_fully_contain_by_above(child_ec, EINA_FALSE))
116           return EINA_FALSE;
117      }
118
119    return EINA_TRUE;
120 }
121
122 static E_Client *
123 _e_focus_policy_topmost_focusable_get(void)
124 {
125    E_Client *ec;
126
127    E_CLIENT_REVERSE_FOREACH(ec)
128      {
129         if (_e_focus_policy_topmost_focus_can_take(ec))
130           return ec;
131      }
132
133    return NULL;
134 }
135
136 static void
137 _focus_policy_topmost_next_focus_set(E_Focus_Policy_Topmost *topmost_policy)
138 {
139    E_Client *focusable_ec, *focused_ec;
140
141    // current focused ec
142    focused_ec = topmost_policy->focused_ec;
143
144    // next focusable ec
145    focusable_ec = _e_focus_policy_topmost_focusable_get();
146    if (focusable_ec == focused_ec) return;
147
148    if (focusable_ec)
149      {
150         if (!focusable_ec->iconic || focusable_ec->exp_iconify.buffer_flush)
151           {
152              ELOGF("FOCUS_TOPMOST", "focus set   | topmost_focus", focusable_ec);
153
154              if (focused_ec)
155                e_client_frame_focus_set(focused_ec, EINA_FALSE);
156
157              e_client_frame_focus_set(focusable_ec, EINA_TRUE);
158           }
159      }
160    else
161      {
162         ELOGF("FOCUS_TOPMOST", "focus unset | No focusable ec", focused_ec);
163
164         e_client_frame_focus_set(focused_ec, EINA_FALSE);
165      }
166 }
167
168 static void
169 _focus_policy_topmost_cb_client_destroy(struct wl_listener *listener, void *data)
170 {
171    E_Focus_Policy_Topmost_Client *topmost_client;
172    E_Focus_Policy_Topmost *topmost_policy;
173    E_Client *ec;
174
175    topmost_client = wl_container_of(listener, topmost_client, client_destroy);
176
177    topmost_policy = topmost_client->topmost_policy;
178    EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
179
180    ec = topmost_client->ec;
181    EINA_SAFETY_ON_NULL_RETURN(ec);
182
183    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
184
185    wl_list_remove(&topmost_client->client_eval_end.link);
186    wl_list_remove(&topmost_client->client_move.link);
187    wl_list_remove(&topmost_client->client_lower.link);
188    wl_list_remove(&topmost_client->client_focus_unset.link);
189    wl_list_remove(&topmost_client->client_focus_set.link);
190    wl_list_remove(&topmost_client->client_mouse_down.link);
191    wl_list_remove(&topmost_client->client_mouse_out.link);
192    wl_list_remove(&topmost_client->client_mouse_in.link);
193    wl_list_remove(&topmost_client->client_destroy.link);
194
195    E_FREE(topmost_client);
196 }
197
198 static void
199 _focus_policy_topmost_cb_client_mouse_in(struct wl_listener *listener, void *data)
200 {
201    E_Focus_Policy_Topmost_Client *topmost_client;
202    E_Focus_Policy_Topmost *topmost_policy;
203    E_Client *ec;
204
205    topmost_client = wl_container_of(listener, topmost_client, client_mouse_in);
206
207    topmost_policy = topmost_client->topmost_policy;
208    EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
209
210    ec = topmost_client->ec;
211    EINA_SAFETY_ON_NULL_RETURN(ec);
212
213    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
214
215    if ((!ec->iconic) && (!e_client_util_ignored_get(ec)))
216      {
217         if (e_config->use_auto_raise)
218           {
219              if (!ec->lock_user_stacking)
220                e_client_raise(ec);
221           }
222      }
223 }
224
225 static void
226 _focus_policy_topmost_cb_client_mouse_out(struct wl_listener *listener, void *data)
227 {
228    // nothing to do
229 }
230
231 static void
232 _focus_policy_topmost_cb_client_mouse_down(struct wl_listener *listener, void *data)
233 {
234    E_Focus_Policy_Topmost_Client *topmost_client;
235    E_Focus_Policy_Topmost *topmost_policy;
236    E_Client *focused_ec, *ec;
237
238    topmost_client = wl_container_of(listener, topmost_client, client_mouse_down);
239
240    topmost_policy = topmost_client->topmost_policy;
241    EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
242
243    ec = topmost_client->ec;
244    EINA_SAFETY_ON_NULL_RETURN(ec);
245
246    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
247
248    if (e_object_is_del(E_OBJECT(ec))) return;
249
250    focused_ec = topmost_policy->focused_ec;
251    if ((focused_ec) && (ec != focused_ec))
252      {
253         if (e_client_focus_policy_click(ec) ||
254             e_config->always_click_to_focus)
255           {
256              if (ec->floating)
257                e_client_raise(ec);
258           }
259
260         if (e_config->always_click_to_raise)
261           {
262              if (!ec->lock_user_stacking)
263                e_client_raise(ec);
264
265              if (ec->parent && e_client_is_belong_to_parent(ec))
266                {
267                   if (!ec->parent->lock_user_stacking)
268                     e_client_raise(ec->parent);
269                }
270           }
271      }
272 }
273
274 static void set_focused_ec(E_Focus_Policy_Topmost *topmost_policy, E_Client *ec)
275 {
276    atomic_store(&topmost_policy->focused_ec, ec);
277
278    wl_signal_emit_mutable(&topmost_policy->events.focused_ec_changed, ec);
279 }
280
281 static void
282 _focus_policy_topmost_cb_client_focus_set(struct wl_listener *listener, void *data)
283 {
284    E_Focus_Policy_Topmost_Client *topmost_client;
285    E_Focus_Policy_Topmost *topmost_policy;
286 #ifdef REFACTOR_DESK_AREA
287    E_Client *focused_ec, *ec;
288 #else
289    E_Client *focused_ec, *ec, *ec2;
290    E_Zone *zone;
291    Eina_List *l, *ll;
292 #endif
293
294    topmost_client = wl_container_of(listener, topmost_client, client_focus_set);
295
296    topmost_policy = topmost_client->topmost_policy;
297    EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
298
299    ec = topmost_client->ec;
300    EINA_SAFETY_ON_NULL_RETURN(ec);
301
302    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
303
304    focused_ec = topmost_policy->focused_ec;
305    if (ec == focused_ec) return;
306
307 #ifdef REFACTOR_DESK_AREA
308 #else
309    zone = topmost_policy->zone;
310 #endif
311
312    ec->focused = 1;
313
314 #ifdef REFACTOR_DESK_AREA
315 #else
316    // TODO: This is not for focus policy, but for fullscreen(Window State) policy.
317    //       Move this code to the better place.
318    int x, total = zone->desk_x_count * zone->desk_y_count;
319    for (x = 0; x < total; x++)
320      {
321         E_Desk *desk = zone->desks[x];
322         /* if there's any fullscreen non-parents on this desk, unfullscreen them */
323         EINA_LIST_FOREACH_SAFE(desk->fullscreen_clients, l, ll, ec2)
324           {
325              if (ec2 == ec) continue;
326              if (e_object_is_del(E_OBJECT(ec2))) continue;
327              /* but only if it's the same desk or one of the clients is sticky */
328              if ((e_desk_has_ec(desk, ec2)) || (ec->sticky || ec2->sticky))
329                {
330                   if (!eina_list_data_find(ec->transients, ec2))
331                      e_client_unfullscreen(ec2);
332                }
333           }
334      }
335 #endif
336
337    // assign the focused_ec
338    set_focused_ec(topmost_policy, ec);
339
340    ELOGF("FOCUS_TOPMOST", "focus_set | focused_ec SET", ec);
341 }
342
343 static void
344 _focus_policy_topmost_cb_client_focus_unset(struct wl_listener *listener, void *data)
345 {
346    E_Focus_Policy_Topmost_Client *topmost_client;
347    E_Focus_Policy_Topmost *topmost_policy;
348    E_Client *ec, *ec2;
349    E_Zone *zone;
350    E_Desk *desk, *desk2;
351    Eina_List *l;
352
353    topmost_client = wl_container_of(listener, topmost_client, client_focus_unset);
354
355    topmost_policy = topmost_client->topmost_policy;
356    EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
357
358    ec = topmost_client->ec;
359    EINA_SAFETY_ON_NULL_RETURN(ec);
360
361    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
362
363    zone = topmost_policy->zone;
364
365    ec->want_focus = ec->focused = 0;
366    if (ec->mouse.in && ec && (!e_client_util_is_popup(ec)) &&
367       (e_config->focus_policy != E_FOCUS_CLICK))
368       e_client_mouse_out(ec, ec->x - 1, ec->y - 1);
369
370    desk = e_zone_desk_find_by_ec(zone, ec);
371    /* if there unfocus client is fullscreen and visible */
372    if ((ec->fullscreen) && (!ec->iconic) && (!ec->hidden) &&
373        ((desk == e_desk_current_get(zone)) || (ec->sticky)))
374       {
375          Eina_Bool have_vis_child = EINA_FALSE;
376
377          /* if any of its children are visible */
378          EINA_LIST_FOREACH(ec->transients, l, ec2)
379          {
380             desk2 = e_zone_desk_find_by_ec(zone, ec2);
381             if (((desk2 == desk) ||
382                  (ec2->sticky) || (ec->sticky)))
383                {
384                   have_vis_child = EINA_TRUE;
385                   break;
386                }
387          }
388          /* if no children are visible, unfullscreen */
389          if ((!e_object_is_del(E_OBJECT(ec))) && (!have_vis_child))
390          e_client_unfullscreen(ec);
391       }
392
393    // assign the focused_ec
394    set_focused_ec(topmost_policy, NULL);
395
396    ELOGF("FOCUS_TOPMOST", "focus_unset | focused_ec UNSET", NULL);
397 }
398
399 static void
400 _focus_policy_topmost_cb_client_lower(struct wl_listener *listener, void *data)
401 {
402    E_Focus_Policy_Topmost_Client *topmost_client;
403    E_Focus_Policy_Topmost *topmost_policy;
404    E_Client *ec;
405
406    topmost_client = wl_container_of(listener, topmost_client, client_lower);
407
408    topmost_policy = topmost_client->topmost_policy;
409    EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
410
411    ec = topmost_client->ec;
412    EINA_SAFETY_ON_NULL_RETURN(ec);
413
414    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
415
416    // no need to change the focused ec when ec is not focused.
417    if (!ec->focused) return;
418
419    // no need to change the focused ec when calc_vis_without_effect is not set.
420    if (e_config->calc_vis_without_effect) return;
421
422    // find the next focus and set it
423    _focus_policy_topmost_next_focus_set(topmost_policy);
424 }
425
426 static void
427 _focus_policy_topmost_cb_client_move(struct wl_listener *listener, void *data)
428 {
429    E_Focus_Policy_Topmost_Client *topmost_client;
430    E_Focus_Policy_Topmost *topmost_policy;
431    E_Client *ec;
432    E_Zone *zone;
433
434    topmost_client = wl_container_of(listener, topmost_client, client_move);
435
436    topmost_policy = topmost_client->topmost_policy;
437    EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
438
439    ec = topmost_client->ec;
440    EINA_SAFETY_ON_NULL_RETURN(ec);
441
442    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
443
444    zone = e_comp_zone_find_by_ec(ec);
445    if (!zone) return;
446
447    // no need to change the focused ec when ec is not focused.
448    if (!ec->focused) return;
449
450    // no need to change the focused ec when ec is in the area of a zone.
451    if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
452                     zone->x, zone->y, zone->w, zone->h))
453      {
454         // find the next focus and set it
455         _focus_policy_topmost_next_focus_set(topmost_policy);
456      }
457 }
458
459 static void
460 _focus_policy_topmost_cb_client_eval_end(struct wl_listener *listener, void *data)
461 {
462    E_Focus_Policy_Topmost_Client *topmost_client;
463    E_Focus_Policy_Topmost *topmost_policy;
464    E_Client *ec;
465
466    topmost_client = wl_container_of(listener, topmost_client, client_eval_end);
467
468    topmost_policy = topmost_client->topmost_policy;
469    EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
470
471    ec = topmost_client->ec;
472    EINA_SAFETY_ON_NULL_RETURN(ec);
473
474    if (e_object_is_del(E_OBJECT(ec))) return;
475
476    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
477
478    ec->take_focus = ec->want_focus = 0;
479 }
480
481 static void
482 _focus_policy_topmost_cb_zone_client_add(struct wl_listener *listener, void *data)
483 {
484    E_Focus_Policy_Topmost *topmost_policy;
485    E_Focus_Policy_Topmost_Client *topmost_client;
486    E_Client *ec;
487
488    topmost_policy = wl_container_of(listener, topmost_policy, zone_client_add);
489
490    ec = (E_Client *)data;
491    EINA_SAFETY_ON_NULL_RETURN(ec);
492
493    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
494
495    topmost_client = E_NEW(E_Focus_Policy_Topmost_Client, 1);
496    EINA_SAFETY_ON_NULL_RETURN(topmost_client);
497
498    topmost_client->ec = ec;
499    topmost_client->topmost_policy = topmost_policy;
500
501    // e_client listeners
502    topmost_client->client_destroy.notify = _focus_policy_topmost_cb_client_destroy;
503    e_client_destroy_listener_add(ec, &topmost_client->client_destroy);
504    topmost_client->client_mouse_in.notify = _focus_policy_topmost_cb_client_mouse_in;
505    e_client_mouse_in_listener_add(ec, &topmost_client->client_mouse_in);
506    topmost_client->client_mouse_out.notify = _focus_policy_topmost_cb_client_mouse_out;
507    e_client_mouse_out_listener_add(ec, &topmost_client->client_mouse_out);
508    topmost_client->client_mouse_down.notify = _focus_policy_topmost_cb_client_mouse_down;
509    e_client_mouse_down_listener_add(ec, &topmost_client->client_mouse_down);
510    topmost_client->client_focus_set.notify = _focus_policy_topmost_cb_client_focus_set;
511    e_client_focus_set_listener_add(ec, &topmost_client->client_focus_set);
512    topmost_client->client_focus_unset.notify = _focus_policy_topmost_cb_client_focus_unset;
513    e_client_focus_unset_listener_add(ec, &topmost_client->client_focus_unset);
514    topmost_client->client_lower.notify = _focus_policy_topmost_cb_client_lower;
515    e_client_lower_listener_add(ec, &topmost_client->client_lower);
516    topmost_client->client_move.notify = _focus_policy_topmost_cb_client_move;
517    e_client_move_listener_add(ec, &topmost_client->client_move);
518    topmost_client->client_eval_end.notify = _focus_policy_topmost_cb_client_eval_end;
519    e_client_eval_end_listener_add(ec, &topmost_client->client_eval_end);
520
521    ELOGF("FOCUS_TOPMOST", "zone_client_add | ", ec);
522 }
523
524 static void
525 _focus_policy_topmost_cb_zone_client_remove(struct wl_listener *listener, void *data)
526 {
527    E_Focus_Policy_Topmost *topmost_policy;
528    E_Client *ec;
529
530    topmost_policy = wl_container_of(listener, topmost_policy, zone_client_remove);
531
532    ec = (E_Client *)data;
533    EINA_SAFETY_ON_NULL_RETURN(ec);
534
535    E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
536
537    ELOGF("FOCUS_TOPMOST", "zone_client_remove | ", ec);
538
539    // find the next focus and set it when ec is focused.
540    if (ec->focused)
541      {
542         _focus_policy_topmost_next_focus_set(topmost_policy);
543
544         // check the critical case
545         if (topmost_policy->focused_ec == ec)
546           {
547              ELOGF("FOCUS_TOPMOST", "CRITICAL. focused is deleted ec.", ec);
548              ELOGF("FOCUS_TOPMOST", "CLIENT FOCUS_SET", NULL);
549              set_focused_ec(topmost_policy, NULL);
550           }
551      }
552 }
553
554 static void
555 _focus_policy_topmost_cb_zone_focus_clear(struct wl_listener *listener, void *data)
556 {
557    E_Focus_Policy_Topmost *topmost_policy;
558    E_Zone *zone;
559
560    topmost_policy = wl_container_of(listener, topmost_policy, zone_focus_clear);
561
562    zone = (E_Zone *)data;
563    if (topmost_policy->zone != zone) return;
564
565    // make focused_ec be NULL
566    set_focused_ec(topmost_policy, NULL);
567
568    ELOGF("FOCUS_TOPMOST", "focus_clear | focused_ec UNSET", NULL);
569 }
570
571 static void
572 _focus_policy_topmost_del(E_Focus_Policy_Impl *impl)
573 {
574    E_Focus_Policy_Topmost *topmost_policy = (E_Focus_Policy_Topmost *)impl;
575
576    if (!topmost_policy) return;
577
578    wl_list_remove(&topmost_policy->zone_focus_clear.link);
579    wl_list_remove(&topmost_policy->zone_client_remove.link);
580    wl_list_remove(&topmost_policy->zone_client_add.link);
581
582    E_FREE(topmost_policy);
583 }
584
585 static E_Client *
586 _focus_policy_topmost_focused_ec_get(E_Focus_Policy_Impl *impl)
587 {
588    E_Focus_Policy_Topmost *topmost_policy;
589    E_Client *focused_ec = NULL;
590
591    topmost_policy = (E_Focus_Policy_Topmost *)impl;
592    EINA_SAFETY_ON_NULL_RETURN_VAL(topmost_policy, NULL);
593
594    focused_ec = atomic_load(&topmost_policy->focused_ec);
595
596    return focused_ec;
597 }
598
599 static Eina_Bool
600 _focus_policy_topmost_update(E_Focus_Policy_Impl *impl)
601 {
602    E_Focus_Policy_Topmost *topmost_policy;
603    E_Zone *zone;
604    E_Client *focusable_ec, *focused_ec;
605
606    topmost_policy = (E_Focus_Policy_Topmost *)impl;
607    EINA_SAFETY_ON_NULL_RETURN_VAL(topmost_policy, EINA_FALSE);
608
609    zone = topmost_policy->zone;
610    EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
611
612    // no need to update the focused ec when zone is not displaying
613    if (!e_zone_is_displaying(zone)) return EINA_FALSE;
614
615    // current focused ec
616    focused_ec = topmost_policy->focused_ec;
617
618    // next focusable ec
619    focusable_ec = _e_focus_policy_topmost_focusable_get();
620    if (focusable_ec == focused_ec) return EINA_TRUE;
621
622    e_client_frame_focus_set(focused_ec, EINA_FALSE);
623
624    if (focusable_ec)
625      {
626         ELOGF("FOCUS_TOPMOST", "focus set | topmost focus calculate Zone(%d)", focusable_ec, zone->id);
627         e_client_frame_focus_set(focusable_ec, EINA_TRUE);
628      }
629    else
630      {
631         ELOGF("FOCUS_TOPMOST", "focus unset | No focusable ec Zone(%d)", focused_ec, zone->id);
632      }
633
634    return EINA_TRUE;
635 }
636
637 static void
638 _focus_policy_topmost_focused_ec_changed_listener_add(E_Focus_Policy_Impl *impl, struct wl_listener *listener)
639 {
640    E_Focus_Policy_Topmost *topmost_policy;
641
642    topmost_policy = (E_Focus_Policy_Topmost *)impl;
643    EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
644
645    wl_signal_add(&topmost_policy->events.focused_ec_changed, listener);
646 }
647
648 EINTERN E_Focus_Policy_Iface *
649 e_focus_policy_iface_topmost_new(E_Zone* zone)
650 {
651    E_Focus_Policy_Iface *policy_iface;
652    E_Focus_Policy_Topmost *topmost_policy;
653
654    EINA_SAFETY_ON_NULL_RETURN_VAL(zone, NULL);
655
656    policy_iface = E_NEW(E_Focus_Policy_Iface, 1);
657    EINA_SAFETY_ON_NULL_RETURN_VAL(policy_iface, NULL);
658
659    topmost_policy = E_NEW(E_Focus_Policy_Topmost, 1);
660    EINA_SAFETY_ON_NULL_GOTO(topmost_policy, fail);
661
662    topmost_policy->zone = zone;
663
664    wl_signal_init(&topmost_policy->events.focused_ec_changed);
665
666    policy_iface->impl = (E_Focus_Policy_Impl *)topmost_policy;
667    policy_iface->del = _focus_policy_topmost_del;
668    policy_iface->focused_ec_get = _focus_policy_topmost_focused_ec_get;
669    policy_iface->update = _focus_policy_topmost_update;
670    policy_iface->focused_ec_changed_listener_add = _focus_policy_topmost_focused_ec_changed_listener_add;
671
672    // zone listeners
673    topmost_policy->zone_client_add.notify = _focus_policy_topmost_cb_zone_client_add;
674    e_zone_client_add_listener_add(zone, &topmost_policy->zone_client_add);
675    topmost_policy->zone_client_remove.notify = _focus_policy_topmost_cb_zone_client_remove;
676    e_zone_client_remove_listener_add(zone, &topmost_policy->zone_client_remove);
677    topmost_policy->zone_focus_clear.notify = _focus_policy_topmost_cb_zone_focus_clear;
678    e_zone_focus_clear_listener_add(zone, &topmost_policy->zone_focus_clear);
679
680    return policy_iface;
681
682 fail:
683    _focus_policy_topmost_del(topmost_policy);
684
685    E_FREE(policy_iface);
686
687    return NULL;
688 }
689