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