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