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