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