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