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