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