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