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