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