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