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