e_comp_object: make an internal header
[platform/upstream/enlightenment.git] / src / bin / e_client.c
1 #include "e.h"
2 #include "e_client_intern.h"
3 #include "e_actions_intern.h"
4 #include "e_appinfo_intern.h"
5 #include "e_bindings_intern.h"
6 #include "e_uuid_store_intern.h"
7 #include "e_utils_intern.h"
8 #include "e_comp_canvas_intern.h"
9 #include "e_comp_wl_intern.h"
10 #include "e_comp_wl_subsurface_intern.h"
11 #include "e_comp_intern.h"
12 #include "e_input_intern.h"
13 #include "e_policy_intern.h"
14 #include "e_map_intern.h"
15 #include "e_policy_visibility_intern.h"
16 #include "e_comp_object_intern.h"
17
18 #define PRI(ec) ((E_Client_Private *)e_object_data_get(E_OBJECT(ec)))
19
20 #define API_ENTRY \
21    EINA_SAFETY_ON_NULL_RETURN(ec); \
22    E_Client_Private *priv = PRI(ec)
23
24 #define API_ENTRY_VAL(ret) \
25    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, ret); \
26    E_Client_Private *priv = PRI(ec)
27
28 typedef struct _E_Client_Private E_Client_Private;
29
30 struct _E_Client_Private
31 {
32    struct
33      {
34         struct wl_signal eval_pre_fetch;
35         struct wl_signal eval_fetch;
36         struct wl_signal eval_pre_post_fetch;
37         struct wl_signal eval_post_fetch;
38         struct wl_signal eval_pre_frame_assign;
39         struct wl_signal eval_post_frame_assign;
40         struct wl_signal eval_pre_new_client;
41         struct wl_signal eval_post_new_client;
42         struct wl_signal eval_visibility;
43         struct wl_signal eval_visibility_end;
44         struct wl_signal eval_end;
45
46         struct wl_signal move_begin;
47         struct wl_signal move_update;
48         struct wl_signal move_end;
49         struct wl_signal move_resize_begin;
50         struct wl_signal move_resize_update;
51         struct wl_signal move_resize_end;
52
53         struct wl_signal destroy;
54         struct wl_signal new_client;
55         struct wl_signal new_client_post;
56
57         struct wl_signal unredirect;
58         struct wl_signal redirect;
59
60         struct wl_signal aux_hint_change;
61         struct wl_signal window_role_change;
62         struct wl_signal transform_change;
63         struct wl_signal activate_done;
64
65         struct wl_signal mouse_in;
66         struct wl_signal mouse_out;
67         struct wl_signal mouse_down;
68
69         struct wl_signal focus_set;
70         struct wl_signal focus_unset;
71         struct wl_signal focus_defer_set;
72         struct wl_signal focus_latest_set;
73
74         struct wl_signal iconify;
75         struct wl_signal uniconify;
76         struct wl_signal maximize;
77         struct wl_signal unmaximize;
78         struct wl_signal fullscreen_pre;
79         struct wl_signal fullscreen;
80         struct wl_signal unfullscreen;
81
82         struct wl_signal move;
83
84         struct wl_signal set_layer;
85         struct wl_signal raise;
86         struct wl_signal lower;
87         struct wl_signal stack_below;
88         struct wl_signal stack_above;
89         struct wl_signal stack_transient_for_done;
90
91         struct wl_signal stick;
92         struct wl_signal unstick;
93
94 #ifdef REFACTOR_DESK_AREA
95         struct wl_signal get_above;
96         struct wl_signal get_below;
97         struct wl_signal get_visible_above;
98         struct wl_signal get_visible_below;
99         struct wl_signal subsurface_stack_update;
100 #endif
101      } events;
102
103    Eina_Bool hide_by_request;
104 };
105
106 static int _e_client_hooks_delete = 0;
107 static int _e_client_hooks_walking = 0;
108
109 static int _e_client_intercept_hooks_delete = 0;
110 static int _e_client_intercept_hooks_walking = 0;
111
112 E_API int E_EVENT_CLIENT_ADD = -1;
113 E_API int E_EVENT_CLIENT_REMOVE = -1;
114 E_API int E_EVENT_CLIENT_ZONE_SET = -1;
115 E_API int E_EVENT_CLIENT_DESK_SET = -1;
116 E_API int E_EVENT_CLIENT_RESIZE = -1;
117 E_API int E_EVENT_CLIENT_MOVE = -1;
118 E_API int E_EVENT_CLIENT_SHOW = -1;
119 E_API int E_EVENT_CLIENT_HIDE = -1;
120 E_API int E_EVENT_CLIENT_ICONIFY = -1;
121 E_API int E_EVENT_CLIENT_UNICONIFY = -1;
122 E_API int E_EVENT_CLIENT_STACK = -1;
123 E_API int E_EVENT_CLIENT_FOCUS_IN = -1;
124 E_API int E_EVENT_CLIENT_FOCUS_OUT = -1;
125 E_API int E_EVENT_CLIENT_PROPERTY = -1;
126 E_API int E_EVENT_CLIENT_FULLSCREEN = -1;
127 E_API int E_EVENT_CLIENT_UNFULLSCREEN = -1;
128 #ifdef _F_ZONE_WINDOW_ROTATION_
129 E_API int E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN = -1;
130 E_API int E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL = -1;
131 E_API int E_EVENT_CLIENT_ROTATION_CHANGE_END = -1;
132 E_API int E_EVENT_CLIENT_ROTATION_GEOMETRY_SET = -1;
133 #endif
134 E_API int E_EVENT_CLIENT_VISIBILITY_CHANGE = -1;
135 E_API int E_EVENT_CLIENT_BUFFER_CHANGE = -1;
136 E_API int E_EVENT_CLIENT_FOCUS_SKIP_SET = -1;
137 E_API int E_EVENT_CLIENT_FOCUS_SKIP_UNSET = -1;
138
139 static Eina_Hash *clients_hash[E_PIXMAP_TYPE_MAX] = {NULL}; // pixmap->client
140
141 static E_Client *ecmove = NULL;
142 static E_Client *ecresize = NULL;
143 static E_Client *action_client = NULL;
144
145 static Eina_Bool comp_grabbed = EINA_FALSE;
146
147 static Eina_List *handlers = NULL;
148 static Eina_List *hooks = NULL;
149
150 static Ecore_Event_Handler *action_handler_mouse = NULL;
151 static Ecore_Timer *action_timer = NULL;
152 static Eina_Rectangle action_orig = {0, 0, 0, 0};
153
154 static E_Client_Resize_Object_Create_Cb _e_client_resize_object_create_cb = NULL;
155
156 EINTERN void e_client_focused_set(E_Client *ec);
157 static void _e_client_transient_for_group_make(E_Client *ec, Eina_List **list);
158 static Evas_Object *_e_client_resize_object_create(E_Client *ec);
159 static void _e_client_resize_object_del(E_Client *ec);
160 static void _e_client_stay_within_canvas(E_Client *ec, int x, int y, int *new_x, int *new_y);
161 static void _e_client_stay_within_canvas_margin(E_Client *ec, int x, int y, int *new_x, int *new_y);
162
163 static Eina_Inlist *_e_client_hooks[] =
164 {
165    [E_CLIENT_HOOK_EVAL_PRE_FETCH] = NULL,
166    [E_CLIENT_HOOK_EVAL_FETCH] = NULL,
167    [E_CLIENT_HOOK_EVAL_PRE_POST_FETCH] = NULL,
168    [E_CLIENT_HOOK_EVAL_POST_FETCH] = NULL,
169    [E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN] = NULL,
170    [E_CLIENT_HOOK_EVAL_POST_FRAME_ASSIGN] = NULL,
171    [E_CLIENT_HOOK_EVAL_PRE_NEW_CLIENT] = NULL,
172    [E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT] = NULL,
173    [E_CLIENT_HOOK_EVAL_END] = NULL,
174    [E_CLIENT_HOOK_FOCUS_SET] = NULL,
175    [E_CLIENT_HOOK_FOCUS_UNSET] = NULL,
176    [E_CLIENT_HOOK_NEW_CLIENT] = NULL,
177    [E_CLIENT_HOOK_MOVE_BEGIN] = NULL,
178    [E_CLIENT_HOOK_MOVE_UPDATE] = NULL,
179    [E_CLIENT_HOOK_MOVE_END] = NULL,
180    [E_CLIENT_HOOK_RESIZE_BEGIN] = NULL,
181    [E_CLIENT_HOOK_RESIZE_UPDATE] = NULL,
182    [E_CLIENT_HOOK_RESIZE_END] = NULL,
183    [E_CLIENT_HOOK_FULLSCREEN_PRE] = NULL,
184    [E_CLIENT_HOOK_DEL] = NULL,
185    [E_CLIENT_HOOK_UNREDIRECT] = NULL,
186    [E_CLIENT_HOOK_REDIRECT] = NULL,
187 #ifdef _F_E_CLIENT_NEW_CLIENT_POST_HOOK_
188    [E_CLIENT_HOOK_NEW_CLIENT_POST] = NULL,
189 #endif
190    [E_CLIENT_HOOK_EVAL_VISIBILITY] = NULL,
191    [E_CLIENT_HOOK_ICONIFY] = NULL,
192    [E_CLIENT_HOOK_UNICONIFY] = NULL,
193    [E_CLIENT_HOOK_AUX_HINT_CHANGE] = NULL,
194    [E_CLIENT_HOOK_WINDOW_ROLE_CHANGE] = NULL,
195    [E_CLIENT_HOOK_TRANSFORM_CHANGE] = NULL,
196    [E_CLIENT_HOOK_ACTIVATE_DONE] = NULL,
197    [E_CLIENT_HOOK_EVAL_VISIBILITY_END] = NULL,
198 };
199
200 static Eina_Inlist *_e_client_intercept_hooks[] =
201 {
202    [E_CLIENT_INTERCEPT_HOOK_FOCUS_REVERT] = NULL,
203    [E_CLIENT_INTERCEPT_HOOK_AUTO_PLACEMENT] = NULL,
204 };
205
206 ///////////////////////////////////////////
207
208 static void
209 _e_client_hooks_clean(void)
210 {
211    Eina_Inlist *l;
212    E_Client_Hook *ch;
213    unsigned int x;
214
215    for (x = 0; x < E_CLIENT_HOOK_LAST; x++)
216      EINA_INLIST_FOREACH_SAFE(_e_client_hooks[x], l, ch)
217        {
218           if (!ch->delete_me) continue;
219           _e_client_hooks[x] = eina_inlist_remove(_e_client_hooks[x], EINA_INLIST_GET(ch));
220           free(ch);
221        }
222 }
223
224 static Eina_Bool
225 _e_client_hook_call(E_Client_Hook_Point hookpoint, E_Client *ec)
226 {
227    E_Client_Hook *ch;
228
229    e_object_ref(E_OBJECT(ec));
230    _e_client_hooks_walking++;
231    EINA_INLIST_FOREACH(_e_client_hooks[hookpoint], ch)
232      {
233         if (ch->delete_me) continue;
234         ch->func(ch->data, ec);
235         if ((hookpoint != E_CLIENT_HOOK_DEL) &&
236           (hookpoint != E_CLIENT_HOOK_MOVE_END) &&
237           (hookpoint != E_CLIENT_HOOK_RESIZE_END) &&
238           (hookpoint != E_CLIENT_HOOK_FOCUS_UNSET) &&
239           e_object_is_del(E_OBJECT(ec)))
240           break;
241      }
242    _e_client_hooks_walking--;
243    if ((_e_client_hooks_walking == 0) && (_e_client_hooks_delete > 0))
244      _e_client_hooks_clean();
245    return !!e_object_unref(E_OBJECT(ec));
246 }
247
248 ///////////////////////////////////////////
249
250 static void
251 _e_client_intercept_hooks_clean(void)
252 {
253    Eina_Inlist *l;
254    E_Client_Intercept_Hook *ch;
255    unsigned int x;
256
257    for (x = 0; x < E_CLIENT_INTERCEPT_HOOK_LAST; x++)
258      EINA_INLIST_FOREACH_SAFE(_e_client_intercept_hooks[x], l, ch)
259        {
260           if (!ch->delete_me) continue;
261           _e_client_intercept_hooks[x] =
262              eina_inlist_remove(_e_client_intercept_hooks[x], EINA_INLIST_GET(ch));
263           free(ch);
264        }
265 }
266
267 static Eina_Bool
268 _e_client_intercept_hook_call(E_Client_Intercept_Hook_Point hookpoint, E_Client *ec)
269 {
270    E_Client_Intercept_Hook *ch;
271    Eina_Bool ret = EINA_TRUE;
272
273    if (e_object_is_del(E_OBJECT(ec)))
274      {
275         if (hookpoint != E_CLIENT_INTERCEPT_HOOK_FOCUS_REVERT)
276           {
277              return ret;
278           }
279      }
280
281    e_object_ref(E_OBJECT(ec));
282    _e_client_intercept_hooks_walking++;
283    EINA_INLIST_FOREACH(_e_client_intercept_hooks[hookpoint], ch)
284      {
285         if (ch->delete_me) continue;
286         if (!(ch->func(ch->data, ec)))
287           {
288              ret = EINA_FALSE;
289              break;
290           }
291      }
292    _e_client_intercept_hooks_walking--;
293    if ((_e_client_intercept_hooks_walking == 0) &&
294        (_e_client_intercept_hooks_delete > 0))
295      _e_client_intercept_hooks_clean();
296
297    e_object_unref(E_OBJECT(ec));
298    return ret;
299 }
300
301 static void
302 _e_client_event_simple_free(void *d EINA_UNUSED, E_Event_Client *ev)
303 {
304    UNREFD(ev->ec, 3);
305    e_object_unref(E_OBJECT(ev->ec));
306    free(ev);
307 }
308
309 static void
310 _e_client_event_simple(E_Client *ec, int type)
311 {
312    E_Event_Client *ev;
313
314    ev = E_NEW(E_Event_Client, 1);
315    if (!ev) return;
316    ev->ec = ec;
317    REFD(ec, 3);
318    e_object_ref(E_OBJECT(ec));
319    ecore_event_add(type, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
320 }
321
322 static void
323 _e_client_event_add(E_Client *ec)
324 {
325    if (ec->reg_ev.add)
326      return;
327
328    ec->reg_ev.add = EINA_TRUE;
329    ELOGF("COMP", "SEND E_EVENT_CLIENT_ADD event", ec);
330    _e_client_event_simple(ec, E_EVENT_CLIENT_ADD);
331 }
332
333 static void
334 _e_client_event_remove(E_Client *ec)
335 {
336    if (!ec->reg_ev.add)
337      return;
338
339    ec->reg_ev.add = EINA_FALSE;
340    ELOGF("COMP", "SEND E_EVENT_CLIENT_REMOVE event", ec);
341    _e_client_event_simple(ec, E_EVENT_CLIENT_REMOVE);
342 }
343
344 static void
345 _e_client_event_show(E_Client *ec)
346 {
347    if (ec->reg_ev.show)
348      return;
349
350    ec->reg_ev.show = EINA_TRUE;
351    _e_client_event_simple(ec, E_EVENT_CLIENT_SHOW);
352 }
353
354 static void
355 _e_client_event_hide(E_Client *ec)
356 {
357    if (!ec->reg_ev.show)
358      return;
359
360    ec->reg_ev.show = EINA_FALSE;
361    _e_client_event_simple(ec, E_EVENT_CLIENT_HIDE);
362 }
363
364 static void
365 _e_client_event_property(E_Client *ec, int prop)
366 {
367    E_Event_Client_Property *ev;
368
369    ev = E_NEW(E_Event_Client_Property, 1);
370    if (!ev) return;
371    ev->ec = ec;
372    ev->property = prop;
373    REFD(ec, 33);
374    e_object_ref(E_OBJECT(ec));
375    ecore_event_add(E_EVENT_CLIENT_PROPERTY, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
376 }
377
378 ////////////////////////////////////////////////
379
380 static int
381 _e_client_action_input_win_del(void)
382 {
383    if (!comp_grabbed) return 0;
384
385    e_comp_ungrab_input(1, 1);
386    comp_grabbed = 0;
387    return 1;
388 }
389
390 static void
391 _e_client_action_finish(void)
392 {
393    if (comp_grabbed)
394      _e_client_action_input_win_del();
395
396    E_FREE_FUNC(action_timer, ecore_timer_del);
397    E_FREE_FUNC(action_handler_mouse, ecore_event_handler_del);
398    if (action_client)
399      {
400         action_client->keyboard_resizing = 0;
401      }
402    action_client = NULL;
403 }
404
405 static void
406 _e_client_transform_point_transform(int cx, int cy, double angle, int x, int y, int *tx, int *ty)
407 {
408    double s = sin(angle * M_PI / 180);
409    double c = cos(angle * M_PI / 180);
410    int rx, ry;
411
412    x -= cx;
413    y -= cy;
414
415    rx = x * c + y * s;
416    ry = - x * s + y * c;
417
418    rx += cx;
419    ry += cy;
420
421    *tx = rx;
422    *ty = ry;
423 }
424
425 static void
426 _e_client_transform_geometry_save(E_Client *ec, E_Map *map)
427 {
428    int i;
429
430    if (!map) return;
431
432    for (i = 0; i < 4; i ++)
433      {
434         e_map_point_precise_coord_get(map, i,
435                                       &ec->transform.saved[i].x,
436                                       &ec->transform.saved[i].y,
437                                       &ec->transform.saved[i].z);
438      }
439 }
440
441 static void
442 _e_client_transform_resize(E_Client *ec)
443 {
444    E_Map *map;
445    int cx, cy;
446    double dx = 0, dy = 0;
447    double px[4], py[4];
448    int pw, ph;
449    int i;
450
451    if (!ec->transformed) return;
452
453    if (!e_pixmap_size_get(ec->pixmap, &pw, &ph))
454      {
455         pw = ec->client.w;
456         ph = ec->client.h;
457      }
458
459    cx = ec->client.x + pw / 2;
460    cy = ec->client.y + ph / 2;
461
462    /* step 1: Rotate resized object and get map points */
463    map = e_map_new_with_direct_render(ec->transform_core.direct_render);
464    e_map_util_points_populate_from_geometry(map,
465                                             ec->client.x, ec->client.y,
466                                             pw, ph,
467                                             0);
468    e_map_util_rotate(map, ec->transform.angle, cx, cy);
469    e_map_util_zoom(map, ec->transform.zoom, ec->transform.zoom, cx, cy);
470
471    for (i = 0; i < 4; i++)
472      e_map_point_precise_coord_get(map, i, &px[i], &py[i], NULL);
473
474    e_map_free(map);
475
476    /* step 2: get adjusted values to keep up fixed position according
477     * to resize mode */
478    switch (ec->resize_mode)
479      {
480       case E_POINTER_RESIZE_R:
481       case E_POINTER_RESIZE_BR:
482          dx = ec->transform.saved[0].x - px[0];
483          dy = ec->transform.saved[0].y - py[0];
484          break;
485       case E_POINTER_RESIZE_BL:
486       case E_POINTER_RESIZE_B:
487          dx = ec->transform.saved[1].x - px[1];
488          dy = ec->transform.saved[1].y - py[1];
489          break;
490       case E_POINTER_RESIZE_TL:
491       case E_POINTER_RESIZE_L:
492          dx = ec->transform.saved[2].x - px[2];
493          dy = ec->transform.saved[2].y - py[2];
494          break;
495       case E_POINTER_RESIZE_T:
496       case E_POINTER_RESIZE_TR:
497          dx = ec->transform.saved[3].x - px[3];
498          dy = ec->transform.saved[3].y - py[3];
499          break;
500       default:
501          break;
502      }
503
504    ec->transform.adjusted.x = dx;
505    ec->transform.adjusted.y = dy;
506
507    /* step 3: set each points of the quadrangle */
508    map = e_map_new_with_direct_render(ec->transform_core.direct_render);
509    e_map_util_points_populate_from_object_full(map, ec->frame, 0);
510
511    for (i = 0; i < 4; i++)
512       e_map_point_precise_coord_set(map, i, px[i] + dx, py[i] + dy, 0);
513
514    e_client_map_set(ec, map);
515    e_client_map_enable_set(ec, EINA_TRUE);
516    e_map_free(map);
517 }
518
519 static void
520 _e_client_transform_resize_handle(E_Client *ec)
521 {
522
523    int new_x, new_y, new_w, new_h;
524    int org_w, org_h;
525    int button_id;
526    int cx, cy;
527    Evas_Point current, moveinfo;
528    E_Zone *zone;
529
530    if (e_object_is_del(E_OBJECT(ec))) return;
531    if (e_client_util_ignored_get(ec)) return;
532    if (!ec->transformed) return;
533
534    zone = e_comp_zone_find_by_ec(ec);
535    if (!zone) return;
536
537    button_id = ec->moveinfo.down.button;
538
539    org_w = ec->mouse.last_down[button_id - 1].w;
540    org_h = ec->mouse.last_down[button_id - 1].h;
541
542    new_w = ec->client.w;
543    new_h = ec->client.h;
544    new_x = ec->client.x;
545    new_y = ec->client.y;
546
547    /* step 1: get center coordinate its' based on original object geometry*/
548    cx = ec->client.x + org_w / 2;
549    cy = ec->client.y + org_h / 2;
550
551    /* step 2: transform coordinates of mouse position
552     * subtract adjusted value from mouse position is needed */
553    current.x = ec->mouse.current.mx - ec->transform.adjusted.x;
554    current.y = ec->mouse.current.my - ec->transform.adjusted.y;
555    moveinfo.x = ec->moveinfo.down.mx - ec->transform.adjusted.x;
556    moveinfo.y = ec->moveinfo.down.my - ec->transform.adjusted.y;
557
558    _e_client_transform_point_transform(cx, cy, ec->transform.angle,
559                                        current.x, current.y,
560                                        &current.x, &current.y);
561    _e_client_transform_point_transform(cx, cy, ec->transform.angle,
562                                        moveinfo.x, moveinfo.y,
563                                        &moveinfo.x, &moveinfo.y);
564
565    /* step 3: calculate new size */
566    if ((ec->resize_mode == E_POINTER_RESIZE_TR) ||
567        (ec->resize_mode == E_POINTER_RESIZE_R) ||
568        (ec->resize_mode == E_POINTER_RESIZE_BR))
569      {
570         if ((button_id >= 1) && (button_id <= 3))
571           new_w = org_w + (current.x - moveinfo.x);
572         else
573           new_w = ec->moveinfo.down.w + (current.x - moveinfo.x);
574      }
575    else if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
576             (ec->resize_mode == E_POINTER_RESIZE_L) ||
577             (ec->resize_mode == E_POINTER_RESIZE_BL))
578      {
579         if ((button_id >= 1) && (button_id <= 3))
580           new_w = org_w - (current.x - moveinfo.x);
581         else
582           new_w = ec->moveinfo.down.w - (current.x - moveinfo.x);
583      }
584
585    if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
586        (ec->resize_mode == E_POINTER_RESIZE_T) ||
587        (ec->resize_mode == E_POINTER_RESIZE_TR))
588      {
589         if ((button_id >= 1) && (button_id <= 3))
590           new_h = org_h - (current.y - moveinfo.y);
591         else
592           new_h = ec->moveinfo.down.h - (current.y - moveinfo.y);
593      }
594    else if ((ec->resize_mode == E_POINTER_RESIZE_BL) ||
595             (ec->resize_mode == E_POINTER_RESIZE_B) ||
596             (ec->resize_mode == E_POINTER_RESIZE_BR))
597      {
598         if ((button_id >= 1) && (button_id <= 3))
599           new_h = org_h + (current.y - moveinfo.y);
600         else
601           new_h = ec->moveinfo.down.h + (current.y - moveinfo.y);
602      }
603
604    new_w = MIN(new_w, zone->w);
605    new_h = MIN(new_h, zone->h);
606
607    /* step 4: move to new position */
608    if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
609        (ec->resize_mode == E_POINTER_RESIZE_L) ||
610        (ec->resize_mode == E_POINTER_RESIZE_BL))
611      new_x += (new_w - org_w);
612    if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
613        (ec->resize_mode == E_POINTER_RESIZE_T) ||
614        (ec->resize_mode == E_POINTER_RESIZE_TR))
615      new_y += (new_h - org_h);
616
617    /* step 5: set geometry to new value */
618    evas_object_geometry_set(ec->frame, new_x, new_y, new_w, new_h);
619 }
620
621 void
622 _e_client_transform_resize_begin(E_Client *ec)
623 {
624    E_Map *map;
625    if (!ec->transformed) return;
626
627    map = e_client_map_get(ec);
628    _e_client_transform_geometry_save(ec, map);
629    e_map_free(map);
630 }
631
632 void
633 _e_client_transform_resize_end(E_Client *ec)
634 {
635    E_Map *map;
636    int new_x = 0, new_y = 0;
637    int cx, cy, pw, ph;
638
639    if (!ec->transformed) return;
640
641    map = e_client_map_get(ec);
642    if (!map) return;
643
644    if (!e_pixmap_size_get(ec->pixmap, &pw, &ph))
645      {
646         pw = ec->client.w;
647         ph = ec->client.h;
648      }
649
650    cx = ec->client.x + pw / 2 + ec->transform.adjusted.x;
651    cy = ec->client.y + ph / 2 + ec->transform.adjusted.y;
652
653    if (ec->transform.zoom != 1.0)
654      {
655         E_Map *tmp_map;
656
657         tmp_map = e_map_dup(map);
658         e_map_util_zoom(tmp_map,
659                            1 / ec->transform.zoom,
660                            1 / ec->transform.zoom,
661                            cx, cy);
662
663         _e_client_transform_geometry_save(ec, tmp_map);
664         e_map_free(tmp_map);
665      }
666    else
667      {
668         _e_client_transform_geometry_save(ec, map);
669      }
670
671    /* move original object to adjusted position after resizing */
672    _e_client_transform_point_transform(cx, cy,
673                                        ec->transform.angle,
674                                        ec->transform.saved[0].x,
675                                        ec->transform.saved[0].y,
676                                        &new_x, &new_y);
677    e_client_util_move_without_frame(ec, new_x, new_y);
678    e_map_util_object_move_sync_set(map, EINA_TRUE);
679    e_map_free(map);
680 }
681
682 static void
683 _e_client_transform_move_end(E_Client *ec)
684 {
685
686    int i;
687    double dx, dy, px, py;
688    E_Map *map;
689
690    if (!ec->transformed) return;
691
692    map = e_client_map_get(ec);
693    if (!map) return;
694
695    if (ec->transform.zoom != 1.0)
696      {
697         e_map_point_precise_coord_get(map, 0, &px, &py, NULL);
698
699         dx = px - ec->transform.saved[0].x;
700         dy = py - ec->transform.saved[0].y;
701
702         for (i = 0; i < 4; i++)
703           {
704              ec->transform.saved[i].x += dx;
705              ec->transform.saved[i].y += dy;
706           }
707      }
708    else
709      _e_client_transform_geometry_save(ec, map);
710    e_map_free(map);
711 }
712
713 EINTERN Eina_Bool
714 e_client_intercept_hook_focus_revert_call(E_Client *ec)
715 {
716   // no need to call the intercept hook if ec is NULL.
717   if (!ec) return EINA_FALSE;
718
719   if (!_e_client_intercept_hook_call(E_CLIENT_INTERCEPT_HOOK_FOCUS_REVERT, ec))
720     {
721        ELOGF("FOCUS", "E_CLIENT_INTERCEPT_HOOK_FOCUS_REVERT Intercepted.", ec);
722        return EINA_TRUE;
723     }
724
725   return EINA_FALSE;
726 }
727
728 EINTERN E_Client *
729 e_client_check_fully_contain_by_above(E_Client *ec, Eina_Bool check_layer)
730 {
731    E_Client *above = NULL;
732    E_Zone *zone = NULL;
733    int x = 0, y = 0, w = 0, h = 0;
734    int ax = 0, ay = 0, aw = 0, ah = 0;
735
736    if (!ec) return NULL;
737
738    e_client_geometry_get(ec, &x, &y, &w, &h);
739
740    zone = e_comp_zone_find_by_ec(ec);
741    if (zone)
742      E_RECTS_CLIP_TO_RECT(x, y, w, h, zone->x, zone->y, zone->w, zone->h);
743
744    above = e_client_above_get(ec);
745    while (above)
746      {
747         if ((check_layer) &&
748             (above->layer <= ec->layer))
749           {
750              above = e_client_above_get(above);
751              continue;
752           }
753
754         if ((!e_object_is_del(E_OBJECT(above))) &&
755             (!e_client_util_ignored_get(above)) &&
756             (above->visible) &&
757             (!above->iconic || e_policy_visibility_client_is_uniconic(above)) &&
758             (!above->bg_state) &&
759             (!above->argb) &&
760             (!above->visibility.force_obscured) &&
761             (above->frame))
762           {
763              e_client_geometry_get(above, &ax, &ay, &aw, &ah);
764              if (E_CONTAINS(ax, ay, aw, ah, x, y, w, h))
765                break;
766           }
767         above = e_client_above_get(above);
768      }
769
770    return above;
771 }
772
773 EINTERN E_Client *
774 e_client_check_obscured_by_children_group(E_Client *ec)
775 {
776    E_Client *cec = NULL;
777    Eina_List *transients = NULL, *l = NULL;
778
779    _e_client_transient_for_group_make(ec, &transients);
780    if (!transients) return NULL;
781
782    EINA_LIST_FOREACH(transients, l, cec)
783      {
784         if (E_CONTAINS(cec->x, cec->y, cec->w, cec->h, ec->x, ec->y, ec->w, ec->h))
785           {
786             if (!cec->argb) break;
787             if (cec->visibility.opaque > 0) break;
788           }
789      }
790
791    eina_list_free(transients);
792
793    return cec;
794 }
795
796 EINTERN Eina_Bool
797 e_client_check_really_iconified(E_Client *ec)
798 {
799    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
800
801    if (!ec->iconic) return EINA_FALSE;
802
803    return ((!e_policy_visibility_client_is_uniconic(ec) &&
804             !e_policy_visibility_client_is_uniconify_render_running(ec)) ||
805            (e_client_is_iconified_by_client(ec)));
806 }
807
808 static void
809 _e_client_event_focus_skip_set(E_Client *ec, Eina_Bool by_client)
810 {
811    E_Event_Client_Focus_Skip_Set *ev;
812
813    ev = E_NEW(E_Event_Client_Focus_Skip_Set, 1);
814    if (!ev) return;
815
816    ev->ec = ec;
817    ev->by_client = by_client;
818    e_object_ref(E_OBJECT(ec));
819
820    ecore_event_add(E_EVENT_CLIENT_FOCUS_SKIP_SET, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
821 }
822
823 static void
824 _e_client_event_focus_skip_unset(E_Client *ec, Eina_Bool by_client)
825 {
826    E_Event_Client_Focus_Skip_Unset *ev;
827
828    ev = E_NEW(E_Event_Client_Focus_Skip_Unset, 1);
829    if (!ev) return;
830
831    ev->ec = ec;
832    ev->by_client = by_client;
833    e_object_ref(E_OBJECT(ec));
834
835    ecore_event_add(E_EVENT_CLIENT_FOCUS_SKIP_UNSET, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
836 }
837
838 E_API void
839 e_client_focus_skip_set(E_Client *ec, Eina_Bool skip, Eina_Bool by_client)
840 {
841    if (!ec) return;
842
843    if (skip)
844      {
845         if (ec->icccm.accepts_focus)
846           {
847              ELOGF("TZPOL", "FOCUS|SKIP SET (by_client:%d)", ec, by_client);
848              ec->icccm.accepts_focus = ec->icccm.take_focus = 0;
849              ec->changes.accepts_focus = 1;
850              EC_CHANGED(ec);
851
852              _e_client_event_focus_skip_set(ec, by_client);
853           }
854      }
855    else
856      {
857         if (!ec->icccm.accepts_focus)
858           {
859              ELOGF("TZPOL", "FOCUS|SKIP UNSET (by_client:%d)", ec, by_client);
860              ec->icccm.accepts_focus = ec->icccm.take_focus = 1;
861              ec->changes.accepts_focus = 1;
862              EC_CHANGED(ec);
863
864              _e_client_event_focus_skip_unset(ec, by_client);
865           }
866      }
867 }
868
869 EINTERN Eina_Bool
870 e_client_check_above_focused(E_Client *ec)
871 {
872    E_Client *focus = NULL;
873    E_Client *above = NULL;
874
875    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
876
877    focus = e_client_focused_get();
878    if (!focus) return EINA_FALSE;
879
880    above = e_client_above_get(ec);
881    while (above)
882      {
883         if (above == focus)
884           return EINA_TRUE;
885
886         above = e_client_above_get(above);
887      }
888
889    return EINA_FALSE;
890 }
891
892 static Eina_Bool
893 _e_client_private_init(E_Client *ec)
894 {
895    E_Client_Private *priv;
896
897    priv = E_NEW(E_Client_Private, 1);
898    if (!priv)
899      return EINA_FALSE;
900
901    wl_signal_init(&priv->events.eval_pre_fetch);
902    wl_signal_init(&priv->events.eval_fetch);
903    wl_signal_init(&priv->events.eval_pre_post_fetch);
904    wl_signal_init(&priv->events.eval_post_fetch);
905    wl_signal_init(&priv->events.eval_pre_frame_assign);
906    wl_signal_init(&priv->events.eval_post_frame_assign);
907    wl_signal_init(&priv->events.eval_pre_new_client);
908    wl_signal_init(&priv->events.eval_post_new_client);
909    wl_signal_init(&priv->events.eval_visibility);
910    wl_signal_init(&priv->events.eval_visibility_end);
911    wl_signal_init(&priv->events.eval_end);
912    wl_signal_init(&priv->events.move_begin);
913    wl_signal_init(&priv->events.move_update);
914    wl_signal_init(&priv->events.move_end);
915    wl_signal_init(&priv->events.move_resize_begin);
916    wl_signal_init(&priv->events.move_resize_update);
917    wl_signal_init(&priv->events.move_resize_end);
918    wl_signal_init(&priv->events.destroy);
919    wl_signal_init(&priv->events.new_client);
920    wl_signal_init(&priv->events.new_client_post);
921    wl_signal_init(&priv->events.unredirect);
922    wl_signal_init(&priv->events.redirect);
923    wl_signal_init(&priv->events.aux_hint_change);
924    wl_signal_init(&priv->events.window_role_change);
925    wl_signal_init(&priv->events.transform_change);
926    wl_signal_init(&priv->events.activate_done);
927    wl_signal_init(&priv->events.mouse_in);
928    wl_signal_init(&priv->events.mouse_out);
929    wl_signal_init(&priv->events.mouse_down);
930    wl_signal_init(&priv->events.focus_set);
931    wl_signal_init(&priv->events.focus_unset);
932    wl_signal_init(&priv->events.focus_defer_set);
933    wl_signal_init(&priv->events.focus_latest_set);
934    wl_signal_init(&priv->events.iconify);
935    wl_signal_init(&priv->events.uniconify);
936    wl_signal_init(&priv->events.maximize);
937    wl_signal_init(&priv->events.unmaximize);
938    wl_signal_init(&priv->events.fullscreen_pre);
939    wl_signal_init(&priv->events.fullscreen);
940    wl_signal_init(&priv->events.unfullscreen);
941    wl_signal_init(&priv->events.move);
942    wl_signal_init(&priv->events.set_layer);
943    wl_signal_init(&priv->events.raise);
944    wl_signal_init(&priv->events.lower);
945    wl_signal_init(&priv->events.stack_below);
946    wl_signal_init(&priv->events.stack_above);
947    wl_signal_init(&priv->events.stack_transient_for_done);
948    wl_signal_init(&priv->events.stick);
949    wl_signal_init(&priv->events.unstick);
950 #ifdef REFACTOR_DESK_AREA
951    wl_signal_init(&priv->events.get_above);
952    wl_signal_init(&priv->events.get_below);
953    wl_signal_init(&priv->events.get_visible_above);
954    wl_signal_init(&priv->events.get_visible_below);
955    wl_signal_init(&priv->events.subsurface_stack_update);
956 #endif
957
958    e_object_data_set(E_OBJECT(ec), priv);
959
960    return EINA_TRUE;
961 }
962
963 static void
964 _e_client_private_finish(E_Client *ec)
965 {
966    E_Client_Private *priv;
967
968    priv = PRI(ec);
969    e_object_data_set(E_OBJECT(ec), NULL);
970
971    free(priv);
972 }
973
974 static void
975 _e_client_free(E_Client *ec)
976 {
977    g_rec_mutex_lock(&e_comp->ec_list_mutex);
978
979    e_comp_object_redirected_set(ec->frame, 0);
980    e_comp_object_render_update_del(ec->frame);
981
982    E_OBJECT(ec)->references++;
983
984    if (ec->new_client)
985      e_comp->new_clients--;
986
987    if (ec->e.state.video_parent && ec->e.state.video_parent_client)
988      {
989         ec->e.state.video_parent_client->e.state.video_child =
990           eina_list_remove(ec->e.state.video_parent_client->e.state.video_child, ec);
991      }
992    if (ec->e.state.video_child)
993      {
994         E_Client *tmp;
995
996         EINA_LIST_FREE(ec->e.state.video_child, tmp)
997           tmp->e.state.video_parent_client = NULL;
998      }
999    E_FREE_FUNC(ec->kill_timer, ecore_timer_del);
1000
1001    E_FREE_FUNC(ec->map_timer, ecore_timer_del);
1002
1003    ec->transients = eina_list_free(ec->transients);
1004    eina_stringshare_replace(&ec->border.name, NULL);
1005    eina_stringshare_replace(&ec->bordername, NULL);
1006    eina_stringshare_replace(&ec->icccm.name, NULL);
1007 #if defined(__cplusplus) || defined(c_plusplus)
1008    eina_stringshare_replace(&ec->icccm.cpp_class, NULL);
1009 #else
1010    eina_stringshare_replace(&ec->icccm.class, NULL);
1011 #endif
1012    eina_stringshare_replace(&ec->icccm.title, NULL);
1013    eina_stringshare_replace(&ec->icccm.window_role, NULL);
1014    eina_stringshare_replace(&ec->netwm.name, NULL);
1015
1016    E_FREE_FUNC(ec->frame, evas_object_del);
1017
1018    E_OBJECT(ec)->references--;
1019    ELOGF("COMP", "CLIENT FREE", ec);
1020
1021    e_uuid_store_entry_del(ec->uuid);
1022
1023    _e_client_private_finish(ec);
1024    free(ec);
1025
1026    g_rec_mutex_unlock(&e_comp->ec_list_mutex);
1027 }
1028
1029 static void
1030 _e_client_del(E_Client *ec)
1031 {
1032    E_Client *child;
1033    E_Pixmap_Type type;
1034
1035    g_rec_mutex_lock(&e_comp->ec_list_mutex);
1036
1037    ec->changed = 0;
1038
1039    if (ec == e_comp_object_dim_client_get())
1040      {
1041         INF("[DIM] client deleted\n");
1042         e_comp_object_dim_client_set(NULL);
1043      }
1044
1045    if (ec->cur_mouse_action)
1046      {
1047         if (ec->cur_mouse_action->func.end)
1048           ec->cur_mouse_action->func.end(E_OBJECT(ec), "");
1049      }
1050    if (action_client == ec) _e_client_action_finish();
1051
1052    if (!stopping)
1053      {
1054         e_client_comp_hidden_set(ec, 1);
1055         evas_object_pass_events_set(ec->frame, 1);
1056      }
1057
1058    E_FREE_FUNC(ec->ping_poller, ecore_poller_del);
1059
1060    wl_signal_emit_mutable(&PRI(ec)->events.destroy, NULL);
1061
1062    /* must be called before parent/child clear */
1063    _e_client_hook_call(E_CLIENT_HOOK_DEL, ec);
1064
1065    _e_client_event_remove(ec);
1066
1067    ELOGF("COMP", "CLIENT DEL", ec);
1068
1069    if (ec->parent)
1070      {
1071         ec->parent->transients = eina_list_remove(ec->parent->transients, ec);
1072         ec->parent = NULL;
1073      }
1074    EINA_LIST_FREE(ec->transients, child)
1075      child->parent = NULL;
1076
1077    type = e_pixmap_type_get(ec->pixmap);
1078    if (type < E_PIXMAP_TYPE_MAX)
1079      eina_hash_del_by_key(clients_hash[type], &ec->pixmap);
1080    e_comp->clients = eina_list_remove(e_comp->clients, ec);
1081    e_comp_object_render_update_del(ec->frame);
1082    e_comp_post_update_purge(ec);
1083    if (e_pixmap_free(ec->pixmap))
1084      e_pixmap_client_set(ec->pixmap, NULL);
1085    ec->pixmap = NULL;
1086
1087    // base_output_resolution
1088    e_util_transform_del(ec->base_output_resolution.transform);
1089    ec->base_output_resolution.transform = NULL;
1090    E_FREE_FUNC(ec->base_output_resolution.hook_subsurf_create, e_comp_wl_hook_del);
1091
1092    if (ec->transform_core.transform_list)
1093      {
1094         E_Util_Transform *transform;
1095
1096         EINA_LIST_FREE(ec->transform_core.transform_list, transform)
1097           {
1098              e_util_transform_unref(transform);
1099           }
1100      }
1101
1102    ec->transform_core.result.enable = EINA_FALSE;
1103
1104    _e_client_resize_object_del(ec);
1105
1106    e_comp_visibility_calculation_set(EINA_TRUE);
1107
1108    g_rec_mutex_unlock(&e_comp->ec_list_mutex);
1109 }
1110
1111 ///////////////////////////////////////////
1112
1113 static Eina_Bool
1114 _e_client_cb_kill_timer(void *data)
1115 {
1116    E_Client *ec = data;
1117
1118 // dont wait until it's hung -
1119 //   if (ec->hung)
1120 //     {
1121    if (ec->netwm.pid > 1)
1122      kill(ec->netwm.pid, SIGKILL);
1123 //     }
1124    ec->kill_timer = NULL;
1125    return ECORE_CALLBACK_CANCEL;
1126 }
1127
1128 static Eina_Bool
1129 _e_client_cb_ping_poller(void *data)
1130 {
1131    E_Client *ec;
1132
1133    ec = data;
1134    if (e_object_is_del(E_OBJECT(ec)))
1135      {
1136         ec->ping_poller = NULL;
1137         return ECORE_CALLBACK_CANCEL;
1138      }
1139
1140    if (ec->ping_ok)
1141      {
1142         if (ec->hung)
1143           {
1144              ec->hung = 0;
1145              evas_object_smart_callback_call(ec->frame, "unhung", NULL);
1146              E_FREE_FUNC(ec->kill_timer, ecore_timer_del);
1147           }
1148      }
1149    else
1150      {
1151         /* if time between last ping and now is greater
1152          * than half the ping interval... */
1153         if ((ecore_loop_time_get() - ec->ping) >
1154             ((e_config->ping_clients_interval *
1155               ecore_poller_poll_interval_get(ECORE_POLLER_CORE)) / 2.0))
1156           {
1157              if (!ec->hung)
1158                {
1159                   ec->hung = 1;
1160                   evas_object_smart_callback_call(ec->frame, "hung", NULL);
1161                   /* FIXME: if below dialog is up - hide it now */
1162                }
1163              if (ec->delete_requested)
1164                {
1165                   /* FIXME: pop up dialog saying app is hung - kill client, or pid */
1166                   e_client_act_kill_begin(ec);
1167                }
1168           }
1169      }
1170    ec->ping_poller = NULL;
1171    e_client_ping(ec);
1172    return ECORE_CALLBACK_CANCEL;
1173 }
1174
1175 ///////////////////////////////////////////
1176
1177 static int
1178 _e_client_action_input_win_new(void)
1179 {
1180    if (comp_grabbed)
1181      {
1182         CRI("DOUBLE COMP GRAB! ACK!!!!");
1183         return 1;
1184      }
1185    comp_grabbed = e_comp_grab_input(1, 1);
1186    if (!comp_grabbed) _e_client_action_input_win_del();
1187    return comp_grabbed;
1188 }
1189
1190 static void
1191 _e_client_action_init(E_Client *ec)
1192 {
1193    action_orig.x = ec->x;
1194    action_orig.y = ec->y;
1195    action_orig.w = ec->w;
1196    action_orig.h = ec->h;
1197
1198    if (action_client)
1199      {
1200         action_client->keyboard_resizing = 0;
1201      }
1202    action_client = ec;
1203 }
1204
1205 static int
1206 _e_client_move_begin(E_Client *ec)
1207 {
1208    if ((ec->fullscreen) || (ec->lock_user_location))
1209      return 0;
1210
1211    if (!_e_client_action_input_win_new()) return 0;
1212    ec->moving = 1;
1213    ecmove = ec;
1214
1215    wl_signal_emit_mutable(&PRI(ec)->events.move_begin, NULL);
1216    _e_client_hook_call(E_CLIENT_HOOK_MOVE_BEGIN, ec);
1217    if (!ec->moving)
1218      {
1219         if (ecmove == ec) ecmove = NULL;
1220         _e_client_action_input_win_del();
1221         return 0;
1222      }
1223    if (!ec->lock_user_stacking)
1224      {
1225         if (e_config->border_raise_on_mouse_action)
1226           e_client_raise(ec);
1227      }
1228
1229    if (e_comp->hwc)
1230      e_comp_client_override_add(ec);
1231
1232    return 1;
1233 }
1234
1235 static int
1236 _e_client_move_end(E_Client *ec)
1237 {
1238    ec->moving = 0;
1239    _e_client_action_input_win_del();
1240
1241    wl_signal_emit_mutable(&PRI(ec)->events.move_end, NULL);
1242    _e_client_hook_call(E_CLIENT_HOOK_MOVE_END, ec);
1243
1244    if (ec->transformed)
1245      _e_client_transform_move_end(ec);
1246
1247    if (e_comp->hwc)
1248      e_comp_client_override_del(ec);
1249
1250    ecmove = NULL;
1251    return 1;
1252 }
1253
1254 static Eina_Bool
1255 _e_client_action_move_timeout(void *data EINA_UNUSED)
1256 {
1257    _e_client_move_end(action_client);
1258    _e_client_action_finish();
1259    return ECORE_CALLBACK_CANCEL;
1260 }
1261
1262 static void
1263 _e_client_action_move_timeout_add(void)
1264 {
1265    E_FREE_FUNC(action_timer, ecore_timer_del);
1266    if (e_config->border_keyboard.timeout)
1267      action_timer = ecore_timer_add(e_config->border_keyboard.timeout, _e_client_action_move_timeout, NULL);
1268 }
1269
1270 static Eina_Bool
1271 _e_client_move_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
1272 {
1273    if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
1274
1275    if (!action_client)
1276      ERR("no action_client!");
1277
1278    if (action_client) _e_client_move_end(action_client);
1279    _e_client_action_finish();
1280    return ECORE_CALLBACK_DONE;
1281 }
1282
1283 static void
1284 _e_client_moveinfo_gather(E_Client *ec, const char *source)
1285 {
1286    if (e_util_glob_match(source, "mouse,*,1"))
1287      ec->moveinfo.down.button = 1;
1288    else if (e_util_glob_match(source, "mouse,*,2"))
1289      ec->moveinfo.down.button = 2;
1290    else if (e_util_glob_match(source, "mouse,*,3"))
1291      ec->moveinfo.down.button = 3;
1292    else
1293      ec->moveinfo.down.button = 0;
1294    if ((ec->moveinfo.down.button >= 1) && (ec->moveinfo.down.button <= 3))
1295      {
1296         ec->moveinfo.down.mx = ec->mouse.last_down[ec->moveinfo.down.button - 1].mx;
1297         ec->moveinfo.down.my = ec->mouse.last_down[ec->moveinfo.down.button - 1].my;
1298      }
1299    else
1300      {
1301         ec->moveinfo.down.mx = ec->mouse.current.mx;
1302         ec->moveinfo.down.my = ec->mouse.current.my;
1303      }
1304 }
1305
1306 static void
1307 _e_client_move_handle(E_Client *ec)
1308 {
1309    int x, y;
1310
1311    if ((ec->moveinfo.down.button >= 1) && (ec->moveinfo.down.button <= 3))
1312      {
1313         x = ec->mouse.last_down[ec->moveinfo.down.button - 1].x +
1314            (ec->mouse.current.mx - ec->moveinfo.down.mx);
1315         y = ec->mouse.last_down[ec->moveinfo.down.button - 1].y +
1316            (ec->mouse.current.my - ec->moveinfo.down.my);
1317      }
1318    else
1319      {
1320         x = ec->moveinfo.down.x +
1321            (ec->mouse.current.mx - ec->moveinfo.down.mx);
1322         y = ec->moveinfo.down.y +
1323            (ec->mouse.current.my - ec->moveinfo.down.my);
1324      }
1325
1326    if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
1327      _e_client_stay_within_canvas(ec, x, y, &x, &y);
1328
1329    if (ec->floating)
1330      _e_client_stay_within_canvas_margin(ec, x, y, &x, &y);
1331
1332    evas_object_move(ec->frame, x, y);
1333
1334    if (e_client_transform_core_enable_get(ec))
1335      {
1336         e_client_transform_core_update(ec);
1337      }
1338 }
1339
1340 static Evas_Object *
1341 _e_client_resize_object_rectangle_get(E_Client *ec)
1342 {
1343    Evas_Object *resize_obj = NULL;
1344
1345    resize_obj = evas_object_rectangle_add(evas_object_evas_get(ec->frame));
1346    EINA_SAFETY_ON_NULL_RETURN_VAL(resize_obj, NULL);
1347
1348    if (e_config->resize_object.customize)
1349      {
1350         evas_object_color_set(resize_obj,
1351                               e_config->resize_object.r,
1352                               e_config->resize_object.g,
1353                               e_config->resize_object.b,
1354                               e_config->resize_object.a);
1355      }
1356    else
1357      evas_object_color_set(resize_obj, 128, 128, 128, 100);
1358
1359    return resize_obj;
1360 }
1361
1362 static Evas_Object *
1363 _e_client_resize_object_image_get(E_Client *ec)
1364 {
1365    int err;
1366    Evas_Object *resize_obj = NULL;
1367
1368    if (!e_config->resize_object.image_path)
1369      {
1370         ELOGF("COMP", "NO resize_object image! Make default resize_object", ec);
1371         goto get_rectangle;
1372      }
1373
1374    resize_obj = evas_object_image_add(evas_object_evas_get(ec->frame));
1375    EINA_SAFETY_ON_NULL_RETURN_VAL(resize_obj, NULL);
1376
1377    evas_object_image_file_set(resize_obj, e_config->resize_object.image_path, NULL);
1378    err = evas_object_image_load_error_get(resize_obj);
1379    if (err != EVAS_LOAD_ERROR_NONE)
1380      {
1381         ELOGF("COMP", "Image load error. path:%s, errno:%d. Make default resize_object",
1382               ec, e_config->resize_object.image_path, err);
1383         evas_object_del(resize_obj);
1384         resize_obj = NULL;
1385         goto get_rectangle;
1386      }
1387
1388    evas_object_image_fill_set(resize_obj, 0, 0, ec->w, ec->h);
1389    evas_object_image_filled_set(resize_obj, EINA_TRUE);
1390
1391    evas_object_image_border_set(resize_obj,
1392                                 e_config->resize_object.border_width.l,
1393                                 e_config->resize_object.border_width.r,
1394                                 e_config->resize_object.border_width.t,
1395                                 e_config->resize_object.border_width.b);
1396
1397    return resize_obj;
1398
1399 get_rectangle:
1400    return _e_client_resize_object_rectangle_get(ec);
1401 }
1402
1403 static Evas_Object *
1404 _e_client_resize_object_create(E_Client *ec)
1405 {
1406    EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, NULL);
1407
1408    Evas_Object *resize_obj = NULL;
1409
1410    if (_e_client_resize_object_create_cb)
1411      resize_obj = _e_client_resize_object_create_cb(ec);
1412    else
1413      {
1414         if (e_config->resize_object.type == 1) // image object
1415           {
1416              resize_obj = _e_client_resize_object_image_get(ec);
1417           }
1418         else // rectangle
1419           {
1420              resize_obj = _e_client_resize_object_rectangle_get(ec);
1421           }
1422      }
1423    EINA_SAFETY_ON_NULL_RETURN_VAL(resize_obj, NULL);
1424
1425    evas_object_pass_events_set(resize_obj, EINA_TRUE);
1426    evas_object_layer_set(resize_obj, evas_object_layer_get(ec->frame));
1427    evas_object_stack_above(resize_obj, ec->frame);
1428    evas_object_name_set(resize_obj, "resize_object");
1429
1430    return resize_obj;
1431 }
1432
1433 static void
1434 _e_client_resize_object_del(E_Client *ec)
1435 {
1436    if (ec == NULL) return;
1437    if (ec->manage_resize.resize_obj == NULL) return;
1438
1439    evas_object_hide(ec->manage_resize.resize_obj);
1440    evas_object_del(ec->manage_resize.resize_obj);
1441    ec->manage_resize.resize_obj = NULL;
1442 }
1443
1444 static void
1445 _e_client_resize_handle(E_Client *ec)
1446 {
1447    int x, y, w, h;
1448    int new_x, new_y, new_w, new_h;
1449    int tw, th;
1450    int trans_x = 0, trans_y = 0;
1451    int trans_w = 0, trans_h = 0;
1452
1453    if (ec->transformed)
1454      {
1455         _e_client_transform_resize_handle(ec);
1456         return;
1457      }
1458
1459    x = ec->x;
1460    y = ec->y;
1461    w = ec->w;
1462    h = ec->h;
1463
1464    if ((ec->resize_mode == E_POINTER_RESIZE_TR) ||
1465        (ec->resize_mode == E_POINTER_RESIZE_R) ||
1466        (ec->resize_mode == E_POINTER_RESIZE_BR))
1467      {
1468         if ((ec->moveinfo.down.button >= 1) &&
1469             (ec->moveinfo.down.button <= 3))
1470           w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w +
1471             (ec->mouse.current.mx - ec->moveinfo.down.mx);
1472         else
1473           w = ec->moveinfo.down.w + (ec->mouse.current.mx - ec->moveinfo.down.mx);
1474      }
1475    else if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1476             (ec->resize_mode == E_POINTER_RESIZE_L) ||
1477             (ec->resize_mode == E_POINTER_RESIZE_BL))
1478      {
1479         if ((ec->moveinfo.down.button >= 1) &&
1480             (ec->moveinfo.down.button <= 3))
1481           w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w -
1482             (ec->mouse.current.mx - ec->moveinfo.down.mx);
1483         else
1484           w = ec->moveinfo.down.w - (ec->mouse.current.mx - ec->moveinfo.down.mx);
1485      }
1486
1487    if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1488        (ec->resize_mode == E_POINTER_RESIZE_T) ||
1489        (ec->resize_mode == E_POINTER_RESIZE_TR))
1490      {
1491         if ((ec->moveinfo.down.button >= 1) &&
1492             (ec->moveinfo.down.button <= 3))
1493           h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h -
1494             (ec->mouse.current.my - ec->moveinfo.down.my);
1495         else
1496           h = ec->moveinfo.down.h - (ec->mouse.current.my - ec->moveinfo.down.my);
1497      }
1498    else if ((ec->resize_mode == E_POINTER_RESIZE_BL) ||
1499             (ec->resize_mode == E_POINTER_RESIZE_B) ||
1500             (ec->resize_mode == E_POINTER_RESIZE_BR))
1501      {
1502         if ((ec->moveinfo.down.button >= 1) &&
1503             (ec->moveinfo.down.button <= 3))
1504           h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h +
1505             (ec->mouse.current.my - ec->moveinfo.down.my);
1506         else
1507           h = ec->moveinfo.down.h + (ec->mouse.current.my - ec->moveinfo.down.my);
1508      }
1509    tw = ec->w;
1510    th = ec->h;
1511
1512    if ((ec->resize_mode == E_POINTER_RESIZE_T) ||
1513        (ec->resize_mode == E_POINTER_RESIZE_TL) ||
1514        (ec->resize_mode == E_POINTER_RESIZE_L) ||
1515        (ec->resize_mode == E_POINTER_RESIZE_BL))
1516      x += (tw - w);
1517    if ((ec->resize_mode == E_POINTER_RESIZE_L) ||
1518        (ec->resize_mode == E_POINTER_RESIZE_TL) ||
1519        (ec->resize_mode == E_POINTER_RESIZE_T) ||
1520        (ec->resize_mode == E_POINTER_RESIZE_TR))
1521      y += (th - h);
1522
1523    new_x = x;
1524    new_y = y;
1525    new_w = w;
1526    new_h = h;
1527    if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
1528      {
1529         E_Zone *zone;
1530         zone = e_comp_zone_find_by_ec(ec);
1531         if (zone)
1532           {
1533              w = MIN(w, zone->w);
1534              h = MIN(h, zone->h);
1535           }
1536      }
1537    e_client_resize_limit(ec, &new_w, &new_h);
1538
1539    if (ec->manage_resize.enable_aspect_ratio)
1540      {
1541         if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1542             (ec->resize_mode == E_POINTER_RESIZE_L) ||
1543             (ec->resize_mode == E_POINTER_RESIZE_BL) ||
1544             (ec->resize_mode == E_POINTER_RESIZE_TR) ||
1545             (ec->resize_mode == E_POINTER_RESIZE_R) ||
1546             (ec->resize_mode == E_POINTER_RESIZE_BR))
1547           {
1548              new_h = (int) ec->manage_resize.ah / ec->manage_resize.aw * new_w;
1549           }
1550         else if ((ec->resize_mode == E_POINTER_RESIZE_T) ||
1551                  (ec->resize_mode == E_POINTER_RESIZE_B))
1552           {
1553              new_w = (int) ec->manage_resize.aw / ec->manage_resize.ah * new_h;
1554           }
1555           new_h += ec->manage_resize.header_h;
1556           new_h += ec->manage_resize.footer_h;
1557      }
1558
1559    if ((ec->resize_mode == E_POINTER_RESIZE_T) ||
1560        (ec->resize_mode == E_POINTER_RESIZE_TL) ||
1561        (ec->resize_mode == E_POINTER_RESIZE_L) ||
1562        (ec->resize_mode == E_POINTER_RESIZE_BL))
1563      new_x += (w - new_w);
1564    if ((ec->resize_mode == E_POINTER_RESIZE_L) ||
1565        (ec->resize_mode == E_POINTER_RESIZE_TL) ||
1566        (ec->resize_mode == E_POINTER_RESIZE_T) ||
1567        (ec->resize_mode == E_POINTER_RESIZE_TR))
1568      new_y += (h - new_h);
1569
1570    if (e_config->interactive_resize)
1571      {
1572         evas_object_geometry_set(ec->frame, new_x, new_y, new_w, new_h);
1573      }
1574    else
1575      {
1576         if (ec->manage_resize.resize_obj == NULL)
1577           {
1578              ec->manage_resize.resize_obj = _e_client_resize_object_create(ec);
1579              EINA_SAFETY_ON_NULL_RETURN(ec->manage_resize.resize_obj);
1580           }
1581
1582         if (e_client_transform_core_enable_get(ec))
1583           {
1584              e_client_transform_core_input_inv_transform(ec, new_x, new_y, &trans_x, &trans_y);
1585              e_client_transform_core_input_inv_transform(ec, new_w, new_h, &trans_w, &trans_h);
1586              evas_object_geometry_set(ec->manage_resize.resize_obj, trans_x, trans_y, trans_w, trans_h);
1587           }
1588         else
1589           evas_object_geometry_set(ec->manage_resize.resize_obj, new_x, new_y, new_w, new_h);
1590         evas_object_show(ec->manage_resize.resize_obj);
1591
1592         ec->manage_resize.x = new_x;
1593         ec->manage_resize.y = new_y;
1594         ec->manage_resize.w = new_w;
1595         ec->manage_resize.h = new_h;
1596      }
1597 }
1598
1599 static int
1600 _e_client_adjust_size_by_ppu(int size, int start_size, unsigned int ppu)
1601 {
1602    if (ppu <= 1) return size;
1603
1604    unsigned int remainder = size % ppu;
1605    if (remainder == 0) return size;
1606
1607    int gap = size - start_size;
1608    int new_size = size;
1609    if (gap > 0)
1610      new_size = size + (ppu - remainder);
1611    else
1612      new_size = size - remainder;
1613
1614    return new_size;
1615 }
1616
1617 static int
1618 _e_client_adjust_position_by_ppu(int pos, int size, int prev_pos, int prev_size)
1619 {
1620    int new_pos = 0;
1621
1622    if (prev_pos == pos)
1623      new_pos = pos;
1624    else
1625      new_pos = (prev_pos + prev_size) - size;
1626
1627    return new_pos;
1628 }
1629
1630 static void
1631 _e_client_adjust_geometry_by_resize_ppu(E_Client *ec)
1632 {
1633    if (ec->manage_resize.unit_size <= 1) return;
1634
1635    ec->manage_resize.w = _e_client_adjust_size_by_ppu(ec->manage_resize.w, ec->w, ec->manage_resize.unit_size);
1636    ec->manage_resize.h = _e_client_adjust_size_by_ppu(ec->manage_resize.h, ec->h, ec->manage_resize.unit_size);
1637
1638    ec->manage_resize.x = _e_client_adjust_position_by_ppu(ec->manage_resize.x, ec->manage_resize.w, ec->x, ec->w);
1639    ec->manage_resize.y = _e_client_adjust_position_by_ppu(ec->manage_resize.y, ec->manage_resize.h, ec->y, ec->h);
1640 }
1641
1642 static int
1643 _e_client_resize_end(E_Client *ec)
1644 {
1645    ec->resize_mode = E_POINTER_RESIZE_NONE;
1646    _e_client_action_input_win_del();
1647
1648    wl_signal_emit_mutable(&PRI(ec)->events.move_resize_end, NULL);
1649    _e_client_hook_call(E_CLIENT_HOOK_RESIZE_END, ec);
1650
1651    if (ec->transformed)
1652      _e_client_transform_resize_end(ec);
1653
1654    if (e_comp->hwc)
1655      e_comp_client_override_del(ec);
1656
1657    ecresize = NULL;
1658
1659    if (!e_config->interactive_resize)
1660      {
1661         if (ec->manage_resize.resize_obj)
1662           {
1663              if (ec->manage_resize.unit_size > 1)
1664                _e_client_adjust_geometry_by_resize_ppu(ec);
1665
1666              e_client_frame_geometry_set(ec,
1667                                          ec->manage_resize.x,
1668                                          ec->manage_resize.y,
1669                                          ec->manage_resize.w,
1670                                          ec->manage_resize.h);
1671              _e_client_resize_object_del(ec);
1672           }
1673      }
1674
1675    return 1;
1676 }
1677
1678 static Eina_Bool
1679 _e_client_action_resize_timeout(void *data EINA_UNUSED)
1680 {
1681    _e_client_resize_end(action_client);
1682    _e_client_action_finish();
1683    return ECORE_CALLBACK_CANCEL;
1684 }
1685
1686 static void
1687 _e_client_action_resize_timeout_add(void)
1688 {
1689    E_FREE_FUNC(action_timer, ecore_timer_del);
1690    if (e_config->border_keyboard.timeout)
1691      action_timer = ecore_timer_add(e_config->border_keyboard.timeout, _e_client_action_resize_timeout, NULL);
1692 }
1693
1694 static Eina_Bool
1695 _e_client_resize_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
1696 {
1697    if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
1698
1699    if (!action_client)
1700      ERR("no action_client!");
1701
1702    if (action_client) _e_client_resize_end(action_client);
1703    _e_client_action_finish();
1704    return ECORE_CALLBACK_DONE;
1705 }
1706
1707 ////////////////////////////////////////////////
1708
1709 static Eina_Bool
1710 _e_client_position_inside_input_rect(E_Client *ec, int tx, int ty)
1711 {
1712    int x, y, w, h;
1713    Eina_Bool res = EINA_FALSE;
1714    Eina_List *list = NULL, *l;
1715    Eina_Rectangle *data;
1716
1717    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
1718
1719    e_client_geometry_get(ec, &x, &y, &w, &h);
1720    e_comp_object_input_rect_get(ec->frame, &list);
1721    if (list)
1722      {
1723         EINA_LIST_FOREACH(list, l, data)
1724           {
1725              if ((tx >= x + data->x) && (tx <= x + data->x + data->w) &&
1726                  (ty >= y + data->y) && (ty <= y + data->y + data->h))
1727                {
1728                   res = EINA_TRUE;
1729                   break;
1730                }
1731           }
1732         list = eina_list_free(list);
1733      }
1734    else
1735      {
1736         if ((tx >= x) && (tx <= x + w) &&
1737             (ty >= y) && (ty <= y + h))
1738           {
1739              res = EINA_TRUE;
1740           }
1741      }
1742
1743    return res;
1744 }
1745
1746 static Eina_Bool
1747 _e_client_under_pointer_helper_ignore_client(E_Desk *desk, E_Client *client)
1748 {
1749    /* If a border was specified which should be excluded from the list
1750     * (because it will be closed shortly for example), skip */
1751    if (e_client_util_ignored_get(client) || (!e_desk_has_ec(desk, client))) return EINA_TRUE;
1752    if (!evas_object_visible_get(client->frame)) return EINA_TRUE;
1753    if (e_policy_client_is_cursor(client)) return EINA_TRUE;
1754    if (e_comp_wl->drag_client == client) return EINA_TRUE;
1755
1756    return EINA_FALSE;
1757 }
1758
1759 static E_Client *
1760 _e_client_under_pointer_helper(E_Desk *desk, E_Client *exclude, int x, int y)
1761 {
1762    E_Client *ec = NULL, *cec;
1763
1764    E_CLIENT_REVERSE_FOREACH(cec)
1765      {
1766         if (_e_client_under_pointer_helper_ignore_client(desk, cec)) continue;
1767         if ((exclude) && (cec == exclude)) continue;
1768         if (!E_INSIDE(x, y, cec->x, cec->y, cec->w, cec->h))
1769           continue;
1770         /* If the layer is higher, the position of the window is higher
1771          * (always on top vs always below) */
1772         if (!ec || (cec->layer > ec->layer))
1773           ec = cec;
1774      }
1775    return ec;
1776 }
1777
1778 static E_Client *
1779 _e_client_under_pointer_input_helper(E_Desk *desk, int x, int y)
1780 {
1781    E_Client *ec = NULL, *cec;
1782
1783    E_CLIENT_REVERSE_FOREACH(cec)
1784      {
1785         if (_e_client_under_pointer_helper_ignore_client(desk, cec)) continue;
1786
1787         Eina_List *list = NULL;
1788         Eina_Rectangle *rect;
1789         Eina_Bool inside = EINA_FALSE;
1790         e_comp_object_input_rect_get(cec->frame, &list);
1791         if (list)
1792           {
1793              EINA_LIST_FREE(list, rect)
1794                {
1795                   if (E_INSIDE(x, y, rect->x, rect->y, rect->w, rect->h))
1796                     inside = EINA_TRUE;
1797                }
1798           }
1799         else if (E_INSIDE(x, y, cec->x, cec->y, cec->w, cec->h))
1800           {
1801              inside = EINA_TRUE;
1802           }
1803
1804         if (!inside) continue;
1805         /* If the layer is higher, the position of the window is higher
1806          * (always on top vs always below) */
1807         if (!ec || (cec->layer > ec->layer))
1808           ec = cec;
1809      }
1810
1811    return ec;
1812 }
1813
1814 ////////////////////////////////////////////////
1815
1816 static void
1817 _e_client_zones_layout_calc(E_Client *ec, int *zx, int *zy, int *zw, int *zh)
1818 {
1819    int x, y, w, h;
1820    E_Zone *zone_above, *zone_below, *zone_left, *zone_right;
1821    E_Zone *zone;
1822
1823    zone = e_comp_zone_find_by_ec(ec);
1824    if (!zone) return;
1825    x = zone->x;
1826    y = zone->y;
1827    w = zone->w;
1828    h = zone->h;
1829
1830    if (eina_list_count(e_comp->zones) == 1)
1831      {
1832         if (zx) *zx = x;
1833         if (zy) *zy = y;
1834         if (zw) *zw = w;
1835         if (zh) *zh = h;
1836         return;
1837      }
1838
1839    zone_left = e_comp_zone_xy_get((x - w + 5), y);
1840    zone_right = e_comp_zone_xy_get((x + w + 5), y);
1841    zone_above = e_comp_zone_xy_get(x, (y - h + 5));
1842    zone_below = e_comp_zone_xy_get(x, (y + h + 5));
1843
1844    if (!(zone_above) && (y))
1845      zone_above = e_comp_zone_xy_get(x, (h - 5));
1846
1847    if (!(zone_left) && (x))
1848      zone_left = e_comp_zone_xy_get((x - 5), y);
1849
1850    if (zone_right)
1851      w = zone_right->x + zone_right->w;
1852
1853    if (zone_left)
1854      w = zone->x + zone->w;
1855
1856    if (zone_below)
1857      h = zone_below->y + zone_below->h;
1858
1859    if (zone_above)
1860      h = zone->y + zone->h;
1861
1862    if ((zone_left) && (zone_right))
1863      w = zone->w + zone_right->x;
1864
1865    if ((zone_above) && (zone_below))
1866      h = zone->h + zone_below->y;
1867
1868    if (x) x -= zone->w;
1869    if (y) y -= zone->h;
1870
1871    if (zx) *zx = x > 0 ? x : 0;
1872    if (zy) *zy = y > 0 ? y : 0;
1873    if (zw) *zw = w;
1874    if (zh) *zh = h;
1875 }
1876
1877 static void
1878 _e_client_stay_within_canvas(E_Client *ec, int x, int y, int *new_x, int *new_y)
1879 {
1880    int new_x_max, new_y_max;
1881    int zw, zh;
1882    Eina_Bool lw, lh;
1883    E_Zone *zone;
1884
1885    zone = e_comp_zone_find_by_ec(ec);
1886    if (!zone)
1887      {
1888         if (new_x) *new_x = x;
1889         if (new_y) *new_y = y;
1890         return;
1891      }
1892
1893    _e_client_zones_layout_calc(ec, NULL, NULL, &zw, &zh);
1894
1895    new_x_max = zw - ec->w;
1896    new_y_max = zh - ec->h;
1897    lw = ec->w > zw ? EINA_TRUE : EINA_FALSE;
1898    lh = ec->h > zh ? EINA_TRUE : EINA_FALSE;
1899
1900    if (lw)
1901      {
1902         if (x <= new_x_max)
1903           *new_x = new_x_max;
1904         else if (x >= 0)
1905           *new_x = 0;
1906      }
1907    else
1908      {
1909         if (x >= new_x_max)
1910           *new_x = new_x_max;
1911         else if (x <= 0)
1912           *new_x = 0;
1913      }
1914
1915    if (lh)
1916      {
1917         if (y <= new_y_max)
1918           *new_y = new_y_max;
1919         else if (y >= 0)
1920           *new_y = 0;
1921      }
1922    else
1923      {
1924         if (y >= new_y_max)
1925           *new_y = new_y_max;
1926         else if (y <= 0)
1927           *new_y = 0;
1928      }
1929 }
1930
1931 static void
1932 _e_client_stay_within_canvas_margin(E_Client *ec, int x, int y, int *new_x, int *new_y)
1933 {
1934    int new_x_max, new_y_max, new_x_min, new_y_min;
1935    int margin_w, margin_h;
1936    int zw, zh;
1937    int cw, ch;
1938    E_Zone *zone;
1939
1940    zone = e_comp_zone_find_by_ec(ec);
1941    if (!zone)
1942      {
1943         if (new_x) *new_x = x;
1944         if (new_y) *new_y = y;
1945         return;
1946      }
1947
1948    cw = ec->w;
1949    ch = ec->h;
1950
1951    _e_client_zones_layout_calc(ec, NULL, NULL, &zw, &zh);
1952
1953    margin_w = zw/3;
1954    margin_h = zh/10;
1955
1956    new_x_min = (margin_w > cw) ? 0 : -(cw - margin_w);
1957    new_x_max = (margin_w > cw) ? (zw - cw) : (zw - margin_w);
1958    new_y_min = (margin_h > ch) ? 0 : -(ch - margin_h);
1959    new_y_max = (margin_h > ch) ? (zh - ch) : (zh - margin_h);
1960
1961    if (x >= new_x_max)
1962      *new_x = new_x_max;
1963    else if (x <= new_x_min)
1964      *new_x = new_x_min;
1965
1966    if (y >= new_y_max)
1967      *new_y = new_y_max;
1968    else if (y <= new_y_min)
1969      *new_y = new_y_min;
1970
1971 }
1972
1973 ////////////////////////////////////////////////
1974
1975 static void
1976 _e_client_transform_core_activate_set(E_Client *ec, Eina_Bool set)
1977 {
1978    if (ec->transform_core.activate == set) return;
1979
1980    ec->transform_core.activate = set;
1981
1982    if (set)
1983      {
1984         if (ec->transform_core.result.enable)
1985           e_client_map_enable_set(ec, EINA_TRUE);
1986      }
1987    else
1988      {
1989         e_client_map_enable_set(ec, EINA_FALSE);
1990      }
1991 }
1992
1993 static void
1994 _e_client_cb_evas_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1995 {
1996    E_Client *ec = data;
1997
1998    if (stopping) return; //ignore all of this if we're shutting down!
1999    if (e_object_is_del(data)) return; //client is about to die
2000    if (ec->cur_mouse_action)
2001      {
2002         if (ec->cur_mouse_action->func.end_mouse)
2003           ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", NULL);
2004         else if (ec->cur_mouse_action->func.end)
2005           ec->cur_mouse_action->func.end(E_OBJECT(ec), "");
2006         E_FREE_FUNC(ec->cur_mouse_action, e_object_unref);
2007      }
2008    if (action_client == ec) _e_client_action_finish();
2009
2010    ec->want_focus = ec->take_focus = 0;
2011
2012    _e_client_transform_core_activate_set(ec, EINA_FALSE);
2013
2014    if (ec->new_client) return;
2015    _e_client_event_hide(ec);
2016
2017    EC_CHANGED(ec);
2018 }
2019
2020 static void
2021 _e_client_cb_evas_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
2022 {
2023    E_Client *ec = data;
2024    E_Map *map;
2025    Evas_Coord x, y;
2026
2027    if (e_object_is_del(data)) return;
2028
2029    ec->pre_res_change.valid = 0;
2030
2031    _e_client_event_simple(ec, E_EVENT_CLIENT_MOVE);
2032
2033    evas_object_geometry_get(ec->frame, &x, &y, NULL, NULL);
2034    if ((e_config->transient.move) && (ec->transients))
2035      {
2036         Eina_List *list = eina_list_clone(ec->transients);
2037         E_Client *child;
2038
2039         EINA_LIST_FREE(list, child)
2040           {
2041              if (child->vkbd.vkbd) continue;
2042
2043              evas_object_move(child->frame,
2044                               child->x + x - ec->pre_cb.x,
2045                               child->y + y - ec->pre_cb.y);
2046           }
2047      }
2048    if (ec->moving || (ecmove == ec))
2049      {
2050         wl_signal_emit_mutable(&PRI(ec)->events.move_resize_update, NULL);
2051         _e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec);
2052      }
2053
2054    if ((!ec->moving) && (ec->transformed))
2055      {
2056         map = e_client_map_get(ec);
2057         _e_client_transform_geometry_save(ec, map);
2058         e_map_free(map);
2059      }
2060
2061    ec->pre_cb.x = x; ec->pre_cb.y = y;
2062
2063    wl_signal_emit_mutable(&PRI(ec)->events.move, NULL);
2064
2065    e_comp_visibility_calculation_set(EINA_TRUE);
2066 }
2067
2068 static void
2069 _e_client_cb_evas_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
2070 {
2071    E_Client *ec = data;
2072    Evas_Coord x, y, w, h;
2073
2074    if (e_object_is_del(data)) return;
2075
2076    ec->pre_res_change.valid = 0;
2077
2078    _e_client_event_simple(ec, E_EVENT_CLIENT_RESIZE);
2079
2080    evas_object_geometry_get(ec->frame, &x, &y, &w, &h);
2081    if ((e_config->transient.resize) && (ec->transients))
2082      {
2083         Eina_List *list = eina_list_clone(ec->transients);
2084         E_Client *child;
2085
2086         EINA_LIST_FREE(list, child)
2087           {
2088              Evas_Coord nx, ny, nw, nh;
2089
2090              if ((ec->pre_cb.w > 0) && (ec->pre_cb.h > 0))
2091                {
2092                   nx = x + (((child->x - x) * w) / ec->pre_cb.w);
2093                   ny = y + (((child->y - y) * h) / ec->pre_cb.h);
2094                   nw = (child->w * w) / ec->pre_cb.w;
2095                   nh = (child->h * h) / ec->pre_cb.h;
2096                   nx += ((nw - child->w) / 2);
2097                   ny += ((nh - child->h) / 2);
2098                   evas_object_move(child->frame, nx, ny);
2099                }
2100           }
2101      }
2102
2103    if (e_client_util_resizing_get(ec) || (ecresize == ec))
2104      {
2105          wl_signal_emit_mutable(&PRI(ec)->events.move_resize_update, NULL);
2106         _e_client_hook_call(E_CLIENT_HOOK_RESIZE_UPDATE, ec);
2107      }
2108    ec->pre_cb.w = w; ec->pre_cb.h = h;
2109
2110    e_client_transform_core_update(ec);
2111    e_comp_visibility_calculation_set(EINA_TRUE);
2112 }
2113
2114 static void
2115 _e_client_cb_evas_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
2116 {
2117    E_Client *ec = data;
2118
2119    if (e_object_is_del(data)) return;
2120
2121    _e_client_transform_core_activate_set(ec, EINA_TRUE);
2122
2123    _e_client_event_show(ec);
2124    EC_CHANGED(ec);
2125 }
2126
2127 static void
2128 _e_client_cb_evas_restack(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
2129 {
2130    E_Client *ec = data;
2131    E_Comp_Wl_Client_Data *child_cdata = NULL;
2132
2133    if (e_object_is_del(data)) return;
2134    if (ec->layer_block) return;
2135    if (ec->layer_pending) return;
2136    if (e_config->transient.raise && ec->transients)
2137      {
2138         Eina_List *list = eina_list_clone(ec->transients);
2139         E_Client *child, *below = NULL, *above = NULL;
2140         E_Transient transient_policy;
2141
2142         E_LIST_REVERSE_FREE(list, child)
2143           {
2144              child_cdata = e_client_cdata_get(child);
2145              if (child_cdata && !child_cdata->mapped)
2146                {
2147                   ELOGF("COMP", "STACK CHANGE CHILD. BUT not mapped. skip. child(ec:%p, win:0x%08zx)", ec, child, e_client_util_win_get(child));
2148                   continue;
2149                }
2150
2151              /* Don't stack iconic transients. If the user wants these shown,
2152               * that's another option.
2153               */
2154              if (child->iconic && e_client_is_iconified_by_client(child)) continue;
2155
2156              transient_policy = e_client_transient_policy_get(child);
2157              if (transient_policy == E_TRANSIENT_ABOVE)
2158                {
2159                   if (below)
2160                     e_client_stack_below(child, below);
2161                   else
2162                     e_client_stack_above(child, ec);
2163                   below = child;
2164                }
2165              else if (transient_policy == E_TRANSIENT_BELOW)
2166                {
2167                   if (above)
2168                     e_client_stack_below(child, above);
2169                   else
2170                     e_client_stack_below(child, ec);
2171                   above = child;
2172                }
2173
2174           }
2175      }
2176    _e_client_event_simple(ec, E_EVENT_CLIENT_STACK);
2177
2178    e_comp_visibility_calculation_set(EINA_TRUE);
2179 }
2180
2181 ////////////////////////////////////////////////
2182 static void
2183 _e_client_aux_hint_eval(E_Client *ec)
2184 {
2185    if (!ec) return;
2186
2187    E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
2188    Eina_List *l, *ll;
2189    E_Comp_Wl_Aux_Hint *hint;
2190
2191    if (cdata && cdata->aux_hint.changed)
2192      {
2193         wl_signal_emit_mutable(&PRI(ec)->events.aux_hint_change, NULL);
2194         _e_client_hook_call(E_CLIENT_HOOK_AUX_HINT_CHANGE, ec);
2195
2196         EINA_LIST_FOREACH_SAFE(cdata->aux_hint.hints, l, ll, hint)
2197           {
2198              hint->changed = EINA_FALSE;
2199              if (hint->deleted)
2200                {
2201                   ELOGF("COMP", "AUX_HINT |Del [%d:%s:%s]", ec, hint->id, hint->hint, hint->val);
2202                   if (hint->hint) eina_stringshare_del(hint->hint);
2203                   if (hint->val) eina_stringshare_del(hint->val);
2204                   cdata->aux_hint.hints = eina_list_remove_list(cdata->aux_hint.hints, l);
2205                   E_FREE(hint);
2206                }
2207           }
2208         cdata->aux_hint.changed = 0;
2209      }
2210 }
2211
2212 static void
2213 _e_client_eval(E_Client *ec)
2214 {
2215    int send_event = 1;
2216    unsigned int prop = 0;
2217    int tx, ty;
2218
2219    if (e_object_is_del(E_OBJECT(ec)))
2220      {
2221         CRI("_e_client_eval(%p) with deleted border! - %d\n", ec, ec->new_client);
2222         ec->changed = 0;
2223         return;
2224      }
2225
2226    TRACE_DS_BEGIN(CLIENT:EVAL);
2227
2228    wl_signal_emit_mutable(&PRI(ec)->events.eval_pre_new_client, NULL);
2229    if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_NEW_CLIENT, ec))
2230      {
2231         TRACE_DS_END();
2232         return;
2233      }
2234
2235    if ((ec->new_client) && (!e_client_util_ignored_get(ec)))
2236      {
2237         wl_signal_emit_mutable(&PRI(ec)->events.eval_post_new_client, NULL);
2238         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT, ec))
2239           {
2240              TRACE_DS_END();
2241              return;
2242           }
2243      }
2244
2245    if (ec->changes.size)
2246      {
2247         ec->changes.size = 0;
2248         evas_object_resize(ec->frame, ec->w, ec->h);
2249
2250         prop |= E_CLIENT_PROPERTY_SIZE;
2251      }
2252    if (ec->changes.pos)
2253      {
2254         ec->changes.tz_position = 0;
2255         ec->changes.pos = 0;
2256         evas_object_move(ec->frame, ec->x, ec->y);
2257         prop |= E_CLIENT_PROPERTY_POS;
2258      }
2259
2260    if (ec->changes.reset_gravity)
2261      {
2262         ec->changes.reset_gravity = 0;
2263         prop |= E_CLIENT_PROPERTY_GRAVITY;
2264      }
2265
2266    if (ec->changes.title)
2267      {
2268         ec->changes.title = 0;
2269         prop |= E_CLIENT_PROPERTY_TITLE;
2270      }
2271
2272    if ((ec->changes.visible) && (ec->visible) && (ec->new_client) && (!ec->iconic))
2273      {
2274         int x, y;
2275
2276         e_input_device_pointer_xy_get(NULL, &x, &y);
2277         if ((!ec->placed) && (!ec->re_manage) &&
2278             (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL) &&
2279             (!((ec->icccm.transient_for != 0) ||
2280                (ec->dialog))) &&
2281             (!ecmove) && (!ecresize))
2282           {
2283              /* Set this window into moving state */
2284
2285              ec->cur_mouse_action = e_action_find("window_move");
2286              if (ec->cur_mouse_action)
2287                {
2288                   if ((!ec->cur_mouse_action->func.end_mouse) &&
2289                       (!ec->cur_mouse_action->func.end))
2290                     ec->cur_mouse_action = NULL;
2291                   if (ec->cur_mouse_action)
2292                     {
2293                        int t;
2294                        tx = x - (ec->w >> 1);
2295                        e_comp_object_frame_geometry_get(ec->frame, NULL, NULL, &t, NULL);
2296                        ty = y - (t >> 1);
2297                        e_client_pos_set(ec, tx, ty);
2298                        EC_CHANGED(ec);
2299                        ec->changes.pos = 1;
2300                     }
2301                }
2302           }
2303
2304         evas_object_show(ec->frame);
2305         if (evas_object_visible_get(ec->frame))
2306           {
2307              ec->changes.visible = 0;
2308              _e_client_event_show(ec);
2309           }
2310      }
2311    else if ((ec->changes.visible) && (ec->new_client))
2312      {
2313         ec->changes.visible = 0;
2314         if (!ec->iconic)
2315           _e_client_event_hide(ec);
2316      }
2317
2318    if (ec->changes.icon)
2319      {
2320         ec->changes.icon = 0;
2321      }
2322
2323    if (ec->new_client)
2324      e_comp->new_clients--;
2325    ec->new_client = 0;
2326    ec->changed = ec->changes.pos || ec->changes.size ||
2327                  ec->changes.stack || ec->changes.prop || ec->changes.border ||
2328                  ec->changes.reset_gravity ||
2329                  ec->changes.shape || ec->changes.shape_input || ec->changes.icon ||
2330                  ec->changes.internal_state ||
2331                  ec->changes.need_maximize || ec->changes.need_unmaximize;
2332    ec->changes.stack = 0;
2333
2334    if (ec->changes.need_maximize)
2335      {
2336         E_Maximize max = ec->maximized;
2337         ec->maximized = E_MAXIMIZE_NONE;
2338         e_client_maximize(ec, max);
2339         ec->changes.need_maximize = 0;
2340      }
2341    else if (ec->changes.need_unmaximize)
2342      {
2343         e_client_unmaximize(ec, ec->maximized);
2344         ec->changes.need_unmaximize = 0;
2345      }
2346
2347    if (ec->need_fullscreen)
2348      {
2349         e_client_fullscreen(ec, e_config->fullscreen_policy);
2350         ec->need_fullscreen = 0;
2351      }
2352
2353    if (ec->changes.accepts_focus)
2354      {
2355         if ((!ec->icccm.accepts_focus) && (!ec->icccm.take_focus))
2356           {
2357              if (!ec->focused)
2358                ec->changes.accepts_focus = 0;
2359           }
2360      }
2361
2362    if (send_event && prop)
2363      {
2364         _e_client_event_property(ec, prop);
2365      }
2366
2367    _e_client_aux_hint_eval(ec);
2368
2369    e_client_transform_core_update(ec);
2370
2371    wl_signal_emit_mutable(&PRI(ec)->events.eval_end, NULL);
2372    _e_client_hook_call(E_CLIENT_HOOK_EVAL_END, ec);
2373
2374    TRACE_DS_END();
2375 }
2376
2377 EINTERN void
2378 e_client_frame_update(E_Client *ec)
2379 {
2380    const char *bordername;
2381
2382    EINA_SAFETY_ON_NULL_RETURN(ec);
2383    if (e_object_is_del(E_OBJECT(ec))) return;
2384
2385    ec->border.changed = 0;
2386    if (!e_comp_object_frame_allowed(ec->frame)) return;
2387    if (ec->fullscreen || ec->borderless)
2388      bordername = "borderless";
2389    else if (ec->bordername)
2390      bordername = ec->bordername;
2391    else if (((ec->icccm.transient_for != 0) || (ec->dialog)) &&
2392             (ec->icccm.min_w == ec->icccm.max_w) &&
2393             (ec->icccm.min_h == ec->icccm.max_h))
2394      bordername = "noresize_dialog";
2395    else if ((ec->icccm.min_w == ec->icccm.max_w) &&
2396             (ec->icccm.min_h == ec->icccm.max_h))
2397      bordername = "noresize";
2398    else if (ec->shaped)
2399      bordername = "shaped";
2400    else if ((ec->netwm.state.skip_taskbar) ||
2401             (ec->netwm.state.skip_pager))
2402      bordername = "skipped";
2403   /*
2404    else if ((ec->internal) && (ec->icccm.class) &&
2405             (!strncmp(ec->icccm.class, "e_fwin", 6)))
2406      bordername = "internal_fileman";
2407   */
2408    else
2409      bordername = e_config->theme_default_border_style;
2410    if (!bordername) bordername = "default";
2411
2412    e_client_border_set(ec, bordername);
2413 }
2414
2415 static Eina_Bool
2416 _e_client_type_match(E_Client *ec, E_Config_Client_Type *m)
2417 {
2418    if (!ec || !m) return EINA_FALSE;
2419    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
2420
2421    if ((int)ec->netwm.type != m->window_type)
2422      return EINA_FALSE;
2423
2424 #if defined(__cplusplus) || defined(c_plusplus)
2425    if (m->clas)
2426      {
2427         if (!ec->icccm.cpp_class)
2428           return EINA_FALSE;
2429
2430         if (!e_util_glob_match(ec->icccm.cpp_class, m->clas))
2431           return EINA_FALSE;
2432      }
2433 #else
2434    if (m->clas)
2435      {
2436         if (!ec->icccm.class)
2437           return EINA_FALSE;
2438
2439         if (!e_util_glob_match(ec->icccm.class, m->clas))
2440           return EINA_FALSE;
2441      }
2442 #endif
2443
2444    if (m->name)
2445      {
2446         if (ec->icccm.name && e_util_glob_match(ec->icccm.name, m->name))
2447           return EINA_TRUE;
2448
2449         if (ec->icccm.title && e_util_glob_match(ec->icccm.title, m->name))
2450           return EINA_TRUE;
2451
2452         if (ec->netwm.name && e_util_glob_match(ec->netwm.name, m->name))
2453           return EINA_TRUE;
2454      }
2455
2456    return EINA_FALSE;
2457 }
2458
2459 EINTERN int
2460 e_client_type_update(E_Client *ec)
2461 {
2462    E_Config_Client_Type *m;
2463    Eina_List *l;
2464    int type = 0;
2465
2466    if (!e_config->client_types) return 0;
2467
2468    EINA_LIST_FOREACH(e_config->client_types, l, m)
2469      {
2470         if (!_e_client_type_match(ec, m)) continue;
2471         else
2472           {
2473              type = m->client_type;
2474              break;
2475           }
2476      }
2477
2478    if (ec->client_type != type)
2479      {
2480         ec->client_type = type;
2481         _e_client_event_property(ec, E_CLIENT_PROPERTY_CLIENT_TYPE);
2482      }
2483
2484    return ec->client_type;
2485 }
2486
2487 static void
2488 _e_client_transform_sub_apply(E_Client *ec, E_Client *epc, double zoom)
2489 {
2490    E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
2491    E_Client *subc;
2492    Eina_List *l;
2493    int px = 0, py = 0;
2494    int ox = 0, oy = 0, ow, oh;
2495    int mx, my, mw, mh;
2496    E_Map *map;
2497
2498    EINA_SAFETY_ON_FALSE_RETURN(e_comp_wl_subsurface_check(ec));
2499
2500    e_comp_wl_subsurface_position_get(ec, &ox, &oy);
2501    ow = cdata->width_from_viewport;
2502    oh = cdata->height_from_viewport;
2503
2504    map = e_client_map_get(epc);
2505    e_map_point_coord_get(map, 0, &px, &py, 0);
2506    e_map_free(map);
2507
2508    mx = ox * zoom + px;
2509    my = oy * zoom + py;
2510    mw = ow * zoom;
2511    mh = oh * zoom;
2512
2513    map = e_map_new_with_direct_render(ec->transform_core.direct_render);
2514    e_map_util_points_populate_from_geometry(map, mx, my, mw, mh, 0);
2515    e_map_util_object_move_sync_set(map, EINA_TRUE);
2516    e_client_map_set(ec, map);
2517    e_client_map_enable_set(ec, EINA_TRUE);
2518
2519    EINA_LIST_FOREACH(cdata->sub.list, l, subc)
2520      _e_client_transform_sub_apply(subc, ec, zoom);
2521    EINA_LIST_REVERSE_FOREACH(cdata->sub.below_list, l, subc)
2522      _e_client_transform_sub_apply(subc, ec, zoom);
2523
2524    e_map_free(map);
2525 }
2526
2527 static void
2528 _e_client_transient_for_group_make(E_Client *ec, Eina_List **list)
2529 {
2530    E_Client *child;
2531    Eina_List *l;
2532
2533    if (!ec) return;
2534    if (!e_config->transient.raise) return;
2535
2536    EINA_LIST_FOREACH(ec->transients, l, child)
2537      {
2538         if (!child) continue;
2539         if (child->iconic) continue;
2540         if (e_client_transient_policy_get(child) == E_TRANSIENT_ABOVE)
2541           {
2542              *list = eina_list_prepend(*list, child);
2543              _e_client_transient_for_group_make(child, list);
2544           }
2545      }
2546 }
2547
2548 EINTERN E_Client *
2549 e_client_transient_child_top_get(E_Client *ec, Eina_Bool consider_focus)
2550 {
2551    E_Client *top_ec = NULL;
2552    Eina_List *transient_list = NULL;
2553
2554    _e_client_transient_for_group_make(ec, &transient_list);
2555
2556    if (transient_list)
2557      {
2558         Eina_List *l = NULL;
2559         E_Client *temp_ec = NULL;
2560         E_Client *temp_ec2 = NULL;
2561
2562         E_CLIENT_REVERSE_FOREACH(temp_ec)
2563           {
2564              if (top_ec) break;
2565              if (temp_ec == ec)
2566                {
2567                   top_ec = ec;
2568                   break;
2569                }
2570
2571              EINA_LIST_FOREACH(transient_list, l, temp_ec2)
2572                {
2573                   if (temp_ec == temp_ec2)
2574                     {
2575                        if (consider_focus)
2576                          {
2577                             if ((temp_ec2->icccm.accepts_focus) ||
2578                                 (temp_ec2->icccm.take_focus))
2579                               {
2580                                  top_ec = temp_ec2;
2581                               }
2582                          }
2583                        else
2584                          {
2585                             top_ec = temp_ec2;
2586                          }
2587                        break;
2588                     }
2589                }
2590           }
2591         eina_list_free(transient_list);
2592      }
2593    return top_ec;
2594 }
2595
2596 #ifdef EC_IS_NOT_VISIBLE
2597 # undef EC_IS_NOT_VISIBLE
2598 #endif
2599 #define EC_IS_NOT_VISIBLE if (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED)
2600
2601 EINTERN Eina_Bool
2602 e_client_visibility_touched_check(E_Client *ec)
2603 {
2604    int tx, ty;
2605
2606    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
2607
2608    tx = wl_fixed_to_int(e_comp->wl_comp_data->ptr.x);
2609    ty = wl_fixed_to_int(e_comp->wl_comp_data->ptr.y);
2610
2611    return _e_client_position_inside_input_rect(ec, tx, ty);
2612 }
2613
2614 EINTERN void
2615 e_client_visibility_change_notify(E_Client *ec)
2616 {
2617    EINA_SAFETY_ON_NULL_RETURN(ec);
2618
2619    if (ec->visibility.changed)
2620      _e_client_event_simple(ec, E_EVENT_CLIENT_VISIBILITY_CHANGE);
2621
2622    wl_signal_emit_mutable(&PRI(ec)->events.eval_visibility, NULL);
2623    _e_client_hook_call(E_CLIENT_HOOK_EVAL_VISIBILITY, ec);
2624 }
2625
2626 EINTERN void
2627 e_client_visibility_end_notify(void)
2628 {
2629    // FIXME: This hook means that the visiblitiy calculation of a zone is done
2630    //        at this idle handler.This is a hook for a zone, not for a client.
2631    //        Therefore, this hook may be defined as a zone hook,
2632    //        ex) E_ZONE_HOOK_EVAL_VISIBILITY_END or E_ZONE_HOOK_EVAL_VISIBILITY_DONE.
2633    _e_client_hook_call(E_CLIENT_HOOK_EVAL_VISIBILITY_END, NULL);
2634 }
2635
2636 static Eina_Bool
2637 _e_client_transform_core_check_change(E_Client *ec)
2638 {
2639    int w = 0;
2640    int h = 0;
2641    Eina_Bool check = EINA_FALSE;
2642    if (!ec) return EINA_FALSE;
2643
2644    if (ec->frame)
2645      evas_object_geometry_get(ec->frame, 0, 0, &w, &h);
2646
2647    // check client position or size change
2648    if (ec->x != ec->transform_core.backup.client_x ||
2649        ec->y != ec->transform_core.backup.client_y ||
2650        ec->w != ec->transform_core.backup.client_w ||
2651        ec->h != ec->transform_core.backup.client_h ||
2652        w     != ec->transform_core.backup.frame_w ||
2653        h     != ec->transform_core.backup.frame_h ||
2654        ec->argb != ec->transform_core.backup.argb)
2655      {
2656         check = EINA_TRUE;
2657         ec->transform_core.backup.client_x = ec->x;
2658         ec->transform_core.backup.client_y = ec->y;
2659         ec->transform_core.backup.client_w = ec->w;
2660         ec->transform_core.backup.client_h = ec->h;
2661         ec->transform_core.backup.frame_w = w;
2662         ec->transform_core.backup.frame_h = h;
2663         ec->transform_core.backup.argb = ec->argb;
2664      }
2665
2666    // check new transform or del transform
2667    if (ec->transform_core.changed)
2668      {
2669         check = EINA_TRUE;
2670         ec->transform_core.changed = EINA_FALSE;
2671      }
2672
2673    // check each transform change
2674    if (ec->transform_core.transform_list)
2675      {
2676         Eina_List *l;
2677         Eina_List *l_next;
2678         E_Util_Transform *transform;
2679
2680         EINA_LIST_FOREACH_SAFE(ec->transform_core.transform_list, l, l_next, transform)
2681           {
2682              // del transform check
2683              if (e_util_transform_ref_count_get(transform) <= 1)
2684                {
2685                   ec->transform_core.transform_list = eina_list_remove(ec->transform_core.transform_list, transform);
2686                   e_util_transform_unref(transform);
2687                   check = EINA_TRUE;
2688                   continue;
2689                }
2690
2691              // transform change test
2692              if (e_util_transform_change_get(transform))
2693                {
2694                   check = EINA_TRUE;
2695                   e_util_transform_change_unset(transform);
2696                }
2697           }
2698      }
2699
2700    if (e_comp_wl_subsurface_check(ec))
2701      {
2702         // check parent matrix change
2703         E_Client *parent = e_comp_wl_subsurface_parent_get(ec);
2704         if (parent && parent->transform_core.result.enable)
2705           {
2706              ec->transform_core.parent.enable = EINA_TRUE;
2707
2708              if (!e_util_transform_matrix_equal_check(&ec->transform_core.parent.matrix,
2709                                                       &parent->transform_core.result.matrix))
2710                {
2711                   check = EINA_TRUE;
2712                   ec->transform_core.parent.matrix = parent->transform_core.result.matrix;
2713                }
2714              if (memcmp(&ec->transform_core.parent.zoom, &parent->transform_core.result.transform.zoom, sizeof(E_Util_Transform_Zoom)) != 0)
2715                {
2716                   check = EINA_TRUE;
2717                   ec->transform_core.parent.zoom = parent->transform_core.result.transform.zoom;
2718                }
2719           }
2720         else if (ec->transform_core.parent.enable)
2721           {
2722              ec->transform_core.parent.enable = EINA_FALSE;
2723              e_util_transform_matrix_load_identity(&ec->transform_core.parent.matrix);
2724              ec->transform_core.parent.zoom.zoom_x = 1.0;
2725              ec->transform_core.parent.zoom.zoom_y = 1.0;
2726              ec->transform_core.parent.zoom.cx = 0;
2727              ec->transform_core.parent.zoom.cy = 0;
2728              check = EINA_TRUE;
2729           }
2730      }
2731
2732    return check;
2733 }
2734
2735 static void
2736 _e_client_transform_core_boundary_update(E_Client *ec, E_Util_Transform_Rect_Vertex *vertices)
2737 {
2738    int minx = 99999, miny = 99999;
2739    int maxx = -99999, maxy = -99999;
2740    int x, y;
2741    int i;
2742
2743    if (!ec) return;
2744    if (!ec->frame) return;
2745    if (!ec->transform_core.result.enable) return;
2746    if (!vertices) return;
2747
2748    for (i = 0; i < 4; ++i)
2749      {
2750         x = 0;
2751         y = 0;
2752
2753         e_util_transform_vertices_pos_round_get(vertices, i, &x, &y, 0, 0);
2754
2755         if (x < minx) minx = x;
2756         if (y < miny) miny = y;
2757         if (x > maxx) maxx = x;
2758         if (y > maxy) maxy = y;
2759      }
2760
2761    ec->transform_core.result.boundary.x = minx;
2762    ec->transform_core.result.boundary.y = miny;
2763    ec->transform_core.result.boundary.w = maxx - minx;
2764    ec->transform_core.result.boundary.h = maxy - miny;
2765
2766    ELOGF("COMP", "[Transform][boundary][%d %d %d %d]",
2767          ec,
2768          ec->transform_core.result.boundary.x,
2769          ec->transform_core.result.boundary.y,
2770          ec->transform_core.result.boundary.w,
2771          ec->transform_core.result.boundary.h);
2772 }
2773
2774 static E_Map *
2775 _e_client_transform_core_map_new(Evas_Object *obj,
2776                                  E_Util_Transform_Rect_Vertex *vertices,
2777                                  E_Util_Transform *transform,
2778                                  Eina_Bool direct_render)
2779 {
2780    E_Map *map;
2781    int i;
2782    int x, y;
2783    double u, v;
2784
2785    map = e_map_new_with_direct_render(direct_render);
2786    EINA_SAFETY_ON_NULL_RETURN_VAL(map, NULL);
2787
2788    e_map_util_points_populate_from_object_full(map, obj, 0);
2789    e_map_util_points_color_set(map, 255, 255, 255, 255);
2790
2791    for (i = 0 ; i < 4 ; ++i)
2792      {
2793         x = 0;
2794         y = 0;
2795
2796         e_util_transform_vertices_pos_round_get(vertices, i, &x, &y, 0, 0);
2797         e_map_point_coord_set(map, i, x, y, 1.0);
2798
2799         if (transform && e_util_transform_texcoord_flag_get(transform))
2800           {
2801              u = 0.0;
2802              v = 0.0;
2803
2804              e_util_transform_texcoord_get(transform, i, &u, &v);
2805              e_map_point_image_uv_set(map, i, u, v);
2806           }
2807      }
2808
2809    return map;
2810 }
2811
2812 static void
2813 _e_client_transform_core_vertices_apply_with_zoom(E_Client *ec,
2814                                         Evas_Object *obj,
2815                                         E_Util_Transform_Rect_Vertex *vertices,
2816                                         E_Util_Transform *transform,
2817                                         E_Util_Transform_Zoom zoom)
2818 {
2819    E_Map *map = NULL;
2820
2821    if (!obj) return;
2822
2823    if (vertices)
2824      {
2825         map = _e_client_transform_core_map_new(obj, vertices, transform,
2826                                                ec->transform_core.direct_render);
2827         EINA_SAFETY_ON_NULL_RETURN(map);
2828
2829         e_map_util_zoom(map, zoom.zoom_x, zoom.zoom_y, zoom.cx, zoom.cy);
2830
2831         e_comp_object_map_set(obj, map);
2832
2833         if (ec->transform_core.activate)
2834           e_comp_object_map_enable_set(obj, EINA_TRUE);
2835         else
2836           e_comp_object_map_enable_set(obj, EINA_FALSE);
2837
2838         e_map_free(map);
2839      }
2840    else
2841      evas_object_map_enable_set(obj, EINA_FALSE);
2842 }
2843
2844 static void
2845 _e_client_transform_core_vertices_apply(E_Client *ec,
2846                                         Evas_Object *obj,
2847                                         E_Util_Transform_Rect_Vertex *vertices,
2848                                         E_Util_Transform *transform)
2849 {
2850    E_Map *map = NULL;
2851
2852    if (!obj) return;
2853
2854    if (vertices)
2855      {
2856         map = _e_client_transform_core_map_new(obj, vertices, transform,
2857                                                ec->transform_core.direct_render);
2858         EINA_SAFETY_ON_NULL_RETURN(map);
2859
2860         e_comp_object_map_set(obj, map);
2861
2862         if (ec->transform_core.activate)
2863           e_comp_object_map_enable_set(obj, EINA_TRUE);
2864         else
2865           e_comp_object_map_enable_set(obj, EINA_FALSE);
2866
2867         e_map_free(map);
2868      }
2869    else
2870      evas_object_map_enable_set(obj, EINA_FALSE);
2871 }
2872
2873 static void
2874 _e_client_transform_core_sub_update(E_Client *ec, E_Util_Transform_Rect_Vertex *vertices)
2875 {
2876    Eina_List *l;
2877    E_Client *subc;
2878    E_Comp_Wl_Client_Data *cdata;
2879
2880    if (!ec) return;
2881
2882    cdata = e_client_cdata_get(ec);
2883    if (!cdata) return;
2884
2885    EINA_LIST_FOREACH(cdata->sub.list, l, subc)
2886       e_client_transform_core_update(subc);
2887
2888    EINA_LIST_FOREACH(cdata->sub.below_list, l, subc)
2889       e_client_transform_core_update(subc);
2890 }
2891
2892 static void
2893 _e_client_cb_hook_shell_surface_ready(void *data EINA_UNUSED, E_Client *ec)
2894 {
2895    if (EINA_UNLIKELY(!ec))
2896      return;
2897
2898    _e_client_aux_hint_eval(ec);
2899 }
2900
2901 // FIXME: This function has to be deleted and it remains for the backward compatibility.
2902 //        Please find and fix to use e_comp_visibility_calculation_set(EINA_TRUE)
2903 //        instead of e_client_visibility_calculate() call at e20 modules.
2904 E_API void
2905 e_client_visibility_calculate(void)
2906 {
2907    e_comp_visibility_calculation_set(EINA_TRUE);
2908 }
2909
2910 E_API void
2911 e_client_visibility_skip_set(E_Client *ec, Eina_Bool skip)
2912 {
2913    if (!ec) return;
2914
2915    ELOGF("POL_VIS", "visibility skip set to %d", ec, skip);
2916    ec->visibility.skip = skip;
2917 }
2918
2919 E_API void
2920 e_client_post_raise_lower_set(E_Client *ec, Eina_Bool raise_set, Eina_Bool lower_set)
2921 {
2922    if (!ec) return;
2923
2924    ec->post_raise = raise_set;
2925    ec->post_lower = lower_set;
2926 }
2927
2928 E_API Eina_Bool
2929 e_client_first_mapped_get(E_Client *ec)
2930 {
2931    if (!ec) return EINA_FALSE;
2932
2933    return ec->first_mapped;
2934 }
2935
2936 EINTERN Eina_Bool e_client_mapped_get(E_Client *ec)
2937 {
2938    E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
2939    EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, EINA_FALSE);
2940
2941   return cdata->mapped;
2942 }
2943
2944 EINTERN void
2945 e_client_mapped_set(E_Client *ec, Eina_Bool set)
2946 {
2947    E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
2948    EINA_SAFETY_ON_NULL_RETURN(cdata);
2949
2950    cdata->mapped = set;
2951 }
2952
2953
2954 ////////////////////////////////////////////////
2955 EINTERN Eina_Bool
2956 e_client_clients_hash_exist()
2957 {
2958   int pix_id;
2959
2960   for (pix_id = 0; pix_id < E_PIXMAP_TYPE_MAX; pix_id++)
2961     {
2962       if (eina_hash_population(clients_hash[pix_id]))
2963         return EINA_TRUE;
2964     }
2965
2966   return EINA_FALSE;
2967 }
2968
2969 EINTERN void
2970 e_client_idler_before(Eina_Bool *check_focus)
2971 {
2972    const Eina_List *l;
2973    E_Client *ec;
2974
2975    *check_focus = EINA_FALSE;
2976
2977    if (!e_client_clients_hash_exist()) return;
2978
2979    TRACE_DS_BEGIN(CLIENT:IDLE BEFORE);
2980
2981    EINA_LIST_FOREACH(e_comp->clients, l, ec)
2982      {
2983         // pass 1 - eval0. fetch properties on new or on change and
2984         // call hooks to decide what to do - maybe move/resize
2985         if (ec->ignored || (!ec->changed)) continue;
2986
2987         wl_signal_emit_mutable(&PRI(ec)->events.eval_pre_fetch, NULL);
2988         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_FETCH, ec)) continue;
2989
2990
2991         /* FETCH is hooked by the compositor to get client hints */
2992         wl_signal_emit_mutable(&PRI(ec)->events.eval_fetch, NULL);
2993         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_FETCH, ec)) continue;
2994
2995         if (ec->new_client)
2996           {
2997              e_client_type_update(ec);
2998           }
2999
3000         /* PRE_POST_FETCH calls e_remember apply for new client */
3001         wl_signal_emit_mutable(&PRI(ec)->events.eval_pre_post_fetch, NULL);
3002         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_POST_FETCH, ec)) continue;
3003         wl_signal_emit_mutable(&PRI(ec)->events.eval_post_fetch, NULL);
3004         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_FETCH, ec)) continue;
3005         wl_signal_emit_mutable(&PRI(ec)->events.eval_pre_frame_assign, NULL);
3006         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN, ec)) continue;
3007
3008         wl_signal_emit_mutable(&PRI(ec)->events.eval_post_frame_assign, NULL);
3009         _e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_FRAME_ASSIGN, ec);
3010      }
3011    // pass 2 - show and hide windows needing hide and eval (main eval)
3012    E_CLIENT_FOREACH(ec)
3013      {
3014         if (e_object_is_del(E_OBJECT(ec))) continue;
3015         if (ec->ignored)
3016           {
3017              // ignored client but needing eval (aux hint) such as remote surfaces
3018              if (ec->changed)
3019                {
3020                   E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
3021                   if (cdata && cdata->first_commit)
3022                     _e_client_aux_hint_eval(ec);
3023                }
3024              continue;
3025           }
3026
3027         if (ec->changes.visible)
3028           {
3029              if (ec->visible)
3030                {
3031                   if ((!ec->new_client) &&
3032                       (!ec->changes.pos) &&
3033                       (!ec->changes.size))
3034                     {
3035                        evas_object_show(ec->frame);
3036                        ec->changes.visible = !evas_object_visible_get(ec->frame);
3037                     }
3038                }
3039              else
3040                {
3041                   evas_object_hide(ec->frame);
3042                   ec->changes.visible = 0;
3043                }
3044           }
3045
3046         if (ec->changed)
3047           {
3048              _e_client_eval(ec);
3049              e_comp_visibility_calculation_set(EINA_TRUE);
3050              if (ec->changes.accepts_focus)
3051                *check_focus = EINA_TRUE;
3052              ec->changes.accepts_focus = 0;
3053           }
3054
3055         if ((ec->changes.visible) && (ec->visible) && (!ec->changed))
3056           {
3057              evas_object_show(ec->frame);
3058              ec->changes.visible = !evas_object_visible_get(ec->frame);
3059              ec->changed = ec->changes.visible;
3060              e_comp_visibility_calculation_set(EINA_TRUE);
3061           }
3062      }
3063
3064    TRACE_DS_END();
3065 }
3066
3067
3068 EINTERN Eina_Bool
3069 e_client_init(void)
3070 {
3071    int pix_id;
3072    for (pix_id = 0; pix_id < E_PIXMAP_TYPE_MAX; pix_id++)
3073      clients_hash[pix_id] = eina_hash_pointer_new(NULL);
3074
3075    E_COMP_WL_HOOK_APPEND(hooks, E_COMP_WL_HOOK_SHELL_SURFACE_READY, _e_client_cb_hook_shell_surface_ready, NULL);
3076
3077    E_EVENT_CLIENT_ADD = ecore_event_type_new();
3078    E_EVENT_CLIENT_REMOVE = ecore_event_type_new();
3079    E_EVENT_CLIENT_DESK_SET = ecore_event_type_new();
3080    E_EVENT_CLIENT_ZONE_SET = ecore_event_type_new();
3081    E_EVENT_CLIENT_RESIZE = ecore_event_type_new();
3082    E_EVENT_CLIENT_MOVE = ecore_event_type_new();
3083    E_EVENT_CLIENT_SHOW = ecore_event_type_new();
3084    E_EVENT_CLIENT_HIDE = ecore_event_type_new();
3085    E_EVENT_CLIENT_ICONIFY = ecore_event_type_new();
3086    E_EVENT_CLIENT_UNICONIFY = ecore_event_type_new();
3087    E_EVENT_CLIENT_STACK = ecore_event_type_new();
3088    E_EVENT_CLIENT_FOCUS_IN = ecore_event_type_new();
3089    E_EVENT_CLIENT_FOCUS_OUT = ecore_event_type_new();
3090    E_EVENT_CLIENT_PROPERTY = ecore_event_type_new();
3091    E_EVENT_CLIENT_FULLSCREEN = ecore_event_type_new();
3092    E_EVENT_CLIENT_UNFULLSCREEN = ecore_event_type_new();
3093 #ifdef _F_ZONE_WINDOW_ROTATION_
3094    E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN = ecore_event_type_new();
3095    E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL = ecore_event_type_new();
3096    E_EVENT_CLIENT_ROTATION_CHANGE_END = ecore_event_type_new();
3097    E_EVENT_CLIENT_ROTATION_GEOMETRY_SET = ecore_event_type_new();
3098 #endif
3099    E_EVENT_CLIENT_VISIBILITY_CHANGE = ecore_event_type_new();
3100    E_EVENT_CLIENT_BUFFER_CHANGE = ecore_event_type_new();
3101    E_EVENT_CLIENT_FOCUS_SKIP_SET = ecore_event_type_new();;
3102    E_EVENT_CLIENT_FOCUS_SKIP_UNSET = ecore_event_type_new();;
3103
3104    return (!!clients_hash[1]);
3105 }
3106
3107 EINTERN void
3108 e_client_shutdown(void)
3109 {
3110    int pix_id;
3111    for (pix_id = 0; pix_id < E_PIXMAP_TYPE_MAX; pix_id++)
3112      E_FREE_FUNC(clients_hash[pix_id], eina_hash_free);
3113
3114    E_FREE_LIST(hooks, e_comp_wl_hook_del);
3115    E_FREE_LIST(handlers, ecore_event_handler_del);
3116
3117 }
3118
3119 E_API void
3120 e_client_unignore(E_Client *ec)
3121 {
3122    E_OBJECT_CHECK(ec);
3123    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3124    if (!ec->ignored) return;
3125
3126    ec->ignored = 0;
3127    _e_client_event_add(ec);
3128 }
3129
3130 static E_Layer
3131 _e_client_convert_fullscreen_layer(int layer)
3132 {
3133    if (layer <= E_LAYER_CLIENT_NORMAL)
3134      return E_LAYER_CLIENT_NORMAL;
3135    else if (layer <= E_LAYER_CLIENT_ABOVE)
3136      return E_LAYER_CLIENT_ABOVE;
3137    else if (layer <= E_LAYER_CLIENT_EDGE)
3138      return E_LAYER_CLIENT_EDGE;
3139    else
3140      return E_LAYER_CLIENT_FULLSCREEN;
3141 }
3142
3143 E_API E_Client *
3144 e_client_new(E_Pixmap *cp, int first_map, int internal)
3145 {
3146    E_Client *ec;
3147    E_Pixmap_Type type;
3148
3149    type = e_pixmap_type_get(cp);
3150    if (type >= E_PIXMAP_TYPE_MAX) return NULL;
3151    if (eina_hash_find(clients_hash[type], &cp)) return NULL;
3152
3153    ec = E_OBJECT_ALLOC(E_Client, E_CLIENT_TYPE, _e_client_free);
3154    if (!ec) return NULL;
3155    e_object_del_func_set(E_OBJECT(ec), E_OBJECT_CLEANUP_FUNC(_e_client_del));
3156
3157    if (!_e_client_private_init(ec))
3158      {
3159         e_object_del(E_OBJECT(ec));
3160         return NULL;
3161      }
3162
3163    uuid_generate(ec->uuid);
3164
3165    ec->focus_policy_override = E_FOCUS_LAST;
3166    e_client_size_set(ec, 1, 1);
3167    ec->internal = internal;
3168
3169    ec->pixmap = cp;
3170    e_pixmap_client_set(cp, ec);
3171    ec->resize_mode = E_POINTER_RESIZE_NONE;
3172    ec->layer = E_LAYER_CLIENT_NORMAL;
3173    ec->first_mapped = EINA_FALSE;
3174    ec->post_raise = EINA_TRUE;
3175    ec->post_lower = EINA_FALSE;
3176    ec->animatable = EINA_TRUE;
3177    ec->maximize_type = e_config->maximize_policy & E_MAXIMIZE_TYPE;
3178    ec->fullscreen_layer = _e_client_convert_fullscreen_layer(e_config->fullscreen_layer);
3179
3180    /* FIXME: if first_map is 1 then we should ignore the first hide event
3181     * or ensure the window is already hidden and events flushed before we
3182     * create a border for it */
3183    if (first_map)
3184      {
3185         ec->changes.pos = 1;
3186         ec->re_manage = 1;
3187      }
3188    ec->new_client = 1;
3189    e_comp->new_clients++;
3190
3191    ec->exp_iconify.by_client = 0;
3192    ec->exp_iconify.not_raise = 0;
3193    ec->exp_iconify.skip_iconify = 0;
3194    ec->exp_iconify.skip_by_remote = 0;
3195    if (e_config->deiconify_approve)
3196      ec->exp_iconify.deiconify_update= 1;
3197    else
3198      ec->exp_iconify.deiconify_update= 0;
3199    if (e_config->use_buffer_flush)
3200      ec->exp_iconify.buffer_flush = 1;
3201    else
3202      ec->exp_iconify.buffer_flush = 0;
3203
3204    e_client_iconified_type_set(ec, E_ICONIFIED_TYPE_NONE);
3205
3206    wl_signal_emit_mutable(&PRI(ec)->events.new_client, NULL);
3207    if (!_e_client_hook_call(E_CLIENT_HOOK_NEW_CLIENT, ec))
3208      {
3209         /* delete the above allocated object */
3210         //e_object_del(E_OBJECT(ec));
3211         return NULL;
3212      }
3213
3214    _e_client_aux_hint_eval(ec);
3215
3216    ec->icccm.title = NULL;
3217    ec->icccm.name = NULL;
3218 #if defined(__cplusplus) || defined(c_plusplus)
3219    ec->icccm.cpp_class = NULL;
3220 #else
3221    ec->icccm.class = NULL;
3222 #endif
3223    ec->icccm.min_w = 1;
3224    ec->icccm.min_h = 1;
3225    ec->icccm.max_w = 32767;
3226    ec->icccm.max_h = 32767;
3227
3228    ec->netwm.pid = 0;
3229    ec->netwm.name = NULL;
3230    ec->netwm.state.skip_taskbar = 0;
3231    ec->netwm.state.skip_pager = 0;
3232    ec->netwm.opacity = 255;
3233
3234    ec->visibility.obscured = E_VISIBILITY_UNKNOWN;
3235    ec->visibility.opaque = -1;
3236    ec->visibility.changed = 0;
3237    ec->visibility.skip = 0;
3238    ec->visibility.last_sent_type = E_VISIBILITY_UNKNOWN;
3239
3240    ec->transform.zoom = 1.0;
3241    ec->transform.angle = 0.0;
3242    ec->transform_core.direct_render = EINA_TRUE;
3243    ec->transform_core.activate = EINA_TRUE;
3244
3245    ec->pointer_enter_sent = EINA_FALSE;
3246
3247    ec->acquire_fence_fd = -1;
3248
3249    EC_CHANGED(ec);
3250
3251    e_comp->clients = eina_list_append(e_comp->clients, ec);
3252    eina_hash_add(clients_hash[type], &ec->pixmap, ec);
3253
3254    ELOGF("COMP", "CLIENT ADD. cp:%p, argb:%d, internal:%d, ignored:%d", ec, cp, ec->argb, internal, ec->ignored);
3255    if (!ec->ignored)
3256      _e_client_event_add(ec);
3257    e_comp_object_client_add(ec);
3258    if (ec->frame)
3259      {
3260         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW, _e_client_cb_evas_show, ec);
3261         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE, _e_client_cb_evas_hide, ec);
3262         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE, _e_client_cb_evas_move, ec);
3263         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESIZE, _e_client_cb_evas_resize, ec);
3264         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESTACK, _e_client_cb_evas_restack, ec);
3265      }
3266
3267    wl_signal_emit_mutable(&PRI(ec)->events.new_client_post, NULL);
3268
3269 #ifdef _F_E_CLIENT_NEW_CLIENT_POST_HOOK_
3270    _e_client_hook_call(E_CLIENT_HOOK_NEW_CLIENT_POST, ec);
3271 #endif
3272
3273    ec->manage_resize.resize_obj = NULL;
3274    ec->manage_resize.x = ec->manage_resize.y = ec->manage_resize.w = ec->manage_resize.h = 0;
3275    ec->manage_resize.enable_aspect_ratio = EINA_FALSE;
3276    ec->manage_resize.aw = ec->manage_resize.ah = 0;
3277    ec->manage_resize.header_h = 0;
3278    ec->manage_resize.footer_h = 0;
3279
3280    ec->visibility.ignore_geometry = e_config->calc_vis_ignore_geometry;
3281
3282    return ec;
3283 }
3284
3285 E_API Eina_Bool e_client_is_internal(E_Client *ec)
3286 {
3287    E_OBJECT_CHECK_RETURN(ec, EINA_TRUE);
3288    return ec->internal;
3289 }
3290
3291 EINTERN void
3292 e_client_desk_iconify_skip_set(E_Client *ec, Eina_Bool skip)
3293 {
3294    if (!ec) return;
3295    ec->user_skip_winlist = skip;
3296 }
3297
3298 EINTERN Eina_Bool
3299 e_client_desk_iconify_skip_get(E_Client *ec)
3300 {
3301    if (!ec) return EINA_FALSE;
3302    return ec->user_skip_winlist;
3303 }
3304
3305 EINTERN Eina_Bool
3306 e_client_comp_grabbed_get(void)
3307 {
3308    return comp_grabbed;
3309 }
3310
3311 EINTERN E_Client *
3312 e_client_action_get(void)
3313 {
3314    return action_client;
3315 }
3316
3317
3318 //////////////////////////////////////////////////////////
3319
3320 EINTERN void
3321 e_client_mouse_in(E_Client *ec, int x, int y)
3322 {
3323    E_Desk *desk;
3324
3325    if (comp_grabbed) return;
3326    if (e_object_is_del(E_OBJECT(ec))) return;
3327    desk = e_comp_desk_find_by_ec(ec);
3328    if (desk && desk->animate_count) return;
3329    ec->mouse.current.mx = x;
3330    ec->mouse.current.my = y;
3331    ec->mouse.in = 1;
3332
3333    wl_signal_emit_mutable(&PRI(ec)->events.mouse_in, NULL);
3334 }
3335
3336 EINTERN void
3337 e_client_mouse_out(E_Client *ec, int x, int y)
3338 {
3339    E_Desk *desk;
3340
3341    if (comp_grabbed) return;
3342    if (ec->fullscreen) return;
3343    if (e_object_is_del(E_OBJECT(ec))) return;
3344    desk = e_comp_desk_find_by_ec(ec);
3345    if (desk && desk->animate_count) return;
3346
3347    ec->mouse.current.mx = x;
3348    ec->mouse.current.my = y;
3349    ec->mouse.in = 0;
3350
3351    wl_signal_emit_mutable(&PRI(ec)->events.mouse_out, NULL);
3352 }
3353
3354 EINTERN void
3355 e_client_mouse_wheel(E_Client *ec, Evas_Point *output, E_Binding_Event_Wheel *ev)
3356 {
3357    EINA_SAFETY_ON_NULL_RETURN(ec);
3358    if (action_client) return;
3359    ec->mouse.current.mx = output->x;
3360    ec->mouse.current.my = output->y;
3361 }
3362
3363 EINTERN void
3364 e_client_mouse_down(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button *ev)
3365 {
3366    EINA_SAFETY_ON_NULL_RETURN(ec);
3367
3368    if (action_client || ec->iconic || e_client_util_ignored_get(ec)) return;
3369    if ((button >= 1) && (button <= 3))
3370      {
3371         ec->mouse.last_down[button - 1].mx = output->x;
3372         ec->mouse.last_down[button - 1].my = output->y;
3373         ec->mouse.last_down[button - 1].x = ec->x;
3374         ec->mouse.last_down[button - 1].y = ec->y;
3375         ec->mouse.last_down[button - 1].w = ec->w;
3376         ec->mouse.last_down[button - 1].h = ec->h;
3377      }
3378    else
3379      {
3380         ec->moveinfo.down.x = ec->x;
3381         ec->moveinfo.down.y = ec->y;
3382         ec->moveinfo.down.w = ec->w;
3383         ec->moveinfo.down.h = ec->h;
3384      }
3385    ec->mouse.current.mx = output->x;
3386    ec->mouse.current.my = output->y;
3387    if ((button >= 1) && (button <= 3))
3388      {
3389         ec->mouse.last_down[button - 1].mx = output->x;
3390         ec->mouse.last_down[button - 1].my = output->y;
3391         ec->mouse.last_down[button - 1].x = ec->x;
3392         ec->mouse.last_down[button - 1].y = ec->y;
3393         ec->mouse.last_down[button - 1].w = ec->w;
3394         ec->mouse.last_down[button - 1].h = ec->h;
3395      }
3396    else
3397      {
3398         ec->moveinfo.down.x = ec->x;
3399         ec->moveinfo.down.y = ec->y;
3400         ec->moveinfo.down.w = ec->w;
3401         ec->moveinfo.down.h = ec->h;
3402      }
3403    ec->mouse.current.mx = output->x;
3404    ec->mouse.current.my = output->y;
3405
3406    wl_signal_emit_mutable(&PRI(ec)->events.mouse_down, NULL);
3407 }
3408
3409 EINTERN void
3410 e_client_mouse_up(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button* ev)
3411 {
3412    EINA_SAFETY_ON_NULL_RETURN(ec);
3413    if (ec->iconic || e_client_util_ignored_get(ec)) return;
3414    if ((button >= 1) && (button <= 3))
3415      {
3416         ec->mouse.last_up[button - 1].mx = output->x;
3417         ec->mouse.last_up[button - 1].my = output->y;
3418         ec->mouse.last_up[button - 1].x = ec->x;
3419         ec->mouse.last_up[button - 1].y = ec->y;
3420      }
3421    ec->mouse.current.mx = output->x;
3422    ec->mouse.current.my = output->y;
3423    /* also we don't pass the same params that went in - then again that */
3424    /* should be ok as we are just ending the action if it has an end */
3425    if (ec->cur_mouse_action)
3426      {
3427         if (ec->cur_mouse_action->func.end_mouse)
3428           ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", ev);
3429         else if (ec->cur_mouse_action->func.end)
3430           ec->cur_mouse_action->func.end(E_OBJECT(ec), "");
3431         e_object_unref(E_OBJECT(ec->cur_mouse_action));
3432         ec->cur_mouse_action = NULL;
3433      }
3434
3435    if ((button >= 1) && (button <= 3))
3436      {
3437         ec->mouse.last_up[button - 1].mx = output->x;
3438         ec->mouse.last_up[button - 1].my = output->y;
3439         ec->mouse.last_up[button - 1].x = ec->x;
3440         ec->mouse.last_up[button - 1].y = ec->y;
3441      }
3442 }
3443
3444 E_API void
3445 e_client_stay_within_canvas_margin(E_Client *ec)
3446 {
3447    int new_x = ec->x;
3448    int new_y = ec->y;
3449
3450    if (ec->floating)
3451      {
3452         _e_client_stay_within_canvas_margin(ec, ec->x, ec->y, &new_x, &new_y);
3453
3454         if ((ec->x != new_x) || (ec->y != new_y))
3455           evas_object_move(ec->frame, new_x, new_y);
3456      }
3457 }
3458
3459 EINTERN void
3460 e_client_mouse_move(E_Client *ec, Evas_Point *output)
3461 {
3462    EINA_SAFETY_ON_NULL_RETURN(ec);
3463    if (ec->iconic || e_client_util_ignored_get(ec)) return;
3464    ec->mouse.current.mx = output->x;
3465    ec->mouse.current.my = output->y;
3466    if (e_client_util_moving_get(ec))
3467      {
3468         _e_client_move_handle(ec);
3469      }
3470    else if (e_client_util_resizing_get(ec))
3471      {
3472         _e_client_resize_handle(ec);
3473      }
3474 }
3475 ///////////////////////////////////////////////////////
3476
3477 EINTERN void
3478 e_client_res_change_geometry_save(E_Client *ec)
3479 {
3480    E_OBJECT_CHECK(ec);
3481    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3482
3483    if (ec->pre_res_change.valid) return;
3484    ec->pre_res_change.valid = 1;
3485    ec->pre_res_change.x = ec->x;
3486    ec->pre_res_change.y = ec->y;
3487    ec->pre_res_change.w = ec->w;
3488    ec->pre_res_change.h = ec->h;
3489    ec->pre_res_change.saved.x = ec->saved.x;
3490    ec->pre_res_change.saved.y = ec->saved.y;
3491    ec->pre_res_change.saved.w = ec->saved.w;
3492    ec->pre_res_change.saved.h = ec->saved.h;
3493 }
3494
3495 EINTERN void
3496 e_client_res_change_geometry_restore(E_Client *ec)
3497 {
3498    E_Zone *zone;
3499
3500    struct
3501    {
3502       unsigned char valid : 1;
3503       int           x, y, w, h;
3504       struct
3505       {
3506          int x, y, w, h;
3507       } saved;
3508    } pre_res_change;
3509
3510    E_OBJECT_CHECK(ec);
3511    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3512    if (!ec->pre_res_change.valid) return;
3513    if (ec->new_client) return;
3514
3515    zone = e_comp_zone_find_by_ec(ec);
3516    if (!zone) return;
3517
3518    memcpy(&pre_res_change, &ec->pre_res_change, sizeof(pre_res_change));
3519
3520    if (ec->fullscreen)
3521      {
3522         e_client_unfullscreen(ec);
3523         e_client_fullscreen(ec, e_config->fullscreen_policy);
3524      }
3525    else if (ec->maximized != E_MAXIMIZE_NONE)
3526      {
3527         E_Maximize max;
3528
3529         max = ec->maximized;
3530         e_client_unmaximize(ec, E_MAXIMIZE_BOTH);
3531         e_client_maximize(ec, max);
3532      }
3533    else
3534      {
3535         int x, y, w, h, zx, zy, zw, zh;
3536
3537         ec->saved.x = ec->pre_res_change.saved.x;
3538         ec->saved.y = ec->pre_res_change.saved.y;
3539         ec->saved.w = ec->pre_res_change.saved.w;
3540         ec->saved.h = ec->pre_res_change.saved.h;
3541
3542         e_zone_useful_geometry_get(zone, &zx, &zy, &zw, &zh);
3543
3544         if (ec->saved.w > zw)
3545           ec->saved.w = zw;
3546         if ((ec->saved.x + ec->saved.w) > (zx + zw))
3547           ec->saved.x = zx + zw - ec->saved.w;
3548
3549         if (ec->saved.h > zh)
3550           ec->saved.h = zh;
3551         if ((ec->saved.y + ec->saved.h) > (zy + zh))
3552           ec->saved.y = zy + zh - ec->saved.h;
3553
3554         x = ec->pre_res_change.x;
3555         y = ec->pre_res_change.y;
3556         w = ec->pre_res_change.w;
3557         h = ec->pre_res_change.h;
3558         if (w > zw)
3559           w = zw;
3560         if (h > zh)
3561           h = zh;
3562         if ((x + w) > (zx + zw))
3563           x = zx + zw - w;
3564         if ((y + h) > (zy + zh))
3565           y = zy + zh - h;
3566         evas_object_geometry_set(ec->frame, x, y, w, h);
3567      }
3568    memcpy(&ec->pre_res_change, &pre_res_change, sizeof(pre_res_change));
3569 }
3570
3571 EINTERN void
3572 e_client_pos_set(E_Client *ec, int x, int y)
3573 {
3574    if (!ec) return;
3575    ec->x = x;
3576    ec->y = y;
3577 }
3578
3579 EINTERN void
3580 e_client_pos_get(E_Client *ec, int *x, int *y)
3581 {
3582    int ex = 0;
3583    int ey = 0;
3584
3585    if (ec)
3586      {
3587         ex = ec->x;
3588         ey = ec->y;
3589      }
3590
3591    if (x) *x = ex;
3592    if (y) *y = ey;
3593 }
3594
3595 E_API void
3596 e_client_size_set(E_Client *ec, int w, int h)
3597 {
3598    if (!ec) return;
3599    ec->w = w;
3600    ec->h = h;
3601 }
3602
3603 E_API void
3604 e_client_size_get(E_Client *ec, int *w, int *h)
3605 {
3606    int ew = 0;
3607    int eh = 0;
3608
3609    if (ec)
3610      {
3611         ew = ec->w;
3612         eh = ec->h;
3613      }
3614
3615    if (w) *w = ew;
3616    if (h) *h = eh;
3617 }
3618
3619 E_API void
3620 e_client_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h)
3621 {
3622    int gx = 0;
3623    int gy = 0;
3624    int gw = 0;
3625    int gh = 0;
3626
3627    E_OBJECT_CHECK(ec);
3628    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3629
3630    if (e_client_transform_core_enable_get(ec))
3631      {
3632         gx = ec->transform_core.result.boundary.x;
3633         gy = ec->transform_core.result.boundary.y;
3634         gw = ec->transform_core.result.boundary.w;
3635         gh = ec->transform_core.result.boundary.h;
3636      }
3637    else
3638      {
3639         if (ec->frame)
3640           {
3641              evas_object_geometry_get(ec->frame, &gx, &gy, &gw, &gh);
3642              if (gw == 0 && gh == 0)
3643                {
3644                   /* In this case, there is no image buffer in e_comp_object, thus it
3645                    * should return geometry value of ec itself. It usually happens if
3646                    * new ec is not mapped yet.
3647                    */
3648                   gw = ec->w;
3649                   gh = ec->h;
3650                   gx = ec->x;
3651                   gy = ec->y;
3652                }
3653           }
3654         else
3655           {
3656              gx = ec->x;
3657              gy = ec->y;
3658              gw = ec->w;
3659              gh = ec->h;
3660           }
3661      }
3662
3663    if (x) *x = gx;
3664    if (y) *y = gy;
3665    if (w) *w = gw;
3666    if (h) *h = gh;
3667 }
3668
3669 E_API E_Client *
3670 e_client_above_get(const E_Client *ec)
3671 {
3672 #ifdef REFACTOR_DESK_AREA
3673    E_Client_Data_Get_Above data;
3674
3675    E_OBJECT_CHECK_RETURN(ec, NULL);
3676    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
3677
3678    data.above_ec = NULL;
3679
3680    wl_signal_emit_mutable(&PRI(ec)->events.get_above, &data);
3681
3682    return data.above_ec;
3683 #else
3684    unsigned int x;
3685    E_Client *ec2;
3686
3687    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
3688    if (EINA_INLIST_GET(ec)->next) //check current layer
3689      {
3690         EINA_INLIST_FOREACH(EINA_INLIST_GET(ec)->next, ec2)
3691           {
3692              if (ec == ec2)
3693                {
3694                   ELOGF("FATAL", "CHECK the ec inlist next", ec);
3695                   continue;
3696                }
3697              if (!e_object_is_del(E_OBJECT(ec2)))
3698                return ec2;
3699           }
3700      }
3701    if (ec->layer == E_LAYER_CLIENT_CURSOR) return NULL;
3702    if (e_comp_canvas_client_layer_map(ec->layer) == 9999) return NULL;
3703
3704    g_rec_mutex_lock(&e_comp->ec_list_mutex);
3705    /* go up the layers until we find one */
3706    for (x = e_comp_canvas_layer_map(ec->layer) + 1; x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_CURSOR); x++)
3707      {
3708         if (!e_comp->layers[x].clients) continue;
3709         EINA_INLIST_FOREACH(e_comp->layers[x].clients, ec2)
3710           {
3711              if (ec == ec2)
3712                {
3713                   ELOGF("FATAL", "EC exist above layer. ec layer_map:%d, cur layer_map:%d",
3714                         ec, e_comp_canvas_layer_map(ec->layer), x);
3715                   continue;
3716                }
3717              if (!e_object_is_del(E_OBJECT(ec2)))
3718                {
3719                   g_rec_mutex_unlock(&e_comp->ec_list_mutex);
3720                   return ec2;
3721                }
3722           }
3723      }
3724    g_rec_mutex_unlock(&e_comp->ec_list_mutex);
3725
3726    return NULL;
3727 #endif
3728 }
3729
3730 E_API E_Client *
3731 e_client_below_get(const E_Client *ec)
3732 {
3733 #ifdef REFACTOR_DESK_AREA
3734    E_Client_Data_Get_Below data;
3735
3736    E_OBJECT_CHECK_RETURN(ec, NULL);
3737    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
3738
3739    data.below_ec = NULL;
3740
3741    wl_signal_emit_mutable(&PRI(ec)->events.get_below, &data);
3742
3743    return data.below_ec;
3744 #else
3745    unsigned int x;
3746    E_Client *ec2;
3747    Eina_Inlist *l;
3748    E_Layer ec_layer, ec_layer_cw;
3749    int cw_layer;
3750
3751    E_OBJECT_CHECK_RETURN(ec, NULL);
3752    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
3753
3754    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
3755    if (EINA_INLIST_GET(ec)->prev) //check current layer
3756      {
3757         for (l = EINA_INLIST_GET(ec)->prev; l; l = l->prev)
3758           {
3759              ec2 = EINA_INLIST_CONTAINER_GET(l, E_Client);
3760              if (ec == ec2)
3761                {
3762                   ELOGF("FATAL", "CHECK the ec inlist prev", ec);
3763                   continue;
3764                }
3765              if (!e_object_is_del(E_OBJECT(ec2)))
3766                return ec2;
3767           }
3768      }
3769
3770    // check layer validation
3771    ec_layer = ec->layer;
3772    if (ec->layer_block || ec->layer_pending)
3773      {
3774         cw_layer = e_comp_object_layer_get(ec->frame);
3775         if (cw_layer >= 0)
3776           {
3777              ec_layer_cw = e_comp_canvas_layer_map_to(cw_layer);
3778              if (ec_layer != ec_layer_cw)
3779                {
3780                   ELOGF("COMP", "LAYER is not same. USE obj layer! (ec->layer:%d, obj:%d). block:%d, pending:%d)", ec, ec_layer, ec_layer_cw, ec->layer_block, ec->layer_pending);
3781                   ec_layer = ec_layer_cw;
3782                }
3783           }
3784      }
3785
3786    if (ec_layer == E_LAYER_CLIENT_DESKTOP) return NULL;
3787    if (e_comp_canvas_client_layer_map(ec_layer) == 9999) return NULL;
3788
3789    /* go down the layers until we find one */
3790    x = e_comp_canvas_layer_map(ec_layer);
3791    if (x > 0) x--;
3792
3793    g_rec_mutex_lock(&e_comp->ec_list_mutex);
3794    for (; x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
3795      {
3796         if (!e_comp->layers[x].clients) continue;
3797         EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2)
3798           {
3799              if (ec == ec2)
3800                {
3801                   ELOGF("FATAL", "EC exist below layer. ec layer_map:%d, cur layer_map:%d",
3802                         ec, e_comp_canvas_layer_map(ec_layer), x);
3803                   continue;
3804                }
3805              if (!e_object_is_del(E_OBJECT(ec2)))
3806                {
3807                   g_rec_mutex_unlock(&e_comp->ec_list_mutex);
3808                   return ec2;
3809                }
3810           }
3811      }
3812    g_rec_mutex_unlock(&e_comp->ec_list_mutex);
3813
3814    return NULL;
3815 #endif
3816 }
3817
3818 EINTERN E_Client *
3819 e_client_visible_above_get(E_Client *ec)
3820 {
3821 #ifdef REFACTOR_DESK_AREA
3822    E_Client_Data_Get_Visible_Above data;
3823
3824    E_OBJECT_CHECK_RETURN(ec, NULL);
3825    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
3826
3827    data.above_ec = NULL;
3828
3829    wl_signal_emit_mutable(&PRI(ec)->events.get_visible_above, &data);
3830
3831    return data.above_ec;
3832 #else
3833    unsigned int x;
3834    E_Client *ec2;
3835
3836    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
3837    if (EINA_INLIST_GET(ec)->next) //check current layer
3838      {
3839         EINA_INLIST_FOREACH(EINA_INLIST_GET(ec)->next, ec2)
3840           {
3841              if (ec == ec2) continue;
3842              if ((!e_object_is_del(E_OBJECT(ec2))) &&
3843                  (!e_client_util_ignored_get(ec2)) &&
3844                  (ec2->visible) &&
3845                  (ec2->frame))
3846                return ec2;
3847           }
3848      }
3849
3850    if (ec->layer == E_LAYER_CLIENT_CURSOR) return NULL;
3851    if (e_comp_canvas_client_layer_map(ec->layer) == 9999) return NULL;
3852
3853    /* go up the layers until we find one */
3854    for (x = e_comp_canvas_layer_map(ec->layer) + 1; x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_CURSOR); x++)
3855      {
3856         if (!e_comp->layers[x].clients) continue;
3857         EINA_INLIST_FOREACH(e_comp->layers[x].clients, ec2)
3858           {
3859              if (ec == ec2) continue;
3860              if ((!e_object_is_del(E_OBJECT(ec2))) &&
3861                  (!e_client_util_ignored_get(ec2)) &&
3862                  (ec2->visible) &&
3863                  (ec2->frame))
3864                return ec2;
3865           }
3866      }
3867
3868    return NULL;
3869 #endif
3870 }
3871
3872 EINTERN E_Client *
3873 e_client_visible_below_get(E_Client *ec)
3874 {
3875 #ifdef REFACTOR_DESK_AREA
3876    E_Client_Data_Get_Visible_Below data;
3877
3878    E_OBJECT_CHECK_RETURN(ec, NULL);
3879    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
3880
3881    data.below_ec = NULL;
3882
3883    wl_signal_emit_mutable(&PRI(ec)->events.get_visible_below, &data);
3884
3885    return data.below_ec;
3886 #else
3887    unsigned int x;
3888    E_Client *ec2;
3889    Eina_Inlist *l;
3890    E_Layer ec_layer, ec_layer_cw;
3891    int cw_layer;
3892
3893    E_OBJECT_CHECK_RETURN(ec, NULL);
3894    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
3895
3896    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
3897    if (EINA_INLIST_GET(ec)->prev) //check current layer
3898      {
3899         for (l = EINA_INLIST_GET(ec)->prev; l; l = l->prev)
3900           {
3901              ec2 = EINA_INLIST_CONTAINER_GET(l, E_Client);
3902              if (ec == ec2) continue;
3903              if ((!e_object_is_del(E_OBJECT(ec2))) &&
3904                  (!e_client_util_ignored_get(ec2)) &&
3905                  (ec2->visible) &&
3906                  (ec2->frame))
3907                return ec2;
3908           }
3909      }
3910
3911    // check layer validation
3912    ec_layer = ec->layer;
3913    if (ec->layer_block || ec->layer_pending)
3914      {
3915         cw_layer = e_comp_object_layer_get(ec->frame);
3916         if (cw_layer >= 0)
3917           {
3918              ec_layer_cw = e_comp_canvas_layer_map_to(cw_layer);
3919              if (ec_layer != ec_layer_cw)
3920                {
3921                   ELOGF("COMP", "LAYER is not same. USE obj layer! (ec->layer:%d, obj:%d). block:%d, pending:%d)", ec, ec_layer, ec_layer_cw, ec->layer_block, ec->layer_pending);
3922                   ec_layer = ec_layer_cw;
3923                }
3924           }
3925      }
3926
3927    /* go down the layers until we find one */
3928    if (e_comp_canvas_layer_map(ec->layer) > e_comp_canvas_layer_map(E_LAYER_MAX)) return NULL;
3929    x = e_comp_canvas_layer_map(ec->layer);
3930    if (x > 0) x--;
3931
3932    for (; x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
3933      {
3934         if (!e_comp->layers[x].clients) continue;
3935         EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2)
3936           {
3937              if (ec == ec2) continue;
3938              if ((!e_object_is_del(E_OBJECT(ec2))) &&
3939                  (!e_client_util_ignored_get(ec2)) &&
3940                  (ec2->visible) &&
3941                  (ec2->frame))
3942                return ec2;
3943           }
3944      }
3945
3946    return NULL;
3947 #endif
3948 }
3949
3950 E_API E_Client *
3951 e_client_bottom_get(void)
3952 {
3953 #ifdef REFACTOR_DESK_AREA
3954    E_Zone *zone;
3955    E_Desk *desk;
3956
3957    // get the bottom ec from current desk at current zone
3958    zone = e_zone_current_get();
3959    desk = e_desk_current_get(zone);
3960
3961    return e_desk_bottom_ec_get(desk);
3962 #else
3963    unsigned int x;
3964    g_rec_mutex_lock(&e_comp->ec_list_mutex);
3965    for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_CURSOR); x++)
3966      {
3967         E_Client *ec2;
3968
3969         if (!e_comp->layers[x].clients) continue;
3970         EINA_INLIST_FOREACH(e_comp->layers[x].clients, ec2)
3971           if (!e_object_is_del(E_OBJECT(ec2)))
3972             {
3973                g_rec_mutex_unlock(&e_comp->ec_list_mutex);
3974                return ec2;
3975             }
3976      }
3977    g_rec_mutex_unlock(&e_comp->ec_list_mutex);
3978
3979    return NULL;
3980 #endif
3981 }
3982
3983 E_API E_Client *
3984 e_client_top_get(void)
3985 {
3986 #ifdef REFACTOR_DESK_AREA
3987    E_Zone *zone;
3988    E_Desk *desk;
3989
3990    // get the top ec from current desk at current zone
3991    zone = e_zone_current_get();
3992    desk = e_desk_current_get(zone);
3993
3994    return e_desk_top_ec_get(desk);
3995 #else
3996    unsigned int x;
3997    g_rec_mutex_lock(&e_comp->ec_list_mutex);
3998    for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_CURSOR); x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
3999      {
4000         E_Client *ec2;
4001
4002         if (!e_comp->layers[x].clients) continue;
4003         EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2)
4004           if (!e_object_is_del(E_OBJECT(ec2)))
4005             {
4006                g_rec_mutex_unlock(&e_comp->ec_list_mutex);
4007                return ec2;
4008             }
4009      }
4010    g_rec_mutex_unlock(&e_comp->ec_list_mutex);
4011
4012    return NULL;
4013 #endif
4014 }
4015
4016 EINTERN unsigned int
4017 e_clients_count(void)
4018 {
4019    return eina_list_count(e_comp->clients);
4020 }
4021
4022
4023 /**
4024  * Set a callback which will be called just prior to updating the
4025  * move coordinates for a border
4026  */
4027 EINTERN void
4028 e_client_move_intercept_cb_set(E_Client *ec, E_Client_Move_Intercept_Cb cb)
4029 {
4030    ec->move_intercept_cb = cb;
4031 }
4032
4033 ///////////////////////////////////////
4034
4035 E_API E_Client_Hook *
4036 e_client_hook_add(E_Client_Hook_Point hookpoint, E_Client_Hook_Cb func, const void *data)
4037 {
4038    E_Client_Hook *ch;
4039
4040    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_CLIENT_HOOK_LAST, NULL);
4041    ch = E_NEW(E_Client_Hook, 1);
4042    if (!ch) return NULL;
4043    ch->hookpoint = hookpoint;
4044    ch->func = func;
4045    ch->data = (void*)data;
4046    _e_client_hooks[hookpoint] = eina_inlist_append(_e_client_hooks[hookpoint], EINA_INLIST_GET(ch));
4047    return ch;
4048 }
4049
4050 E_API void
4051 e_client_hook_del(E_Client_Hook *ch)
4052 {
4053    ch->delete_me = 1;
4054    if (_e_client_hooks_walking == 0)
4055      {
4056         _e_client_hooks[ch->hookpoint] = eina_inlist_remove(_e_client_hooks[ch->hookpoint], EINA_INLIST_GET(ch));
4057         free(ch);
4058      }
4059    else
4060      _e_client_hooks_delete++;
4061 }
4062
4063 ///////////////////////////////////////
4064
4065 E_API E_Client_Intercept_Hook *
4066 e_client_intercept_hook_add(E_Client_Intercept_Hook_Point hookpoint, E_Client_Intercept_Hook_Cb func, const void *data)
4067 {
4068    E_Client_Intercept_Hook *ch;
4069
4070    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_CLIENT_INTERCEPT_HOOK_LAST, NULL);
4071    ch = E_NEW(E_Client_Intercept_Hook, 1);
4072    if (!ch) return NULL;
4073    ch->hookpoint = hookpoint;
4074    ch->func = func;
4075    ch->data = (void*)data;
4076    _e_client_intercept_hooks[hookpoint] = eina_inlist_append(_e_client_intercept_hooks[hookpoint], EINA_INLIST_GET(ch));
4077    return ch;
4078 }
4079
4080 E_API void
4081 e_client_intercept_hook_del(E_Client_Intercept_Hook *ch)
4082 {
4083    if (!ch) return;
4084
4085    ch->delete_me = 1;
4086    if (_e_client_intercept_hooks_walking == 0)
4087      {
4088         _e_client_intercept_hooks[ch->hookpoint] =
4089            eina_inlist_remove(_e_client_intercept_hooks[ch->hookpoint], EINA_INLIST_GET(ch));
4090         free(ch);
4091      }
4092    else
4093      _e_client_intercept_hooks_delete++;
4094 }
4095
4096 E_API void
4097 e_client_focus_latest_set(E_Client *ec)
4098 {
4099    EINA_SAFETY_ON_NULL_RETURN(ec);
4100
4101    wl_signal_emit_mutable(&PRI(ec)->events.focus_latest_set, NULL);
4102 }
4103
4104 E_API void
4105 e_client_focus_defer_set(E_Client *ec)
4106 {
4107    EINA_SAFETY_ON_NULL_RETURN(ec);
4108
4109    wl_signal_emit_mutable(&PRI(ec)->events.focus_defer_set, NULL);
4110 }
4111
4112 EINTERN void
4113 e_client_focused_set(E_Client *ec)
4114 {
4115    E_Client *focused_ec;
4116    E_Zone *zone;
4117
4118    if (ec)
4119      ELOGF("FOCUS", "CLIENT FOCUSED_SET : SET", ec);
4120    else
4121      ELOGF("FOCUS", "CLIENT FOCUSED_SET : UNSET", NULL);
4122
4123   focused_ec = e_comp_focused_ec_get();
4124   if (ec == focused_ec) return;
4125
4126    TRACE_DS_BEGIN(CLIENT:FOCUSED SET);
4127
4128    // unset the current focused_ec if focused_ec is not being deleted
4129    if (focused_ec)
4130      {
4131        if (!e_object_is_del(E_OBJECT(focused_ec)))
4132          {
4133             // FIXME: Remove focus_unset event of client.
4134             //        Instead, make zone focus_unset event and use it.
4135             wl_signal_emit_mutable(&PRI(focused_ec)->events.focus_unset, NULL);
4136             _e_client_hook_call(E_CLIENT_HOOK_FOCUS_UNSET, focused_ec);
4137
4138             if (e_object_ref_get(E_OBJECT(focused_ec)) > 0)
4139               {
4140                  _e_client_event_simple(focused_ec, E_EVENT_CLIENT_FOCUS_OUT);
4141               }
4142          }
4143      }
4144
4145    // clear the current focused_ec when ec is NULL
4146    if (!ec)
4147      {
4148         zone = e_comp_zone_find_by_ec(focused_ec);
4149         e_zone_focus_clear(zone);
4150         TRACE_DS_END();
4151         return;
4152      }
4153
4154    // FIXME: Remove focus_set event of client.
4155    //        Instead, make zone focus_set event and use it.
4156    // set the new current focused_ec
4157    wl_signal_emit_mutable(&PRI(ec)->events.focus_set, NULL);
4158    _e_client_hook_call(E_CLIENT_HOOK_FOCUS_SET, ec);
4159
4160    // send the client_focuse_in event
4161    _e_client_event_simple(ec, E_EVENT_CLIENT_FOCUS_IN);
4162
4163    TRACE_DS_END();
4164 }
4165
4166 EINTERN void
4167 e_client_activate(E_Client *ec)
4168 {
4169    E_OBJECT_CHECK(ec);
4170    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4171
4172    TRACE_DS_BEGIN(CLIENT:ACTIVATE);
4173
4174    ELOGF("COMP", "Set launching flag..", ec);
4175    ec->launching = EINA_TRUE;
4176
4177    ec->exp_iconify.not_raise = 0;
4178
4179    if (ec->iconic)
4180      {
4181          if (!ec->lock_user_iconify)
4182            e_client_uniconify(ec);
4183      }
4184    ELOGF("COMP", "Un-Set ICONIFY BY CLIENT", ec);
4185    ec->exp_iconify.by_client = 0;
4186    e_client_iconified_type_set(ec, E_ICONIFIED_TYPE_NONE);
4187
4188    wl_signal_emit_mutable(&PRI(ec)->events.activate_done, NULL);
4189    _e_client_hook_call(E_CLIENT_HOOK_ACTIVATE_DONE, ec);
4190
4191    TRACE_DS_END();
4192 }
4193
4194 E_API E_Client *
4195 e_client_focused_get(void)
4196 {
4197    return e_comp_focused_ec_get();
4198 }
4199
4200 EINTERN Eina_List *
4201 e_client_lost_windows_get(E_Zone *zone)
4202 {
4203    Eina_List *list = NULL;
4204    const Eina_List *l;
4205    E_Client *ec;
4206    int loss_overlap = 5;
4207
4208    E_OBJECT_CHECK_RETURN(zone, NULL);
4209    E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, NULL);
4210    EINA_LIST_FOREACH(e_comp->clients, l, ec)
4211      {
4212         if (!e_zone_has_ec(zone, ec)) continue;
4213         if (e_client_util_ignored_get(ec)) continue;
4214
4215         if (!E_INTERSECTS(zone->x + loss_overlap,
4216                           zone->y + loss_overlap,
4217                           zone->w - (2 * loss_overlap),
4218                           zone->h - (2 * loss_overlap),
4219                           ec->x, ec->y, ec->w, ec->h))
4220           {
4221              list = eina_list_append(list, ec);
4222           }
4223      }
4224    return list;
4225 }
4226
4227 ///////////////////////////////////////
4228
4229 EINTERN void
4230 e_client_maximized_geometry_set(E_Client *ec, int x, int y, int w, int h)
4231 {
4232    if (!ec) return;
4233
4234    ec->maximized_info.x = x;
4235    ec->maximized_info.y = y;
4236    ec->maximized_info.w = w;
4237    ec->maximized_info.h = h;
4238
4239    e_client_frame_geometry_set(ec, x, y, w, h);
4240 }
4241
4242 EINTERN void
4243 e_client_maximized_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h)
4244 {
4245    if (!ec) return;
4246
4247    if (x) *x = ec->maximized_info.x;
4248    if (y) *y = ec->maximized_info.y;
4249    if (w) *w = ec->maximized_info.w;
4250    if (h) *h = ec->maximized_info.h;
4251 }
4252
4253 EINTERN void
4254 e_client_maximize_update(E_Client *ec)
4255 {
4256    E_Maximize max;
4257
4258    E_OBJECT_CHECK(ec);
4259    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4260
4261    if (ec->maximized)
4262      {
4263         max = ec->maximized;
4264         ec->maximized = 0;
4265         e_client_maximize(ec, max);
4266      }
4267 }
4268
4269 E_API void
4270 e_client_maximize(E_Client *ec, E_Maximize max)
4271 {
4272    E_OBJECT_CHECK(ec);
4273    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4274
4275    if (!(max & E_MAXIMIZE_DIRECTION)) max |= E_MAXIMIZE_BOTH;
4276
4277    if ((ec->maximized & E_MAXIMIZE_DIRECTION) == (max & E_MAXIMIZE_DIRECTION))
4278      {
4279         if ((ec->maximized & E_MAXIMIZE_TYPE) == (max & E_MAXIMIZE_TYPE))
4280           return;
4281      }
4282
4283    if (ec->new_client)
4284      {
4285         ec->changes.need_maximize = 1;
4286         ec->maximized &= ~E_MAXIMIZE_TYPE;
4287         ec->maximized |= max;
4288         EC_CHANGED(ec);
4289         return;
4290      }
4291
4292    if (!ec->fullscreen)
4293      {
4294         // call the maximize hook of a client
4295         wl_signal_emit_mutable(&PRI(ec)->events.maximize, &max);
4296
4297         // store the E_Maximize value
4298         ec->maximized = max;
4299         ec->changes.need_unmaximize = 0;
4300
4301         evas_object_smart_callback_call(ec->frame, "maximize_done", NULL);
4302      }
4303    else
4304      {
4305         // store the E_Maximize value
4306         ec->maximized = max;
4307         ec->changes.need_unmaximize = 0;
4308      }
4309 }
4310
4311 E_API void
4312 e_client_unmaximize(E_Client *ec, E_Maximize max)
4313 {
4314    E_OBJECT_CHECK(ec);
4315    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4316
4317    if (!(max & E_MAXIMIZE_DIRECTION))
4318      {
4319         CRI("BUG: Unmaximize call without direction!");
4320         return;
4321      }
4322    if (ec->new_client)
4323      {
4324         ec->changes.need_unmaximize = 1;
4325         EC_CHANGED(ec);
4326         return;
4327      }
4328
4329    /* Remove directions not used */
4330    max &= (ec->maximized & E_MAXIMIZE_DIRECTION);
4331    /* Can only remove existing maximization directions */
4332    if (!max) return;
4333
4334    if (!ec->fullscreen)
4335      {
4336         evas_object_smart_callback_call(ec->frame, "unmaximize_pre", NULL);
4337
4338         // call the unmaximize hook of a client
4339         wl_signal_emit_mutable(&PRI(ec)->events.unmaximize, &max);
4340
4341         evas_object_smart_callback_call(ec->frame, "unmaximize_done", NULL);
4342      }
4343
4344    ec->maximized = E_MAXIMIZE_NONE;
4345    ec->changes.need_unmaximize = 0;
4346 }
4347
4348 EINTERN void
4349 e_client_fullscreen(E_Client *ec, E_Fullscreen policy)
4350 {
4351    E_OBJECT_CHECK(ec);
4352    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4353
4354    if (ec->fullscreen) return;
4355
4356    // call the fullscreen_pre hook of a client
4357    wl_signal_emit_mutable(&PRI(ec)->events.fullscreen_pre, NULL);
4358    _e_client_hook_call(E_CLIENT_HOOK_FULLSCREEN_PRE, ec);
4359
4360    if (ec->skip_fullscreen) return;
4361    if (ec->new_client)
4362      {
4363         ec->need_fullscreen = 1;
4364         return;
4365      }
4366
4367    ec->saved.layer = ec->layer;
4368    e_client_layer_set(ec, ec->fullscreen_layer);
4369
4370    ec->fullscreen = 1;
4371
4372    // call the fullscreen hook of a client
4373    wl_signal_emit_mutable(&PRI(ec)->events.fullscreen, &policy);
4374
4375    ec->fullscreen_policy = policy;
4376
4377    _e_client_event_simple(ec, E_EVENT_CLIENT_FULLSCREEN);
4378 }
4379
4380 EINTERN void
4381 e_client_unfullscreen(E_Client *ec)
4382 {
4383    E_OBJECT_CHECK(ec);
4384    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4385
4386    ec->need_fullscreen = 0;
4387
4388    if (!ec->fullscreen) return;
4389
4390    ec->fullscreen = 0;
4391
4392    E_Fullscreen policy = ec->fullscreen_policy;
4393
4394    // call the unfullscreen hook of a client
4395    wl_signal_emit_mutable(&PRI(ec)->events.unfullscreen, &policy);
4396
4397    e_client_layer_set(ec, ec->saved.layer);
4398
4399    ec->fullscreen_policy = E_FULLSCREEN_RESIZE;
4400
4401    _e_client_event_simple(ec, E_EVENT_CLIENT_UNFULLSCREEN);
4402 }
4403
4404 ///////////////////////////////////////
4405 EINTERN Eina_Bool
4406 e_client_is_parent_iconify_by_client(E_Client *ec)
4407 {
4408    E_Client *parent = ec->parent;
4409    if (!parent) return EINA_FALSE;
4410
4411    if ((parent->exp_iconify.type == E_ICONIFIED_TYPE_ICONIFY_BY_CLIENT) ||
4412        (parent->exp_iconify.type == E_ICONIFIED_TYPE_PARENT_ICONIFY_BY_CLIENT))
4413      return EINA_TRUE;
4414
4415    return EINA_FALSE;
4416 }
4417
4418 E_API void
4419 e_client_iconify(E_Client *ec)
4420 {
4421    E_OBJECT_CHECK(ec);
4422    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4423
4424    E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
4425    Eina_Bool iconified_by_client = e_client_is_iconified_by_client(ec);
4426
4427    ELOGF("TZVIS", "ICONIFY  |iconic:%d  |argb:%d       |not_raise:%d   |by_client:%d, type:%d",
4428          ec, ec->iconic, ec->argb, (unsigned int)ec->exp_iconify.not_raise,
4429          ec->exp_iconify.by_client, ec->exp_iconify.type);
4430
4431    if (ec->iconic) return;
4432    if (ec->exp_iconify.skip_iconify && !iconified_by_client) return;
4433    if (ec->exp_iconify.skip_by_remote) return;
4434    if (!cdata || !cdata->mapped)
4435      {
4436         if (!iconified_by_client)
4437           {
4438              ELOGF("TZVIS", "Not mapped.. So, don't iconify", ec);
4439              return;
4440           }
4441         else
4442           {
4443              ELOGF("TZVIS", "Not mapped.. But, iconify by user request", ec);
4444           }
4445      }
4446
4447    TRACE_DS_BEGIN(CLIENT:ICONIFY);
4448
4449    wl_signal_emit_mutable(&PRI(ec)->events.iconify, NULL);
4450    _e_client_hook_call(E_CLIENT_HOOK_ICONIFY, ec);
4451
4452    TRACE_DS_END();
4453 }
4454
4455 E_API void
4456 e_client_uniconify(E_Client *ec)
4457 {
4458    E_Comp_Wl_Client_Data *cdata;
4459
4460    E_OBJECT_CHECK(ec);
4461    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4462
4463    cdata = e_client_cdata_get(ec);
4464
4465    ELOGF("TZVIS", "UNICONIFY|iconic:%d  |argb:%d       |not_raise:%d  |by_client:%d, type:%d |mapped:%d",
4466          ec, ec->iconic, ec->argb, (unsigned int)ec->exp_iconify.not_raise,
4467          ec->exp_iconify.by_client, ec->exp_iconify.type,
4468          cdata ? cdata->mapped : 0);
4469
4470    if (!ec->iconic) return;
4471
4472    TRACE_DS_BEGIN(CLIENT:UNICONIFY);
4473
4474     // call the uniconify hook of a client
4475    wl_signal_emit_mutable(&PRI(ec)->events.uniconify, NULL);
4476    _e_client_hook_call(E_CLIENT_HOOK_UNICONIFY, ec);
4477
4478    TRACE_DS_END();
4479 }
4480
4481 E_API void
4482 e_client_iconified_type_set(E_Client *ec, E_Iconified_Type type)
4483 {
4484    if (!ec) return;
4485    ec->exp_iconify.type = type;
4486 }
4487
4488 EINTERN E_Iconified_Type
4489 e_client_iconified_type_get(E_Client *ec)
4490 {
4491    if (!ec) return E_ICONIFIED_TYPE_NONE;
4492    return ec->exp_iconify.type;
4493 }
4494
4495 E_API Eina_Bool e_client_is_iconified_by_client(E_Client *ec)
4496 {
4497    if (!ec) return EINA_FALSE;
4498
4499    if (ec->exp_iconify.type == E_ICONIFIED_TYPE_ICONIFY_BY_CLIENT)
4500      return EINA_TRUE;
4501
4502    if (ec->exp_iconify.type == E_ICONIFIED_TYPE_DESK_ICONIFY_BY_CLIENT)
4503      return EINA_TRUE;
4504
4505    if (ec->exp_iconify.type == E_ICONIFIED_TYPE_PARENT_ICONIFY_BY_CLIENT)
4506      return EINA_TRUE;
4507
4508    if (ec->exp_iconify.by_client)
4509      {
4510         ELOGF("POL", "CHECK. mismatch value. by_client:%d, type:%d", ec, ec->exp_iconify.by_client, ec->exp_iconify.type);
4511         return EINA_TRUE;
4512      }
4513
4514    return EINA_FALSE;
4515 }
4516
4517 ///////////////////////////////////////
4518
4519 EINTERN void e_client_hide_by_request_set(E_Client *ec, Eina_Bool set)
4520 {
4521    API_ENTRY;
4522    priv->hide_by_request = set;
4523 }
4524
4525 EINTERN Eina_Bool e_client_hide_by_request_get(E_Client *ec)
4526 {
4527    API_ENTRY_VAL(EINA_FALSE);
4528    return priv->hide_by_request;
4529 }
4530
4531 ///////////////////////////////////////
4532
4533 EINTERN void
4534 e_client_stick(E_Client *ec)
4535 {
4536    E_OBJECT_CHECK(ec);
4537    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4538    if (ec->sticky) return;
4539
4540    // call the stick hook of a client
4541    wl_signal_emit_mutable(&PRI(ec)->events.stick, NULL);
4542
4543    // send the sticky property event of a client
4544    _e_client_event_property(ec, E_CLIENT_PROPERTY_STICKY);
4545 }
4546
4547 EINTERN void
4548 e_client_unstick(E_Client *ec)
4549 {
4550    E_OBJECT_CHECK(ec);
4551    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4552
4553    if (!ec->sticky) return;
4554
4555    // call the unstick hook of a client
4556    wl_signal_emit_mutable(&PRI(ec)->events.unstick, NULL);
4557
4558   // send the sticky property event of a client
4559    _e_client_event_property(ec, E_CLIENT_PROPERTY_STICKY);
4560 }
4561
4562 EINTERN void
4563 e_client_pinned_set(E_Client *ec, Eina_Bool set)
4564 {
4565    E_Layer layer;
4566
4567    EINA_SAFETY_ON_NULL_RETURN(ec);
4568    if (set)
4569      layer = E_LAYER_CLIENT_ABOVE;
4570    else
4571      layer = E_LAYER_CLIENT_NORMAL;
4572
4573    e_client_layer_set(ec, layer);
4574
4575    EC_CHANGED(ec);
4576 }
4577
4578 ///////////////////////////////////////
4579
4580 EINTERN Eina_Bool
4581 e_client_border_set(E_Client *ec, const char *name)
4582 {
4583    Eina_Stringshare *pborder;
4584
4585    E_OBJECT_CHECK_RETURN(ec, EINA_FALSE);
4586    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE);
4587    if (!e_comp_object_frame_allowed(ec->frame)) return EINA_FALSE;
4588    if (ec->border.changed)
4589      CRI("CALLING WHEN border.changed SET!");
4590
4591    if (!e_util_strcmp(ec->border.name, name)) return EINA_TRUE;
4592    pborder = ec->border.name;
4593    ec->border.name = eina_stringshare_add(name);
4594    if (e_comp_object_frame_theme_set(ec->frame, name))
4595      {
4596         eina_stringshare_del(pborder);
4597         return EINA_TRUE;
4598      }
4599    eina_stringshare_del(ec->border.name);
4600    ec->border.name = pborder;
4601    return EINA_FALSE;
4602 }
4603
4604 ///////////////////////////////////////
4605
4606 EINTERN void
4607 e_client_comp_hidden_set(E_Client *ec, Eina_Bool hidden)
4608 {
4609    E_OBJECT_CHECK(ec);
4610    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4611
4612    hidden = !!hidden;
4613    if (ec->comp_hidden == hidden) return;
4614    ec->comp_hidden = hidden;
4615    evas_object_smart_callback_call(ec->frame, "comp_hidden", NULL);
4616 }
4617
4618 ///////////////////////////////////////
4619
4620 EINTERN void
4621 e_client_act_move_keyboard(E_Client *ec)
4622 {
4623    EINA_SAFETY_ON_NULL_RETURN(ec);
4624
4625    if (!_e_client_move_begin(ec))
4626      return;
4627
4628    _e_client_action_init(ec);
4629    _e_client_action_move_timeout_add();
4630
4631    wl_signal_emit_mutable(&PRI(ec)->events.move_update, NULL);
4632    if (!_e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec)) return;
4633    evas_object_freeze_events_set(ec->frame, 1);
4634
4635    if (!action_handler_mouse)
4636      action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_client_move_mouse_down, NULL);
4637 }
4638
4639 EINTERN void
4640 e_client_act_resize_keyboard(E_Client *ec)
4641 {
4642    EINA_SAFETY_ON_NULL_RETURN(ec);
4643
4644    ec->resize_mode = E_POINTER_RESIZE_TL;
4645    ec->keyboard_resizing = 1;
4646    if (!e_client_resize_begin(ec))
4647      {
4648         ec->keyboard_resizing = 0;
4649         return;
4650      }
4651
4652    _e_client_action_init(ec);
4653    _e_client_action_resize_timeout_add();
4654    evas_object_freeze_events_set(ec->frame, 1);
4655
4656    if (!action_handler_mouse)
4657      action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_client_resize_mouse_down, NULL);
4658 }
4659
4660 EINTERN void
4661 e_client_act_move_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev)
4662 {
4663    E_OBJECT_CHECK(ec);
4664    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4665    if (e_client_util_resizing_get(ec) || (ec->moving)) return;
4666    if (ev)
4667      {
4668         char source[256];
4669
4670         snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button);
4671         _e_client_moveinfo_gather(ec, source);
4672      }
4673    if (!_e_client_move_begin(ec))
4674      return;
4675
4676    _e_client_action_init(ec);
4677 }
4678
4679 E_API void
4680 e_client_act_move_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED)
4681 {
4682    E_OBJECT_CHECK(ec);
4683    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4684    if (!ec->moving) return;
4685    _e_client_move_end(ec);
4686    _e_client_action_finish();
4687 }
4688
4689 EINTERN void
4690 e_client_act_resize_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev, E_Pointer_Mode resize_mode)
4691 {
4692    E_OBJECT_CHECK(ec);
4693    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4694    if (ec->lock_user_size) return;
4695    if (e_client_util_resizing_get(ec) || (ec->moving)) return;
4696    if (ev)
4697      {
4698         char source[256];
4699         snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button);
4700         _e_client_moveinfo_gather(ec, source);
4701
4702         if (resize_mode != E_POINTER_RESIZE_NONE)
4703           {
4704              ec->resize_mode = resize_mode;
4705           }
4706         else
4707           {
4708              /* Use canvas.x, canvas.y of event.
4709               * Transformed coordinates has to be considered for accurate resize_mode
4710               * rather than absolute coordinates. */
4711              if ((ev->canvas.x > (ec->x + ec->w / 5)) &&
4712                  (ev->canvas.x < (ec->x + ec->w * 4 / 5)))
4713                {
4714                   if (ev->canvas.y < (ec->y + ec->h / 2)) ec->resize_mode = E_POINTER_RESIZE_T;
4715                   else ec->resize_mode = E_POINTER_RESIZE_B;
4716                }
4717              else if (ev->canvas.x < (ec->x + ec->w / 2))
4718                {
4719                   if ((ev->canvas.y > (ec->y + ec->h / 5)) && (ev->canvas.y < (ec->y + ec->h * 4 / 5))) ec->resize_mode = E_POINTER_RESIZE_L;
4720                   else if (ev->canvas.y < (ec->y + ec->h / 2)) ec->resize_mode = E_POINTER_RESIZE_TL;
4721                   else ec->resize_mode = E_POINTER_RESIZE_BL;
4722                }
4723              else
4724                {
4725                   if ((ev->canvas.y > (ec->y + ec->h / 5)) && (ev->canvas.y < (ec->y + ec->h * 4 / 5))) ec->resize_mode = E_POINTER_RESIZE_R;
4726                   else if (ev->canvas.y < (ec->y + ec->h / 2)) ec->resize_mode = E_POINTER_RESIZE_TR;
4727                   else ec->resize_mode = E_POINTER_RESIZE_BR;
4728                }
4729           }
4730      }
4731    if (!e_client_resize_begin(ec))
4732      return;
4733    _e_client_action_init(ec);
4734 }
4735
4736 EINTERN void
4737 e_client_act_resize_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED)
4738 {
4739    E_OBJECT_CHECK(ec);
4740    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4741    if (e_client_util_resizing_get(ec))
4742      {
4743         _e_client_resize_end(ec);
4744         ec->changes.reset_gravity = 1;
4745         if (!e_object_is_del(E_OBJECT(ec)))
4746           EC_CHANGED(ec);
4747      }
4748    _e_client_action_finish();
4749 }
4750
4751 EINTERN void
4752 e_client_act_menu_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev, int key)
4753 {
4754    E_OBJECT_CHECK(ec);
4755    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4756 }
4757
4758 EINTERN void
4759 e_client_act_close_begin(E_Client *ec)
4760 {
4761    E_OBJECT_CHECK(ec);
4762    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4763    if (ec->lock_close) return;
4764    if (ec->icccm.delete_request)
4765      {
4766         ec->delete_requested = 1;
4767         evas_object_smart_callback_call(ec->frame, "delete_request", NULL);
4768      }
4769    else if (e_config->kill_if_close_not_possible)
4770      {
4771         e_client_act_kill_begin(ec);
4772      }
4773 }
4774
4775 EINTERN void
4776 e_client_act_kill_begin(E_Client *ec)
4777 {
4778    E_OBJECT_CHECK(ec);
4779    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4780    if (ec->internal) return;
4781    if (ec->lock_close) return;
4782    if ((ec->netwm.pid > 1) && (e_config->kill_process))
4783      {
4784         kill(ec->netwm.pid, SIGINT);
4785         ec->kill_timer = ecore_timer_add(e_config->kill_timer_wait,
4786                                          _e_client_cb_kill_timer, ec);
4787      }
4788    else
4789      evas_object_smart_callback_call(ec->frame, "kill_request", NULL);
4790 }
4791
4792 ////////////////////////////////////////////
4793
4794 EINTERN void
4795 e_client_ping(E_Client *ec)
4796 {
4797    E_OBJECT_CHECK(ec);
4798    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4799
4800    if (!e_config->ping_clients) return;
4801
4802    EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(ec)));
4803
4804    ec->ping_ok = 0;
4805    evas_object_smart_callback_call(ec->frame, "ping", NULL);
4806    ec->ping = ecore_loop_time_get();
4807    if (ec->ping_poller) ecore_poller_del(ec->ping_poller);
4808    ec->ping_poller = ecore_poller_add(ECORE_POLLER_CORE,
4809                                       e_config->ping_clients_interval,
4810                                       _e_client_cb_ping_poller, ec);
4811 }
4812
4813 ////////////////////////////////////////////
4814 E_API void
4815 e_client_cursor_map_apply(E_Client *ec, int rotation, int x, int y)
4816 {
4817    // TODO: remove(deprecate) this e_client_cursor_map_apply.
4818 }
4819
4820 EINTERN void
4821 e_client_move_cancel(void)
4822 {
4823    if (!ecmove) return;
4824    if (ecmove->cur_mouse_action)
4825      {
4826         E_Client *ec;
4827
4828         ec = ecmove;
4829         e_object_ref(E_OBJECT(ec));
4830         if (ec->cur_mouse_action->func.end_mouse)
4831           ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", NULL);
4832         else if (ec->cur_mouse_action->func.end)
4833           ec->cur_mouse_action->func.end(E_OBJECT(ec), "");
4834         e_object_unref(E_OBJECT(ec->cur_mouse_action));
4835         ec->cur_mouse_action = NULL;
4836         e_object_unref(E_OBJECT(ec));
4837      }
4838    else
4839      _e_client_move_end(ecmove);
4840 }
4841
4842 EINTERN void
4843 e_client_resize_cancel(void)
4844 {
4845    if (!ecresize) return;
4846    if (ecresize->cur_mouse_action)
4847      {
4848         E_Client *ec;
4849
4850         ec = ecresize;
4851         e_object_ref(E_OBJECT(ec));
4852         if (ec->cur_mouse_action->func.end_mouse)
4853           ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", NULL);
4854         else if (ec->cur_mouse_action->func.end)
4855           ec->cur_mouse_action->func.end(E_OBJECT(ec), "");
4856         e_object_unref(E_OBJECT(ec->cur_mouse_action));
4857         ec->cur_mouse_action = NULL;
4858         e_object_unref(E_OBJECT(ec));
4859      }
4860    else
4861      _e_client_resize_end(ecresize);
4862 }
4863
4864 EINTERN Eina_Bool
4865 e_client_resize_begin(E_Client *ec)
4866 {
4867    if ((ec->fullscreen) || (ec->lock_user_size))
4868      goto error;
4869    if (!_e_client_action_input_win_new()) goto error;
4870    ecresize = ec;
4871    if (ec->manage_resize.enable_aspect_ratio)
4872      {
4873         ELOGF("RESIZE", "Set resize aspect ratio.. ratio(%dx%d)", ec, ec->w, ec->h);
4874         ec->manage_resize.aw = ec->w;
4875         ec->manage_resize.ah = ec->h - ec->manage_resize.header_h - ec->manage_resize.footer_h;
4876      }
4877
4878    wl_signal_emit_mutable(&PRI(ec)->events.move_begin, NULL);
4879    _e_client_hook_call(E_CLIENT_HOOK_RESIZE_BEGIN, ec);
4880    if (ec->transformed)
4881      _e_client_transform_resize_begin(ec);
4882    if (!e_client_util_resizing_get(ec))
4883      {
4884         if (ecresize == ec) ecresize = NULL;
4885         _e_client_action_input_win_del();
4886         return EINA_FALSE;
4887      }
4888    if (!ec->lock_user_stacking)
4889      {
4890         if (e_config->border_raise_on_mouse_action)
4891           e_client_raise(ec);
4892      }
4893
4894    if (e_comp->hwc)
4895      e_comp_client_override_add(ec);
4896
4897    return EINA_TRUE;
4898 error:
4899    ec->resize_mode = E_POINTER_RESIZE_NONE;
4900    return EINA_FALSE;
4901 }
4902
4903
4904 ////////////////////////////////////////////
4905
4906 EINTERN void
4907 e_client_frame_recalc(E_Client *ec)
4908 {
4909    EINA_SAFETY_ON_NULL_RETURN(ec);
4910    if (!ec->frame) return;
4911    evas_object_smart_callback_call(ec->frame, "frame_recalc", NULL);
4912 }
4913
4914 ////////////////////////////////////////////
4915
4916 EINTERN void
4917 e_client_signal_move_begin(E_Client *ec, const char *sig, const char *src EINA_UNUSED)
4918 {
4919    E_OBJECT_CHECK(ec);
4920    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4921
4922    if (e_client_util_resizing_get(ec) || (ec->moving)) return;
4923    _e_client_moveinfo_gather(ec, sig);
4924    if (!_e_client_move_begin(ec)) return;
4925 }
4926
4927 EINTERN void
4928 e_client_signal_move_end(E_Client *ec, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
4929 {
4930    E_OBJECT_CHECK(ec);
4931    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4932    if (!ec->moving) return;
4933    _e_client_move_end(ec);
4934 }
4935
4936 EINTERN void
4937 e_client_signal_resize_begin(E_Client *ec, const char *dir, const char *sig, const char *src EINA_UNUSED)
4938 {
4939    int resize_mode = E_POINTER_RESIZE_BR;
4940
4941    E_OBJECT_CHECK(ec);
4942    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4943
4944    if (e_client_util_resizing_get(ec) || (ec->moving)) return;
4945    if (!strcmp(dir, "tl"))
4946      {
4947         resize_mode = E_POINTER_RESIZE_TL;
4948      }
4949    else if (!strcmp(dir, "t"))
4950      {
4951         resize_mode = E_POINTER_RESIZE_T;
4952      }
4953    else if (!strcmp(dir, "tr"))
4954      {
4955         resize_mode = E_POINTER_RESIZE_TR;
4956      }
4957    else if (!strcmp(dir, "r"))
4958      {
4959         resize_mode = E_POINTER_RESIZE_R;
4960      }
4961    else if (!strcmp(dir, "br"))
4962      {
4963         resize_mode = E_POINTER_RESIZE_BR;
4964      }
4965    else if (!strcmp(dir, "b"))
4966      {
4967         resize_mode = E_POINTER_RESIZE_B;
4968      }
4969    else if (!strcmp(dir, "bl"))
4970      {
4971         resize_mode = E_POINTER_RESIZE_BL;
4972      }
4973    else if (!strcmp(dir, "l"))
4974      {
4975         resize_mode = E_POINTER_RESIZE_L;
4976      }
4977    ec->resize_mode = resize_mode;
4978    _e_client_moveinfo_gather(ec, sig);
4979    if (!e_client_resize_begin(ec))
4980      return;
4981 }
4982
4983 EINTERN void
4984 e_client_signal_resize_end(E_Client *ec, const char *dir EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
4985 {
4986    E_OBJECT_CHECK(ec);
4987    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4988    if (!e_client_util_resizing_get(ec)) return;
4989    _e_client_resize_handle(ec);
4990    _e_client_resize_end(ec);
4991    ec->changes.reset_gravity = 1;
4992    EC_CHANGED(ec);
4993 }
4994
4995 ////////////////////////////////////////////
4996
4997 EINTERN void
4998 e_client_resize_limit(E_Client *ec, int *w, int *h)
4999 {
5000    E_OBJECT_CHECK(ec);
5001    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5002
5003    if (ec->frame)
5004      e_comp_object_frame_wh_unadjust(ec->frame, *w, *h, w, h);
5005    if (*h < 1) *h = 1;
5006    if (*w < 1) *w = 1;
5007
5008    if ((ec->icccm.max_w > 0) && (*w > ec->icccm.max_w)) *w = ec->icccm.max_w;
5009    else if (*w < ec->icccm.min_w)
5010      *w = ec->icccm.min_w;
5011    if ((ec->icccm.max_h > 0) && (*h > ec->icccm.max_h)) *h = ec->icccm.max_h;
5012    else if (*h < ec->icccm.min_h)
5013      *h = ec->icccm.min_h;
5014
5015    if (ec->frame)
5016      e_comp_object_frame_wh_adjust(ec->frame, *w, *h, w, h);
5017 }
5018
5019 ////////////////////////////////////////////
5020
5021
5022
5023 EINTERN E_Client *
5024 e_client_under_pointer_get(E_Desk *desk, E_Client *exclude)
5025 {
5026    int x, y;
5027
5028    /* We need to ensure that we can get the comp window for the
5029     * zone of either the given desk or the desk of the excluded
5030     * window, so return if neither is given */
5031    if (desk)
5032      e_input_device_pointer_xy_get(NULL, &x, &y);
5033    else if (exclude)
5034      e_input_device_pointer_xy_get(NULL, &x, &y);
5035    else
5036      return NULL;
5037
5038    if (!desk)
5039      {
5040         desk = exclude->desk;
5041         if (!desk)
5042           {
5043              if (exclude->zone)
5044                desk = e_desk_current_get(exclude->zone);
5045              else
5046                desk = e_desk_current_get(e_zone_current_get());
5047           }
5048      }
5049
5050    return desk ? _e_client_under_pointer_helper(desk, exclude, x, y) : NULL;
5051 }
5052
5053 E_API E_Client *e_client_under_position_get(E_Desk *desk, int x, int y, E_Client *exclude)
5054 {
5055    if (!desk) return NULL;
5056
5057    return _e_client_under_pointer_helper(desk, exclude, x, y);
5058 }
5059
5060 E_API E_Client *e_client_under_position_input_get(E_Desk *desk, int x, int y)
5061 {
5062    if (!desk) return NULL;
5063
5064    return _e_client_under_pointer_input_helper(desk, x, y);
5065 }
5066
5067 ////////////////////////////////////////////
5068
5069 ////////////////////////////////////////////
5070
5071 E_API void
5072 e_client_redirected_set(E_Client *ec, Eina_Bool set)
5073 {
5074    EINA_SAFETY_ON_NULL_RETURN(ec);
5075    if (ec->input_only) return;
5076    set = !!set;
5077    if (ec->redirected == set) return;
5078    if (set)
5079      {
5080         e_client_frame_recalc(ec);
5081
5082         wl_signal_emit_mutable(&PRI(ec)->events.redirect, NULL);
5083         if (!_e_client_hook_call(E_CLIENT_HOOK_REDIRECT, ec)) return;
5084      }
5085    else
5086      {
5087         wl_signal_emit_mutable(&PRI(ec)->events.unredirect, NULL);
5088         if (!_e_client_hook_call(E_CLIENT_HOOK_UNREDIRECT, ec)) return;
5089      }
5090    e_comp_object_redirected_set(ec->frame, set);
5091    ec->redirected = !!set;
5092 }
5093
5094 ////////////////////////////////////////////
5095
5096 E_API void
5097 e_client_transform_update(E_Client *ec)
5098 {
5099    if (e_client_util_resizing_get(ec))
5100      _e_client_transform_resize(ec);
5101 }
5102
5103 ////////////////////////////////////////////
5104
5105 EINTERN void
5106 e_client_transform_apply(E_Client *ec, double angle, double zoom, int cx, int cy)
5107 {
5108    E_Map *map;
5109    E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
5110    E_Client *subc;
5111    Eina_List *l;
5112
5113    if (e_comp_wl_subsurface_check(ec))
5114      return;
5115
5116    /* check if it's different with current state */
5117    if ((ec->transform.angle == angle) &&
5118        (ec->transform.zoom == zoom) &&
5119        (ec->transform.center.x == cx) &&
5120        (ec->transform.center.y == cy))
5121      return;
5122
5123    /* use previous value if any required value is invalid */
5124    if (angle == -1.0)
5125      angle = ec->transform.angle;
5126    if (zoom == -1.0)
5127      zoom = ec->transform.zoom;
5128    if (!E_INSIDE(cx, cy,
5129                  ec->client.x, ec->client.y,
5130                  ec->client.w, ec->client.h))
5131      {
5132         cx = ec->transform.center.x;
5133         cy = ec->transform.center.y;
5134      }
5135
5136    if ((angle == 0) && (zoom == 1.0))
5137      {
5138         e_client_transform_clear(ec);
5139         return;
5140      }
5141
5142    map = e_map_new_with_direct_render(ec->transform_core.direct_render);
5143    e_map_util_points_populate_from_object_full(map, ec->frame, 0);
5144
5145    e_map_util_rotate(map, angle, cx, cy);
5146    _e_client_transform_geometry_save(ec, map);
5147
5148    e_map_util_zoom(map, zoom, zoom, cx, cy);
5149
5150    e_map_util_object_move_sync_set(map, EINA_TRUE);
5151    e_client_map_set(ec, map);
5152    e_client_map_enable_set(ec, EINA_TRUE);
5153
5154    EINA_LIST_FOREACH(cdata->sub.list, l, subc)
5155      _e_client_transform_sub_apply(subc, ec, zoom);
5156    EINA_LIST_REVERSE_FOREACH(cdata->sub.below_list, l, subc)
5157      _e_client_transform_sub_apply(subc, ec, zoom);
5158
5159    e_map_free(map);
5160
5161    ec->transform.zoom = zoom;
5162    ec->transform.angle = angle;
5163    ec->transform.center.x = cx;
5164    ec->transform.center.y = cy;
5165    ec->transformed = EINA_TRUE;
5166 }
5167
5168 ////////////////////////////////////////////
5169
5170 EINTERN void
5171 e_client_transform_clear(E_Client *ec)
5172 {
5173    E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
5174    E_Client *subc;
5175    Eina_List *l;
5176
5177    e_client_map_enable_set(ec, EINA_FALSE);
5178    e_client_map_set(ec, NULL);
5179
5180    EINA_LIST_FOREACH(cdata->sub.list, l, subc)
5181      _e_client_transform_sub_apply(subc, ec, 1.0);
5182    EINA_LIST_REVERSE_FOREACH(cdata->sub.below_list, l, subc)
5183      _e_client_transform_sub_apply(subc, ec, 1.0);
5184
5185    ec->transform.zoom = 1.0;
5186    ec->transform.angle = 0.0;
5187    ec->transformed = EINA_FALSE;
5188 }
5189
5190 E_API Eina_Bool
5191 e_client_transform_core_enable_get(E_Client *ec)
5192 {
5193    if (!ec) return EINA_FALSE;
5194    return ec->transform_core.result.enable;
5195 }
5196
5197 E_API void
5198 e_client_transform_core_add(E_Client *ec, E_Util_Transform *transform)
5199 {
5200    if (!ec) return;
5201    if (!transform) return;
5202
5203    // duplication check
5204    if (ec->transform_core.transform_list &&
5205        eina_list_data_find(ec->transform_core.transform_list, transform) == transform)
5206      {
5207         return;
5208      }
5209
5210    ec->transform_core.transform_list = eina_list_append(ec->transform_core.transform_list, transform);
5211    ec->transform_core.changed = EINA_TRUE;
5212    e_util_transform_ref(transform);
5213   // e_client_transform_core_update(ec);
5214 }
5215
5216 E_API void
5217 e_client_transform_core_remove(E_Client *ec, E_Util_Transform *transform)
5218 {
5219    if (!ec) return;
5220    if (!transform) return;
5221
5222    if (ec->transform_core.transform_list &&
5223        eina_list_data_find(ec->transform_core.transform_list, transform) == transform)
5224      {
5225         ec->transform_core.transform_list = eina_list_remove(ec->transform_core.transform_list, transform);
5226         e_util_transform_unref(transform);
5227         ec->transform_core.changed = EINA_TRUE;
5228      }
5229
5230    e_client_transform_core_update(ec);
5231 }
5232
5233 E_API void
5234 e_client_transform_core_update(E_Client *ec)
5235 {
5236    if (!ec) return;
5237    if (ec->new_client) return;
5238    if (!_e_client_transform_core_check_change(ec)) return;
5239
5240    if (ec->transform_core.transform_list || ec->transform_core.parent.enable)
5241      {
5242         E_Util_Transform_Rect source_rect;
5243         E_Util_Transform_Matrix matrix, boundary_matrix;
5244         E_Util_Transform_Zoom zoom;
5245         Eina_List *l;
5246         Eina_Bool background;
5247         E_Util_Transform *temp_trans;
5248
5249         // 1. init state
5250         ec->transform_core.result.enable = EINA_TRUE;
5251         e_util_transform_rect_client_rect_get(&source_rect, ec);
5252         e_util_transform_init(&ec->transform_core.result.transform);
5253
5254         // 2. merge transform
5255         EINA_LIST_FOREACH(ec->transform_core.transform_list, l, temp_trans)
5256           {
5257              e_util_transform_merge(&ec->transform_core.result.transform, temp_trans);
5258           }
5259         zoom = ec->transform_core.result.transform.zoom;
5260
5261         // 2.5 check viewport
5262         if (e_util_transform_viewport_flag_get(&ec->transform_core.result.transform))
5263           {
5264              int vx = 0, vy = 0, vw = 0, vh = 0;
5265              e_util_transform_viewport_get(&ec->transform_core.result.transform, &vx, &vy, &vw, &vh);
5266              e_util_transform_rect_init(&source_rect, vx, vy, vw, vh);
5267           }
5268
5269         // 3. apply background transform
5270         matrix = e_util_transform_convert_to_matrix(&ec->transform_core.result.transform, &source_rect);
5271
5272         if (e_util_transform_bg_transform_flag_get(&ec->transform_core.result.transform))
5273           {
5274              boundary_matrix = e_util_transform_bg_convert_to_matrix(&ec->transform_core.result.transform, &source_rect);
5275              background = EINA_TRUE;
5276           }
5277         else
5278           {
5279              background = EINA_FALSE;
5280              boundary_matrix = matrix;
5281           }
5282
5283         if (background != ec->transform_core.background)
5284           {
5285              if (background)
5286                {
5287                   e_comp_object_transform_bg_set(ec->frame, EINA_TRUE);
5288                }
5289              else
5290                {
5291                   e_comp_object_transform_bg_set(ec->frame, EINA_FALSE);
5292                }
5293
5294              ec->transform_core.background = background;
5295           }
5296
5297         // 3.1 if 24bit window then set transp rect
5298         if (!ec->argb)
5299           {
5300              int angle = 0;
5301
5302              e_util_transform_rotation_round_get(&ec->transform_core.result.transform, 0, 0, &angle);
5303              angle %= 90;
5304
5305              if (angle == 0) // when transform angle is 0, 90, 180, 270, 360. then set transp rect
5306                e_comp_object_transform_transp_set(ec->frame, EINA_TRUE);
5307              else
5308                e_comp_object_transform_transp_set(ec->frame, EINA_FALSE);
5309           }
5310         else
5311           e_comp_object_transform_transp_set(ec->frame, EINA_FALSE);
5312
5313         // 3.5 parent matrix multiply
5314         if (ec->transform_core.parent.enable)
5315           {
5316              matrix = e_util_transform_matrix_multiply(&ec->transform_core.parent.matrix,
5317                                                        &matrix);
5318              boundary_matrix = e_util_transform_matrix_multiply(&ec->transform_core.parent.matrix,
5319                                                                 &boundary_matrix);
5320
5321              ec->transform_core.result.transform.use_zoom = EINA_TRUE;
5322              zoom.zoom_x *= ec->transform_core.parent.zoom.zoom_x;
5323              zoom.zoom_y *= ec->transform_core.parent.zoom.zoom_y;
5324              zoom.cx += ec->transform_core.parent.zoom.cx;
5325              zoom.cy += ec->transform_core.parent.zoom.cy;
5326           }
5327
5328         // 4. apply matrix to vertices
5329         ec->transform_core.result.matrix = matrix;
5330         ec->transform_core.result.inv_matrix = e_util_transform_matrix_inverse_get(&matrix);
5331         ec->transform_core.result.vertices = e_util_transform_rect_to_vertices(&source_rect);
5332         ec->transform_core.result.boundary.vertices = e_util_transform_rect_to_vertices(&source_rect);
5333         ec->transform_core.result.vertices = e_util_transform_matrix_multiply_rect_vertex(&matrix,
5334                                                                                           &ec->transform_core.result.vertices);
5335         ec->transform_core.result.boundary.vertices = e_util_transform_matrix_multiply_rect_vertex(&boundary_matrix,
5336                                                                                                    &ec->transform_core.result.boundary.vertices);
5337         ec->transform_core.result.transform.zoom = zoom;
5338
5339         // 5. apply vertices
5340         if (ec->transform_core.result.transform.use_zoom)
5341           {
5342              // TODO: apply zoom values to vertices
5343              e_comp_object_transform_transp_vertices_set_with_zoom(ec->frame, &ec->transform_core.result.vertices,
5344                                                                    ec->transform_core.result.transform.zoom);
5345              e_comp_object_transform_bg_vertices_set_with_zoom(ec->frame, &ec->transform_core.result.boundary.vertices,
5346                                                                ec->transform_core.result.transform.zoom);
5347              _e_client_transform_core_boundary_update(ec, &ec->transform_core.result.boundary.vertices);
5348              _e_client_transform_core_vertices_apply_with_zoom(ec, ec->frame, &ec->transform_core.result.vertices, &ec->transform_core.result.transform,
5349                                                                ec->transform_core.result.transform.zoom);
5350           }
5351         else
5352           {
5353              e_comp_object_transform_transp_vertices_set(ec->frame, &ec->transform_core.result.vertices);
5354              e_comp_object_transform_bg_vertices_set(ec->frame, &ec->transform_core.result.boundary.vertices);
5355              _e_client_transform_core_boundary_update(ec, &ec->transform_core.result.boundary.vertices);
5356              _e_client_transform_core_vertices_apply(ec, ec->frame, &ec->transform_core.result.vertices, &ec->transform_core.result.transform);
5357           }
5358
5359         // 6. subsurface update
5360         _e_client_transform_core_sub_update(ec, &ec->transform_core.result.vertices);
5361
5362         if (!e_object_is_del(E_OBJECT(ec)))
5363           {
5364              wl_signal_emit_mutable(&PRI(ec)->events.transform_change, NULL);
5365              _e_client_hook_call(E_CLIENT_HOOK_TRANSFORM_CHANGE, ec);
5366           }
5367      }
5368    else
5369      {
5370         if (ec->transform_core.result.enable)
5371           {
5372              ec->transform_core.result.enable = EINA_FALSE;
5373              _e_client_transform_core_vertices_apply(ec, ec->frame, NULL, NULL);
5374              e_comp_object_transform_bg_set(ec->frame, EINA_FALSE);
5375              ec->transform_core.background = EINA_FALSE;
5376              e_comp_object_transform_transp_set(ec->frame, EINA_FALSE);
5377              _e_client_transform_core_sub_update(ec, NULL);
5378
5379              if (!e_object_is_del(E_OBJECT(ec)))
5380                {
5381                   wl_signal_emit_mutable(&PRI(ec)->events.transform_change, NULL);
5382                   _e_client_hook_call(E_CLIENT_HOOK_TRANSFORM_CHANGE, ec);
5383                }
5384           }
5385      }
5386
5387    e_comp_visibility_calculation_set(EINA_TRUE);
5388 }
5389
5390 E_API int
5391 e_client_transform_core_transform_count_get(E_Client *ec)
5392 {
5393    if (!ec) return 0;
5394    if (!ec->transform_core.transform_list) return 0;
5395    return eina_list_count(ec->transform_core.transform_list);
5396 }
5397
5398 E_API E_Util_Transform*
5399 e_client_transform_core_transform_get(E_Client *ec, int index)
5400 {
5401    if (!ec) return NULL;
5402    if (!ec->transform_core.transform_list) return NULL;
5403    if (index < 0 || index >= e_client_transform_core_transform_count_get(ec))
5404       return NULL;
5405
5406    return (E_Util_Transform*)eina_list_nth(ec->transform_core.transform_list, index);
5407 }
5408
5409 E_API void
5410 e_client_transform_core_input_transform(E_Client *ec, int x, int y, int *out_x, int *out_y)
5411 {
5412    E_Util_Transform_Vertex vertex, result_vertex;
5413
5414    if (!ec) return;
5415    if (!e_client_transform_core_enable_get(ec)) return;
5416
5417    e_util_transform_vertex_init(&vertex, x, y, 0.0, 1.0);
5418
5419    result_vertex = e_util_transform_matrix_multiply_vertex(&ec->transform_core.result.inv_matrix, &vertex);
5420    e_util_transform_vertex_pos_round_get(&result_vertex, out_x, out_y, NULL, NULL);
5421 }
5422
5423 E_API void
5424 e_client_transform_core_input_inv_transform(E_Client *ec, int x, int y, int *out_x, int *out_y)
5425 {
5426    E_Util_Transform_Vertex vertex, result_vertex;
5427
5428    if (!ec) return;
5429    if (!e_client_transform_core_enable_get(ec)) return;
5430
5431    e_util_transform_vertex_init(&vertex, x, y, 0.0, 1.0);
5432
5433    result_vertex = e_util_transform_matrix_multiply_vertex(&ec->transform_core.result.matrix, &vertex);
5434    e_util_transform_vertex_pos_round_get(&result_vertex, out_x, out_y, NULL, NULL);
5435 }
5436
5437 EINTERN void
5438 e_client_transform_core_input_inv_rect_transform(E_Client *ec, int x, int y, int *out_x, int *out_y)
5439 {
5440    int gw = 0, gh = 0;
5441    if (!ec) return;
5442    if (!e_client_transform_core_enable_get(ec)) return;
5443    e_client_geometry_get(ec, NULL, NULL, &gw, &gh);
5444
5445    e_util_transform_matrix_inv_rect_coords_get(&ec->transform_core.result.transform,
5446                                                &ec->transform_core.result.vertices,
5447                                                gw, gh,
5448                                                x, y, out_x, out_y);
5449 }
5450
5451 E_API void
5452 e_client_transform_core_direct_render_set(E_Client *ec, Eina_Bool set)
5453 {
5454    EINA_SAFETY_ON_NULL_RETURN(ec);
5455
5456    if (ec->transform_core.direct_render == set) return;
5457
5458    ec->transform_core.direct_render = set;
5459    ec->transform_core.changed = EINA_TRUE;
5460
5461    e_client_transform_core_update(ec);
5462 }
5463
5464 EINTERN E_Pixmap *
5465 e_client_pixmap_change(E_Client *ec, E_Pixmap *newcp)
5466 {
5467    E_Pixmap_Type oldtype, newtype;
5468    E_Pixmap *oldcp;
5469
5470    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
5471    EINA_SAFETY_ON_NULL_RETURN_VAL(ec->pixmap, NULL);
5472    EINA_SAFETY_ON_NULL_RETURN_VAL(newcp, NULL);
5473
5474    oldcp = ec->pixmap;
5475
5476    oldtype = e_pixmap_type_get(oldcp);
5477    if (oldtype >= E_PIXMAP_TYPE_MAX) return NULL;
5478
5479    newtype = e_pixmap_type_get(newcp);
5480    if (newtype >= E_PIXMAP_TYPE_MAX) return NULL;
5481
5482    if (eina_hash_find(clients_hash[oldtype], &oldcp))
5483      eina_hash_del_by_key(clients_hash[oldtype], &oldcp);
5484    e_pixmap_client_set(oldcp, NULL);
5485
5486    ec->pixmap = newcp;
5487    e_pixmap_client_set(newcp, ec);
5488
5489    eina_hash_add(clients_hash[newtype], &newcp, ec);
5490
5491    return oldcp;
5492 }
5493
5494 E_API void
5495 e_client_window_role_set(E_Client *ec, const char *role)
5496 {
5497    EINA_SAFETY_ON_NULL_RETURN(ec);
5498
5499    if (eina_stringshare_replace(&ec->icccm.window_role, role))
5500      {
5501         wl_signal_emit_mutable(&PRI(ec)->events.window_role_change, NULL);
5502         _e_client_hook_call(E_CLIENT_HOOK_WINDOW_ROLE_CHANGE, ec);
5503      }
5504 }
5505
5506 EINTERN Eina_Bool
5507 e_client_key_send(E_Client *ec, int keycode, Eina_Bool pressed, Ecore_Device *dev, unsigned int time)
5508 {
5509    Eina_Bool res;
5510
5511    res = e_comp_wl_key_send(ec, keycode, pressed, dev, time);
5512
5513    return res;
5514 }
5515
5516 EINTERN Eina_Bool
5517 e_client_key_cancel(E_Client *ec, int keycode, Ecore_Device *dev, unsigned int time)
5518 {
5519    Eina_Bool res;
5520
5521    res = e_comp_wl_key_cancel(ec, keycode, dev, time);
5522
5523    return res;
5524 }
5525
5526 EINTERN Eina_Bool
5527 e_client_touch_send(E_Client *ec, int idx, int x, int y, Eina_Bool pressed, Ecore_Device *dev, double radius_x, double radius_y, double pressure, double angle, unsigned int time)
5528 {
5529    Eina_Bool res;
5530
5531    res = e_comp_wl_touch_send(ec, idx, x, y, pressed, dev, radius_x, radius_y, pressure, angle, time);
5532
5533    return res;
5534 }
5535
5536 EINTERN Eina_Bool
5537 e_client_touch_update_send(E_Client *ec, int idx, int x, int y, Ecore_Device *dev, double radius_x, double radius_y, double pressure, double angle, unsigned int time)
5538 {
5539    Eina_Bool res;
5540
5541    res = e_comp_wl_touch_update_send(ec, idx, x, y, dev, radius_x, radius_y, pressure, angle, time);
5542
5543    return res;
5544 }
5545
5546 EINTERN Eina_Bool
5547 e_client_touch_cancel_send(E_Client *ec)
5548 {
5549    Eina_Bool res;
5550
5551    res = e_comp_wl_touch_cancel_send(ec);
5552
5553    return res;
5554 }
5555
5556 EINTERN Eina_Bool
5557 e_client_mouse_button_send(E_Client *ec, int buttons, Eina_Bool pressed, Ecore_Device *dev, unsigned int time)
5558 {
5559    Eina_Bool res;
5560
5561    res = e_comp_wl_mouse_button_send(ec, buttons, pressed, dev, time);
5562
5563    return res;
5564 }
5565
5566 EINTERN Eina_Bool
5567 e_client_mouse_move_send(E_Client *ec, int x, int y, Ecore_Device *dev, unsigned int time)
5568 {
5569    Eina_Bool res;
5570
5571    res = e_comp_wl_mouse_move_send(ec, x, y, dev, time);
5572
5573    return res;
5574 }
5575
5576 EINTERN Eina_Bool
5577 e_client_mouse_wheel_send(E_Client *ec, int direction, int z, Ecore_Device *dev, unsigned int time)
5578 {
5579    Eina_Bool res;
5580
5581    res = e_comp_wl_mouse_wheel_send(ec, direction, z, dev, time);
5582
5583    return res;
5584 }
5585
5586 EINTERN Eina_Bool
5587 e_client_mouse_in_send(E_Client *ec, int x, int y, Ecore_Device *dev, unsigned int time)
5588 {
5589    Eina_Bool res;
5590
5591    res = e_comp_wl_mouse_in_send(ec, x, y, dev, time);
5592
5593    return res;
5594 }
5595
5596 EINTERN Eina_Bool
5597 e_client_mouse_out_send(E_Client *ec, Ecore_Device *dev, unsigned int time)
5598 {
5599    Eina_Bool res;
5600
5601    res = e_comp_wl_mouse_out_send(ec, dev, time);
5602
5603    return res;
5604 }
5605
5606 E_API Eina_Bool
5607 e_client_video_client_has(E_Client *ec)
5608 {
5609    return e_comp_wl_video_subsurface_has(ec);
5610 }
5611
5612 E_API Eina_Bool
5613 e_client_normal_client_has(E_Client *ec)
5614 {
5615    return e_comp_wl_normal_subsurface_has(ec);
5616 }
5617
5618 E_API Eina_Bool
5619 e_client_cursor_hide(E_Client *ec)
5620 {
5621    return e_comp_wl_cursor_hide(ec);
5622 }
5623
5624 E_API void
5625 e_client_visibility_force_obscured_set(E_Client *ec, Eina_Bool set)
5626 {
5627    if (!ec) return;
5628
5629    ELOGF("TZVIS", "VIS_FORCE_OBSCURED :%d", ec, set);
5630
5631    ec->visibility.force_obscured = set;
5632    e_comp_visibility_calculation_set(EINA_TRUE);
5633 }
5634
5635 EINTERN E_Capture_Save_State
5636 e_client_image_save(E_Client *ec, const char *dir, const char *name, E_Capture_Client_Save_End_Cb func_end, void *data, Eina_Bool skip_child)
5637 {
5638    return e_comp_wl_capture_client_image_save(ec, dir, name, func_end, data, skip_child);
5639 }
5640
5641 static void
5642 _e_client_base_output_resolution_hook_subsurf_create(void *data, E_Client *subc)
5643 {
5644    E_Client *ec, *parent;
5645
5646    ec = data;
5647    if (ec != subc)
5648      return;
5649
5650    ec->base_output_resolution.use = 0;
5651    ec->base_output_resolution.w = 0;
5652    ec->base_output_resolution.h = 0;
5653    if (ec->base_output_resolution.transform)
5654      {
5655         e_client_transform_core_remove(ec, ec->base_output_resolution.transform);
5656         E_FREE_FUNC(ec->base_output_resolution.transform, e_util_transform_del);
5657         ELOGF("POL_APPINFO", "Cancel TRANSFORM for subsurface", ec);
5658      }
5659
5660    /* Update transform for toplevel surface.
5661     * The transform of subsurface will be updated by its parent accordingly. */
5662    parent = e_comp_wl_topmost_parent_get(ec);
5663    if (parent)
5664      {
5665         parent->transform_core.changed = EINA_TRUE;
5666         e_client_transform_core_update(parent);
5667      }
5668
5669    /* TODO: Do we need to apply it again if subsurface is destroyed? */
5670 }
5671
5672 static void
5673 _e_client_base_output_resolution_set(E_Client *ec, int width, int height)
5674 {
5675    if (!ec) return;
5676    ec->base_output_resolution.use = 1;
5677    ec->base_output_resolution.w = width;
5678    ec->base_output_resolution.h = height;
5679    ec->base_output_resolution.transform = e_util_transform_new();
5680    e_util_transform_role_set(ec->base_output_resolution.transform, "base_output_resolution");
5681    e_client_transform_core_add(ec, ec->base_output_resolution.transform);
5682
5683    if (!ec->base_output_resolution.hook_subsurf_create)
5684      {
5685         ec->base_output_resolution.hook_subsurf_create =
5686            e_comp_wl_hook_add(E_COMP_WL_HOOK_SUBSURFACE_CREATE,
5687                               _e_client_base_output_resolution_hook_subsurf_create,
5688                               ec);
5689      }
5690 }
5691
5692 E_API void
5693 e_client_base_output_resolution_transform_adjust(E_Client *ec)
5694 {
5695    E_Desk *desk;
5696
5697    EINA_SAFETY_ON_NULL_RETURN(ec);
5698    if (!ec->base_output_resolution.use) return;
5699    if (!ec->base_output_resolution.transform) return;
5700
5701    desk = e_comp_desk_find_by_ec(ec);
5702    EINA_SAFETY_ON_NULL_RETURN(desk);
5703
5704    ELOGF("POL_APPINFO", "Apply TRANSFORM... desk:(%dx%d), ec:(%dx%d)",
5705          ec, desk->geom.w, desk->geom.h, ec->w, ec->h);
5706
5707    e_util_transform_scale(ec->base_output_resolution.transform,
5708                           (double)desk->geom.w /(double)ec->base_output_resolution.w,
5709                           (double)desk->geom.h /(double)ec->base_output_resolution.h,
5710                           1.0);
5711    e_client_transform_core_update(ec);
5712 }
5713
5714 E_API Eina_Bool
5715 e_client_base_output_resolution_update(E_Client *ec)
5716 {
5717    E_Appinfo *eai = NULL;
5718    int configured_width, configured_height;
5719    int width, height;
5720    E_Desk *desk;
5721
5722    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
5723
5724   if (!e_config->configured_output_resolution.use) return EINA_TRUE;
5725   if (ec->base_output_resolution.use) return EINA_TRUE;
5726
5727   /* Check whether it's subsurface or not
5728    * The resolution of subsurface will follow the resolution of its toplevel surface.
5729    * Transform for subsurface will be applied when toplevel surface does by
5730    * implementation of e_client_transform_core.
5731    */
5732   if (e_comp_wl_subsurface_check(ec))
5733     return EINA_FALSE;
5734
5735    desk = e_comp_desk_find_by_ec(ec);
5736    EINA_SAFETY_ON_NULL_RETURN_VAL(desk, EINA_FALSE);
5737
5738   configured_width = e_config->configured_output_resolution.w;
5739   configured_height = e_config->configured_output_resolution.h;
5740
5741   if (!ec->netwm.pid)
5742     {
5743        ELOGF("POL_APPINFO", "NO PID... USE configured_output_resolution(%d,%d) pid:%d", ec,
5744              configured_width, configured_height, ec->netwm.pid);
5745        goto use_configured;
5746     }
5747
5748    eai = e_appinfo_find_with_pid(ec->netwm.pid);
5749    if (!eai)
5750      {
5751         ELOGF("POL_APPINFO", "NO APPINFO... USE configured_output_resolution(%d,%d) pid:%d", ec,
5752               configured_width, configured_height, ec->netwm.pid);
5753         goto use_configured;
5754      }
5755
5756    if (!e_appinfo_base_output_resolution_available_get(eai))
5757      {
5758         ELOGF("POL_APPINFO", "NO AVAILABLE BASE SCREEN RESOLUTION... QUERY base_output_resolution", ec);
5759         e_policy_base_output_resolution_info_update(ec->netwm.pid);
5760      }
5761
5762    if (!e_appinfo_base_output_resolution_get(eai, &width, &height))
5763      {
5764         ELOGF("POL_APPINFO", "NO BASE SCREEN RESOLUTION... USE configured_output_resolution(%d,%d) pid:%d", ec,
5765               configured_width, configured_height, ec->netwm.pid);
5766         goto use_configured;
5767       }
5768
5769    if ((width == 0) && (height == 0))
5770      {
5771         ELOGF("POL_APPINFO", "SKIP SET BASE SCREEN RESOLUTION... base_output_resolution size:(%d,%d) pid:%d", ec, width, height, ec->netwm.pid);
5772         return EINA_TRUE;
5773      }
5774
5775    if ((desk->geom.w == width) && (desk->geom.h == height))
5776      {
5777         ELOGF("POL_APPINFO", "SKIP SET BASE SCREEN RESOLUTION... base_output_resolution is same with desk size:(%d,%d), pid:%d", ec, width, height, ec->netwm.pid);
5778         return EINA_TRUE;
5779      }
5780
5781    /* set the base_output_resolution of the e_client */
5782    _e_client_base_output_resolution_set(ec, width, height);
5783
5784    ELOGF("POL_APPINFO", "USE base_output_resolution(%d,%d) pid:%d", ec, width, height, ec->netwm.pid);
5785
5786    return EINA_TRUE;
5787
5788 use_configured:
5789
5790    if ((desk->geom.w == configured_width) && (desk->geom.h == configured_height))
5791      {
5792         ELOGF("POL_APPINFO", "SKIP use configured_output_resolution (same with desk size:(%d,%d), pid:%d)", ec, configured_width, configured_height, ec->netwm.pid);
5793      }
5794    else
5795      {
5796         /* set the base_output_resolution of the e_client as a default */
5797         _e_client_base_output_resolution_set(ec, configured_width, configured_height);
5798      }
5799
5800    return EINA_TRUE;
5801 }
5802
5803 E_API Eina_Bool
5804 e_client_base_output_resolution_useful_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h)
5805 {
5806    int zx, zy, zw, zh;
5807    E_Zone *zone;
5808
5809    E_OBJECT_CHECK_RETURN(ec, EINA_FALSE);
5810
5811    zone = e_comp_zone_find_by_ec(ec);
5812    EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
5813
5814    e_zone_useful_geometry_get(zone, &zx, &zy, &zw, &zh);
5815
5816    if (x) *x = zx;
5817    if (y) *y = zy;
5818    if (w) *w = zw;
5819    if (h) *h = zh;
5820
5821    if (ec->base_output_resolution.use)
5822      {
5823         if (w) *w = ec->base_output_resolution.w;
5824         if (h) *h = ec->base_output_resolution.h;
5825      }
5826
5827    return EINA_TRUE;
5828 }
5829
5830 E_API Eina_Bool
5831 e_client_base_output_resolution_desk_useful_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h, Eina_Bool consider_obstacle_area)
5832 {
5833    int zx, zy, zw, zh;
5834    E_Zone *zone;
5835
5836    E_OBJECT_CHECK_RETURN(ec, EINA_FALSE);
5837
5838    zone = e_comp_zone_find_by_ec(ec);
5839    EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
5840
5841    e_zone_desk_useful_geometry_get(zone, ec->desk, &zx, &zy, &zw, &zh, consider_obstacle_area);
5842
5843    if (x) *x = zx;
5844    if (y) *y = zy;
5845    if (w) *w = zw;
5846    if (h) *h = zh;
5847
5848    if (ec->base_output_resolution.use)
5849      {
5850         // TODO: Consider obstacle area
5851         if (w) *w = ec->base_output_resolution.w;
5852         if (h) *h = ec->base_output_resolution.h;
5853      }
5854
5855    return EINA_TRUE;
5856 }
5857
5858 /* change the base_output_resolution of the bind_ec by checking the base_output_resolution of provider_ec's appinfo */
5859 EINTERN Eina_Bool
5860 e_client_base_output_resolution_rsm_update(E_Client *bind_ec, E_Client *provider_ec)
5861 {
5862    E_Appinfo *epai = NULL;
5863    int configured_width, configured_height;
5864    int width, height;
5865    E_Desk *bind_ec_desk;
5866
5867    EINA_SAFETY_ON_NULL_RETURN_VAL(bind_ec, EINA_FALSE);
5868    EINA_SAFETY_ON_NULL_RETURN_VAL(provider_ec, EINA_FALSE);
5869
5870    bind_ec_desk = e_comp_desk_find_by_ec(bind_ec);
5871    EINA_SAFETY_ON_NULL_RETURN_VAL(bind_ec_desk, EINA_FALSE);
5872
5873   if (!e_config->configured_output_resolution.use) return EINA_TRUE;
5874
5875   configured_width = e_config->configured_output_resolution.w;
5876   configured_height = e_config->configured_output_resolution.h;
5877
5878   if (bind_ec->base_output_resolution.use)
5879     {
5880        ELOGF("POL_APPINFO", "DELETE EXISTED BINDER BASE SCREEN RESOLUTION... base_output_resolution is same with desk size:(%d,%d), bind_pid:%d", bind_ec,
5881              bind_ec->base_output_resolution.w, bind_ec->base_output_resolution.h, bind_ec->netwm.pid);
5882
5883        bind_ec->base_output_resolution.use = 0;
5884        bind_ec->base_output_resolution.w = 0;
5885        bind_ec->base_output_resolution.h = 0;
5886        e_client_transform_core_remove(bind_ec, bind_ec->base_output_resolution.transform);
5887        E_FREE_FUNC(bind_ec->base_output_resolution.transform, e_util_transform_del);
5888     }
5889
5890   if (!provider_ec->netwm.pid)
5891     {
5892        ELOGF("POL_APPINFO", "NO PROVIDER PID... USE configured_output_resolution(%d,%d) provider_pid:%d", provider_ec,
5893              configured_width, configured_height, provider_ec->netwm.pid);
5894        goto use_configured;
5895     }
5896
5897    epai = e_appinfo_find_with_pid(provider_ec->netwm.pid);
5898    if (!epai)
5899      {
5900         ELOGF("POL_APPINFO", "NO PROVIDER APPINFO... USE configured_output_resolution(%d,%d) provider_pid:%d", provider_ec,
5901               configured_width, configured_height, provider_ec->netwm.pid);
5902         goto use_configured;
5903      }
5904
5905    if (!e_appinfo_base_output_resolution_get(epai, &width, &height))
5906      {
5907         ELOGF("POL_APPINFO", "NO PROVIDER APPINFO BASE SCREEN RESOLUTION... USE configured_output_resolution(%d,%d) provider_pid:%d", provider_ec,
5908               configured_width, configured_height, provider_ec->netwm.pid);
5909         goto use_configured;
5910       }
5911
5912    if ((width == 0) && (height == 0))
5913      {
5914         ELOGF("POL_APPINFO", "NO PROVIDER WIDTH and HEIGHT... SKIP base_output_resolution due to size:(%d,%d) provider_pid:%d", provider_ec,
5915              width, height, provider_ec->netwm.pid);
5916         return EINA_TRUE;
5917      }
5918
5919    if ((bind_ec_desk->geom.w == width) && (bind_ec_desk->geom.h == height))
5920      {
5921         ELOGF("POL_APPINFO", "SKIP SET BINDER BASE SCREEN RESOLUTION... base_output_resolution is same with desk size:(%d,%d), bind_pid:%d", bind_ec,
5922             width, height, bind_ec->netwm.pid);
5923         return EINA_TRUE;
5924      }
5925
5926    /* set the base_output_resolution of the e_client */
5927    _e_client_base_output_resolution_set(bind_ec, width, height);
5928    e_client_base_output_resolution_transform_adjust(bind_ec);
5929
5930    ELOGF("POL_APPINFO", "USE BINDER base_output_resolution(%d,%d) bind_pid:%d", bind_ec, width, height, bind_ec->netwm.pid);
5931
5932    return EINA_TRUE;
5933
5934 use_configured:
5935
5936    if ((bind_ec_desk->geom.w == configured_width) && (bind_ec_desk->geom.h == configured_height))
5937      {
5938         ELOGF("POL_APPINFO", "SKIP BINDER use configured_output_resolution (same with desk size:(%d,%d), bind_pid:%d)", bind_ec,
5939              configured_width, configured_height, bind_ec->netwm.pid);
5940      }
5941    else
5942      {
5943         /* set the base_output_resolution of the e_client as a default */
5944         _e_client_base_output_resolution_set(bind_ec, configured_width, configured_height);
5945      }
5946
5947    return EINA_TRUE;
5948 }
5949
5950 /* tizen_move_resize */
5951 EINTERN Eina_Bool
5952 e_client_pending_geometry_has(E_Client *ec)
5953 {
5954    if (!eina_list_count(ec->surface_sync.pending_geometry))
5955      return EINA_FALSE;
5956
5957    return ec->surface_sync.wait_commit;
5958 }
5959
5960 EINTERN void
5961 e_client_pending_geometry_flush(E_Client *ec)
5962 {
5963    E_Client_Pending_Geometry *geo;
5964
5965    if (!eina_list_count(ec->surface_sync.pending_geometry))
5966      {
5967         EINA_LIST_FREE(ec->surface_sync.pending_geometry, geo)
5968           {
5969              E_FREE(geo);
5970           }
5971         ec->surface_sync.wait_commit = EINA_FALSE;
5972         ELOGF("POSSIZE", "pending geometry has flushed", ec);
5973      }
5974 }
5975
5976 EINTERN void
5977 e_client_pending_geometry_last_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h)
5978 {
5979    Eina_List *l;
5980    E_Client_Pending_Geometry *geo;
5981    int gx = 0;
5982    int gy = 0;
5983    int gw = 0;
5984    int gh = 0;
5985
5986    EINA_LIST_REVERSE_FOREACH(ec->surface_sync.pending_geometry, l, geo)
5987      {
5988         gx = geo->x;
5989         gy = geo->y;
5990         gw = geo->w;
5991         gh = geo->h;
5992         break;
5993      }
5994
5995    if (x) *x = gx;
5996    if (y) *y = gy;
5997    if (w) *w = gw;
5998    if (h) *h = gh;
5999 }
6000
6001 E_API void
6002 e_client_frame_focus_set(E_Client *ec, Eina_Bool focus)
6003 {
6004    if (!ec) return;
6005    evas_object_focus_set(ec->frame, focus);
6006 }
6007
6008 EINTERN void
6009 e_client_frame_geometry_set(E_Client *ec, int x, int y, int w, int h)
6010 {
6011    if (!ec) return;
6012
6013    if (ec->internal || ec->input_only)
6014      {
6015         evas_object_geometry_set(ec->frame, x, y, w, h);
6016      }
6017    else
6018      {
6019         if ((ec->w != w) || (ec->h != h))
6020           {
6021              ELOGF("POSSIZE", "Set move_after_resize. old(%d,%d,%dx%d), new(%d,%d,%dx%d)", ec, ec->x, ec->y, ec->w, ec->h, x, y, w, h);
6022              ec->move_after_resize = EINA_TRUE;
6023
6024              e_client_pos_set(ec, x, y);
6025              evas_object_resize(ec->frame, w, h);
6026           }
6027         else
6028           evas_object_geometry_set(ec->frame, x, y, w, h);
6029      }
6030 }
6031
6032 EAPI void
6033 e_client_util_move_resize_without_frame(E_Client *ec, int x, int y, int w, int h)
6034 {
6035    if (!ec) return;
6036
6037    if (ec->internal || ec->input_only)
6038      {
6039         e_client_util_move_without_frame(ec, x, y);
6040         e_client_util_resize_without_frame(ec, w, h);
6041      }
6042    else
6043      {
6044         if ((ec->w != w) || (ec->h != h))
6045           {
6046              ELOGF("POSSIZE", "Set move_after_resize. old(%d,%d,%dx%d), new(%d,%d,%dx%d)", ec, ec->x, ec->y, ec->w, ec->h, x, y, w, h);
6047              ec->move_after_resize = EINA_TRUE;
6048
6049              e_comp_object_frame_xy_adjust(ec->frame, x, y, &x, &y);
6050              e_client_pos_set(ec, x, y);
6051              e_client_util_resize_without_frame(ec, w, h);
6052           }
6053         else
6054           {
6055              e_client_util_move_without_frame(ec, x, y);
6056              e_client_util_resize_without_frame(ec, w, h);
6057           }
6058      }
6059 }
6060
6061 E_API Eina_Bool
6062 e_client_layer_set(E_Client *ec,
6063                    E_Layer layer)
6064 {
6065    E_OBJECT_CHECK_RETURN(ec, EINA_FALSE);
6066    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE);
6067    if (!ec->frame) return EINA_FALSE;
6068
6069    if (e_comp_canvas_client_layer_map(layer) == 9999)
6070      return EINA_FALSE; //invalid layer is not allowed
6071
6072 #ifdef REFACTOR_DESK_AREA
6073 #else
6074    if (ec->desk_area.enable)
6075      {
6076         if (e_client_layer_set_by_desk_area(ec, layer))
6077           {
6078              // restack according to desk group rule
6079              e_desk_area_ec_rearrange(ec->desk_area.desk_area, ec);
6080              return EINA_TRUE;
6081           }
6082      }
6083    ec->desk_area.layer_backup = layer;
6084 #endif
6085
6086    evas_object_layer_set(ec->frame, layer);
6087    if (ec->layer != layer)
6088      {
6089         /* check exceptional case */
6090         if ((ec->fullscreen) &&
6091             (ec->saved.layer != layer))
6092           {
6093              ELOGF("LAYER", "(%d) fail to backup at saved.layer for fullscreen", ec, layer);
6094              return EINA_FALSE;
6095           }
6096         // if e_comp_object fail to change ec->layer due to ec->layer_pending or block
6097         // leave log and apply ec->layer according to set
6098         // as a result it restores back to given layer when pending or block is free
6099         ELOGF("LAYER", "change layer from %d to %d if in case layer pending(%d) or block(%d)",
6100               ec, ec->layer, layer, ec->layer_pending, ec->layer_block);
6101         if (ec->layer_pending || ec->layer_block)
6102           {
6103              ec->layer = layer;
6104              return EINA_TRUE;
6105           }
6106      }
6107
6108    wl_signal_emit_mutable(&PRI(ec)->events.set_layer, NULL);
6109
6110    return EINA_TRUE;
6111 }
6112
6113 E_API E_Layer
6114 e_client_layer_get(E_Client *ec)
6115 {
6116    short layer;
6117
6118    E_OBJECT_CHECK_RETURN(ec, E_LAYER_BOTTOM);
6119    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, E_LAYER_BOTTOM);
6120    if (!ec->frame) return E_LAYER_BOTTOM;
6121
6122    layer = evas_object_layer_get(ec->frame);
6123    if (ec->layer != layer)
6124      {
6125         /* client could be on temperory layer while pending or block,
6126          * in that case, client restores back to ec->layer after pending/block finish */
6127         if (ec->layer_block || ec->layer_pending)
6128           return ec->layer;
6129
6130         /* otherwise, client is on unexpected layer */
6131         ELOGF("LAYER", "layer dismatch ec->layer %d | evas obj layer %d ",
6132               ec, ec->layer, layer);
6133
6134         if (e_comp_canvas_client_layer_map(layer) == 9999)
6135           return E_LAYER_BOTTOM; //not on E_LAYER_CLIENT
6136      }
6137
6138    return ec->layer;
6139 }
6140
6141 #ifdef REFACTOR_DESK_AREA
6142 #else
6143 static void
6144 _e_client_desk_area_original_layer_save(E_Client *ec, E_Layer layer)
6145 {
6146    E_OBJECT_CHECK(ec);
6147    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
6148    ec->desk_area.layer_backup = layer;
6149 }
6150
6151 EINTERN Eina_Bool
6152 e_client_layer_set_by_desk_area(E_Client *ec, E_Layer layer)
6153 {
6154    E_Desk_Area *eda;
6155    E_Layer edg_layer;
6156    E_Layer org_layer;
6157
6158    if (!ec) return EINA_FALSE;
6159    if (!ec->frame) return EINA_FALSE;
6160    if (!ec->desk_area.enable) return EINA_FALSE;
6161    if (!ec->desk_area.desk_area) return EINA_FALSE;
6162
6163    eda = ec->desk_area.desk_area;
6164
6165    // save original layer
6166    _e_client_desk_area_original_layer_save(ec, layer);
6167
6168    // get desk_area layer
6169    edg_layer = (E_Layer)e_desk_area_layer_get(eda);
6170    org_layer = e_client_desk_area_original_layer_get(ec);
6171
6172    ELOGF("EDG", "layer_set by desk_area... layer:%d, org_layer:%d, new_layer:%d", ec, layer, org_layer, edg_layer);
6173    if (org_layer == edg_layer)
6174      {
6175         e_client_raise(ec);
6176      }
6177    else
6178      {
6179         evas_object_layer_set(ec->frame, edg_layer);
6180         if (edg_layer == ec->layer)
6181           e_client_raise(ec);
6182      }
6183
6184    return EINA_TRUE;
6185 }
6186
6187 EINTERN void
6188 e_client_desk_area_original_layer_restore(E_Client *ec)
6189 {
6190    if (!ec) return;
6191
6192    // Do we need to check ec->desk_area.enable?
6193    // if ec->desk_area.enable is true, then e_client_layer_set calls
6194    // e_desk_area_ec_edg_layer_set(). that's too bad. :(
6195    // so, we MUST make a policy for ordering of the desk group layer restore
6196    // and the desk group enable.
6197    if (ec->desk_area.enable) return;
6198    e_client_layer_set(ec, ec->desk_area.layer_backup);
6199 }
6200
6201 EINTERN E_Layer
6202 e_client_desk_area_original_layer_get(E_Client *ec)
6203 {
6204    if (!ec) return E_LAYER_DESKTOP;
6205
6206    if (ec->desk_area.enable)
6207      return ec->desk_area.layer_backup;
6208    else
6209      return ec->layer;
6210 }
6211
6212 EINTERN Eina_Bool
6213 e_client_desk_area_client_layer_set(E_Client *ec, E_Desk_Area_Client_Layer edgc_layer)
6214 {
6215    E_OBJECT_CHECK_RETURN(ec, EINA_FALSE);
6216    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE);
6217    if ((edgc_layer < E_DESK_AREA_CLIENT_LAYER_DESKTOP) ||
6218        (edgc_layer >= E_DESK_AREA_CLIENT_LAYER_MAX))
6219      return EINA_FALSE;
6220
6221    ec->desk_area.edgc_layer = edgc_layer;
6222    return EINA_TRUE;
6223 }
6224
6225 EINTERN E_Desk_Area_Client_Layer
6226 e_client_desk_area_client_layer_get(E_Client *ec)
6227 {
6228    E_OBJECT_CHECK_RETURN(ec, E_DESK_AREA_CLIENT_LAYER_DESKTOP);
6229
6230    return ec->desk_area.edgc_layer;
6231 }
6232
6233 //FIXME: use e_desk_area_ec_reassign(eda, ec) instead of this api
6234 E_API Eina_Bool
6235 e_client_desk_area_set(E_Client *ec, E_Desk_Area *eda)
6236 {
6237    E_Desk_Area *old_edg;
6238
6239    if (!ec) return EINA_FALSE;
6240
6241 #if 0 // if this is removed.. then below if (eda != old_edg) is removed also...
6242    if (ec->desk_area.desk_area == eda)
6243      return EINA_TRUE;
6244 #endif
6245
6246    ELOGF("EDG", "Desk Group Set (new:%p, old:%p)", ec, eda, ec->desk_area.desk_area);
6247    old_edg = ec->desk_area.desk_area;
6248    if (old_edg)
6249      e_desk_area_ec_remove(old_edg, ec);
6250
6251    ec->desk_area.desk_area = eda;
6252    e_desk_area_ec_add(eda, ec);
6253
6254 #if 0 // if this is removed.. then above if (ec->desk_area.desk_area == eda) is removed also...
6255    if (eda != old_edg)
6256 #endif
6257      {
6258         e_desk_area_ec_update(eda, ec);
6259         e_desk_area_ec_rearrange(ec->desk_area.desk_area, ec);
6260      }
6261
6262    return EINA_TRUE;
6263 }
6264 #endif
6265
6266 static void
6267 _raise_between_sibling_under_parent(E_Client *ec)
6268 {
6269    ELOGF("POL", "RAISE child window between sibling. So, stack below under the parent (win:%zx, ec:%p)", ec, e_client_util_win_get(ec->parent), ec->parent);
6270    e_client_stack_below(ec, ec->parent);
6271 }
6272
6273 static void
6274 _raise_between_sibling_on_parent(E_Client *ec)
6275 {
6276    E_Client *top_child = NULL;
6277    top_child = e_client_transient_child_top_get(ec->parent, EINA_FALSE);
6278    if (!top_child)
6279      {
6280         ELOGF("POL", "RAISE child window... Stack above on the parent (win:%zx, ec:%p)", ec, e_client_util_win_get(ec->parent), ec->parent);
6281         e_client_stack_above(ec, ec->parent);
6282      }
6283    else
6284      {
6285         if (top_child != ec)
6286           {
6287              ELOGF("POL", "RAISE child window between sibling... Stack above on the top child (win:%zx, ec:%p)", ec, e_client_util_win_get(top_child), top_child);
6288              e_client_stack_above(ec, top_child);
6289           }
6290         else
6291           ELOGF("POL", "RAISE child window between sibling... already on the top. STAY", ec);
6292      }
6293 }
6294
6295 static void
6296 _raise_belong_to_parent(E_Client *ec)
6297 {
6298    if (e_client_transient_policy_get(ec) == E_TRANSIENT_BELOW)
6299      _raise_between_sibling_under_parent(ec);
6300    else
6301      _raise_between_sibling_on_parent(ec);
6302 }
6303
6304 E_API void
6305 e_client_raise(E_Client *ec)
6306 {
6307    if (!ec) return;
6308
6309 #ifdef REFACTOR_DESK_AREA
6310 #else
6311    if (ec->desk_area.enable)
6312      {
6313         E_Desk_Area *eda;
6314         eda = ec->desk_area.desk_area;
6315         if (eda)
6316           {
6317              e_desk_area_ec_raise(eda, ec);
6318              return;
6319           }
6320      }
6321 #endif
6322
6323    if (ec->parent && e_client_is_belong_to_parent(ec))
6324      _raise_belong_to_parent(ec);
6325    else
6326      evas_object_raise(ec->frame);
6327
6328    wl_signal_emit_mutable(&PRI(ec)->events.raise, NULL);
6329 }
6330
6331 static void
6332 _e_client_transient_for_below_group_make(E_Client *ec, Eina_List **list)
6333 {
6334    // list : Head is the bottommost child
6335    E_Client *child;
6336    Eina_List *l;
6337
6338    if (!ec) return;
6339
6340    EINA_LIST_REVERSE_FOREACH(ec->transients, l, child)
6341      {
6342         if (!child) continue;
6343         if (e_client_transient_policy_get(child) != E_TRANSIENT_BELOW) continue;
6344         if (!e_client_is_belong_to_parent(child)) continue;
6345
6346         *list = eina_list_prepend(*list, child);
6347         _e_client_transient_for_group_make(child, list);
6348      }
6349 }
6350
6351 E_API E_Client *
6352 e_client_transient_child_bottom_get(E_Client *ec)
6353 {
6354    E_Client *bottom_ec = NULL;
6355    Eina_List *transient_below_list = NULL;
6356    Eina_List *l = NULL;
6357
6358    _e_client_transient_for_below_group_make(ec, &transient_below_list);
6359
6360    if (transient_below_list)
6361      {
6362         E_Client *temp_ec = NULL;
6363         E_Client *temp_ec2 = NULL;
6364
6365         E_CLIENT_FOREACH(temp_ec)
6366           {
6367              if (bottom_ec) break;
6368
6369              if (temp_ec == ec)
6370                {
6371                   bottom_ec = ec;
6372                   break;
6373                }
6374
6375              EINA_LIST_FOREACH(transient_below_list, l, temp_ec2)
6376                {
6377                   if (temp_ec == temp_ec2)
6378                     {
6379                        bottom_ec = temp_ec2;
6380                        break;
6381                     }
6382                }
6383           }
6384         eina_list_free(transient_below_list);
6385      }
6386    return bottom_ec;
6387 }
6388
6389 static void
6390 _lower_between_sibling_under_parent(E_Client *ec)
6391 {
6392    E_Client *bottom_child = NULL;
6393    bottom_child = e_client_transient_child_bottom_get(ec->parent);
6394    if (!bottom_child)
6395      {
6396         ELOGF("POL", "LOWER child window between sibling... Stack below under the parent (win:%zx, ec:%p)", ec, e_client_util_win_get(ec->parent), ec->parent);
6397         e_client_stack_below(ec, ec->parent);
6398      }
6399    else
6400      {
6401         if (bottom_child != ec)
6402           {
6403              ELOGF("POL", "LOWER child window between sibling... Stack below under the bottom child (win:%zx, ec:%p)", ec, e_client_util_win_get(bottom_child), bottom_child);
6404              e_client_stack_below(ec, bottom_child);
6405           }
6406         else
6407           ELOGF("POL", "LOWER child window between sibling... already under the bottom. STAY", ec);
6408      }
6409 }
6410
6411 static void
6412 _lower_between_sibling_on_parent(E_Client *ec)
6413 {
6414    ELOGF("POL", "LOWER child window between sibling... So, stack above on the parent (win:%zx, ec:%p)", ec, e_client_util_win_get(ec->parent), ec->parent);
6415    e_client_stack_above(ec, ec->parent);
6416 }
6417
6418 static void
6419 _lower_belong_to_parent(E_Client *ec)
6420 {
6421    if (e_client_transient_policy_get(ec) == E_TRANSIENT_BELOW)
6422      _lower_between_sibling_under_parent(ec);
6423    else
6424      _lower_between_sibling_on_parent(ec);
6425 }
6426
6427 E_API void
6428 e_client_lower(E_Client *ec)
6429 {
6430    if (!ec) return;
6431
6432 #ifdef REFACTOR_DESK_AREA
6433 #else
6434    if (ec->desk_area.enable)
6435      {
6436         E_Desk_Area *eda;
6437         eda = ec->desk_area.desk_area;
6438         if (eda)
6439           {
6440              e_desk_area_ec_lower(eda, ec);
6441
6442              wl_signal_emit_mutable(&PRI(ec)->events.lower, NULL);
6443              return;
6444           }
6445      }
6446 #endif
6447
6448    if (ec->parent && e_client_is_belong_to_parent(ec))
6449      _lower_belong_to_parent(ec);
6450    else
6451      evas_object_lower(ec->frame);
6452
6453    wl_signal_emit_mutable(&PRI(ec)->events.lower, NULL);
6454 }
6455
6456 E_API void
6457 e_client_stack_above(E_Client *ec, E_Client *above)
6458 {
6459    if (!ec) return;
6460    if (!ec->frame) return;
6461    if (!above) return;
6462    if (!above->frame) return;
6463
6464 #ifdef REFACTOR_DESK_AREA
6465 #else
6466    if (ec->desk_area.enable)
6467      {
6468         E_Desk_Area *eda;
6469         eda = ec->desk_area.desk_area;
6470         if (eda)
6471           {
6472              e_desk_area_ec_stack_above(eda, ec, above);
6473              return;
6474           }
6475      }
6476 #endif
6477
6478    evas_object_stack_above(ec->frame, above->frame);
6479
6480    wl_signal_emit_mutable(&PRI(ec)->events.stack_above, NULL);
6481 }
6482
6483 E_API void
6484 e_client_stack_below(E_Client *ec, E_Client *below)
6485 {
6486    if (!ec) return;
6487    if (!ec->frame) return;
6488    if (!below) return;
6489    if (!below->frame) return;
6490
6491 #ifdef REFACTOR_DESK_AREA
6492 #else
6493    if (ec->desk_area.enable)
6494      {
6495         E_Desk_Area *eda;
6496         eda = ec->desk_area.desk_area;
6497         if (eda)
6498           {
6499              e_desk_area_ec_stack_below(eda, ec, below);
6500              return;
6501           }
6502      }
6503 #endif
6504
6505    evas_object_stack_below(ec->frame, below->frame);
6506
6507    wl_signal_emit_mutable(&PRI(ec)->events.stack_below, NULL);
6508 }
6509
6510 E_API int
6511 e_client_show_pending_set(E_Client *ec)
6512 {
6513    if (!ec) return 0;
6514
6515    ec->show_pending.count++;
6516    ELOGF("E_CLIENT", "SET show_pending. (count:%d, run:%d)", ec, ec->show_pending.count, ec->show_pending.running);
6517    return ec->show_pending.count;
6518 }
6519
6520 E_API int
6521 e_client_show_pending_unset(E_Client *ec)
6522 {
6523    if (!ec) return 0;
6524    if (ec->show_pending.count <= 0) return 0;
6525
6526    ec->show_pending.count--;
6527    ELOGF("E_CLIENT", "UNSET show_pending. (count:%d, run:%d)", ec, ec->show_pending.count, ec->show_pending.running);
6528    if (ec->show_pending.count == 0 && ec->show_pending.running)
6529      {
6530         ec->show_pending.running = EINA_FALSE;
6531         if (ec->frame)
6532           {
6533              ELOGF("E_CLIENT", "evas_object_show by unset show_pending", ec);
6534              evas_object_show(ec->frame);
6535              //e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
6536              EC_CHANGED(ec);
6537           }
6538      }
6539
6540    return ec->show_pending.count;
6541 }
6542
6543 static Eina_Bool
6544 _e_client_surface_tree_foreach_helper(E_Client *ec, E_Client_Surface_Tree_Foreach func, void *data)
6545 {
6546    E_Client *subc;
6547    Eina_List *l, *ll;
6548    Eina_Bool res = EINA_TRUE;
6549    E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
6550
6551    if (!cdata)
6552      return res;
6553
6554    EINA_LIST_FOREACH_SAFE(cdata->sub.below_list, l, ll, subc)
6555      {
6556         res = _e_client_surface_tree_foreach_helper(subc, func, data);
6557         if (!res)
6558           break;
6559      }
6560
6561    if (res)
6562      {
6563         res = func(data, ec);
6564         if (res)
6565           {
6566              EINA_LIST_FOREACH_SAFE(cdata->sub.list, l, ll, subc)
6567                {
6568                   res = _e_client_surface_tree_foreach_helper(subc,
6569                                                               func,
6570                                                               data);
6571                   if (!res)
6572                     break;
6573                }
6574           }
6575      }
6576
6577    return res;
6578 }
6579
6580 E_API void
6581 e_client_surface_tree_foreach(E_Client *ec, E_Client_Surface_Tree_Foreach func, void *data)
6582 {
6583    EINA_SAFETY_ON_NULL_RETURN(ec);
6584    EINA_SAFETY_ON_NULL_RETURN(func);
6585
6586    _e_client_surface_tree_foreach_helper(ec, func, data);
6587 }
6588
6589 EINTERN E_Comp_Wl_Client_Data *
6590 e_client_cdata_new(E_Client *ec)
6591 {
6592    E_Comp_Wl_Client_Data *cdata;
6593
6594    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
6595
6596    if (!(cdata = E_NEW(E_Comp_Wl_Client_Data, 1)))
6597      {
6598         ERR("Could not allocate new E_Comp_Wl_Client_Data structure");
6599         return NULL;
6600      }
6601    ec->comp_data = cdata;
6602
6603    return cdata;
6604 }
6605
6606 EINTERN void
6607 e_client_cdata_free(E_Client *ec)
6608 {
6609   EINA_SAFETY_ON_NULL_RETURN(ec);
6610   if (!ec->comp_data) return;
6611
6612   E_FREE(ec->comp_data);
6613 }
6614
6615 EINTERN E_Comp_Wl_Client_Data *
6616 e_client_cdata_get(E_Client *ec)
6617 {
6618    if (!ec) return NULL;
6619
6620    return ec->comp_data;
6621 }
6622
6623 EINTERN Eina_Bool
6624 e_client_map_set(E_Client *ec, E_Map *em)
6625 {
6626    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
6627
6628    return e_map_set_to_comp_object(em, ec->frame);
6629 }
6630
6631 E_API E_Map *
6632 e_client_map_get(const E_Client *ec)
6633 {
6634    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
6635
6636    return e_map_get_from_comp_object(ec->frame);
6637 }
6638
6639 EINTERN Eina_Bool
6640 e_client_map_enable_set(E_Client *ec, Eina_Bool enable)
6641 {
6642    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
6643    EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, EINA_FALSE);
6644
6645    evas_object_map_enable_set(ec->frame, enable);
6646
6647    return EINA_TRUE;
6648 }
6649
6650 EINTERN void
6651 e_client_belong_to_parent_set(E_Client *ec, Eina_Bool set)
6652 {
6653    if (!ec) return;
6654    ec->belong_to_parent = set;
6655 }
6656
6657 EINTERN Eina_Bool
6658 e_client_is_belong_to_parent(E_Client *ec)
6659 {
6660    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
6661    return ec->belong_to_parent;
6662 }
6663
6664 EINTERN void
6665 e_client_transient_policy_set(E_Client *ec, E_Transient policy)
6666 {
6667    if (!ec) return;
6668    ec->transient_policy = policy;
6669 }
6670
6671 E_API E_Transient
6672 e_client_transient_policy_get(E_Client *ec)
6673 {
6674    if (!ec) return E_TRANSIENT_ABOVE;
6675    return ec->transient_policy;
6676 }
6677
6678 EINTERN void
6679 e_client_resize_object_create_cb_set(E_Client_Resize_Object_Create_Cb cb)
6680 {
6681    if (_e_client_resize_object_create_cb && cb)
6682      CRI("ATTEMPTING TO OVERWRITE EXISTING CLIENT RESIZE OBJECT CREATE HOOK!!!");
6683    _e_client_resize_object_create_cb = cb;
6684 }
6685
6686 EINTERN void
6687 e_client_resize_unit_size_set(E_Client *ec, unsigned int unit_size)
6688 {
6689    if (!ec) return;
6690
6691    // FYI, we consider 0 and 1 to be the same value as a default unit size.
6692    ec->manage_resize.unit_size = unit_size;
6693 }
6694
6695 EINTERN void
6696 e_client_desk_zoom_enable_set(E_Client *ec, Eina_Bool enable)
6697 {
6698    if (!ec) return;
6699    ec->desk_zoom.enable = enable;
6700 }
6701
6702 EINTERN Eina_Bool
6703 e_client_desk_zoom_enable_get(E_Client *ec)
6704 {
6705    if (!ec) return EINA_FALSE;
6706    return ec->desk_zoom.enable;
6707 }
6708
6709 EINTERN void
6710 e_client_layout_apply(E_Client *ec, Eina_Bool apply)
6711 {
6712    if (!ec) return;
6713    ec->apply_layout = apply;
6714 }
6715
6716 EINTERN Eina_Bool
6717 e_client_is_layout_apply(E_Client *ec)
6718 {
6719    if (!ec) return EINA_FALSE;
6720    return ec->apply_layout;
6721 }
6722
6723 E_API E_Client *
6724 e_client_from_surface_resource(struct wl_resource *surface_resource)
6725 {
6726    EINA_SAFETY_ON_NULL_RETURN_VAL(surface_resource, NULL);
6727
6728    return e_comp_wl_util_client_from_surface_resource(surface_resource);
6729 }
6730
6731 EINTERN void
6732 e_client_fps_update(E_Client *ec)
6733 {
6734    double dt;
6735    double tim;
6736
6737    EINA_SAFETY_ON_NULL_RETURN(ec);
6738
6739    if (!ec->fps.enabled) return;
6740
6741    tim = ecore_time_get();
6742
6743    dt = tim - ec->fps.frametimes[0];
6744
6745    ec->fps.frametimes[0] = tim;
6746    ec->fps.time += dt;
6747    ec->fps.cframes++;
6748
6749    if (ec->fps.lapse == 0.0)
6750      {
6751         ec->fps.lapse = tim;
6752         ec->fps.flapse = ec->fps.cframes;
6753      }
6754    else if ((tim - ec->fps.lapse) >= 0.5)
6755      {
6756         ec->fps.fps = (ec->fps.cframes - ec->fps.flapse) /
6757                       (tim - ec->fps.lapse);
6758         ec->fps.lapse = tim;
6759         ec->fps.flapse = ec->fps.cframes;
6760         ec->fps.time = 0.0;
6761      }
6762 }
6763
6764 EINTERN Eina_Bool
6765 e_client_fps_get(E_Client *ec, double *fps)
6766 {
6767    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
6768
6769    if (ec->fps.old_fps == ec->fps.fps)
6770      return EINA_FALSE;
6771
6772    if (ec->fps.fps > 0.0)
6773      {
6774         *fps = ec->fps.fps;
6775         ec->fps.old_fps = ec->fps.fps;
6776         return EINA_TRUE;
6777      }
6778
6779    return EINA_FALSE;
6780 }
6781
6782 EINTERN void
6783 e_client_fps_enable(E_Client *ec, Eina_Bool enable)
6784 {
6785    EINA_SAFETY_ON_NULL_RETURN(ec);
6786
6787    ec->fps.enabled = enable;
6788 }
6789
6790 EINTERN Eina_Bool
6791 e_client_explicit_sync_get(E_Client *ec)
6792 {
6793    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
6794
6795    return ec->explicit_sync;
6796 }
6797
6798 EINTERN Eina_Bool
6799 e_client_explicit_sync_set(E_Client *ec, Eina_Bool enable)
6800 {
6801    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
6802
6803    ec->explicit_sync = enable;
6804
6805    return EINA_TRUE;
6806 }
6807
6808 EINTERN int
6809 e_client_explicit_sync_acquire_fence_fd_get(E_Client *ec)
6810 {
6811    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, -1);
6812
6813    return ec->acquire_fence_fd;
6814 }
6815
6816 EINTERN Eina_Bool
6817 e_client_explicit_sync_acquire_fence_fd_set(E_Client *ec, int fd)
6818 {
6819   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
6820
6821   ec->acquire_fence_fd = fd;
6822
6823   return EINA_TRUE;
6824 }
6825
6826 EINTERN Eina_Bool
6827 e_client_intercept_hook_auto_placement_call(E_Client *ec)
6828 {
6829   // no need to call the intercept hook if ec is NULL.
6830   if (!ec) return EINA_FALSE;
6831
6832   if (!_e_client_intercept_hook_call(E_CLIENT_INTERCEPT_HOOK_AUTO_PLACEMENT, ec))
6833     {
6834        ELOGF("FOCUS", "E_CLIENT_INTERCEPT_HOOK_AUTO_PLACEMENT Intercepted.", ec);
6835        return EINA_TRUE;
6836     }
6837
6838   return EINA_FALSE;
6839 }
6840
6841 EINTERN void
6842 e_client_iconify_event_send(E_Client *ec)
6843 {
6844    EINA_SAFETY_ON_NULL_RETURN(ec);
6845
6846    _e_client_event_simple(ec, E_EVENT_CLIENT_ICONIFY);
6847 }
6848
6849 EINTERN void
6850 e_client_uniconify_event_send(E_Client *ec)
6851 {
6852    EINA_SAFETY_ON_NULL_RETURN(ec);
6853
6854    _e_client_event_simple(ec, E_EVENT_CLIENT_UNICONIFY);
6855 }
6856
6857 EINTERN void
6858 e_client_stack_transient_for_done_notify(E_Client *ec)
6859 {
6860    EINA_SAFETY_ON_NULL_RETURN(ec);
6861
6862    wl_signal_emit_mutable(&PRI(ec)->events.stack_transient_for_done, NULL);
6863 }
6864
6865 #ifdef REFACTOR_DESK_AREA
6866 EINTERN void
6867 e_client_subsurface_stack_update(E_Client *ec)
6868 {
6869    EINA_SAFETY_ON_NULL_RETURN(ec);
6870
6871    wl_signal_emit_mutable(&PRI(ec)->events.subsurface_stack_update, ec);
6872 }
6873 #endif
6874
6875 EINTERN void
6876 e_client_eval_pre_fetch_listener_add(E_Client *ec, struct wl_listener *listener)
6877 {
6878    API_ENTRY;
6879    wl_signal_add(&priv->events.eval_pre_fetch, listener);
6880 }
6881
6882 EINTERN void
6883 e_client_eval_fetch_listener_add(E_Client *ec, struct wl_listener *listener)
6884 {
6885    API_ENTRY;
6886    wl_signal_add(&priv->events.eval_fetch, listener);
6887 }
6888
6889 EINTERN void
6890 e_client_eval_pre_post_fetch_listener_add(E_Client *ec, struct wl_listener *listener)
6891 {
6892    API_ENTRY;
6893    wl_signal_add(&priv->events.eval_pre_post_fetch, listener);
6894 }
6895
6896 EINTERN void
6897 e_client_eval_post_fetch_listener_add(E_Client *ec, struct wl_listener *listener)
6898 {
6899    API_ENTRY;
6900    wl_signal_add(&priv->events.eval_post_fetch, listener);
6901 }
6902
6903 EINTERN void
6904 e_client_eval_pre_frame_assign_listener_add(E_Client *ec, struct wl_listener *listener)
6905 {
6906    API_ENTRY;
6907    wl_signal_add(&priv->events.eval_pre_frame_assign, listener);
6908 }
6909
6910 EINTERN void
6911 e_client_eval_post_frame_assign_listener_add(E_Client *ec, struct wl_listener *listener)
6912 {
6913    API_ENTRY;
6914    wl_signal_add(&priv->events.eval_post_frame_assign, listener);
6915 }
6916
6917 EINTERN void
6918 e_client_eval_pre_new_client_listener_add(E_Client *ec, struct wl_listener *listener)
6919 {
6920    API_ENTRY;
6921    wl_signal_add(&priv->events.eval_pre_new_client, listener);
6922 }
6923
6924 EINTERN void
6925 e_client_eval_post_new_client_listener_add(E_Client *ec, struct wl_listener *listener)
6926 {
6927    API_ENTRY;
6928    wl_signal_add(&priv->events.eval_post_new_client, listener);
6929 }
6930
6931 EINTERN void
6932 e_client_eval_visibility_listener_add(E_Client *ec, struct wl_listener *listener)
6933 {
6934    API_ENTRY;
6935    wl_signal_add(&priv->events.eval_visibility, listener);
6936 }
6937
6938 EINTERN void
6939 e_client_eval_visibility_end_listener_add(E_Client *ec, struct wl_listener *listener)
6940 {
6941    API_ENTRY;
6942    wl_signal_add(&priv->events.eval_visibility_end, listener);
6943 }
6944
6945 EINTERN void
6946 e_client_eval_end_listener_add(E_Client *ec, struct wl_listener *listener)
6947 {
6948    API_ENTRY;
6949    wl_signal_add(&priv->events.eval_end, listener);
6950 }
6951
6952 EINTERN void
6953 e_client_move_begin_listener_add(E_Client *ec, struct wl_listener *listener)
6954 {
6955    API_ENTRY;
6956    wl_signal_add(&priv->events.move_begin, listener);
6957 }
6958
6959 EINTERN void
6960 e_client_move_update_listener_add(E_Client *ec, struct wl_listener *listener)
6961 {
6962    API_ENTRY;
6963    wl_signal_add(&priv->events.move_update, listener);
6964 }
6965
6966 EINTERN void
6967 e_client_move_end_listener_add(E_Client *ec, struct wl_listener *listener)
6968 {
6969    API_ENTRY;
6970    wl_signal_add(&priv->events.move_end, listener);
6971 }
6972
6973 EINTERN void
6974 e_client_move_resize_begin_listener_add(E_Client *ec, struct wl_listener *listener)
6975 {
6976    API_ENTRY;
6977    wl_signal_add(&priv->events.move_resize_begin, listener);
6978 }
6979
6980 EINTERN void
6981 e_client_move_resize_update_listener_add(E_Client *ec, struct wl_listener *listener)
6982 {
6983    API_ENTRY;
6984    wl_signal_add(&priv->events.move_resize_update, listener);
6985 }
6986
6987 EINTERN void
6988 e_client_move_resize_end_listener_add(E_Client *ec, struct wl_listener *listener)
6989 {
6990    API_ENTRY;
6991    wl_signal_add(&priv->events.move_resize_end, listener);
6992 }
6993
6994 EINTERN void
6995 e_client_destroy_listener_add(E_Client *ec, struct wl_listener *listener)
6996 {
6997    API_ENTRY;
6998    wl_signal_add(&priv->events.destroy, listener);
6999 }
7000
7001 EINTERN void
7002 e_client_new_client_listener_add(E_Client *ec, struct wl_listener *listener)
7003 {
7004    API_ENTRY;
7005    wl_signal_add(&priv->events.new_client, listener);
7006 }
7007
7008 EINTERN void
7009 e_client_new_client_post_listener_add(E_Client *ec, struct wl_listener *listener)
7010 {
7011    API_ENTRY;
7012    wl_signal_add(&priv->events.new_client_post, listener);
7013 }
7014
7015 EINTERN void
7016 e_client_unredirect_listener_add(E_Client *ec, struct wl_listener *listener)
7017 {
7018    API_ENTRY;
7019    wl_signal_add(&priv->events.unredirect, listener);
7020 }
7021
7022 EINTERN void
7023 e_client_redirect_listener_add(E_Client *ec, struct wl_listener *listener)
7024 {
7025    API_ENTRY;
7026    wl_signal_add(&priv->events.redirect, listener);
7027 }
7028
7029 EINTERN void
7030 e_client_aux_hint_change_listener_add(E_Client *ec, struct wl_listener *listener)
7031 {
7032    API_ENTRY;
7033    wl_signal_add(&priv->events.aux_hint_change, listener);
7034 }
7035
7036 EINTERN void
7037 e_client_window_role_change_listener_add(E_Client *ec, struct wl_listener *listener)
7038 {
7039    API_ENTRY;
7040    wl_signal_add(&priv->events.window_role_change, listener);
7041 }
7042
7043 EINTERN void
7044 e_client_transform_change_listener_add(E_Client *ec, struct wl_listener *listener)
7045 {
7046    API_ENTRY;
7047    wl_signal_add(&priv->events.transform_change, listener);
7048 }
7049
7050 EINTERN void
7051 e_client_activate_done_listener_add(E_Client *ec, struct wl_listener *listener)
7052 {
7053    API_ENTRY;
7054    wl_signal_add(&priv->events.activate_done, listener);
7055 }
7056
7057 EINTERN void
7058 e_client_mouse_in_listener_add(E_Client *ec, struct wl_listener *listener)
7059 {
7060    API_ENTRY;
7061    wl_signal_add(&priv->events.mouse_in, listener);
7062 }
7063
7064 EINTERN void
7065 e_client_mouse_out_listener_add(E_Client *ec, struct wl_listener *listener)
7066 {
7067    API_ENTRY;
7068    wl_signal_add(&priv->events.mouse_out, listener);
7069 }
7070
7071 EINTERN void
7072 e_client_mouse_down_listener_add(E_Client *ec, struct wl_listener *listener)
7073 {
7074    API_ENTRY;
7075    wl_signal_add(&priv->events.mouse_down, listener);
7076 }
7077
7078 EINTERN void
7079 e_client_focus_set_listener_add(E_Client *ec, struct wl_listener *listener)
7080 {
7081    API_ENTRY;
7082    wl_signal_add(&priv->events.focus_set, listener);
7083 }
7084
7085 EINTERN void
7086 e_client_focus_unset_listener_add(E_Client *ec, struct wl_listener *listener)
7087 {
7088    API_ENTRY;
7089    wl_signal_add(&priv->events.focus_unset, listener);
7090 }
7091
7092 EINTERN void
7093 e_client_focus_defer_set_listener_add(E_Client *ec, struct wl_listener *listener)
7094 {
7095    API_ENTRY;
7096    wl_signal_add(&priv->events.focus_defer_set, listener);
7097 }
7098
7099 EINTERN void
7100 e_client_focus_latest_set_listener_add(E_Client *ec, struct wl_listener *listener)
7101 {
7102    API_ENTRY;
7103    wl_signal_add(&priv->events.focus_latest_set, listener);
7104 }
7105
7106 EINTERN void
7107 e_client_iconify_listener_add(E_Client *ec, struct wl_listener *listener)
7108 {
7109    API_ENTRY;
7110    wl_signal_add(&priv->events.iconify, listener);
7111 }
7112
7113 EINTERN void
7114 e_client_uniconify_listener_add(E_Client *ec, struct wl_listener *listener)
7115 {
7116    API_ENTRY;
7117    wl_signal_add(&priv->events.uniconify, listener);
7118 }
7119
7120 EINTERN void
7121 e_client_maximize_listener_add(E_Client *ec, struct wl_listener *listener)
7122 {
7123    API_ENTRY;
7124    wl_signal_add(&priv->events.maximize, listener);
7125 }
7126
7127 EINTERN void
7128 e_client_unmaximize_listener_add(E_Client *ec, struct wl_listener *listener)
7129 {
7130    API_ENTRY;
7131    wl_signal_add(&priv->events.unmaximize, listener);
7132 }
7133
7134 EINTERN void
7135 e_client_fullscreen_pre_listener_add(E_Client *ec, struct wl_listener *listener)
7136 {
7137    API_ENTRY;
7138    wl_signal_add(&priv->events.fullscreen_pre, listener);
7139 }
7140
7141 EINTERN void
7142 e_client_fullscreen_listener_add(E_Client *ec, struct wl_listener *listener)
7143 {
7144    API_ENTRY;
7145    wl_signal_add(&priv->events.fullscreen, listener);
7146 }
7147
7148 EINTERN void
7149 e_client_unfullscreen_listener_add(E_Client *ec, struct wl_listener *listener)
7150 {
7151    API_ENTRY;
7152    wl_signal_add(&priv->events.unfullscreen, listener);
7153 }
7154
7155 EINTERN void
7156 e_client_move_listener_add(E_Client *ec, struct wl_listener *listener)
7157 {
7158    API_ENTRY;
7159    wl_signal_add(&priv->events.move, listener);
7160 }
7161
7162 EINTERN void
7163 e_client_raise_listener_add(E_Client *ec, struct wl_listener *listener)
7164 {
7165    API_ENTRY;
7166    wl_signal_add(&priv->events.raise, listener);
7167 }
7168
7169 EINTERN void
7170 e_client_lower_listener_add(E_Client *ec, struct wl_listener *listener)
7171 {
7172    API_ENTRY;
7173    wl_signal_add(&priv->events.lower, listener);
7174 }
7175
7176 EINTERN void
7177 e_client_stack_below_listener_add(E_Client *ec, struct wl_listener *listener)
7178 {
7179    API_ENTRY;
7180    wl_signal_add(&priv->events.stack_below, listener);
7181 }
7182
7183 EINTERN void
7184 e_client_stack_above_listener_add(E_Client *ec, struct wl_listener *listener)
7185 {
7186    API_ENTRY;
7187    wl_signal_add(&priv->events.stack_above, listener);
7188 }
7189
7190 EINTERN void
7191 e_client_set_layer_listener_add(E_Client *ec, struct wl_listener *listener)
7192 {
7193    API_ENTRY;
7194    wl_signal_add(&priv->events.set_layer, listener);
7195 }
7196
7197 EINTERN void
7198 e_client_stack_transient_for_done_listener_add(E_Client *ec, struct wl_listener *listener)
7199 {
7200    API_ENTRY;
7201    wl_signal_add(&priv->events.stack_transient_for_done, listener);
7202 }
7203
7204 EINTERN void
7205 e_client_stick_listener_add(E_Client *ec, struct wl_listener *listener)
7206 {
7207    API_ENTRY;
7208    wl_signal_add(&priv->events.stick, listener);
7209 }
7210
7211 EINTERN void
7212 e_client_unstick_listener_add(E_Client *ec, struct wl_listener *listener)
7213 {
7214    API_ENTRY;
7215    wl_signal_add(&priv->events.unstick, listener);
7216 }
7217
7218 EINTERN struct wl_listener *
7219 e_client_destroy_listener_get(E_Client *ec, wl_notify_func_t notify)
7220 {
7221    API_ENTRY_VAL(NULL);
7222    return wl_signal_get(&priv->events.destroy, notify);
7223 }
7224
7225 #ifdef REFACTOR_DESK_AREA
7226 EINTERN void
7227 e_client_get_above_listener_add(E_Client *ec, struct wl_listener *listener)
7228 {
7229    API_ENTRY;
7230    wl_signal_add(&priv->events.get_above, listener);
7231 }
7232
7233 EINTERN void
7234 e_client_get_below_listener_add(E_Client *ec, struct wl_listener *listener)
7235 {
7236    API_ENTRY;
7237    wl_signal_add(&priv->events.get_below, listener);
7238 }
7239
7240 EINTERN void
7241 e_client_get_visible_above_listener_add(E_Client *ec, struct wl_listener *listener)
7242 {
7243    API_ENTRY;
7244    wl_signal_add(&priv->events.get_visible_above, listener);
7245 }
7246
7247 EINTERN void
7248 e_client_get_visible_below_listener_add(E_Client *ec, struct wl_listener *listener)
7249 {
7250    API_ENTRY;
7251    wl_signal_add(&priv->events.get_visible_below, listener);
7252 }
7253
7254 EINTERN void
7255 e_client_subsurface_stack_update_listener_add(E_Client *ec, struct wl_listener *listener)
7256 {
7257    API_ENTRY;
7258    wl_signal_add(&priv->events.subsurface_stack_update, listener);
7259 }
7260 #endif
7261
7262 EINTERN void
7263 e_client_shell_configure_send(E_Client *ec, uint32_t edges, int32_t width, int32_t height)
7264 {
7265    EINA_SAFETY_ON_NULL_RETURN(ec);
7266    EINA_SAFETY_ON_NULL_RETURN(ec->comp_data);
7267
7268    if ((!ec->comp_data->shell.surface) ||
7269        (!ec->comp_data->shell.configure_send))
7270      return;
7271
7272    ec->comp_data->shell.configure_send(ec->comp_data->shell.surface, edges, width, height);
7273 }
7274
7275 EINTERN void
7276 e_client_shell_configure(E_Client *ec, Evas_Coord x, Evas_Coord y, Evas_Coord width, Evas_Coord height)
7277 {
7278    EINA_SAFETY_ON_NULL_RETURN(ec);
7279    EINA_SAFETY_ON_NULL_RETURN(ec->comp_data);
7280
7281    if ((!ec->comp_data->shell.surface) ||
7282        (!ec->comp_data->shell.configure))
7283      return;
7284
7285    ec->comp_data->shell.configure(ec->comp_data->shell.surface, x, y, width, height);
7286 }
7287
7288 EINTERN void
7289 e_client_shell_ping(E_Client *ec)
7290 {
7291    EINA_SAFETY_ON_NULL_RETURN(ec);
7292    EINA_SAFETY_ON_NULL_RETURN(ec->comp_data);
7293
7294    if ((!ec->comp_data->shell.surface) ||
7295        (!ec->comp_data->shell.ping))
7296      return;
7297
7298    ec->comp_data->shell.ping(ec->comp_data->shell.surface);
7299 }
7300
7301 static void
7302 _e_client_shell_map(E_Client *ec)
7303 {
7304    EINA_SAFETY_ON_NULL_RETURN(ec);
7305    EINA_SAFETY_ON_NULL_RETURN(ec->comp_data);
7306
7307    if ((!ec->comp_data->shell.surface) ||
7308        (!ec->comp_data->shell.map))
7309      return;
7310
7311    ec->comp_data->shell.map(ec->comp_data->shell.surface);
7312 }
7313
7314 EINTERN void
7315 e_client_shell_unmap(E_Client *ec)
7316 {
7317    EINA_SAFETY_ON_NULL_RETURN(ec);
7318    EINA_SAFETY_ON_NULL_RETURN(ec->comp_data);
7319
7320    if ((!ec->comp_data->shell.surface) ||
7321        (!ec->comp_data->shell.unmap))
7322      return;
7323
7324    ec->comp_data->shell.unmap(ec->comp_data->shell.surface);
7325 }
7326
7327 EINTERN void
7328 e_client_show(E_Client *ec)
7329 {
7330    EINA_SAFETY_ON_NULL_RETURN(ec);
7331    EINA_SAFETY_ON_NULL_RETURN(ec->comp_data);
7332
7333    if (ec->comp_data->mapped)
7334      return;
7335
7336    if ((ec->comp_data->shell.surface) && (ec->comp_data->shell.map) &&
7337        (!ec->ignored))
7338      {
7339         ELOGF("E_CLIENT", "Map.", ec);
7340         _e_client_shell_map(ec);
7341      }
7342    else if (ec->internal || e_comp_wl_subsurface_can_show(ec) ||
7343             (ec == e_comp_wl->drag_client))
7344      {
7345         ELOGF("E_CLIENT", "Map. internal:%d, drag:%d",
7346               ec, ec->internal, (ec == e_comp_wl->drag_client));
7347         ec->visible = EINA_TRUE;
7348         ec->ignored = 0;
7349         evas_object_show(ec->frame);
7350         ec->comp_data->mapped = 1;
7351      }
7352 }
7353
7354 EINTERN void
7355 e_client_hide(E_Client *ec)
7356 {
7357    API_ENTRY;
7358
7359    EINA_SAFETY_ON_NULL_RETURN(ec->comp_data);
7360
7361    if (!ec->comp_data->mapped)
7362      return;
7363
7364    if ((ec->comp_data->shell.surface) && (ec->comp_data->shell.unmap))
7365      {
7366         ELOGF("E_CLIENT", "Unmap", ec);
7367
7368         if (priv->hide_by_request)
7369           ELOGF("COMP", "Currenlty hide_by_request state.", ec);
7370
7371         if (ec->show_pending.count > 0)
7372           {
7373              ELOGF("E_CLIENT", "Reset show_pending!!! (count:%d, run:%d)", ec, ec->show_pending.count, ec->show_pending.running);
7374              ec->show_pending.count = 0;
7375              if (ec->show_pending.running)
7376                {
7377                   // need to send visibility false;
7378                   ec->visibility.obscured = E_VISIBILITY_UNOBSCURED;
7379                   ELOGF("POL_VIS", "CLIENT VIS ON (fake).  argb:%d, opaque:%2d", ec, ec->argb, ec->visibility.opaque);
7380                   EC_CHANGED(ec);
7381                }
7382              ec->show_pending.running = EINA_FALSE;
7383           }
7384         e_client_shell_unmap(ec);
7385      }
7386    else if ((ec->internal) || (e_comp_wl_subsurface_check(ec)) ||
7387             (ec == e_comp_wl->drag_client))
7388      {
7389         ELOGF("E_CLIENT", "Unmap. internal:%d, sub:%p, drag:%d",
7390               ec, ec->internal, ec->comp_data->sub.data, (ec == e_comp_wl->drag_client));
7391         ec->visible = EINA_FALSE;
7392         evas_object_hide(ec->frame);
7393         ec->comp_data->mapped = 0;
7394      }
7395 }