e_client: use e_client_visibility_set/get funtions
[platform/upstream/enlightenment.git] / src / bin / e_policy_visibility.c
1 /*
2  * activity    : The client which has full screen size and normal type.
3  * foreground  : The client which is unobscured.
4  * background  : The client which is fully obscured by others.
5  */
6
7 #include "e_policy_visibility_intern.h"
8 #include "e_policy_intern.h"
9 #include "e_comp_wl_rsm_intern.h"
10 #include "e_comp_intern.h"
11 #include "e_policy_wl_intern.h"
12 #include "e_client_intern.h"
13 #include "e_comp_object_intern.h"
14 #include "e_config_intern.h"
15
16 #ifdef ENABLE_TTRACE
17 # include <ttrace.h>
18 # undef TRACE_DS_BEGIN
19 # undef TRACE_DS_END
20
21 # define TRACE_DS_BEGIN(NAME) traceBegin(TTRACE_TAG_WINDOW_MANAGER, "DS:POL:"#NAME)
22 # define TRACE_DS_END() traceEnd(TTRACE_TAG_WINDOW_MANAGER)
23 #else
24 # define TRACE_DS_BEGIN(NAME)
25 # define TRACE_DS_END()
26 #endif
27
28 typedef enum _E_Pol_Vis_Type
29 {
30    E_POL_VIS_TYPE_NON_ALPHA,
31    E_POL_VIS_TYPE_ALPHA,
32    E_POL_VIS_TYPE_ALPHA_OPAQUE,
33 } E_Pol_Vis_Type;
34
35 struct _E_Pol_Vis_Hook
36 {
37    EINA_INLIST;
38    E_Pol_Vis_Hook_Type type;
39    E_Pol_Vis_Hook_Cb   cb;
40    void               *data;
41    Eina_Bool           delete_me;
42 };
43
44 static Eina_Bool _e_policy_check_transient_child_visible(E_Client *ancestor_ec, E_Client *ec);
45 static Eina_Bool _e_policy_check_above_alpha_opaque(E_Client *ec);
46 static void      _e_policy_client_iconify_by_visibility(E_Client *ec);
47 static void      _e_policy_client_ancestor_uniconify(E_Client *ec);
48 static void      _e_policy_client_below_uniconify(E_Client *ec);
49 static void      _e_policy_client_uniconify_by_visibility(E_Client *ec);
50
51 static inline Eina_Bool  _e_vis_client_is_grabbed(E_Vis_Client *vc);
52 static void              _e_vis_client_grab_remove(E_Vis_Client *vc, E_Vis_Grab *grab);
53 static Eina_Bool         _e_vis_client_grab_cancel(E_Vis_Client *vc);
54 static void              _e_vis_client_job_exec(E_Vis_Client *vc, E_Vis_Job_Type type);
55 static Eina_Bool         _e_vis_grab_job_filter(E_Vis_Grab *grab, E_Vis_Job_Type type);
56 static Eina_Bool         _e_vis_ec_activity_check(E_Client *ec, Eina_Bool check_alpha, Eina_Bool check_fullsize);
57 static void              _e_vis_client_job_exec_by_type(E_Vis_Client *vc, E_Vis_Job_Type type);
58 static void              _e_vis_ec_setup(E_Client *ec);
59 static void              _e_vis_ec_reset(E_Client *ec);
60 static E_Pol_Vis_Type    _e_vis_ec_above_visible_type(E_Client *ec, Eina_Bool check_child);
61 static Eina_Bool         _e_vis_ec_below_uniconify(E_Client *ec, E_Pol_Vis_Type above_vis_type);
62 static void              _e_vis_cb_child_launch_done(void *data, Evas_Object *obj, const char *signal, const char *source);
63 static void              _e_vis_update_foreground_job_queue(void);
64 static void              _e_vis_update_forground_list(void);
65 static Eina_Bool         _e_vis_client_check_send_pre_visibility(E_Vis_Client *vc, Eina_Bool raise);
66
67 static E_Vis            *pol_vis = NULL;
68 /* the list for E_Vis_Job */
69 static E_Vis_Job_Group  *pol_job_group = NULL;
70 /* the head of list for E_Vis_Job_Group */
71 static Eina_Clist        pol_job_group_head = EINA_CLIST_INIT(pol_job_group_head);
72
73 static Eina_Bool         pol_job_exec_walking = EINA_FALSE;
74 static Eina_Bool         pol_vis_disable_norender = EINA_FALSE;
75
76 static Eina_Inlist *_e_pol_vis_hooks[] =
77 {
78    [E_POL_VIS_HOOK_TYPE_FG_SET] = NULL,
79    [E_POL_VIS_HOOK_TYPE_UNICONIFY_RENDER_RUNNING] = NULL,
80    [E_POL_VIS_HOOK_TYPE_LOWER] = NULL,
81    [E_POL_VIS_HOOK_TYPE_HIDE] = NULL,
82 };
83
84 static int _e_pol_vis_hooks_delete = 0;
85 static int _e_pol_vis_hooks_walking = 0;
86
87 static inline Eina_Bool
88 _e_vis_client_is_grabbed(E_Vis_Client *vc)
89 {
90    return !!vc->job.grab_list;
91 }
92
93 static inline Eina_Bool
94 _e_vis_client_is_iconic(E_Vis_Client *vc)
95 {
96    return (vc->state == E_VIS_ICONIFY_STATE_ICONIC);
97 }
98
99 static inline Eina_Bool
100 _e_vis_client_is_uniconic(E_Vis_Client *vc)
101 {
102    return (vc->state == E_VIS_ICONIFY_STATE_UNICONIC);
103 }
104
105 static inline Eina_Bool
106 _e_vis_client_is_uniconify_render_running(E_Vis_Client *vc)
107 {
108    return (vc->state == E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY);
109 }
110
111 static inline Eina_Bool
112 _e_vis_client_is_uniconify_render_running_done(E_Vis_Client *vc)
113 {
114    return (vc->state == E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY_RENDER_DONE);
115 }
116
117 static inline void
118 _e_vis_client_below_uniconify_skip_set(E_Vis_Client *vc, Eina_Bool skip)
119 {
120    vc->skip_below_uniconify = skip;
121 }
122
123 static inline Eina_Bool
124 _e_vis_client_is_below_uniconify_skip(E_Vis_Client *vc)
125 {
126    return (vc->skip_below_uniconify == EINA_TRUE);
127 }
128
129 static void
130 _e_pol_vis_hooks_clean(void)
131 {
132    Eina_Inlist *l;
133    E_Pol_Vis_Hook *h;
134    unsigned int x;
135
136    for (x = 0; x < E_POL_VIS_HOOK_TYPE_LAST; x++)
137      EINA_INLIST_FOREACH_SAFE(_e_pol_vis_hooks[x], l, h)
138        {
139           if (!h->delete_me) continue;
140           _e_pol_vis_hooks[x] = eina_inlist_remove(_e_pol_vis_hooks[x],
141                                                    EINA_INLIST_GET(h));
142           E_FREE(h);
143        }
144 }
145
146 static Eina_Bool
147 _e_pol_vis_hook_call(E_Pol_Vis_Hook_Type type, E_Client *ec)
148 {
149    E_Pol_Vis_Hook *h;
150
151    e_object_ref(E_OBJECT(ec));
152
153    _e_pol_vis_hooks_walking++;
154    EINA_INLIST_FOREACH(_e_pol_vis_hooks[type], h)
155      {
156         if (h->delete_me) continue;
157         h->cb(h->data, ec);
158      }
159    _e_pol_vis_hooks_walking--;
160
161    if ((_e_pol_vis_hooks_walking == 0) &&
162        (_e_pol_vis_hooks_delete > 0))
163      _e_pol_vis_hooks_clean();
164
165    return !!e_object_unref(E_OBJECT(ec));
166 }
167
168 static Eina_Bool
169 _e_policy_check_transient_child_visible(E_Client *ancestor_ec, E_Client *ec)
170 {
171    Eina_Bool visible = EINA_FALSE;
172    Eina_List *list = NULL;
173    E_Client *child_ec = NULL;
174    int anc_x, anc_y, anc_w, anc_h;
175    int child_x, child_y, child_w, child_h;
176
177    if (!ancestor_ec) return EINA_FALSE;
178
179    e_client_geometry_get(ancestor_ec, &anc_x, &anc_y, &anc_w, &anc_h);
180
181    list = eina_list_clone(ec->transients);
182    EINA_LIST_FREE(list, child_ec)
183      {
184         if (visible == EINA_TRUE) continue;
185
186         if (!child_ec->comp_data) continue;
187         if (!child_ec->comp_data->mapped && !child_ec->use_splash) continue;
188         if (e_client_transient_policy_get(child_ec) == E_TRANSIENT_BELOW) continue;
189
190         if ((child_ec->exp_iconify.skip_iconify == EINA_TRUE) ||
191             (child_ec->exp_iconify.skip_by_remote == EINA_TRUE))
192           {
193              if (e_client_visibility_get(child_ec) == E_VISIBILITY_UNOBSCURED)
194                {
195                   ELOGF("Find visible child", "ancestor(win:0x%08zx, ec:%p), child(win:0x%08zx, ec:%p)",
196                         ec,
197                         e_client_util_win_get(ancestor_ec), ancestor_ec,
198                         e_client_util_win_get(child_ec), child_ec);
199                   return EINA_TRUE;
200                }
201              else
202                {
203                   if (!child_ec->iconic)
204                     {
205                        e_client_geometry_get(child_ec, &child_x, &child_y, &child_w, &child_h);
206                        if (E_CONTAINS(child_x, child_y, child_w, child_h, anc_x, anc_y, anc_w, anc_h))
207                          {
208                             ELOGF("Find visible child", "ancestor(win:0x%08zx, ec:%p), child(win:0x%08zx, ec:%p)",
209                                   ec,
210                                   e_client_util_win_get(ancestor_ec), ancestor_ec,
211                                   e_client_util_win_get(child_ec), child_ec);
212                             return EINA_TRUE;
213                          }
214                     }
215                }
216           }
217         else
218           {
219              if ((!child_ec->iconic && (e_client_visibility_get(child_ec) != E_VISIBILITY_UNKNOWN)) ||
220                  (e_client_visibility_get(child_ec) == E_VISIBILITY_UNOBSCURED))
221                {
222                   ELOGF("Find visible child", "ancestor(win:0x%08zx, ec:%p), child(win:0x%08zx, ec:%p, iconic:%d, vis:%d)",
223                         ec,
224                         e_client_util_win_get(ancestor_ec), ancestor_ec,
225                         e_client_util_win_get(child_ec), child_ec, child_ec->iconic, e_client_visibility_get(child_ec));
226                   return EINA_TRUE;
227                }
228           }
229
230         visible = _e_policy_check_transient_child_visible(ancestor_ec, child_ec);
231      }
232
233    return visible;
234 }
235
236 static Eina_Bool
237 _e_policy_check_above_alpha_opaque(E_Client *ec)
238 {
239    E_Client *above_ec;
240    Evas_Object *o;
241    Eina_Bool alpha_opaque = EINA_FALSE;
242    int ex, ey, ew, eh;
243    int ax, ay, aw, ah;
244
245    e_client_geometry_get(ec, &ex, &ey, &ew, &eh);
246
247    for (o = evas_object_above_get(ec->frame); o; o = evas_object_above_get(o))
248      {
249         above_ec = evas_object_data_get(o, "E_Client");
250         if (!above_ec) continue;
251         if (e_client_util_ignored_get(above_ec)) continue;
252         if (above_ec->comp_data && !above_ec->comp_data->mapped) continue;
253
254         e_client_geometry_get(above_ec, &ax, &ay, &aw, &ah);
255         if (!E_CONTAINS(ax, ay, aw, ah, ex, ey, ew, eh)) continue;
256
257         if (above_ec->argb)
258           {
259              if (above_ec->visibility.opaque <= 0)
260                continue;
261              else
262                {
263                   if (e_client_visibility_get(above_ec) == E_VISIBILITY_UNOBSCURED)
264                     {
265                        alpha_opaque = EINA_TRUE;
266                     }
267                   else
268                     {
269                        if (!above_ec->iconic)
270                          {
271                             if (above_ec->comp_data && above_ec->comp_data->mapped)
272                               alpha_opaque = EINA_TRUE;
273                          }
274                     }
275                }
276           }
277         break;
278      }
279
280    return alpha_opaque;
281 }
282
283 static void
284 _e_policy_client_iconify_by_visibility(E_Client *ec)
285 {
286    int skip_iconify = 0;
287
288    if (e_config->transient.iconify)
289      {
290         if (_e_policy_check_transient_child_visible(ec, ec))
291           {
292              skip_iconify |= 1;
293           }
294      }
295
296    if (e_comp_client_zone_is_displaying(ec))
297      {
298         // check above window is alpha opaque or not
299         if (_e_policy_check_above_alpha_opaque(ec))
300           {
301              skip_iconify |= 2;
302           }
303      }
304
305    if (skip_iconify)
306      {
307         ELOGF("SKIP.. ICONIFY_BY_WM", "win:0x%08zx cause_type:%d", ec, e_client_util_win_get(ec), skip_iconify);
308         if (pol_vis)
309           _e_vis_update_forground_list();
310         return;
311      }
312
313    ELOGF("ICONIFY_BY_WM", "win:0x%08zx", ec, e_client_util_win_get(ec));
314    e_policy_wl_iconify_state_change_send(ec, 1);
315    e_client_iconified_type_set(ec, E_ICONIFIED_TYPE_VISIBILITY);
316    e_client_iconify(ec);
317
318    /* if client has obscured parent, try to iconify the parent also */
319    if (ec->parent)
320      {
321         if (e_client_visibility_get(ec->parent) == E_VISIBILITY_FULLY_OBSCURED)
322           {
323              e_policy_client_iconify_by_visibility(ec->parent);
324
325              E_VIS_CLIENT_GET(vc, ec->parent);
326              if (vc)
327                {
328                   if (_e_vis_client_is_uniconify_render_running(vc))
329                     {
330                        VS_INF(ec, "Uniconify render because parent(win:%zx, ec:%p)", e_client_util_win_get(ec->parent), ec->parent);
331                        e_policy_visibility_client_uniconify(ec, !ec->parent->exp_iconify.not_raise);
332                     }
333                }
334           }
335      }
336 }
337
338 static void
339 _e_policy_client_ancestor_uniconify(E_Client *ec)
340 {
341    Eina_List *list = NULL;
342    Eina_List *l = NULL;
343    E_Client *parent = NULL;
344    int transient_iconify = 0;
345    int count = 0;
346    Eina_Bool ret = EINA_FALSE;
347
348    if (!ec) return;
349    if (e_object_is_del(E_OBJECT(ec))) return;
350    if (!ec->iconic) return;
351    if (e_client_is_iconified_by_client(ec)) return;
352    if (ec->bg_state) return;
353    if (ec->exp_iconify.skip_iconify) return;
354    if (ec->exp_iconify.skip_by_remote) return;
355
356    parent = ec->parent;
357    while (parent)
358      {
359         if (count > 10)
360           {
361              // something strange state.
362              ELOGF("CHECK transient_for tree", "win:0x%08zx, parent:0x%08zx", NULL, e_client_util_win_get(ec), e_client_util_win_get(parent));
363              break;
364           }
365
366         if (e_object_is_del(E_OBJECT(parent))) break;
367         if (!parent->iconic) break;
368         if (e_client_is_iconified_by_client(parent)) break;
369         if (parent->bg_state) break;
370         if (parent->exp_iconify.skip_iconify) break;
371         if (parent->exp_iconify.skip_by_remote) break;
372
373         if (eina_list_data_find(list, parent))
374           {
375              // very bad. there are loop for parenting
376              ELOGF("Very BAD. Circling transient_for window", "win:0x%08zx, parent:0x%08zx", NULL, e_client_util_win_get(ec), e_client_util_win_get(parent));
377              break;
378           }
379
380         list = eina_list_prepend(list, parent);
381         parent = parent->parent;
382
383         // for preventing infiniting loop
384         count++;
385      }
386
387    transient_iconify = e_config->transient.iconify;
388    e_config->transient.iconify = 0;
389
390    parent = NULL;
391    EINA_LIST_FOREACH(list, l, parent)
392      {
393         ELOGF("UNICONIFY_BY_WM", "parent_win:0x%08zx", parent, e_client_util_win_get(parent));
394         ret = e_policy_visibility_client_uniconify(parent, 0);
395         if (!ret)
396           {
397              parent->exp_iconify.not_raise = 1;
398              e_client_uniconify(parent);
399              e_policy_wl_iconify_state_change_send(parent, 0);
400           }
401      }
402    eina_list_free(list);
403
404    e_config->transient.iconify = transient_iconify;
405 }
406
407 static void
408 _e_policy_client_below_uniconify(E_Client *ec)
409 {
410    E_Client *below_ec;
411    Evas_Object *o;
412
413    for (o = evas_object_below_get(ec->frame); o; o = evas_object_below_get(o))
414      {
415         below_ec = evas_object_data_get(o, "E_Client");
416         if (!below_ec) continue;
417         if (e_client_util_ignored_get(below_ec)) continue;
418
419         if (ec->parent == below_ec) break;
420         if (!below_ec->iconic) break;
421
422         if (e_client_visibility_get(below_ec) == E_VISIBILITY_FULLY_OBSCURED)
423           {
424              e_policy_client_uniconify_by_visibility(below_ec);
425           }
426
427         break;
428      }
429 }
430
431 static void
432 _e_policy_client_uniconify_by_visibility(E_Client *ec)
433 {
434    Eina_Bool ret = EINA_FALSE;
435
436    _e_policy_client_ancestor_uniconify(ec);
437
438    ELOGF("UNICONIFY_BY_WM", "win:0x%08zx, argb:%d", ec, e_client_util_win_get(ec), ec->argb);
439    ret = e_policy_visibility_client_uniconify(ec, 0);
440    if (!ret)
441      {
442         e_policy_visibility_client_hide_job_cancel(ec);
443         ec->exp_iconify.not_raise = 1;
444         e_client_uniconify(ec);
445         e_policy_wl_iconify_state_change_send(ec, 0);
446      }
447
448    if ((ec->visibility.opaque > 0) && (ec->argb))
449      {
450         _e_policy_client_below_uniconify(ec);
451      }
452 }
453
454 EINTERN void
455 e_policy_client_visibility_send(E_Client *ec)
456 {
457    e_policy_wl_visibility_send(ec, e_client_visibility_get(ec));
458 }
459
460 EINTERN void
461 e_policy_client_iconify_by_visibility(E_Client *ec)
462 {
463    E_Comp_Wl_Client_Data *cdata;
464
465    if (!ec) return;
466    if (ec->iconic) return;
467    if (ec->bg_state) return;
468    if (ec->exp_iconify.skip_iconify) return;
469    if (ec->exp_iconify.skip_by_remote) return;
470    if (e_client_util_ignored_get(ec)) return;
471    if (e_client_is_iconified_by_client(ec)) return;
472
473    cdata = (E_Comp_Wl_Client_Data *)ec->comp_data;
474    if (cdata && !cdata->mapped) return;
475
476    _e_policy_client_iconify_by_visibility(ec);
477 }
478
479 EINTERN void
480 e_policy_client_uniconify_by_visibility(E_Client *ec)
481 {
482    E_Comp_Wl_Client_Data *cdata;
483
484    if (!ec) return;
485    if (e_object_is_del(E_OBJECT(ec))) return;
486    if (!ec->iconic) return;
487    if (e_client_is_iconified_by_client(ec)) return;
488    if (ec->bg_state) return;
489    if (ec->exp_iconify.skip_iconify) return;
490    if (ec->exp_iconify.skip_by_remote) return;
491
492    cdata = (E_Comp_Wl_Client_Data *)ec->comp_data;
493    if (cdata && !cdata->mapped) return;
494
495    _e_policy_client_uniconify_by_visibility(ec);
496 }
497
498 EINTERN void
499 e_policy_client_iconic_state_change_send(E_Client *ec, int iconic)
500 {
501    if (!ec) return;
502    e_policy_wl_iconify_state_change_send(ec, iconic);
503 }
504
505 static inline void
506 _e_vis_clist_unlink(Eina_Clist *elem)
507 {
508    if (eina_clist_element_is_linked(elem))
509      eina_clist_remove(elem);
510 }
511
512 static void
513 _e_vis_clist_clean(Eina_Clist *list, void (*free_func)(Eina_Clist *elem))
514 {
515    Eina_Clist *elem;
516
517    while ((elem = eina_clist_head(list)) != NULL)
518      {
519         eina_clist_remove(elem);
520         if (free_func) free_func(elem);
521      }
522 }
523
524 static void
525 _e_vis_update_forground_list(void)
526 {
527    E_Client *ec, *fg_activity = NULL;
528
529    DBG("VISIBILITY | Update Foreground Client List");
530
531    /* clear list of fg_clients before updating */
532    E_FREE_FUNC(pol_vis->fg_clients, eina_list_free);
533
534    /* update foreground client list and find activity client */
535    E_CLIENT_REVERSE_FOREACH(ec)
536      {
537         /* TODO: check if client is included to zone of mobile */
538         if (!evas_object_visible_get(ec->frame)) continue;
539
540         pol_vis->fg_clients = eina_list_append(pol_vis->fg_clients, ec);
541         if (_e_vis_ec_activity_check(ec, EINA_TRUE, EINA_TRUE))
542           {
543              fg_activity = ec;
544              break;
545           }
546      }
547
548    if (pol_vis->activity != fg_activity)
549      {
550         DBG("VISIBILITY | \tPrev: %s(%p)", pol_vis->activity ? NAME(pol_vis->activity) : "", pol_vis->activity);
551         DBG("VISIBILITY | \tNew : %s(%p)", fg_activity ? NAME(fg_activity) : "", fg_activity);
552         pol_vis->activity = fg_activity;
553         /* TODO do we need to raise event like E_EVENT_VISIBILITY_ACTIVITY_CHANGE? */
554         _e_pol_vis_hook_call(E_POL_VIS_HOOK_TYPE_FG_SET, fg_activity);
555      }
556 }
557
558 static void
559 _e_vis_update_cb_job(void *data EINA_UNUSED)
560 {
561    if (pol_vis->job.bg_find)
562      {
563         _e_vis_update_forground_list();
564         pol_vis->job.bg_find = EINA_FALSE;
565      }
566    pol_vis->job.handler = NULL;
567 }
568
569 static void
570 _e_vis_update_job_queue(void)
571 {
572    if (pol_vis->job.handler)
573      ecore_job_del(pol_vis->job.handler);
574    pol_vis->job.handler = ecore_job_add(_e_vis_update_cb_job, NULL);
575 }
576
577 static void
578 _e_vis_update_foreground_job_queue(void)
579 {
580    pol_vis->job.bg_find = EINA_TRUE;
581    _e_vis_update_job_queue();
582 }
583
584 static Eina_Bool
585 _e_vis_job_is_grabbed(E_Vis_Client *vc, E_Vis_Job_Type type)
586 {
587    E_Vis_Grab *grab;
588    Eina_List *l;
589
590    EINA_LIST_FOREACH(vc->job.grab_list, l, grab)
591      {
592         if (_e_vis_grab_job_filter(grab, type))
593           return EINA_TRUE;
594      }
595
596    return EINA_FALSE;
597 }
598
599 static Eina_Bool
600 _e_vis_job_push(E_Vis_Job *job)
601 {
602    if (!pol_job_group)
603      {
604         pol_job_group = E_NEW(E_Vis_Job_Group, 1);
605         if (!pol_job_group)
606           return EINA_FALSE;
607         eina_clist_init(&pol_job_group->job_head);
608      }
609    eina_clist_add_tail(&pol_job_group->job_head, &job->entry);
610    return EINA_TRUE;
611 }
612
613 static Eina_Bool
614 _e_vis_job_find(E_Vis_Client *vc, E_Vis_Job_Type type)
615 {
616    E_Vis_Job_Group *group, *tmp_group;
617    E_Vis_Job *job, *tmp_job;
618
619    EINA_CLIST_FOR_EACH_ENTRY_SAFE(group, tmp_group,
620                                   &pol_job_group_head, E_Vis_Job_Group, entry)
621      {
622         EINA_CLIST_FOR_EACH_ENTRY_SAFE(job, tmp_job,
623                                        &group->job_head, E_Vis_Job, entry)
624           {
625              if (job->vc != vc) continue;
626              if (job->type == type)
627                return EINA_TRUE;
628           }
629      }
630
631    return EINA_FALSE;
632 }
633
634 static Eina_Bool
635 _e_vis_job_add(E_Vis_Client *vc, E_Vis_Job_Type type, Ecore_Task_Cb timeout_func)
636 {
637    E_VIS_ALLOC_RET_VAL(job, E_Vis_Job, 1, EINA_FALSE);
638    if (!_e_vis_job_push(job))
639      {
640         free(job);
641         return EINA_FALSE;
642      }
643    job->vc = vc;
644    job->type = type;
645    job->timer = ecore_timer_add(e_config->deiconify_pending_timeout, timeout_func, job);
646    VS_INF(vc->ec, "NEW JOB:%p, type:%d", job, type);
647
648    return EINA_TRUE;
649 }
650
651 static void
652 _e_vis_job_del(Eina_Clist *elem)
653 {
654    E_Vis_Job *job;
655
656    _e_vis_clist_unlink(elem);
657    job = EINA_CLIST_ENTRY(elem, E_Vis_Job, entry);
658
659    VS_INF(job->vc->ec, "FREE JOB:%p, type:%d", job, job->type);
660    E_FREE_FUNC(job->timer, ecore_timer_del);
661    free(job);
662 }
663
664 static void
665 _e_vis_job_group_del(Eina_Clist *elem)
666 {
667    E_Vis_Job_Group *group;
668
669    _e_vis_clist_unlink(elem);
670    group = EINA_CLIST_ENTRY(elem, E_Vis_Job_Group, entry);
671    _e_vis_clist_clean(&group->job_head, _e_vis_job_del);
672    free(group);
673 }
674
675 static void
676 _e_vis_job_exec(Eina_Clist *elem)
677 {
678    E_Vis_Job *job;
679
680    _e_vis_clist_unlink(elem);
681    job = EINA_CLIST_ENTRY(elem, E_Vis_Job, entry);
682    if (job->deleted)
683      goto end;
684
685    VS_INF(job->vc->ec, "EXEC JOB:%p, type:%d (is_del ec:%d)", job, job->type, e_object_is_del(E_OBJECT(job->vc->ec)));
686    /* After calling the function below, ec may have been deleted.
687     * This is because the delayed ec deletion is perfromed in the following function.
688     * Therefore, be careful when leaving out detailed log message about deleted ec
689     * to avoid segmentation fault error.
690     */
691    _e_vis_client_job_exec(job->vc, job->type);
692
693 end:
694    INF("VISIBILITY | FREE JOB:%p, type:%d", job, job->type);
695    E_FREE_FUNC(job->timer, ecore_timer_del);
696    free(job);
697 }
698
699 static void
700 _e_vis_job_group_exec(E_Vis_Job_Group *group)
701 {
702    _e_vis_clist_unlink(&group->entry);
703    _e_vis_clist_clean(&group->job_head, _e_vis_job_exec);
704    free(group);
705 }
706
707 static Eina_Bool
708 _e_vis_job_group_eval(E_Vis_Job_Group *group)
709 {
710    E_Vis_Job *job, *tmp;
711
712    EINA_CLIST_FOR_EACH_ENTRY_SAFE(job, tmp,
713                                   &group->job_head, E_Vis_Job, entry)
714      {
715         if (job->deleted) continue;
716         if (_e_vis_client_is_grabbed(job->vc))
717           return EINA_FALSE;
718      }
719    return EINA_TRUE;
720 }
721
722 static void
723 _e_vis_job_group_state_update(E_Vis_Job_Group *group)
724 {
725    E_Vis_Job *job, *tmp;
726    EINA_CLIST_FOR_EACH_ENTRY_SAFE(job, tmp,
727                                   &group->job_head, E_Vis_Job, entry)
728      {
729         if (job->deleted) continue;
730         if (_e_vis_client_is_uniconify_render_running_done(job->vc))
731           {
732              job->vc->state = E_VIS_ICONIFY_STATE_UNICONIC;
733              VS_DBG(job->vc->ec, "\tUPDATE ICONIC STATE: %s", "UNICONIC");
734           }
735      }
736 }
737
738 static void
739 _e_vis_job_queue_update(void)
740 {
741    if (!pol_job_group) return;
742    eina_clist_add_tail(&pol_job_group_head, &pol_job_group->entry);
743    pol_job_group = NULL;
744 }
745
746 /* FIXME just add a ecore job, and do real evaluate in the job. */
747 static void
748 _e_vis_job_eval(void)
749 {
750    E_Vis_Job_Group *group, *tmp;
751
752    INF("VISIBILITY | Job Eval Begin");
753
754    _e_vis_job_queue_update();
755
756    pol_job_exec_walking = EINA_TRUE;
757    EINA_CLIST_FOR_EACH_ENTRY_SAFE(group, tmp, &pol_job_group_head,
758                                   E_Vis_Job_Group, entry)
759      {
760         /* if all of job in the group is ready */
761         if (!_e_vis_job_group_eval(group))
762           break;
763
764         /* updates state to uniconic from render_done */
765         _e_vis_job_group_state_update(group);
766
767         /* execute all of job in the group */
768         _e_vis_job_group_exec(group);
769      }
770    pol_job_exec_walking = EINA_FALSE;
771
772    INF("VISIBILITY | Job Eval End");
773 }
774
775 static Eina_Bool
776 _e_vis_job_cancel(E_Vis_Client *vc, E_Vis_Job_Type type)
777 {
778    Eina_Bool ret = EINA_FALSE;
779    E_Vis_Job_Group *group, *tmp_group;
780    E_Vis_Job *job, *tmp_job;
781
782    /* update queue before deleting */
783    _e_vis_job_queue_update();
784
785    EINA_CLIST_FOR_EACH_ENTRY_SAFE(group, tmp_group,
786                                   &pol_job_group_head, E_Vis_Job_Group, entry)
787      {
788         EINA_CLIST_FOR_EACH_ENTRY_SAFE(job, tmp_job,
789                                        &group->job_head, E_Vis_Job, entry)
790           {
791              if (job->vc != vc) continue;
792              if (job->type != type) continue;
793
794              VS_INF(vc->ec, "Find Job:%p, type:%d", job, type);
795              _e_vis_job_del(&job->entry);
796              vc->job.count--;
797              VS_INF(vc->ec, "Decrease VC JOB count:%d by cancel", vc->job.count);
798              ret = EINA_TRUE;
799           }
800         if (!eina_clist_empty(&group->job_head)) continue;
801         _e_vis_job_group_del(&group->entry);
802      }
803
804    /* evaluate job list after deleting an element */
805    _e_vis_job_eval();
806
807    return ret;
808 }
809
810 static void
811 _e_vis_job_del_by_client(E_Vis_Client *vc)
812 {
813    E_Vis_Job_Group *group, *tmp_group;
814    E_Vis_Job *job, *tmp_job;
815
816    /* update queue before deleting */
817    _e_vis_job_queue_update();
818
819    EINA_CLIST_FOR_EACH_ENTRY_SAFE(group, tmp_group,
820                                   &pol_job_group_head, E_Vis_Job_Group, entry)
821      {
822         EINA_CLIST_FOR_EACH_ENTRY_SAFE(job, tmp_job,
823                                        &group->job_head, E_Vis_Job, entry)
824           {
825              if (job->vc != vc) continue;
826
827              if (pol_job_exec_walking)
828                job->deleted = EINA_TRUE;
829              else
830                _e_vis_job_del(&job->entry);
831           }
832         if (!eina_clist_empty(&group->job_head)) continue;
833         _e_vis_job_group_del(&group->entry);
834      }
835
836    /* evaluate job list after deleting an element */
837    if (!pol_job_exec_walking)
838      _e_vis_job_eval();
839 }
840
841 static E_Vis_Grab *
842 _e_vis_grab_new(E_Vis_Client *vc, E_Vis_Job_Type type, const char *name, Ecore_Task_Cb timeout_func)
843 {
844    E_VIS_ALLOC_RET_VAL(grab, E_Vis_Grab, 1, NULL);
845    grab->vc = vc;
846    grab->type = type;
847    grab->name = eina_stringshare_add(name);
848    grab->timer = ecore_timer_add(e_config->deiconify_pending_timeout, timeout_func, grab);
849
850    return grab;
851 }
852
853 static void
854 _e_vis_grab_del(E_Vis_Grab *grab)
855 {
856    E_FREE_FUNC(grab->timer, ecore_timer_del);
857    E_FREE_FUNC(grab->name, eina_stringshare_del);
858    free(grab);
859 }
860
861 static void
862 _e_vis_grab_release(E_Vis_Grab *grab)
863 {
864    if (!grab->deleted)
865      _e_vis_client_grab_remove(grab->vc, grab);
866
867    _e_vis_grab_del(grab);
868 }
869
870 static Eina_Bool
871 _e_vis_grab_job_filter(E_Vis_Grab *grab, E_Vis_Job_Type job_type)
872 {
873    return grab->type & job_type;
874 }
875
876 static Eina_Bool
877 _e_vis_client_cb_buffer_attach(void *data, int type EINA_UNUSED, void *event)
878 {
879    E_Vis_Client *vc;
880    E_Vis_Grab *grab;
881    E_Client *ec;
882    E_Event_Client *ev;
883    E_Client *provider_ec;
884    Eina_List *l;
885
886    ev = event;
887    vc = data;
888    provider_ec = e_comp_wl_remote_surface_bound_provider_ec_get(vc->ec);
889    if (vc->ec != ev->ec && provider_ec != ev->ec)
890      goto renew;
891
892    ec = vc->ec;
893
894    VS_INF(ec, "FINISH Uniconify render(ev:%p, vc:%p, provider:%p)", ev->ec, vc->ec, provider_ec);
895
896    /* force update
897     * NOTE: this update can invoke some functions related to visibility grab */
898    /* if comp_object is not redirected, the compositor doesn't want to update it */
899    if (e_comp_object_redirected_get(ec->frame))
900      {
901         e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
902         e_comp_object_dirty(ec->frame);
903         e_comp_object_render(ec->frame);
904      }
905
906    l = eina_list_clone(vc->wait_buf_attach_grab_list);
907    vc->wait_buf_attach_grab_list = eina_list_free(vc->wait_buf_attach_grab_list);
908    EINA_LIST_FREE(l, grab)
909      {
910         E_FREE_FUNC(grab, _e_vis_grab_release);
911      }
912
913    E_FREE_FUNC(vc->buf_attach, ecore_event_handler_del);
914 renew:
915    return ECORE_CALLBACK_PASS_ON;
916 }
917
918 static void
919 _e_vis_client_buffer_attach_handler_add(E_Vis_Client *vc, E_Vis_Grab *grab)
920 {
921    vc->wait_buf_attach_grab_list = eina_list_append(vc->wait_buf_attach_grab_list, grab);
922
923    if (vc->buf_attach)
924      return;
925
926    vc->buf_attach =
927       ecore_event_handler_add(E_EVENT_CLIENT_BUFFER_CHANGE,
928                               _e_vis_client_cb_buffer_attach, vc);
929 }
930
931 static void
932 _e_vis_client_job_exec(E_Vis_Client *vc, E_Vis_Job_Type type)
933 {
934    // Check if pol_vis is already deleted.
935    if (!pol_vis) goto done;
936    if (!vc->ec) goto done;
937
938    // Check if the vc->ec is already deleted and there is no data in clients_hash.
939    if (!eina_hash_find(pol_vis->clients_hash, &vc->ec)) goto done;
940
941    switch (type)
942      {
943       case E_VIS_JOB_TYPE_ACTIVATE:
944       case E_VIS_JOB_TYPE_UNICONIFY:
945       case E_VIS_JOB_TYPE_UNICONIFY_BY_VISIBILITY:
946          /* check previous state first */
947          if (vc->state != E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY_WAITING_FOR_CHILD)
948            vc->state = E_VIS_ICONIFY_STATE_UNICONIC;
949          break;
950       case E_VIS_JOB_TYPE_SHOW:
951          vc->state = E_VIS_ICONIFY_STATE_UNICONIC;
952          break;
953       default:
954          break;
955      }
956
957    VS_DBG(vc->ec, "\tUPDATE ICONIC STATE: %s", STATE_STR(vc));
958
959    _e_vis_client_job_exec_by_type(vc, type);
960
961 done:
962    vc->job.count--;
963    VS_INF(vc->ec, "Decrease VC JOB count:%d", vc->job.count);
964
965    if (vc->job.count == 0)
966      {
967         if (vc->ec && e_object_is_del(E_OBJECT(vc->ec)))
968           {
969              /* all of enqueued job is executed */
970              VS_INF(vc->ec, "Deleted Client: UNREF Delay Del");
971              e_pixmap_free(vc->ec->pixmap);
972              e_object_delay_del_unref(E_OBJECT(vc->ec));
973           }
974      }
975 }
976
977 static void
978 _e_vis_client_grab_add(E_Vis_Client *vc, E_Vis_Grab *grab)
979 {
980    VS_INF(vc->ec, "Add Client Visibility Grab: %p(%s)", grab, grab->name);
981
982    vc->job.grab_list = eina_list_append(vc->job.grab_list, grab);
983 }
984
985 static void
986 _e_vis_client_grab_remove(E_Vis_Client *vc, E_Vis_Grab *grab)
987 {
988    VS_INF(vc->ec, "Remove Client Visibility Grab: %p(%s)", grab, grab->name);
989
990    if (!vc->job.grab_list)
991      {
992         VS_ERR(vc->ec, "The list of grab is empty");
993         return;
994      }
995
996    vc->job.grab_list = eina_list_remove(vc->job.grab_list, grab);
997    if (!vc->job.grab_list)
998      {
999         if (vc->state == E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY)
1000           {
1001              vc->state = E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY_RENDER_DONE;
1002              VS_DBG(vc->ec, "\tUPDATE ICONIC STATE: %s", STATE_STR(vc));
1003           }
1004
1005         _e_vis_job_eval();
1006      }
1007 }
1008
1009 static Eina_Bool
1010 _e_vis_client_grab_cb_timeout(void *data)
1011 {
1012    E_Vis_Grab *grab = data;
1013    if (!grab) return ECORE_CALLBACK_DONE;
1014
1015    ELOGF("POL_VIS", "TIMEOUT(%f) Grab(%p), name: %s", NULL, e_config->deiconify_pending_timeout, grab, grab->name);
1016    ELOGF("POL_VIS", "Info is_del:%d", grab->vc->ec, e_object_is_del(E_OBJECT(grab->vc->ec)));
1017    grab->timer = NULL;
1018    grab->deleted = 1;
1019    _e_vis_client_grab_remove(grab->vc, grab);
1020
1021    return ECORE_CALLBACK_DONE;
1022 }
1023
1024 static E_Vis_Grab *
1025 _e_vis_client_grab_get(E_Vis_Client *vc, E_Vis_Job_Type type, const char *name)
1026 {
1027    E_Vis_Grab *grab;
1028
1029    grab = _e_vis_grab_new(vc, type, name, _e_vis_client_grab_cb_timeout);
1030    if (!grab)
1031      return NULL;
1032
1033    VS_INF(vc->ec, "Get job Grab(%p), name: %s", grab, name);
1034
1035    _e_vis_client_grab_add(vc, grab);
1036
1037    return grab;
1038 }
1039
1040 static Eina_Bool
1041 _e_vis_client_grab_cancel(E_Vis_Client *vc)
1042 {
1043    EINA_SAFETY_ON_NULL_RETURN_VAL(vc, EINA_FALSE);
1044
1045    if (_e_vis_client_is_uniconify_render_running(vc))
1046      {
1047         vc->state = E_VIS_ICONIFY_STATE_ICONIC;
1048         VS_DBG(vc->ec, "\tUPDATE ICONIC STATE: %s", STATE_STR(vc));
1049
1050         VS_INF(vc->ec, "Visibility changed while waiting Uniconify. Release grab.");
1051         E_FREE_FUNC(vc->grab, _e_vis_grab_release);
1052
1053         E_Vis_Grab *grab;
1054         Eina_List *l;
1055
1056         l = eina_list_clone(vc->wait_buf_attach_grab_list);
1057         vc->wait_buf_attach_grab_list = eina_list_free(vc->wait_buf_attach_grab_list);
1058         EINA_LIST_FREE(l, grab)
1059           {
1060              E_FREE_FUNC(grab, _e_vis_grab_release);
1061           }
1062
1063         return EINA_TRUE;
1064      }
1065
1066    return EINA_FALSE;
1067 }
1068
1069 static void
1070 _e_vis_client_cb_evas_show(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
1071 {
1072    OBJ_EC_GET(ec, obj);
1073    VS_DBG(ec, "CALLBACK 'SHOW'...");
1074    _e_vis_update_foreground_job_queue();
1075    E_VIS_CLIENT_GET_OR_RETURN(vc, ec);
1076    if (vc->state != E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY)
1077      {
1078         vc->state = E_VIS_ICONIFY_STATE_UNICONIC;
1079         VS_DBG(ec, "\tUPDATE ICONIC STATE: %s", "UNICONIC");
1080      }
1081 }
1082
1083 static void
1084 _e_vis_client_cb_evas_hide(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
1085 {
1086    OBJ_EC_GET(ec, obj);
1087    VS_DBG(ec, "CALLBACK 'HIDE'...");
1088    _e_vis_update_foreground_job_queue();
1089    E_VIS_CLIENT_GET_OR_RETURN(vc, ec);
1090    vc->state = ec->iconic ? E_VIS_ICONIFY_STATE_ICONIC : E_VIS_ICONIFY_STATE_UNICONIC;
1091    VS_DBG(ec, "\tUPDATE ICONIC STATE: %s", STATE_STR(vc));
1092    vc->prepare_emitted = 0;
1093
1094    if (ec->iconic && ec->exp_iconify.buffer_flush)
1095      e_pixmap_buffer_clear(ec->pixmap, EINA_FALSE);
1096 }
1097
1098 static void
1099 _e_vis_client_cb_evas_move(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
1100 {
1101    Evas_Coord x, y;
1102    Eina_Bool visible;
1103
1104    OBJ_EC_GET(ec, obj);
1105    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1106    visible = evas_object_visible_get(obj);
1107    VS_DBG(ec, "CALLBACK 'MOVE'... %d %d (v %d)", x, y, visible);
1108    if (visible) _e_vis_update_foreground_job_queue();
1109 }
1110
1111 static void
1112 _e_vis_client_cb_evas_resize(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
1113 {
1114    Evas_Coord w, h;
1115    Eina_Bool visible;
1116
1117    OBJ_EC_GET(ec, obj);
1118    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1119    visible = evas_object_visible_get(obj);
1120    VS_DBG(ec, "CALLBACK 'RESIZE'... %d %d (v %d)", w, h, visible);
1121    if (visible) _e_vis_update_foreground_job_queue();
1122 }
1123
1124 static void
1125 _e_vis_client_cb_evas_restack(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1126 {
1127    Eina_Bool visible;
1128
1129    OBJ_EC_GET(ec, obj);
1130    visible = evas_object_visible_get(obj);
1131    VS_DBG(ec, "CALLBACK 'RESTACK'... v %d", visible);
1132    if (visible) _e_vis_update_foreground_job_queue();
1133 }
1134
1135 static Eina_Bool
1136 _e_vis_client_grab_clear_cb(void *data)
1137 {
1138    E_Vis_Grab *grab = data;
1139    E_Pol_Vis_Type above_vis_type;
1140
1141    VS_INF(grab->vc->ec, "FORCE CLEAR! Grab %s, cur state:%d", grab->name, grab->vc->state);
1142    grab->timer = NULL;
1143
1144    if (grab->vc->state == E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY)
1145      {
1146         above_vis_type = _e_vis_ec_above_visible_type(grab->vc->ec, EINA_FALSE);
1147         if (above_vis_type != E_POL_VIS_TYPE_NON_ALPHA)
1148           _e_vis_ec_below_uniconify(grab->vc->ec, above_vis_type);
1149      }
1150
1151    grab->deleted = 1;
1152    _e_vis_client_grab_remove(grab->vc, grab);
1153
1154    return ECORE_CALLBACK_DONE;
1155 }
1156
1157 void
1158 _e_vis_client_delay_del(E_Object *obj)
1159 {
1160    E_Client *ec;
1161
1162    ec = (E_Client *)obj;
1163    E_VIS_CLIENT_GET_OR_RETURN(vc, ec);
1164    if (vc->job.count)
1165      {
1166         VS_INF(ec, "REF Delay Del");
1167         e_pixmap_ref(ec->pixmap);
1168         e_object_delay_del_ref(obj);
1169         if (vc->grab)
1170           {
1171              E_FREE_FUNC(vc->grab->timer, ecore_timer_del);
1172              vc->grab->timer = ecore_timer_add(E_CLEAR_GRAB_TIMEOUT, _e_vis_client_grab_clear_cb, vc->grab);
1173           }
1174
1175         E_Vis_Grab *grab;
1176         Eina_List *l;
1177         EINA_LIST_FOREACH(vc->wait_buf_attach_grab_list, l, grab)
1178           {
1179              E_FREE_FUNC(grab->timer, ecore_timer_del);
1180              grab->timer = ecore_timer_add(E_CLEAR_GRAB_TIMEOUT, _e_vis_client_grab_clear_cb, grab);
1181           }
1182      }
1183 }
1184
1185 static Eina_Bool
1186 _e_vis_client_job_timeout(void *data)
1187 {
1188    E_Vis_Job *job = data;
1189    if (!job) return ECORE_CALLBACK_DONE;
1190
1191    ELOGF("POL_VIS", "TIMEOUT(%f) JOB:%p, type:%d", NULL, e_config->deiconify_pending_timeout, job, job->type);
1192    ELOGF("POL_VIS", "Info is_del:%d", job->vc->ec, e_object_is_del(E_OBJECT(job->vc->ec)));
1193    job->timer = NULL;
1194
1195    /* FIXME delete all grab and evaluate it instead of exec */
1196    _e_vis_job_exec(&job->entry);
1197    _e_vis_job_eval();
1198
1199    return ECORE_CALLBACK_DONE;
1200 }
1201
1202 static void
1203 _e_vis_client_job_add(E_Vis_Client *vc, E_Vis_Job_Type type)
1204 {
1205    VS_DBG(vc->ec, "Add Job: type %d", type);
1206
1207    if (!_e_vis_job_add(vc, type, _e_vis_client_job_timeout))
1208      return;
1209
1210    vc->job.count++;
1211    VS_INF(vc->ec, "Increase VC JOB count:%d", vc->job.count);
1212 }
1213
1214 static void
1215 _e_vis_client_del(E_Vis_Client *vc)
1216 {
1217    E_Vis_Grab *grab;
1218    Eina_List *l;
1219
1220    VS_INF(vc->ec, "CLIENT DEL");
1221
1222    l = eina_list_clone(vc->wait_buf_attach_grab_list);
1223    vc->wait_buf_attach_grab_list = eina_list_free(vc->wait_buf_attach_grab_list);
1224    EINA_LIST_FREE(l, grab)
1225      {
1226         VS_INF(vc->ec, "Remove remain grab(%p) in wait_buf_attach list", grab);
1227         E_FREE_FUNC(grab, _e_vis_grab_release);
1228      }
1229
1230    E_FREE_FUNC(vc->grab, _e_vis_grab_release);
1231    E_LIST_REVERSE_FREE(vc->job.grab_list, grab)
1232      {
1233         VS_INF(vc->ec, "CRI... Not handled grab (%p)", grab);
1234         grab->deleted = 1;
1235      }
1236
1237    /* if it's intended normal operation, there is no job to delete. */
1238    _e_vis_job_del_by_client(vc);
1239    /* clear event handler of E_Client */
1240    _e_vis_ec_reset(vc->ec);
1241    /* delete buffer attach handler for client */
1242    E_FREE_FUNC(vc->buf_attach, ecore_event_handler_del);
1243
1244    free(vc);
1245 }
1246
1247 static void
1248 _e_vis_client_add(E_Client *ec)
1249 {
1250    VS_DBG(ec, "CLIENT ADD");
1251
1252    if (e_policy_client_is_subsurface(ec))
1253      return;
1254
1255    E_VIS_ALLOC_RET(vc, E_Vis_Client, 1);
1256    vc->ec = ec;
1257
1258    _e_vis_ec_setup(ec);
1259    eina_hash_add(pol_vis->clients_hash, &ec, vc);
1260 }
1261
1262 static void
1263 _e_vis_client_prepare_foreground_signal_emit(E_Vis_Client *vc)
1264 {
1265    /* TODO should emit signal only if it's real foreground. */
1266    if (vc->prepare_emitted)
1267      return;
1268    vc->prepare_emitted = 1;
1269    evas_object_smart_callback_call(vc->ec->frame, "e,visibility,prepare,foreground", vc->ec);
1270 }
1271
1272 EINTERN void
1273 e_vis_client_send_pre_visibility_event(E_Client *ec)
1274 {
1275    Eina_Bool intercepted;
1276
1277    if (!ec) return;
1278    if ((ec->visibility.last_sent_type == E_VISIBILITY_PRE_UNOBSCURED) ||
1279        (ec->visibility.last_sent_type == E_VISIBILITY_UNOBSCURED))
1280      return;
1281
1282    intercepted = e_policy_interceptor_call(E_POLICY_INTERCEPT_SEND_PRE_VISIBILITY, ec);
1283    if (intercepted)
1284      {
1285         ELOGF("POL_VIS", "Handled by Intercept function", ec);
1286         return;
1287      }
1288
1289    e_policy_wl_visibility_send(ec, E_VISIBILITY_PRE_UNOBSCURED);
1290 }
1291
1292 EINTERN void
1293 e_vis_client_check_send_pre_visibility_event(E_Client *ec, Eina_Bool raise)
1294 {
1295    if (!ec) return;
1296
1297    E_VIS_CLIENT_GET_OR_RETURN(vc, ec);
1298
1299    if (_e_vis_client_check_send_pre_visibility(vc, raise))
1300      {
1301         ELOGF("POL_VIS", "SEND pre-unobscured visibility event", ec);
1302         e_vis_client_send_pre_visibility_event(ec);
1303      }
1304 }
1305
1306 static Eina_Bool
1307 _e_vis_client_is_uniconify_render_necessary(E_Vis_Client *vc)
1308 {
1309    E_Client *ec = NULL;
1310    if (vc) ec = vc->ec;
1311    if (!ec) return EINA_FALSE;
1312    if (!ec->exp_iconify.buffer_flush)
1313      {
1314         if (ec && ec->exp_iconify.deiconify_update) // hint or conf->deiconify_approve set deiconify update 1
1315           goto need_deiconify_render;
1316
1317         VS_INF(ec, "Not necessary deiconify rendering");
1318         return EINA_FALSE;
1319      }
1320
1321 need_deiconify_render:
1322    if (_e_vis_client_is_uniconic(vc))
1323      {
1324         VS_INF(vc->ec, "Already uniconic state");
1325         return EINA_FALSE;
1326      }
1327
1328    return EINA_TRUE;
1329 }
1330
1331 static Eina_Bool
1332 _e_vis_client_check_obscured_by_children(E_Client *ec)
1333 {
1334    Eina_Bool obscured = EINA_FALSE;
1335    E_Client *child = NULL;
1336    const Eina_List *l = NULL;
1337    int ex, ey, ew, eh;
1338    int cx, cy, cw, ch;
1339
1340    e_client_geometry_get(ec, &ex, &ey, &ew, &eh);
1341
1342    EINA_LIST_FOREACH(ec->transients, l, child)
1343      {
1344         if (e_client_transient_policy_get(child) == E_TRANSIENT_BELOW)
1345           continue;
1346
1347         e_client_geometry_get(child, &cx, &cy, &cw, &ch);
1348         if (!E_CONTAINS(cx, cy, cw, ch, ex, ey, ew, eh)) continue;
1349
1350         if (!child->argb)
1351           {
1352              ELOGF("POL_VIS", "Fully Obscured by child (win:%zx, child:%p)",
1353                    ec, e_client_util_win_get(child), child);
1354              obscured = EINA_TRUE;
1355              break;
1356           }
1357         else
1358           {
1359              if (child->visibility.opaque > 0)
1360                {
1361                   ELOGF("POL_VIS", "Fully Obscured by alpha opaque child (win:%zx, child:%p)",
1362                         ec, e_client_util_win_get(child), child);
1363                   obscured = EINA_TRUE;
1364                   break;
1365                }
1366           }
1367      }
1368
1369    return obscured;
1370 }
1371
1372 static Eina_Bool
1373 _e_vis_client_check_obscured_by_same_layer(E_Client *ec)
1374 {
1375    Eina_Bool obscured = EINA_FALSE;
1376    E_Client *above = NULL;
1377    int ex, ey, ew, eh;
1378    int ax, ay, aw, ah;
1379
1380    e_client_geometry_get(ec, &ex, &ey, &ew, &eh);
1381
1382    for (above = e_client_above_get(ec); above; above = e_client_above_get(above))
1383      {
1384         if (above->layer > ec->layer) break;
1385         if (e_client_util_ignored_get(above)) continue;
1386         if (e_object_is_del(E_OBJECT(above))) continue;
1387         if (above->iconic && e_client_is_iconified_by_client(above)) continue;
1388         if (above->bg_state) continue;
1389         if (above->comp_data && !above->comp_data->mapped) continue;
1390
1391         e_client_geometry_get(above, &ax, &ay, &aw, &ah);
1392         if (!E_CONTAINS(ax, ay, aw, ah, ex, ey, ew, eh)) continue;
1393
1394         if (!above->argb)
1395           {
1396              ELOGF("POL_VIS", "Fully Obscured by above (win:%zx, ec:%p, layer:%d)",
1397                    ec, e_client_util_win_get(above), above, above->layer);
1398              obscured = EINA_TRUE;
1399              break;
1400           }
1401         else
1402           {
1403              if (above->visibility.opaque <= 0)
1404                continue;
1405              else
1406                {
1407                   ELOGF("POL_VIS", "Fully Obscured by alpha opaque above (win:%zx, ec:%p, layer:%d)",
1408                         ec, e_client_util_win_get(above), above, above->layer);
1409                   obscured = EINA_TRUE;
1410                   break;
1411                }
1412           }
1413      }
1414
1415    return obscured;
1416 }
1417
1418 static Eina_Bool
1419 _e_vis_client_check_obscured_by_above_layers(E_Client *ec)
1420 {
1421    Eina_Bool obscured = EINA_FALSE;
1422    E_Client *above = NULL;
1423    int ex, ey, ew, eh;
1424    int ax, ay, aw, ah;
1425
1426    e_client_geometry_get(ec, &ex, &ey, &ew, &eh);
1427
1428    for (above = e_client_above_get(ec); above; above = e_client_above_get(above))
1429      {
1430         if (above->layer <= ec->layer) continue;
1431         if (e_client_util_ignored_get(above)) continue;
1432         if (e_object_is_del(E_OBJECT(above))) continue;
1433         if (above->iconic && e_client_is_iconified_by_client(above)) continue;
1434         if (above->bg_state) continue;
1435         if (above->comp_data && !above->comp_data->mapped) continue;
1436
1437         e_client_geometry_get(above, &ax, &ay, &aw, &ah);
1438         if (!E_CONTAINS(ax, ay, aw, ah, ex, ey, ew, eh)) continue;
1439
1440         if (!above->argb)
1441           {
1442              ELOGF("POL_VIS", "Fully Obscured by above (win:%zx, ec:%p, layer:%d)",
1443                    ec, e_client_util_win_get(above), above, above->layer);
1444              obscured = EINA_TRUE;
1445              break;
1446           }
1447         else
1448           {
1449              if (above->visibility.opaque <= 0)
1450                continue;
1451              else
1452                {
1453                   ELOGF("POL_VIS", "Fully Obscured by alpha opaque above (win:%zx, ec:%p, layer:%d)",
1454                         ec, e_client_util_win_get(above), above, above->layer);
1455                   obscured = EINA_TRUE;
1456                   break;
1457                }
1458           }
1459      }
1460
1461    return obscured;
1462 }
1463
1464 static Eina_Bool
1465 _e_vis_client_check_send_pre_visibility(E_Vis_Client *vc, Eina_Bool raise)
1466 {
1467    Eina_Bool send_vis_event = EINA_TRUE;
1468    E_Client *ec;
1469
1470    ec = vc->ec;
1471
1472    if (_e_vis_client_is_uniconic(vc))
1473      return EINA_FALSE;
1474
1475    if (!e_comp_client_zone_is_displaying(ec))
1476      return EINA_FALSE;
1477
1478    // check all windows on above layers, if obscured by above then return FALSE
1479    if (_e_vis_client_check_obscured_by_above_layers(ec))
1480      {
1481         ELOGF("POL_VIS", "DO NOT Need to SEND pre-visibility.. obscured by above (above layer)", ec);
1482         return EINA_FALSE;
1483      }
1484
1485    if (!raise)
1486      {
1487         // check above windows in same layer
1488         if (_e_vis_client_check_obscured_by_same_layer(ec))
1489           {
1490              ELOGF("POL_VIS", "DO NOT Need to SEND pre-visibility.. obscured by above (same layer)", ec);
1491              send_vis_event = EINA_FALSE;
1492           }
1493      }
1494    else
1495      {
1496         if (ec->transients)
1497           {
1498              // check children windows
1499              if (_e_vis_client_check_obscured_by_children(ec))
1500                {
1501                   ELOGF("POL_VIS", "DO NOT Need to SEND pre-visibility.. obscured by child", ec);
1502                   send_vis_event = EINA_FALSE;
1503                }
1504           }
1505      }
1506
1507    return send_vis_event;
1508 }
1509
1510 static Eina_Bool
1511 _e_vis_client_add_uniconify_render_pending(E_Vis_Client *vc, E_Vis_Job_Type type, Eina_Bool raise, Eina_Bool force_send)
1512 {
1513    E_Client *ec;
1514    Eina_Bool send_vis_event = EINA_TRUE;
1515
1516    ec = vc->ec;
1517
1518    if (!e_comp_client_zone_is_displaying(ec))
1519      {
1520         VS_DBG(ec, "Display off. no need to uniconify render.");
1521         return EINA_FALSE;
1522      }
1523
1524    if (ec->comp_data && !ec->comp_data->mapped)
1525      {
1526         ELOGF("POL_VIS", "Not mapped. no need to uniconify render.", ec);
1527         return EINA_FALSE;
1528      }
1529
1530    /* do not add child window which is obscured by 24 bit parent window */
1531    if ((ec->parent) &&
1532        !(ec->parent->argb) &&
1533        (e_client_transient_policy_get(ec) == E_TRANSIENT_BELOW))
1534      {
1535         VS_INF(ec, "Transient below. no need to uniconify render.");
1536         return EINA_FALSE;
1537      }
1538
1539    if (_e_vis_client_is_uniconify_render_running(vc))
1540      goto end;
1541
1542    if (!force_send)
1543      send_vis_event = _e_vis_client_check_send_pre_visibility(vc, raise);
1544
1545    if (send_vis_event)
1546      {
1547         ELOGF("POL_VIS", "SEND pre-unobscured visibility event", ec);
1548         e_vis_client_send_pre_visibility_event(ec);
1549      }
1550
1551    if (!_e_vis_client_is_uniconify_render_necessary(vc))
1552      return EINA_FALSE;
1553
1554    if (_e_vis_client_is_uniconify_render_running_done(vc))
1555      goto end;
1556
1557    ec->exp_iconify.not_raise = !raise;
1558
1559    VS_DBG(ec, "BEGIN Uniconify render: raise %d", raise);
1560
1561    _e_vis_client_prepare_foreground_signal_emit(vc);
1562    vc->state = E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY;
1563    VS_DBG(vc->ec, "\tUPDATE ICONIC STATE: %s", STATE_STR(vc));
1564    E_Vis_Grab *grab = _e_vis_client_grab_get(vc, type, __func__);
1565    _e_vis_client_buffer_attach_handler_add(vc, grab);
1566
1567    e_policy_wl_iconify_state_change_send(ec, 0);
1568    _e_pol_vis_hook_call(E_POL_VIS_HOOK_TYPE_UNICONIFY_RENDER_RUNNING, ec);
1569
1570 end:
1571    _e_vis_client_job_add(vc, type);
1572
1573   return EINA_TRUE;
1574 }
1575
1576 static Eina_Bool
1577 _e_vis_client_defer_move(E_Vis_Client *vc, E_Vis_Job_Type type)
1578 {
1579    if (!vc) return EINA_FALSE;
1580
1581    VS_DBG(vc->ec, "\tDEFER MOVE: %s", STATE_STR(vc));
1582    E_Vis_Grab *grab = _e_vis_client_grab_get(vc, type, __func__);
1583    _e_vis_client_buffer_attach_handler_add(vc, grab);
1584
1585    _e_vis_client_job_add(vc, type);
1586
1587    return EINA_TRUE;
1588 }
1589
1590 static inline Eina_Bool
1591 _e_vis_ec_special_check(E_Client *ec)
1592 {
1593    return ((e_policy_client_is_quickpanel(ec) && ec->argb)||
1594            e_policy_client_is_subsurface(ec) ||
1595            e_policy_client_is_keyboard(ec) ||
1596            e_policy_client_is_keyboard_sub(ec) ||
1597            e_policy_client_is_floating(ec));
1598 }
1599
1600 static Eina_Bool
1601 _e_vis_ec_activity_check(E_Client *ec, Eina_Bool check_alpha, Eina_Bool check_fullsize)
1602 {
1603    int x, y, w, h;
1604    E_Comp_Object_Content_Type type = E_COMP_OBJECT_CONTENT_TYPE_NONE;
1605    int check_mapped = 1;
1606    E_Desk *desk;
1607
1608    /* check if ignored */
1609    if (e_client_util_ignored_get(ec)) return EINA_FALSE;
1610    /* check transparent */
1611    if (check_alpha && ((ec->argb) && (ec->visibility.opaque <= 0))) return EINA_FALSE;
1612    /* check deleted client */
1613    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
1614    /* check launchscreen */
1615    if (ec->frame) type = e_comp_object_content_type_get(ec->frame);
1616    if ((type == E_COMP_OBJECT_CONTENT_TYPE_EXT_IMAGE) ||
1617        (type == E_COMP_OBJECT_CONTENT_TYPE_EXT_EDJE))
1618      check_mapped = 0;
1619    /* check unmapped client */
1620    if (check_mapped && ec->comp_data && !ec->comp_data->mapped) return EINA_FALSE;
1621    /* check iconify window by client */
1622    if ((ec->iconic) && (e_client_is_iconified_by_client(ec))) return EINA_FALSE;
1623    /* check background state */
1624    if (ec->bg_state) return EINA_FALSE;
1625    /* check special client */
1626    if (_e_vis_ec_special_check(ec)) return EINA_FALSE;
1627
1628    desk = e_comp_desk_find_by_ec(ec);
1629    if (!desk) return EINA_FALSE;
1630
1631    /* check if full screen */
1632    e_client_geometry_get(ec, &x, &y, &w, &h);
1633    E_RECTS_CLIP_TO_RECT(x, y, w, h, desk->geom.x, desk->geom.y, desk->geom.w, desk->geom.h);
1634    if (check_fullsize &&
1635        !E_CONTAINS(x, y, w, h, desk->geom.x, desk->geom.y, desk->geom.w, desk->geom.h)) return EINA_FALSE;
1636
1637    /* check if obscured by force */
1638    if (ec->visibility.force_obscured)
1639      return EINA_FALSE;
1640
1641    return EINA_TRUE;
1642 }
1643
1644 static void
1645 _e_vis_client_job_exec_by_type(E_Vis_Client *vc, E_Vis_Job_Type type)
1646 {
1647    E_Client *ec = vc->ec;
1648
1649    VS_INF(ec, "Job Run: type %d", type);
1650
1651    switch (type)
1652      {
1653       case E_VIS_JOB_TYPE_ACTIVATE:
1654          if (ec->visibility.force_obscured) break;
1655          e_client_activate(ec);
1656          if (e_policy_client_is_lockscreen(ec))
1657            e_policy_stack_clients_restack_above_lockscreen(ec, EINA_TRUE);
1658          else
1659            e_policy_stack_check_above_lockscreen(ec, ec->layer);
1660          break;
1661       case E_VIS_JOB_TYPE_UNICONIFY:
1662          if (ec->visibility.force_obscured) break;
1663          e_client_uniconify(ec);
1664          break;
1665       case E_VIS_JOB_TYPE_UNICONIFY_BY_VISIBILITY:
1666          ec->exp_iconify.not_raise = 1;
1667          e_client_uniconify(ec);
1668          ec->exp_iconify.not_raise = 0;
1669          break;
1670       case E_VIS_JOB_TYPE_LOWER:
1671          e_client_lower(ec);
1672          break;
1673       case E_VIS_JOB_TYPE_HIDE:
1674          evas_object_hide(ec->frame);
1675          break;
1676       case E_VIS_JOB_TYPE_LAYER_LOWER:
1677          e_client_layer_set(ec, vc->layer);
1678          break;
1679       case E_VIS_JOB_TYPE_ICONIFY:
1680          e_client_iconify(ec);
1681          break;
1682       case E_VIS_JOB_TYPE_SHOW:
1683          /* checks for dectecting hide request after show request */
1684          if ((!e_object_is_del(E_OBJECT(ec))) &&
1685              (ec->visible) && (!ec->hidden) &&
1686              (!ec->iconic) && (!ec->ignored))
1687            evas_object_show(ec->frame);
1688
1689          if (vc->wait_for_child)
1690            {
1691               e_comp_object_signal_callback_del_full(vc->wait_for_child->frame,
1692                                                      "e,action,launch,done", "e",
1693                                                      _e_vis_cb_child_launch_done, vc);
1694               e_pixmap_free(vc->wait_for_child->pixmap);
1695               e_object_delay_del_unref(E_OBJECT(vc->wait_for_child));
1696               vc->wait_for_child = NULL;
1697            }
1698          break;
1699       case E_VIS_JOB_TYPE_DEFER_MOVE:
1700          /* handle defered job regarding move */
1701          if ((!e_object_is_del(E_OBJECT(ec))) &&
1702              (ec->visible) && (!ec->hidden) &&
1703              (!ec->iconic) && (!ec->ignored))
1704            evas_object_move(ec->frame, ec->x, ec->y);
1705          break;
1706
1707       default:
1708          VS_ERR(ec, "Unkown job type: %d", type);
1709          break;
1710      }
1711 }
1712
1713 static E_Pol_Vis_Type
1714 _e_vis_ec_above_visible_type(E_Client *ec, Eina_Bool check_child)
1715 {
1716    E_Client *above;
1717    E_Pol_Vis_Type above_vis_type = E_POL_VIS_TYPE_ALPHA;
1718    int ex, ey, ew, eh;
1719    int ax, ay, aw, ah;
1720    int cx, cy, cw, ch;
1721    int zx, zy, zw, zh;
1722    E_Desk *desk;
1723
1724    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, E_POL_VIS_TYPE_ALPHA);
1725    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_zone_find_by_ec(ec), E_POL_VIS_TYPE_ALPHA);
1726
1727    desk = e_comp_desk_find_by_ec(ec);
1728    EINA_SAFETY_ON_NULL_RETURN_VAL(desk, EINA_FALSE);
1729
1730    cx = desk->geom.x;
1731    cy = desk->geom.y;
1732    cw = desk->geom.w;
1733    ch = desk->geom.h;
1734
1735    e_client_geometry_get(ec, &ex, &ey, &ew, &eh);
1736    e_zone_useful_geometry_get(e_comp_zone_find_by_ec(ec), &zx, &zy, &zw, &zh);
1737
1738    // check whether ec is out of its container or not
1739    if (!E_INTERSECTS(ex, ey, ew, eh, cx, cy, cw, ch))
1740      return E_POL_VIS_TYPE_NON_ALPHA;
1741
1742    // crop ec size with zone size
1743    E_RECTS_CLIP_TO_RECT(ex, ey, ew, eh, zx, zy, zw, zh);
1744
1745    for (above = e_client_above_get(ec); above; above = e_client_above_get(above))
1746      {
1747         if (e_client_util_ignored_get(above)) continue;
1748         if (above->frame && evas_object_data_get(above->frame, "comp_skip")) continue;
1749         if (check_child && (above->parent == ec)) continue;
1750         if (above->first_mapped)
1751           {
1752              if (above->comp_data && !above->comp_data->mapped)
1753                continue;
1754           }
1755
1756         if (above->iconic && e_client_is_iconified_by_client(above))
1757           continue;
1758
1759         if (above->bg_state)
1760           continue;
1761
1762         if (above->e.state.rot.pending_show)
1763           continue;
1764
1765         e_client_geometry_get(above, &ax, &ay, &aw, &ah);
1766         if (!E_CONTAINS(ax, ay, aw, ah, ex, ey, ew, eh)) continue;
1767
1768         if (e_client_visibility_get(above) == E_VISIBILITY_UNOBSCURED)
1769           {
1770              if (!above->argb)
1771                above_vis_type = E_POL_VIS_TYPE_NON_ALPHA;
1772              else
1773                {
1774                   if (above->visibility.opaque > 0)
1775                     above_vis_type = E_POL_VIS_TYPE_ALPHA_OPAQUE;
1776
1777                   continue;
1778                }
1779           }
1780         else
1781           {
1782              if (!above->visible)
1783                continue;
1784
1785              above_vis_type = E_POL_VIS_TYPE_NON_ALPHA;
1786           }
1787
1788         break;
1789      }
1790
1791    return above_vis_type;
1792 }
1793
1794 static Eina_Bool
1795 _e_vis_client_check_obscure_below(E_Client *ec)
1796 {
1797    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
1798
1799    if (e_client_util_ignored_get(ec)) return EINA_FALSE;
1800    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
1801    if (ec->iconic && e_client_is_iconified_by_client(ec)) return EINA_FALSE;
1802    if (ec->bg_state) return EINA_FALSE;
1803    if (ec->comp_data && !ec->comp_data->mapped) return EINA_FALSE;
1804    if ((ec->argb) && (ec->visibility.opaque <= 0)) return EINA_FALSE;
1805    if (e_client_visibility_get(ec) != E_VISIBILITY_UNOBSCURED) return EINA_FALSE;
1806    if (!ec->visible) return EINA_FALSE;
1807
1808    return EINA_TRUE;
1809 }
1810
1811 static void
1812 _e_vis_ec_below_activity_clients_get(E_Client *ec, Eina_List **below_list)
1813 {
1814    E_Client *below;
1815    E_Client *above;
1816    Eina_Tiler *above_tile = NULL;
1817    Eina_Tiler *below_tile = NULL;
1818    Eina_Tiler *temp_tile = NULL;
1819    Eina_Rectangle r;
1820    Eina_Rectangle desk_rect;
1821    int x, y, w, h;
1822    E_Desk *desk;
1823
1824    desk = e_comp_desk_find_by_ec(ec);
1825    EINA_SAFETY_ON_NULL_RETURN(desk);
1826
1827    EINA_RECTANGLE_SET(&desk_rect, desk->geom.x, desk->geom.y, desk->geom.w, desk->geom.h);
1828
1829    above_tile = eina_tiler_new(desk->geom.w, desk->geom.h);
1830    EINA_SAFETY_ON_NULL_GOTO(above_tile, finish);
1831    below_tile = eina_tiler_new(desk->geom.w, desk->geom.h);
1832    EINA_SAFETY_ON_NULL_GOTO(below_tile, finish);
1833    temp_tile = eina_tiler_new(desk->geom.w, desk->geom.h);
1834    EINA_SAFETY_ON_NULL_GOTO(temp_tile, finish);
1835
1836    eina_tiler_tile_size_set(above_tile, 1, 1);
1837    eina_tiler_tile_size_set(below_tile, 1, 1);
1838    eina_tiler_tile_size_set(temp_tile, 1, 1);
1839
1840    for (above = e_client_above_get(ec); above; above = e_client_above_get(above))
1841      {
1842         if (_e_vis_client_check_obscure_below(above))
1843           {
1844              e_client_geometry_get(above, &x, &y, &w, &h);
1845              EINA_RECTANGLE_SET(&r, x, y, w, h);
1846              eina_tiler_rect_add(above_tile, &r);
1847           }
1848      }
1849
1850    // if fully obscured by aboves, no need to get below list
1851    eina_tiler_rect_add(temp_tile, &desk_rect);
1852    eina_tiler_subtract(temp_tile, above_tile);
1853    if (eina_tiler_empty(temp_tile))
1854      goto finish;
1855
1856    for (below = e_client_below_get(ec); below; below = e_client_below_get(below))
1857      {
1858         if (!_e_vis_ec_activity_check(below, EINA_FALSE, EINA_FALSE)) continue;
1859         e_client_geometry_get(below, &x, &y, &w, &h);
1860         EINA_RECTANGLE_SET(&r, x, y, w, h);
1861         eina_tiler_rect_add(below_tile, &r);
1862
1863         // get unobscured region of below ec
1864         eina_tiler_clear(temp_tile);
1865         eina_tiler_union(temp_tile, above_tile);
1866         eina_tiler_union(temp_tile, below_tile);
1867         eina_tiler_subtract(temp_tile, above_tile);
1868
1869         if (eina_tiler_empty(temp_tile)) continue;
1870
1871         E_VIS_CLIENT_GET(vc, below);
1872         if (!vc) continue;
1873
1874         if ((e_client_transient_policy_get(below) == E_TRANSIENT_BELOW) &&
1875             (below->parent == ec))
1876           continue;
1877
1878         if (!below->internal)
1879           *below_list = eina_list_prepend(*below_list, vc);
1880
1881         if (!(below->argb) || !(below->visibility.opaque <= 0))
1882           {
1883              eina_tiler_union(above_tile, below_tile);
1884
1885              // if fully obscured by aboves, no need to continue
1886              eina_tiler_rect_add(temp_tile, &desk_rect);
1887              eina_tiler_subtract(temp_tile, above_tile);
1888              if (eina_tiler_empty(temp_tile))
1889                break;
1890           }
1891      }
1892
1893 finish:
1894    if (above_tile)
1895      eina_tiler_free(above_tile);
1896
1897    if (below_tile)
1898      eina_tiler_free(below_tile);
1899
1900    if (temp_tile)
1901      eina_tiler_free(temp_tile);
1902 }
1903
1904 static Eina_Bool
1905 _e_vis_ec_below_uniconify(E_Client *ec, E_Pol_Vis_Type above_vis_type)
1906 {
1907    Eina_List *below_list = NULL;
1908    Eina_Bool ret = EINA_FALSE;
1909    E_Vis_Client *below_vc;
1910    Eina_Bool send_vis;
1911
1912    if (!ec) return EINA_FALSE;
1913
1914    if (!e_comp_client_zone_is_displaying(ec))
1915      return EINA_FALSE;
1916
1917    /* find below activity clients */
1918    _e_vis_ec_below_activity_clients_get(ec, &below_list);
1919    if (!below_list)
1920      {
1921         VS_INF(ec, "There is NO below activity");
1922         return EINA_FALSE;
1923      }
1924    else
1925      {
1926         if (above_vis_type == E_POL_VIS_TYPE_ALPHA_OPAQUE)
1927           send_vis = EINA_FALSE;
1928         else
1929           send_vis = EINA_TRUE;
1930
1931         EINA_LIST_FREE(below_list, below_vc)
1932           {
1933              Eina_Bool job_added = EINA_FALSE;
1934              E_Client *below_ec = below_vc->ec;
1935
1936              if (below_ec == ec->parent)
1937                {
1938                   /* Check if its parent is waiting for a child's uniconify.
1939                    * if so cancel the waiting now.
1940                    */
1941                   if (below_vc->state == E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY_WAITING_FOR_CHILD)
1942                     {
1943                        E_FREE_FUNC(below_vc->grab, _e_vis_grab_release);
1944                        continue;
1945                     }
1946
1947                   ELOGF("POL_VIS", "SEND pre-unobscured visibility event", below_ec);
1948                   e_vis_client_send_pre_visibility_event(below_ec);
1949                }
1950
1951              job_added = _e_vis_client_add_uniconify_render_pending(below_vc, E_VIS_JOB_TYPE_UNICONIFY_BY_VISIBILITY, 0, send_vis);
1952
1953              if (!job_added)
1954                {
1955                   if ((below_ec->iconic) && (!e_client_is_iconified_by_client(below_ec)))
1956                     {
1957                        // show evas obj if uniconify pending is not necessary
1958                        ELOGF("POL_VIS", "Show below iconic client in advance", below_ec);
1959                        below_ec->exp_iconify.not_raise = 1;
1960                        e_client_uniconify(below_ec);
1961                        e_policy_wl_iconify_state_change_send(below_ec, 0);
1962                     }
1963                }
1964
1965              ret |= job_added;
1966           }
1967      }
1968
1969    return ret;
1970 }
1971
1972 static void
1973 _e_vis_ec_setup(E_Client *ec)
1974 {
1975    e_object_delay_del_set(E_OBJECT(ec), _e_vis_client_delay_del);
1976    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW,     _e_vis_client_cb_evas_show,     NULL);
1977    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE,     _e_vis_client_cb_evas_hide,     NULL);
1978    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE,     _e_vis_client_cb_evas_move,     NULL);
1979    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESIZE,   _e_vis_client_cb_evas_resize,   NULL);
1980    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESTACK,  _e_vis_client_cb_evas_restack,  NULL);
1981 }
1982
1983 static void
1984 _e_vis_ec_reset(E_Client *ec)
1985 {
1986    e_object_delay_del_set(E_OBJECT(ec), NULL);
1987    evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_SHOW,     _e_vis_client_cb_evas_show);
1988    evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_HIDE,     _e_vis_client_cb_evas_hide);
1989    evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_MOVE,     _e_vis_client_cb_evas_move);
1990    evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_RESIZE,   _e_vis_client_cb_evas_resize);
1991    evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_RESTACK,  _e_vis_client_cb_evas_restack);
1992 }
1993
1994 static void
1995 _e_vis_hook_new_client_post(void *data EINA_UNUSED, E_Client *ec)
1996 {
1997    _e_vis_client_add(ec);
1998 }
1999
2000 static void
2001 _e_vis_client_remove(E_Client *ec)
2002 {
2003    E_VIS_CLIENT_GET_OR_RETURN(vc, ec);
2004    eina_hash_del_by_key(pol_vis->clients_hash, &ec);
2005
2006    if (pol_vis->activity == ec)
2007      pol_vis->activity = NULL;
2008
2009    if (!stopping)
2010      _e_vis_update_foreground_job_queue();
2011 }
2012
2013 static void
2014 _e_vis_hook_client_del(void *data EINA_UNUSED, E_Client *ec)
2015 {
2016    E_VIS_CLIENT_GET_OR_RETURN(vc, ec);
2017    if (vc->skip_hook_del) return;
2018    _e_vis_client_remove(ec);
2019 }
2020
2021 static Eina_Bool
2022 _e_vis_cb_client_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
2023 {
2024    E_Event_Client *ev;
2025
2026    ev = event;
2027    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ev->ec, ECORE_CALLBACK_PASS_ON);
2028
2029    vc->skip_hook_del = EINA_TRUE;
2030
2031    return ECORE_CALLBACK_PASS_ON;
2032 }
2033
2034 static Eina_Bool
2035 _e_vis_cb_client_remove(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
2036 {
2037    E_Event_Client *ev;
2038
2039    ev = event;
2040    _e_vis_client_remove(ev->ec);
2041
2042    return ECORE_CALLBACK_PASS_ON;
2043 }
2044
2045 static void
2046 _e_vis_cb_child_launch_done(void *data, Evas_Object *obj, const char *signal, const char *source)
2047 {
2048    E_Vis_Client *vc;
2049    Evas_Object *comp_obj;
2050
2051    vc = data;
2052    comp_obj = evas_object_data_get(obj, "comp_smart_obj");
2053
2054    E_FREE_FUNC(vc->grab, _e_vis_grab_release);
2055    if (comp_obj)
2056      e_comp_object_signal_callback_del_full(comp_obj, "e,action,launch,done", "e", _e_vis_cb_child_launch_done, vc);
2057 }
2058
2059 static void
2060 _e_vis_transient_group_make(E_Client *ec, Eina_List **list)
2061 {
2062    E_Client *child;
2063    Eina_List *l;
2064
2065    if (!ec) return;
2066
2067    if (e_config->transient.raise)
2068      {
2069         EINA_LIST_FOREACH(ec->transients, l, child)
2070           {
2071              if (!child) continue;
2072              if (child->iconic && e_client_is_iconified_by_client(ec))
2073                continue;
2074              if (child->bg_state)
2075                continue;
2076
2077              if (e_client_transient_policy_get(child) == E_TRANSIENT_ABOVE)
2078                {
2079                   *list = eina_list_prepend(*list, child);
2080                   _e_vis_transient_group_make(child, list);
2081                }
2082           }
2083      }
2084 }
2085
2086 static E_Client *
2087 _e_vis_transient_top_get(E_Client *ec)
2088 {
2089    E_Client *topmost = NULL;
2090    Eina_List *transient_list = NULL;
2091
2092    _e_vis_transient_group_make(ec, &transient_list);
2093
2094    if (transient_list)
2095      {
2096         topmost = eina_list_data_get(transient_list);
2097         eina_list_free(transient_list);
2098      }
2099    return topmost;
2100 }
2101
2102 static Eina_Bool
2103 _e_vis_intercept_show(void *data EINA_UNUSED, E_Client *ec)
2104 {
2105    int ex, ey, ew, eh;
2106    int tx, ty, tw, th;
2107
2108    VS_DBG(ec, "INTERCEPT SHOW: new_client %d size %d %d",
2109           ec->new_client, ec->w, ec->h);
2110
2111    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_TRUE);
2112
2113    if (vc->state == E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY_WAITING_FOR_CHILD)
2114      {
2115         ELOGF("POL", "Waiting child uniconify. running.", ec);
2116         return EINA_FALSE;
2117      }
2118
2119    if (ec->transients)
2120      {
2121         E_Client *topmost;
2122
2123         topmost = _e_vis_transient_top_get(ec);
2124         if (!topmost) return EINA_TRUE;
2125
2126         if (e_client_transient_policy_get(topmost) == E_TRANSIENT_BELOW)
2127           return EINA_TRUE;
2128
2129         /* allow show if topmost child is alpha window or not fully cover region of ec */
2130         e_client_geometry_get(ec, &ex, &ey, &ew, &eh);
2131         e_client_geometry_get(topmost, &tx, &ty, &tw, &th);
2132         if ((topmost->argb) || !(E_CONTAINS(tx, ty, tw, th, ex, ey, ew, eh)))
2133           return EINA_TRUE;
2134
2135         /* do not show until child is shown */
2136         if (e_config->transient.iconify)
2137           {
2138              /* wait for child's uniconify */
2139              if (ec->iconic && topmost->iconic)
2140                {
2141                   if (topmost->pixmap && e_pixmap_usable_get(topmost->pixmap))
2142                     {
2143                        if ((e_policy_visibility_client_is_uniconic(topmost)) &&
2144                            (e_client_visibility_get(topmost) == E_VISIBILITY_UNOBSCURED))
2145                          {
2146                             ELOGF("COMP", "Already child(win:0x%08zx ec:%p) uniconify_render done..", ec, e_client_util_win_get(topmost), topmost);
2147                             return EINA_TRUE;
2148                          }
2149
2150                        ELOGF("COMP", "Set launching flag..", topmost);
2151                        topmost->launching = EINA_TRUE;
2152
2153                        vc->state = E_VIS_ICONIFY_STATE_RUNNING_UNICONIFY_WAITING_FOR_CHILD;
2154                        VS_DBG(vc->ec, "\tUPDATE ICONIC STATE: %s", STATE_STR(vc));
2155                        vc->grab = _e_vis_client_grab_get(vc, E_VIS_JOB_TYPE_SHOW, __func__);
2156                        e_comp_object_signal_callback_add(topmost->frame,
2157                                                          "e,action,launch,done",
2158                                                          "e",
2159                                                          _e_vis_cb_child_launch_done,
2160                                                          vc);
2161
2162                        /* do not allow child's removal */
2163                        vc->wait_for_child = topmost;
2164                        e_pixmap_ref(topmost->pixmap);
2165                        e_object_delay_del_ref(E_OBJECT(topmost));
2166                        _e_vis_client_job_add(vc, E_VIS_JOB_TYPE_SHOW);
2167                        ELOGF("POL", "Waiting child uniconify. new.", ec);
2168                        return EINA_FALSE;
2169                     }
2170                }
2171           }
2172
2173      }
2174    return EINA_TRUE;
2175 }
2176
2177 static Eina_Bool
2178 _e_vis_intercept_hide(void *data EINA_UNUSED, E_Client *ec)
2179 {
2180    E_Pol_Vis_Type above_vis_type;
2181    Eina_Bool pending = EINA_TRUE;
2182
2183    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_TRUE);
2184
2185    VS_DBG(ec, "INTERCEPTOR HIDE");
2186
2187    if (_e_vis_job_find(vc, E_VIS_JOB_TYPE_HIDE))
2188      {
2189         VS_INF(ec, "Already Pending HIDE...");
2190         return EINA_FALSE;
2191      }
2192
2193    if (ec->argb)
2194      {
2195         VS_DBG(ec, "Window is transparent.");
2196         pending = EINA_FALSE;
2197      }
2198
2199    if (_e_vis_client_is_below_uniconify_skip(vc))
2200      {
2201         VS_DBG(ec, "Skip to uniconify below client");
2202         pending = EINA_FALSE;
2203      }
2204
2205    above_vis_type = _e_vis_ec_above_visible_type(ec, EINA_FALSE);
2206    if ((pending) && (above_vis_type == E_POL_VIS_TYPE_NON_ALPHA))
2207      {
2208         VS_DBG(ec, "Obscured by above window.");
2209         pending = EINA_FALSE;
2210      }
2211
2212    if ((pending) && (!_e_vis_ec_below_uniconify(ec, above_vis_type)))
2213      {
2214         VS_DBG(ec, "Failed to uniconify below client");
2215         pending = EINA_FALSE;
2216      }
2217
2218    _e_pol_vis_hook_call(E_POL_VIS_HOOK_TYPE_HIDE, ec);
2219
2220    if (!pending)
2221      {
2222         if (!_e_vis_job_is_grabbed(vc, E_VIS_JOB_TYPE_HIDE))
2223           return EINA_TRUE;
2224      }
2225
2226    /* add hide job, it will be executed after below activity client finishs updating */
2227    _e_vis_client_job_add(vc, E_VIS_JOB_TYPE_HIDE);
2228
2229    return EINA_FALSE;
2230 }
2231
2232 static Eina_Bool
2233 _e_vis_idle_enter(void *data)
2234 {
2235    _e_vis_job_queue_update();
2236    return ECORE_CALLBACK_PASS_ON;
2237 }
2238
2239 static void
2240 _e_vis_event_init(void)
2241 {
2242    E_LIST_HOOK_APPEND(pol_vis->hooks, E_CLIENT_HOOK_NEW_CLIENT_POST, _e_vis_hook_new_client_post, NULL);
2243    E_LIST_HOOK_APPEND(pol_vis->hooks, E_CLIENT_HOOK_DEL, _e_vis_hook_client_del, NULL);
2244
2245    E_LIST_HANDLER_APPEND(pol_vis->handlers, E_EVENT_CLIENT_ADD,   _e_vis_cb_client_add, NULL);
2246    E_LIST_HANDLER_APPEND(pol_vis->handlers, E_EVENT_CLIENT_REMOVE,   _e_vis_cb_client_remove, NULL);
2247
2248    E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(pol_vis->interceptors, E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER,  _e_vis_intercept_show, NULL);
2249    E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(pol_vis->interceptors, E_COMP_OBJECT_INTERCEPT_HOOK_HIDE,         _e_vis_intercept_hide, NULL);
2250
2251    pol_vis->idle_enter = ecore_idle_enterer_add(_e_vis_idle_enter, NULL);
2252 }
2253
2254 EINTERN E_Client*
2255 e_policy_visibility_main_activity_get(void)
2256 {
2257    EINA_SAFETY_ON_NULL_RETURN_VAL(pol_vis, NULL);
2258    return pol_vis->activity;
2259 }
2260
2261 EINTERN Eina_List*
2262 e_policy_visibility_foreground_clients_get(void)
2263 {
2264    if (!pol_vis->fg_clients) return NULL;
2265    return eina_list_clone(pol_vis->fg_clients);
2266 }
2267
2268 E_API Eina_Bool
2269 e_policy_visibility_client_is_activity(E_Client *ec)
2270 {
2271    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
2272    return _e_vis_ec_activity_check(ec, EINA_TRUE, EINA_TRUE);
2273 }
2274
2275 E_API E_Vis_Grab *
2276 e_policy_visibility_client_grab_get(E_Client *ec, const char *name)
2277 {
2278    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, NULL);
2279    if (!name)
2280      {
2281         VS_ERR(ec, "Trying to get the grab without name used hint");
2282         return NULL;
2283      }
2284    return _e_vis_client_grab_get(vc, E_VIS_JOB_TYPE_ALL, name);
2285 }
2286
2287 EINTERN E_Vis_Grab *
2288 e_policy_visibility_client_filtered_grab_get(E_Client *ec, E_Vis_Job_Type type, const char *name)
2289 {
2290    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, NULL);
2291    if (!name)
2292      {
2293         VS_ERR(ec, "Trying to get the grab without name used hint");
2294         return NULL;
2295      }
2296    return _e_vis_client_grab_get(vc, type, name);
2297 }
2298
2299 E_API void
2300 e_policy_visibility_client_grab_release(E_Vis_Grab *grab)
2301 {
2302    EINA_SAFETY_ON_NULL_RETURN(grab);
2303    _e_vis_grab_release(grab);
2304 }
2305
2306 EINTERN Eina_Bool
2307 e_policy_visibility_client_grab_cancel(E_Client *ec)
2308 {
2309    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2310    return _e_vis_client_grab_cancel(vc);
2311 }
2312
2313 EINTERN Eina_Bool
2314 e_policy_visibility_client_hide_job_cancel(E_Client *ec)
2315 {
2316    if (!ec) return EINA_FALSE;
2317    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2318
2319    VS_INF(ec, "Find and Cancel HIDE job...");
2320    return _e_vis_job_cancel(vc, E_VIS_JOB_TYPE_HIDE);
2321 }
2322
2323 EINTERN Eina_Bool
2324 e_policy_visibility_client_lower_job_cancel(E_Client *ec)
2325 {
2326    if (!ec) return EINA_FALSE;
2327    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2328
2329    VS_INF(ec, "Find and Cancel LOWER job...");
2330    return _e_vis_job_cancel(vc, E_VIS_JOB_TYPE_LOWER);
2331 }
2332
2333 EINTERN Eina_Bool
2334 e_policy_visibility_client_uniconify_by_visibility_job_cancel(E_Client *ec)
2335 {
2336    Eina_Bool ret = EINA_FALSE;
2337
2338    if (!ec) return EINA_FALSE;
2339    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2340
2341    VS_INF(ec, "Find and Cancel Uniconify by visibility job...");
2342    ret = _e_vis_job_cancel(vc, E_VIS_JOB_TYPE_UNICONIFY_BY_VISIBILITY);
2343
2344    if (e_policy_visibility_client_is_uniconify_render_running(ec))
2345      {
2346         vc->state = E_VIS_ICONIFY_STATE_ICONIC;
2347         VS_INF(vc->ec, "UPDATE ICONIC STATE: %s", STATE_STR(vc));
2348      }
2349
2350    if (!_e_vis_job_is_grabbed(vc, E_VIS_JOB_TYPE_ALL ^ E_VIS_JOB_TYPE_UNICONIFY_BY_VISIBILITY))
2351      {
2352         vc->state = E_VIS_ICONIFY_STATE_ICONIC;
2353         VS_DBG(vc->ec, "\tUPDATE ICONIC STATE: %s", STATE_STR(vc));
2354         E_FREE_FUNC(vc->grab, _e_vis_grab_release);
2355
2356         E_Vis_Grab *grab;
2357         Eina_List *l;
2358
2359         l = eina_list_clone(vc->wait_buf_attach_grab_list);
2360         vc->wait_buf_attach_grab_list = eina_list_free(vc->wait_buf_attach_grab_list);
2361         EINA_LIST_FREE(l, grab)
2362           {
2363              E_FREE_FUNC(grab, _e_vis_grab_release);
2364           }
2365      }
2366
2367    return ret;
2368 }
2369
2370 EINTERN Eina_Bool
2371 e_policy_visibility_client_raising_job_cancel(E_Client *ec)
2372 {
2373    Eina_Bool ret = EINA_FALSE;
2374
2375    if (!ec) return EINA_FALSE;
2376    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2377
2378    if (_e_vis_job_find(vc, E_VIS_JOB_TYPE_RAISE))
2379      {
2380          VS_INF(ec, "Find and Cancel raising job: E_VIS_JOB_TYPE_RAISE");
2381          ret = _e_vis_job_cancel(vc, E_VIS_JOB_TYPE_RAISE);
2382      }
2383    if (_e_vis_job_find(vc, E_VIS_JOB_TYPE_ACTIVATE))
2384      {
2385          VS_INF(ec, "Find and Cancel raising job: E_VIS_JOB_TYPE_ACTIVATE");
2386          ret = _e_vis_job_cancel(vc, E_VIS_JOB_TYPE_ACTIVATE);
2387      }
2388    if (_e_vis_job_find(vc, E_VIS_JOB_TYPE_UNICONIFY))
2389      {
2390          VS_INF(ec, "Find and Cancel raising job: E_VIS_JOB_TYPE_UNICONIFY");
2391          ret = _e_vis_job_cancel(vc, E_VIS_JOB_TYPE_UNICONIFY);
2392      }
2393
2394    if (ret && e_policy_visibility_client_is_uniconify_render_running(ec))
2395      {
2396         vc->state = E_VIS_ICONIFY_STATE_ICONIC;
2397         VS_INF(vc->ec, "UPDATE ICONIC STATE: %s", STATE_STR(vc));
2398      }
2399
2400    return ret;
2401 }
2402
2403 EINTERN Eina_Bool
2404 e_policy_visibility_client_raise(E_Client *ec)
2405 {
2406    E_Client *child;
2407    Eina_List *l;
2408    Eina_Bool ret = EINA_FALSE;
2409
2410
2411    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2412
2413    VS_DBG(ec, "API ENTRY | RAISE");
2414
2415    if (!ec->iconic && !ec->exp_iconify.deiconify_update)
2416      return EINA_FALSE;
2417
2418    if (e_client_is_iconified_by_client(ec))
2419      return EINA_FALSE;
2420
2421    if (!ec->iconic && ec->bg_state)
2422      {
2423         ELOGF("POL", "Currently bg_state. so return...", ec);
2424         return EINA_FALSE;
2425      }
2426
2427    ret = _e_vis_client_add_uniconify_render_pending(vc, E_VIS_JOB_TYPE_UNICONIFY, 1, EINA_FALSE);
2428
2429    /* uniconify its transients recursively */
2430    if (e_config->transient.raise)
2431      {
2432         l = eina_list_clone(ec->transients);
2433
2434         EINA_LIST_FREE(l, child)
2435            ret |= e_policy_visibility_client_raise(child);
2436      }
2437
2438    /* TODO find topmost activity client and emit signal */
2439
2440    return ret;
2441 }
2442
2443 E_API Eina_Bool
2444 e_policy_visibility_client_lower(E_Client *ec)
2445 {
2446    E_Pol_Vis_Type above_vis_type;
2447    Eina_Bool ret = EINA_TRUE;
2448
2449    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2450
2451    if ((ec->comp_data) && (!ec->comp_data->mapped))
2452      {
2453         VS_DBG(ec, "client Unmapped.");
2454         return EINA_FALSE;
2455      }
2456
2457    if (ec->bg_state)
2458      {
2459         VS_DBG(ec, "client is background state.");
2460         return EINA_FALSE;
2461      }
2462
2463    VS_DBG(ec, "API ENTRY | LOWER");
2464
2465    /* if vc has job grab, release them */
2466    _e_vis_client_grab_cancel(vc);
2467
2468    e_policy_visibility_client_raising_job_cancel(ec);
2469
2470    if (ec->argb)
2471      {
2472         VS_DBG(ec, "Window is transparent.");
2473         ret = EINA_FALSE;
2474      }
2475
2476    above_vis_type = _e_vis_ec_above_visible_type(ec, EINA_TRUE);
2477    if (above_vis_type == E_POL_VIS_TYPE_NON_ALPHA)
2478      {
2479         VS_DBG(ec, "Obscured by above window.");
2480         ret = EINA_FALSE;
2481      }
2482
2483    if ((ret) && (!_e_vis_ec_below_uniconify(ec, above_vis_type)))
2484      {
2485         VS_DBG(ec, "Failed to uniconify below client");
2486         ret = EINA_FALSE;
2487      }
2488
2489    _e_pol_vis_hook_call(E_POL_VIS_HOOK_TYPE_LOWER, ec);
2490
2491    if (!ret)
2492      {
2493         if (!_e_vis_job_is_grabbed(vc, E_VIS_JOB_TYPE_LOWER))
2494           return EINA_FALSE;
2495      }
2496
2497    /* add lower job, it will be executed after below activity client finishs updating */
2498    _e_vis_client_job_add(vc, E_VIS_JOB_TYPE_LOWER);
2499
2500    return EINA_TRUE;
2501 }
2502
2503 EINTERN Eina_Bool
2504 e_policy_visibility_client_iconify(E_Client *ec)
2505 {
2506    E_Pol_Vis_Type above_vis_type;
2507
2508    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2509
2510    VS_DBG(ec, "API ENTRY | ICONIFY");
2511
2512    /* if vc has job grab, release them */
2513    _e_vis_client_grab_cancel(vc);
2514
2515    if (ec->argb)
2516      {
2517         VS_DBG(ec, "Window is transparent.");
2518         return EINA_FALSE;
2519      }
2520
2521    if (ec->iconic) return EINA_FALSE;
2522
2523    above_vis_type = _e_vis_ec_above_visible_type(ec, EINA_TRUE);
2524    if (above_vis_type == E_POL_VIS_TYPE_NON_ALPHA)
2525      {
2526         VS_DBG(ec, "Obscured by above window.");
2527         return EINA_FALSE;
2528      }
2529
2530    if (!_e_vis_ec_below_uniconify(ec, above_vis_type))
2531      {
2532         VS_DBG(ec, "Failed to uniconify below client");
2533         return EINA_FALSE;
2534      }
2535
2536    /* add lower job, it will be executed after below activity client finishs updating */
2537    _e_vis_client_job_add(vc, E_VIS_JOB_TYPE_ICONIFY);
2538
2539    return EINA_TRUE;
2540 }
2541
2542 EINTERN Eina_Bool
2543 e_policy_visibility_client_uniconify(E_Client *ec, Eina_Bool raise)
2544 {
2545    E_Client *child;
2546    Eina_List *l;
2547    Eina_Bool ret = EINA_FALSE;
2548
2549    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2550    if (!ec->iconic && !ec->exp_iconify.deiconify_update)
2551      return EINA_FALSE;
2552
2553    if (!ec->visible)
2554      {
2555         ELOGF("POL", "UNICONIFY. but NOT MAPPED. So skip...", ec);
2556         return EINA_FALSE;
2557      }
2558
2559    if (!ec->iconic && ec->bg_state)
2560      {
2561         ELOGF("POL", "Currently bg_state. so return...", ec);
2562         return EINA_FALSE;
2563      }
2564
2565    VS_DBG(ec, "API ENTRY | UNICONIFY");
2566
2567    /* TODO search clients to be really foreground and uniconify it.
2568     * suppose that transients will be above on the parent. */
2569
2570    if (raise)
2571      ret = _e_vis_client_add_uniconify_render_pending(vc, E_VIS_JOB_TYPE_UNICONIFY, raise, EINA_FALSE);
2572    else
2573      ret = _e_vis_client_add_uniconify_render_pending(vc, E_VIS_JOB_TYPE_UNICONIFY_BY_VISIBILITY, raise, EINA_FALSE);
2574
2575    /* uniconify its transients recursively */
2576    if (e_config->transient.iconify)
2577      {
2578         l = eina_list_clone(ec->transients);
2579
2580         EINA_LIST_FREE(l, child)
2581           {
2582              if (e_client_is_iconified_by_client(child)) continue;
2583
2584              ret |= e_policy_visibility_client_uniconify(child, raise);
2585           }
2586      }
2587
2588    /* TODO find topmost activity client and emit signal */
2589
2590    return ret;
2591 }
2592
2593 EINTERN Eina_Bool
2594 e_policy_visibility_client_wait_child(E_Client *ec, E_Vis_Job_Type type)
2595 {
2596    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2597
2598    _e_vis_client_job_add(vc, type);
2599
2600    return EINA_TRUE;
2601 }
2602
2603 EINTERN Eina_Bool
2604 e_policy_visibility_client_activate(E_Client *ec)
2605 {
2606    E_Client *child;
2607    Eina_List *l;
2608    Eina_Bool ret = EINA_FALSE;
2609    Eina_Bool ret_child = EINA_FALSE;
2610
2611    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2612
2613    if (!ec->iconic && ec->bg_state)
2614      {
2615         ELOGF("POL", "Currently bg_state. so return...", ec);
2616         return EINA_FALSE;
2617      }
2618
2619    VS_DBG(ec, "API ENTRY | ACTIVATE");
2620
2621    ret = _e_vis_client_add_uniconify_render_pending(vc, E_VIS_JOB_TYPE_ACTIVATE, 1, EINA_FALSE);
2622
2623    /* TODO search clients to be foreground
2624     * suppose that transients will be above on the parent. */
2625
2626    /* uniconify its transients recursively */
2627    if (e_config->transient.iconify)
2628      {
2629         Eina_Bool pend = EINA_FALSE;
2630         l = eina_list_clone(ec->transients);
2631
2632         EINA_LIST_FREE(l, child)
2633           {
2634              if (e_client_is_iconified_by_client(child)) continue;
2635
2636              pend = e_policy_visibility_client_uniconify(child, EINA_TRUE);
2637              if (pend)
2638                {
2639                   ELOGF("POL", "uniconify_pending child (win:0x%08zx ec:%p)", ec, e_client_util_win_get(child), child);
2640                   ret_child = pend;
2641                }
2642           }
2643      }
2644
2645    if ((ret == EINA_FALSE) && (ret_child == EINA_TRUE))
2646      {
2647         e_policy_visibility_client_wait_child(ec, E_VIS_JOB_TYPE_ACTIVATE);
2648         ret = EINA_TRUE;
2649      }
2650
2651    /* TODO find topmost activity client and emit signal */
2652
2653    return ret;
2654 }
2655
2656 EINTERN Eina_Bool
2657 e_policy_visibility_client_layer_lower(E_Client *ec, E_Layer layer)
2658 {
2659    E_Pol_Vis_Type above_vis_type;
2660
2661    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2662
2663    VS_DBG(ec, "API ENTRY | LAYER LOWER (layer:%d)", layer);
2664
2665    /* if vc has job grab, release them */
2666    _e_vis_client_grab_cancel(vc);
2667
2668    if (ec->argb)
2669      {
2670         VS_DBG(ec, "Window is transparent.");
2671         return EINA_FALSE;
2672      }
2673
2674    above_vis_type = _e_vis_ec_above_visible_type(ec, EINA_TRUE);
2675    if (above_vis_type == E_POL_VIS_TYPE_NON_ALPHA)
2676      {
2677         VS_DBG(ec, "Obscured by above window.");
2678         return EINA_FALSE;
2679      }
2680
2681    if (!_e_vis_ec_below_uniconify(ec, above_vis_type))
2682      {
2683         VS_DBG(ec, "Failed to uniconify below client");
2684         return EINA_FALSE;
2685      }
2686
2687    /* add lower lower job, it will be executed after below activity client finishs updating */
2688    vc->layer = layer;
2689    _e_vis_client_job_add(vc, E_VIS_JOB_TYPE_LAYER_LOWER);
2690
2691    return EINA_TRUE;
2692 }
2693
2694 EINTERN void
2695 e_policy_visibility_client_defer_move(E_Client *ec)
2696 {
2697    E_VIS_CLIENT_GET_OR_RETURN(vc, ec);
2698    VS_DBG(ec, "API ENTRY | Defered Move");
2699
2700    if (ec->comp_data && !ec->comp_data->mapped)
2701      {
2702         ELOGF("POL_VIS", "Not mapped. no need to defer move.", ec);
2703         return;
2704      }
2705
2706    _e_vis_client_defer_move(vc, E_VIS_JOB_TYPE_DEFER_MOVE);
2707 }
2708
2709 EINTERN Eina_Bool
2710 e_policy_visibility_client_is_iconic(E_Client *ec)
2711 {
2712    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2713
2714    return _e_vis_client_is_iconic(vc);
2715 }
2716
2717 EINTERN Eina_Bool
2718 e_policy_visibility_client_is_uniconic(E_Client *ec)
2719 {
2720    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2721
2722    return _e_vis_client_is_uniconic(vc);
2723 }
2724
2725 E_API Eina_Bool
2726 e_policy_visibility_client_is_uniconify_render_running(E_Client *ec)
2727 {
2728    Eina_Bool running = EINA_FALSE;
2729    E_VIS_CLIENT_GET_OR_RETURN_VAL(vc, ec, EINA_FALSE);
2730
2731    if ((_e_vis_client_is_uniconify_render_running(vc)) ||
2732        (_e_vis_client_is_uniconify_render_running_done(vc)))
2733      running = EINA_TRUE;
2734
2735    return running;
2736 }
2737
2738 E_API void
2739 e_policy_visibility_client_below_uniconify_skip_set(E_Client *ec, Eina_Bool skip)
2740 {
2741    E_VIS_CLIENT_GET_OR_RETURN(vc, ec);
2742
2743    _e_vis_client_below_uniconify_skip_set(vc, skip);
2744 }
2745
2746 EINTERN void
2747 e_policy_visibility_norender_disable_set(Eina_Bool disable)
2748 {
2749    ELOGF("POL_VIS", "NO RENDER DISABLE SET: %d", NULL, disable);
2750    pol_vis_disable_norender = disable;
2751 }
2752
2753 E_API E_Pol_Vis_Hook *
2754 e_policy_visibility_hook_add(E_Pol_Vis_Hook_Type type, E_Pol_Vis_Hook_Cb cb, const void *data)
2755 {
2756    E_Pol_Vis_Hook *h;
2757
2758    EINA_SAFETY_ON_TRUE_RETURN_VAL(type >= E_POL_VIS_HOOK_TYPE_LAST, NULL);
2759
2760    h = E_NEW(E_Pol_Vis_Hook, 1);
2761    EINA_SAFETY_ON_NULL_RETURN_VAL(h, NULL);
2762
2763    h->type = type;
2764    h->cb = cb;
2765    h->data = (void *)data;
2766
2767    _e_pol_vis_hooks[type] = eina_inlist_append(_e_pol_vis_hooks[type],
2768                                                EINA_INLIST_GET(h));
2769
2770    return h;
2771 }
2772
2773 E_API void
2774 e_policy_visibility_hook_del(E_Pol_Vis_Hook *h)
2775 {
2776    h->delete_me = EINA_TRUE;
2777    if (_e_pol_vis_hooks_walking == 0)
2778      {
2779         _e_pol_vis_hooks[h->type] = eina_inlist_remove(_e_pol_vis_hooks[h->type],
2780                                                        EINA_INLIST_GET(h));
2781         E_FREE(h);
2782      }
2783    else
2784      _e_pol_vis_hooks_delete++;
2785 }
2786
2787 EINTERN double
2788 e_policy_visibility_timeout_get(void)
2789 {
2790    return e_config->deiconify_pending_timeout;
2791 }
2792
2793 EINTERN Eina_Bool
2794 e_policy_visibility_init(void)
2795 {
2796    E_Client *ec;
2797
2798    INF("Init Visibility Module");
2799    if (pol_vis)
2800      return EINA_TRUE;
2801
2802    pol_vis = E_NEW(E_Vis, 1);
2803    if (!pol_vis)
2804      {
2805         ERR("Failed to allocate 'E_Vis'");
2806         return EINA_FALSE;
2807      }
2808
2809    pol_vis->clients_hash = eina_hash_pointer_new((Eina_Free_Cb)_e_vis_client_del);
2810
2811    E_CLIENT_REVERSE_FOREACH(ec)
2812       _e_vis_client_add(ec);
2813
2814    _e_vis_event_init();
2815    _e_vis_update_forground_list();
2816
2817    return EINA_TRUE;
2818 }
2819
2820 EINTERN void
2821 e_policy_visibility_shutdown(void)
2822 {
2823    INF("Shutdown Visibility Module");
2824
2825    if (!pol_vis)
2826      return;
2827
2828    _e_vis_clist_clean(&pol_job_group_head, _e_vis_job_group_del);
2829
2830    E_FREE_FUNC(pol_vis->clients_hash, eina_hash_free);
2831    E_FREE_FUNC(pol_vis->idle_enter, ecore_idle_enterer_del);
2832    E_FREE_LIST(pol_vis->hooks, e_client_hook_del);
2833    E_FREE_LIST(pol_vis->handlers, ecore_event_handler_del);
2834    E_FREE_LIST(pol_vis->interceptors, e_comp_object_intercept_hook_del);
2835    E_FREE(pol_vis);
2836 }