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