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