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