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