1 #include "e.h"
2 
3 static int _e_client_hooks_delete = 0;
4 static int _e_client_hooks_walking = 0;
5 
6 E_API int E_EVENT_CLIENT_ADD = -1;
7 E_API int E_EVENT_CLIENT_REMOVE = -1;
8 E_API int E_EVENT_CLIENT_ZONE_SET = -1;
9 E_API int E_EVENT_CLIENT_DESK_SET = -1;
10 E_API int E_EVENT_CLIENT_RESIZE = -1;
11 E_API int E_EVENT_CLIENT_MOVE = -1;
12 E_API int E_EVENT_CLIENT_SHOW = -1;
13 E_API int E_EVENT_CLIENT_HIDE = -1;
14 E_API int E_EVENT_CLIENT_ICONIFY = -1;
15 E_API int E_EVENT_CLIENT_UNICONIFY = -1;
16 E_API int E_EVENT_CLIENT_STACK = -1;
17 E_API int E_EVENT_CLIENT_FOCUS_IN = -1;
18 E_API int E_EVENT_CLIENT_FOCUS_OUT = -1;
19 E_API int E_EVENT_CLIENT_PROPERTY = -1;
20 E_API int E_EVENT_CLIENT_FULLSCREEN = -1;
21 E_API int E_EVENT_CLIENT_UNFULLSCREEN = -1;
22 
23 static Eina_Hash *clients_hash[2] = {NULL}; // pixmap->client
24 
25 static unsigned int focus_track_frozen = 0;
26 
27 static int warp_to = 0;
28 static int warp_to_x = 0;
29 static int warp_to_y = 0;
30 static int warp_x[2] = {0}; //{cur,prev}
31 static int warp_y[2] = {0}; //{cur,prev}
32 static Ecore_Timer *warp_timer = NULL;
33 
34 static E_Client *focused = NULL;
35 static E_Client *warp_client = NULL;
36 static E_Client *ecmove = NULL;
37 static E_Client *ecresize = NULL;
38 static E_Client *action_client = NULL;
39 static E_Drag *client_drag = NULL;
40 
41 static Eina_List *focus_stack = NULL;
42 static Eina_List *raise_stack = NULL;
43 
44 static Eina_Bool comp_grabbed = EINA_FALSE;
45 static Evas_Object *action_rect;
46 
47 static Eina_List *handlers = NULL;
48 //static Eina_Bool client_grabbed = EINA_FALSE;
49 
50 static Ecore_Event_Handler *action_handler_key = NULL;
51 static Ecore_Event_Handler *action_handler_mouse = NULL;
52 static Ecore_Timer *action_timer = NULL;
53 static Eina_Rectangle action_orig = {0, 0, 0, 0};
54 
55 static E_Client_Layout_Cb _e_client_layout_cb = NULL;
56 
57 EINTERN void e_client_focused_set(E_Client *ec);
58 
59 static Eina_Inlist *_e_client_hooks[E_CLIENT_HOOK_LAST] = {NULL};
60 
61 ///////////////////////////////////////////
62 
63 static Eina_Bool
_e_client_cb_efreet_cache_update(void * data EINA_UNUSED,int type EINA_UNUSED,void * ev EINA_UNUSED)64 _e_client_cb_efreet_cache_update(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
65 {
66    const Eina_List *l;
67    E_Client *ec;
68 
69    /* mark all clients for desktop/icon updates */
70    EINA_LIST_FOREACH(e_comp->clients, l, ec)
71      {
72         E_FREE_FUNC(ec->desktop, efreet_desktop_free);
73         if (e_object_is_del(E_OBJECT(ec))) continue;
74         ec->changes.icon = 1;
75         EC_CHANGED(ec);
76      }
77    return ECORE_CALLBACK_RENEW;
78 }
79 
80 static Eina_Bool
_e_client_cb_config_icon_theme(void * data EINA_UNUSED,int type EINA_UNUSED,void * ev EINA_UNUSED)81 _e_client_cb_config_icon_theme(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
82 {
83    const Eina_List *l;
84    E_Client *ec;
85 
86    /* mark all clients for desktop/icon updates */
87    EINA_LIST_FOREACH(e_comp->clients, l, ec)
88      {
89         if (e_object_is_del(E_OBJECT(ec))) continue;
90         ec->changes.icon = 1;
91         EC_CHANGED(ec);
92      }
93    return ECORE_CALLBACK_RENEW;
94 }
95 
96 static Eina_Bool
_e_client_cb_config_mode(void * data EINA_UNUSED,int type EINA_UNUSED,void * ev EINA_UNUSED)97 _e_client_cb_config_mode(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED)
98 {
99    const Eina_List *l;
100    E_Client *ec;
101    E_Layer layer;
102 
103    /* move fullscreen borders above everything */
104 
105    if (e_config->mode.presentation)
106      layer = E_LAYER_CLIENT_TOP;
107    else if (!e_config->allow_above_fullscreen)
108      layer = E_LAYER_CLIENT_FULLSCREEN;
109    else
110      return ECORE_CALLBACK_RENEW;
111 
112    EINA_LIST_FOREACH(e_comp->clients, l, ec)
113      {
114         if (e_object_is_del(E_OBJECT(ec))) continue;
115         if ((ec->fullscreen) || (ec->need_fullscreen))
116           {
117              ec->fullscreen = 0;
118              evas_object_layer_set(ec->frame, layer);
119              ec->fullscreen = 1;
120           }
121      }
122    return ECORE_CALLBACK_PASS_ON;
123 }
124 
125 static Eina_Bool
_e_client_cb_pointer_warp(void * data EINA_UNUSED,int type EINA_UNUSED,E_Event_Pointer_Warp * ev)126 _e_client_cb_pointer_warp(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Pointer_Warp *ev)
127 {
128    if (ecmove)
129      evas_object_move(ecmove->frame, ecmove->x + (ev->curr.x - ev->prev.x), ecmove->y + (ev->curr.y - ev->prev.y));
130    return ECORE_CALLBACK_RENEW;
131 }
132 
133 
134 static Eina_Bool
_e_client_cb_desk_window_profile_change(void * data EINA_UNUSED,int type EINA_UNUSED,E_Event_Desk_Window_Profile_Change * ev EINA_UNUSED)135 _e_client_cb_desk_window_profile_change(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Desk_Window_Profile_Change *ev EINA_UNUSED)
136 {
137    const Eina_List *l;
138    E_Client *ec;
139 
140    EINA_LIST_FOREACH(e_comp->clients, l, ec)
141      {
142         if (e_object_is_del(E_OBJECT(ec))) continue;
143         ec->e.fetch.profile = 1;
144         EC_CHANGED(ec);
145      }
146    return ECORE_CALLBACK_RENEW;
147 }
148 
149 static void
_e_client_cb_drag_finished(E_Drag * drag,int dropped EINA_UNUSED)150 _e_client_cb_drag_finished(E_Drag *drag, int dropped EINA_UNUSED)
151 {
152    E_Client *ec;
153 
154    ec = drag->data;
155    UNREFD(ec, 1);
156    e_object_unref(E_OBJECT(ec));
157    client_drag = NULL;
158 }
159 
160 static void
_e_client_desk_window_profile_wait_desk_delfn(void * data,void * obj)161 _e_client_desk_window_profile_wait_desk_delfn(void *data, void *obj)
162 {
163    E_Client *ec = data;
164    E_Desk *desk = obj, *new_desk;
165    const char *p;
166    int i;
167 
168    if (e_object_is_del(E_OBJECT(ec))) return;
169 
170    ec->e.state.profile.wait_desk_delfn = NULL;
171    eina_stringshare_replace(&ec->e.state.profile.wait, NULL);
172    if (ec->e.state.profile.wait_desk)
173      e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk));
174    ec->e.state.profile.wait_desk = NULL;
175    ec->e.state.profile.wait_for_done = 0;
176 
177    if (!ec->e.state.profile.use) return;
178 
179    new_desk = e_comp_desk_window_profile_get(desk->window_profile);
180    if (new_desk)
181      e_client_desk_set(ec, new_desk);
182    else
183      {
184         for (i = 0; i < ec->e.state.profile.num; i++)
185           {
186              p = ec->e.state.profile.available_list[i];
187              new_desk = e_comp_desk_window_profile_get(p);
188              if (new_desk)
189                {
190                   e_client_desk_set(ec, new_desk);
191                   break;
192                }
193           }
194      }
195 }
196 ////////////////////////////////////////////////
197 
198 
199 static Eina_Bool
_e_client_pointer_warp_to_center_timer(void * data EINA_UNUSED)200 _e_client_pointer_warp_to_center_timer(void *data EINA_UNUSED)
201 {
202    if (warp_to && warp_client)
203      {
204         int x, y;
205         double spd;
206 
207         ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
208         /* move hasn't happened yet */
209         if ((x == warp_x[1]) && (y == warp_y[1]))
210            return EINA_TRUE;
211         if ((abs(x - warp_x[0]) > 5) || (abs(y - warp_y[0]) > 5))
212           {
213              /* User moved the mouse, so stop warping */
214              warp_to = 0;
215              goto cleanup;
216           }
217 
218         spd = e_config->pointer_warp_speed;
219         warp_x[1] = x = warp_x[0];
220         warp_y[1] = y = warp_y[0];
221         warp_x[0] = (x * (1.0 - spd)) + (warp_to_x * spd);
222         warp_y[0] = (y * (1.0 - spd)) + (warp_to_y * spd);
223         if ((warp_x[0] == x) && (warp_y[0] == y))
224           {
225              warp_x[0] = warp_to_x;
226              warp_y[0] = warp_to_y;
227              warp_to = 0;
228              goto cleanup;
229           }
230         ecore_evas_pointer_warp(e_comp->ee, warp_x[0], warp_y[0]);
231         return ECORE_CALLBACK_RENEW;
232      }
233 cleanup:
234    E_FREE_FUNC(warp_timer, ecore_timer_del);
235    if (warp_client)
236      {
237         warp_x[0] = warp_x[1] = warp_y[0] = warp_y[1] = -1;
238         if (warp_client->modal)
239           {
240              warp_client = NULL;
241              return ECORE_CALLBACK_CANCEL;
242           }
243         e_focus_event_mouse_in(warp_client);
244         if (warp_client->iconic)
245           {
246              if (!warp_client->lock_user_iconify)
247                e_client_uniconify(warp_client);
248           }
249         if (warp_client->shaded)
250           {
251              if (!warp_client->lock_user_shade)
252                e_client_unshade(warp_client, warp_client->shade_dir);
253           }
254 
255         if (!warp_client->lock_focus_out)
256           {
257              evas_object_focus_set(warp_client->frame, 1);
258              e_client_focus_latest_set(warp_client);
259           }
260         warp_client = NULL;
261      }
262    return ECORE_CALLBACK_CANCEL;
263 }
264 
265 ////////////////////////////////////////////////
266 
267 static void
_e_client_hooks_clean(void)268 _e_client_hooks_clean(void)
269 {
270    Eina_Inlist *l;
271    E_Client_Hook *ch;
272    unsigned int x;
273 
274    for (x = 0; x < E_CLIENT_HOOK_LAST; x++)
275      EINA_INLIST_FOREACH_SAFE(_e_client_hooks[x], l, ch)
276        {
277           if (!ch->delete_me) continue;
278           _e_client_hooks[x] = eina_inlist_remove(_e_client_hooks[x], EINA_INLIST_GET(ch));
279           free(ch);
280        }
281 }
282 
283 static Eina_Bool
_e_client_hook_call(E_Client_Hook_Point hookpoint,E_Client * ec)284 _e_client_hook_call(E_Client_Hook_Point hookpoint, E_Client *ec)
285 {
286    E_Client_Hook *ch;
287 
288    e_object_ref(E_OBJECT(ec));
289    _e_client_hooks_walking++;
290    EINA_INLIST_FOREACH(_e_client_hooks[hookpoint], ch)
291      {
292         if (ch->delete_me) continue;
293         ch->func(ch->data, ec);
294         if ((hookpoint != E_CLIENT_HOOK_DEL) &&
295           (hookpoint != E_CLIENT_HOOK_MOVE_END) &&
296           (hookpoint != E_CLIENT_HOOK_RESIZE_END) &&
297           (hookpoint != E_CLIENT_HOOK_FOCUS_UNSET) &&
298           e_object_is_del(E_OBJECT(ec)))
299           break;
300      }
301    _e_client_hooks_walking--;
302    if ((_e_client_hooks_walking == 0) && (_e_client_hooks_delete > 0))
303      _e_client_hooks_clean();
304    return !!e_object_unref(E_OBJECT(ec));
305 }
306 
307 ///////////////////////////////////////////
308 
309 static void
_e_client_event_simple_free(void * d EINA_UNUSED,E_Event_Client * ev)310 _e_client_event_simple_free(void *d EINA_UNUSED, E_Event_Client *ev)
311 {
312    UNREFD(ev->ec, 3);
313    e_object_unref(E_OBJECT(ev->ec));
314    free(ev);
315 }
316 
317 static void
_e_client_event_simple(E_Client * ec,int type)318 _e_client_event_simple(E_Client *ec, int type)
319 {
320    E_Event_Client *ev;
321 
322    ev = E_NEW(E_Event_Client, 1);
323    ev->ec = ec;
324    REFD(ec, 3);
325    e_object_ref(E_OBJECT(ec));
326    ecore_event_add(type, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
327 }
328 
329 static void
_e_client_event_property(E_Client * ec,int prop)330 _e_client_event_property(E_Client *ec, int prop)
331 {
332    E_Event_Client_Property *ev;
333 
334    ev = E_NEW(E_Event_Client_Property, 1);
335    ev->ec = ec;
336    ev->property = prop;
337    REFD(ec, 33);
338    e_object_ref(E_OBJECT(ec));
339    ecore_event_add(E_EVENT_CLIENT_PROPERTY, ev, (Ecore_End_Cb)_e_client_event_simple_free, NULL);
340 }
341 
342 static void
_e_client_event_desk_set_free(void * d EINA_UNUSED,E_Event_Client_Desk_Set * ev)343 _e_client_event_desk_set_free(void *d EINA_UNUSED, E_Event_Client_Desk_Set *ev)
344 {
345    UNREFD(ev->ec, 4);
346    e_object_unref(E_OBJECT(ev->ec));
347    e_object_unref(E_OBJECT(ev->desk));
348    free(ev);
349 }
350 
351 static void
_e_client_event_zone_set_free(void * d EINA_UNUSED,E_Event_Client_Zone_Set * ev)352 _e_client_event_zone_set_free(void *d EINA_UNUSED, E_Event_Client_Zone_Set *ev)
353 {
354    UNREFD(ev->ec, 5);
355    e_object_unref(E_OBJECT(ev->ec));
356    e_object_unref(E_OBJECT(ev->zone));
357    free(ev);
358 }
359 
360 ////////////////////////////////////////////////
361 
362 static int
_e_client_action_input_win_del(void)363 _e_client_action_input_win_del(void)
364 {
365    if (!comp_grabbed) return 0;
366 
367    comp_grabbed = 0;
368    E_FREE_FUNC(action_rect, evas_object_del);
369    e_comp_shape_queue();
370    e_comp_ungrab_input(1, 1);
371    return 1;
372 }
373 
374 static void
_e_client_action_finish(void)375 _e_client_action_finish(void)
376 {
377    if (comp_grabbed)
378      _e_client_action_input_win_del();
379 
380    if (action_handler_key && action_client)
381      evas_object_freeze_events_set(action_client->frame, 0);
382    E_FREE_FUNC(action_timer, ecore_timer_del);
383    E_FREE_FUNC(action_handler_key,  ecore_event_handler_del);
384    E_FREE_FUNC(action_handler_mouse, ecore_event_handler_del);
385    if (action_client)
386      {
387         action_client->keyboard_resizing = 0;
388         if (action_client->internal_elm_win)
389           ecore_event_window_ignore_events(elm_win_window_id_get(action_client->internal_elm_win), 0);
390      }
391    action_client = NULL;
392 }
393 
394 static void
_e_client_mouse_action_end(E_Client * ec)395 _e_client_mouse_action_end(E_Client *ec)
396 {
397    if (!ec->cur_mouse_action) return;
398    if (ec->cur_mouse_action->func.end_mouse)
399      ec->cur_mouse_action->func.end_mouse(E_OBJECT(ec), "", NULL);
400    else if (ec->cur_mouse_action->func.end)
401      ec->cur_mouse_action->func.end(E_OBJECT(ec), "");
402    E_FREE_FUNC(ec->cur_mouse_action, e_object_unref);
403 }
404 
405 static void
_e_client_revert_focus(E_Client * ec)406 _e_client_revert_focus(E_Client *ec)
407 {
408    E_Client *pec;
409    E_Desk *desk;
410 
411    if (stopping) return;
412 
413    if (!ec->focused) return;
414    if (!ec->zone) return;
415 
416    desk = e_desk_current_get(ec->zone);
417    if (ec->desk == desk)
418      evas_object_focus_set(ec->frame, 0);
419 
420    if (ec->stack.prev)
421      {
422         ec->stack.focus_skip = 1;
423         pec = e_client_stack_active_adjust(ec);
424         ec->stack.focus_skip = 0;
425         if ((pec != ec) && (!pec->iconic))
426           evas_object_focus_set(pec->frame, 1);
427         else
428           {
429              if ((e_object_is_del(E_OBJECT(ec))) || (ec->iconic))
430                {
431                   Eina_Bool unlock = ec->lock_focus_out;
432                   ec->lock_focus_out = 1;
433                   pec = e_desk_last_focused_focus(desk);
434                   ec->lock_focus_out = unlock;
435                }
436           }
437      }
438    else if ((ec->parent) &&
439             (ec->parent->desk == desk) && (ec->parent->modal == ec))
440      {
441         evas_object_focus_set(ec->parent->frame, 1);
442         if (e_config->raise_on_revert_focus)
443           evas_object_raise(ec->parent->frame);
444      }
445    else if (e_config->focus_revert_on_hide_or_close)
446      {
447         Eina_Bool unlock = ec->lock_focus_out;
448         ec->lock_focus_out = 1;
449         pec = e_desk_last_focused_focus(desk);
450         ec->lock_focus_out = unlock;
451      }
452    else if (e_config->focus_policy == E_FOCUS_MOUSE)
453      {
454         pec = e_client_under_pointer_get(desk, ec);
455         if (pec)
456           evas_object_focus_set(pec->frame, 1);
457         /* no autoraise/revert here because it's probably annoying */
458      }
459 }
460 
461 static void
_e_client_free(E_Client * ec)462 _e_client_free(E_Client *ec)
463 {
464    if (ec->pixmap)
465      {
466         if (e_pixmap_free(ec->pixmap))
467           e_pixmap_client_set(ec->pixmap, NULL);
468         ec->pixmap = NULL;
469      }
470 
471    if (ec->frame)
472      {
473         e_comp_object_redirected_set(ec->frame, 0);
474         e_comp_object_render_update_del(ec->frame);
475      }
476 
477    E_OBJECT(ec)->references++;
478    if (ec->fullscreen)
479      {
480         ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
481         if (!ec->desk->fullscreen_clients)
482           e_comp_render_queue();
483      }
484    if (ec->new_client)
485      e_comp->new_clients--;
486    if (ec->e.state.profile.use)
487      {
488         e_client_desk_window_profile_wait_desk_set(ec, NULL);
489 
490         if (ec->e.state.profile.available_list)
491           {
492              int i;
493              for (i = 0; i < ec->e.state.profile.num; i++)
494                eina_stringshare_replace(&ec->e.state.profile.available_list[i], NULL);
495              E_FREE(ec->e.state.profile.available_list);
496           }
497 
498         ec->e.state.profile.num = 0;
499 
500         eina_stringshare_replace(&ec->e.state.profile.set, NULL);
501         eina_stringshare_replace(&ec->e.state.profile.wait, NULL);
502         eina_stringshare_replace(&ec->e.state.profile.name, NULL);
503         ec->e.state.profile.wait_for_done = 0;
504         ec->e.state.profile.use = 0;
505      }
506 
507    if (ec->e.state.video_parent && ec->e.state.video_parent_client)
508      {
509         ec->e.state.video_parent_client->e.state.video_child =
510           eina_list_remove(ec->e.state.video_parent_client->e.state.video_child, ec);
511      }
512    if (ec->e.state.video_child)
513      {
514         E_Client *tmp;
515 
516         EINA_LIST_FREE(ec->e.state.video_child, tmp)
517           tmp->e.state.video_parent_client = NULL;
518      }
519    E_FREE_FUNC(ec->internal_elm_win, evas_object_del);
520    E_FREE_FUNC(ec->desktop, efreet_desktop_free);
521    E_FREE_FUNC(ec->post_job, ecore_idle_enterer_del);
522 
523    E_FREE_FUNC(ec->kill_timer, ecore_timer_del);
524    E_FREE_LIST(ec->pending_resize, free);
525 
526    if (ec->remember)
527      {
528         E_Remember *rem;
529 
530         rem = ec->remember;
531         ec->remember = NULL;
532         e_remember_unuse(rem);
533      }
534    ec->group = eina_list_free(ec->group);
535    ec->transients = eina_list_free(ec->transients);
536    ec->stick_desks = eina_list_free(ec->stick_desks);
537 
538    E_FREE(ec->netwm.extra_types);
539    eina_stringshare_replace(&ec->border.name, NULL);
540    eina_stringshare_replace(&ec->bordername, NULL);
541    eina_stringshare_replace(&ec->icccm.name, NULL);
542    eina_stringshare_replace(&ec->icccm.class, NULL);
543    eina_stringshare_replace(&ec->icccm.title, NULL);
544    eina_stringshare_replace(&ec->icccm.icon_name, NULL);
545    eina_stringshare_replace(&ec->icccm.machine, NULL);
546    eina_stringshare_replace(&ec->icccm.window_role, NULL);
547    if ((ec->icccm.command.argc > 0) && (ec->icccm.command.argv))
548      {
549         int i;
550 
551         for (i = 0; i < ec->icccm.command.argc; i++)
552           free(ec->icccm.command.argv[i]);
553         E_FREE(ec->icccm.command.argv);
554      }
555    eina_stringshare_replace(&ec->netwm.name, NULL);
556    eina_stringshare_replace(&ec->netwm.icon_name, NULL);
557    eina_stringshare_replace(&ec->internal_icon, NULL);
558    eina_stringshare_replace(&ec->internal_icon_key, NULL);
559    eina_stringshare_replace(&ec->uuid, NULL);
560 
561    focus_stack = eina_list_remove(focus_stack, ec);
562    raise_stack = eina_list_remove(raise_stack, ec);
563 
564    e_hints_client_list_set();
565    if (ec->e.state.profile.wait_desk)
566      {
567         e_object_delfn_del(E_OBJECT(ec->e.state.profile.wait_desk),
568                            ec->e.state.profile.wait_desk_delfn);
569         ec->e.state.profile.wait_desk_delfn = NULL;
570         e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk));
571      }
572    if (ec->stack.prev) ec->stack.prev->stack.next = ec->stack.next;
573    if (ec->stack.next) ec->stack.next->stack.prev = ec->stack.prev;
574 
575    ec->e.state.profile.wait_desk = NULL;
576    evas_object_del(ec->frame);
577    E_OBJECT(ec)->references--;
578 
579    free(ec);
580 }
581 
582 static void
_e_client_del(E_Client * ec)583 _e_client_del(E_Client *ec)
584 {
585    E_Client *child;
586    E_Client_Volume_Sink *sink;
587 
588    EINA_LIST_FREE(ec->sinks, sink)
589      e_client_volume_sink_remove(ec, sink);
590    for (child = ec->stack.next; child; child = child->stack.next)
591      e_client_act_close_begin(child);
592    ec->changed = 0;
593    focus_stack = eina_list_remove(focus_stack, ec);
594    raise_stack = eina_list_remove(raise_stack, ec);
595    if (ec->exe_inst)
596      {
597         if (ec->exe_inst->phony && (eina_list_count(ec->exe_inst->clients) == 1))
598           {
599              if (e_exec_phony_del(ec->exe_inst))
600                ec->exe_inst = NULL;
601           }
602         else
603           {
604              if (!ec->exe_inst->deleted)
605                {
606                   ec->exe_inst->clients = eina_list_remove(ec->exe_inst->clients, ec);
607                   ec->exe_inst = NULL;
608                }
609           }
610      }
611 
612    _e_client_mouse_action_end(ec);
613    if (action_client == ec) _e_client_action_finish();
614    e_pointer_type_pop(e_comp->pointer, ec, NULL);
615 
616    if (warp_client == ec)
617      {
618         E_FREE_FUNC(warp_timer, ecore_timer_del);
619         warp_client = NULL;
620      }
621 
622    if ((client_drag) && (client_drag->data == ec))
623      {
624         e_object_del(E_OBJECT(client_drag));
625         client_drag = NULL;
626      }
627    if (ec->border_menu) e_menu_deactivate(ec->border_menu);
628    if (!stopping)
629      {
630         e_client_comp_hidden_set(ec, 1);
631         if (ec->frame) evas_object_pass_events_set(ec->frame, 1);
632      }
633 
634    E_FREE_FUNC(ec->border_locks_dialog, e_object_del);
635    E_FREE_FUNC(ec->border_remember_dialog, e_object_del);
636    E_FREE_FUNC(ec->border_border_dialog, e_object_del);
637    E_FREE_FUNC(ec->border_prop_dialog, e_object_del);
638    E_FREE_FUNC(ec->color_editor, evas_object_del);
639    e_int_client_menu_del(ec);
640    E_FREE_FUNC(ec->raise_timer, ecore_timer_del);
641 
642    if (ec->internal_elm_win)
643      evas_object_hide(ec->internal_elm_win);
644 
645    if (ec->focused)
646      _e_client_revert_focus(ec);
647    if (ec->frame) evas_object_focus_set(ec->frame, 0);
648 
649    E_FREE_FUNC(ec->ping_poller, ecore_poller_del);
650    eina_hash_del_by_key(clients_hash[e_pixmap_type_get(ec->pixmap)], &ec->pixmap);
651    /* must be called before parent/child clear */
652    _e_client_hook_call(E_CLIENT_HOOK_DEL, ec);
653    E_FREE(ec->comp_data);
654 
655    if ((!ec->new_client) && (!stopping))
656      _e_client_event_simple(ec, E_EVENT_CLIENT_REMOVE);
657 
658    if (ec->parent)
659      {
660         ec->parent->transients = eina_list_remove(ec->parent->transients, ec);
661         ec->parent = NULL;
662      }
663    EINA_LIST_FREE(ec->transients, child)
664      child->parent = NULL;
665 
666    if (ec->leader)
667      {
668         ec->leader->group = eina_list_remove(ec->leader->group, ec);
669         if (ec->leader->modal == ec)
670           ec->leader->modal = NULL;
671         ec->leader = NULL;
672      }
673    EINA_LIST_FREE(ec->group, child)
674      child->leader = NULL;
675 
676    e_comp->clients = eina_list_remove(e_comp->clients, ec);
677    if (ec->frame) e_comp_object_render_update_del(ec->frame);
678 }
679 
680 ///////////////////////////////////////////
681 
682 static Eina_Bool
_e_client_cb_kill_timer(void * data)683 _e_client_cb_kill_timer(void *data)
684 {
685    E_Client *ec = data;
686 
687 // dont wait until it's hung -
688 //   if (ec->hung)
689 //     {
690    if (ec->netwm.pid > 1)
691      kill(ec->netwm.pid, SIGKILL);
692 //     }
693    ec->kill_timer = NULL;
694    return ECORE_CALLBACK_CANCEL;
695 }
696 
697 static Eina_Bool
_e_client_cb_ping_poller(void * data)698 _e_client_cb_ping_poller(void *data)
699 {
700    E_Client *ec;
701 
702    ec = data;
703    if (ec->ping_ok)
704      {
705         if (ec->hung)
706           {
707              ec->hung = 0;
708              evas_object_smart_callback_call(ec->frame, "unhung", NULL);
709              E_FREE_FUNC(ec->kill_timer, ecore_timer_del);
710           }
711      }
712    else
713      {
714         /* if time between last ping and now is greater
715          * than half the ping interval... */
716         if ((ecore_loop_time_get() - ec->ping) >
717             ((e_config->ping_clients_interval *
718               ecore_poller_poll_interval_get(ECORE_POLLER_CORE)) / 2.0))
719           {
720              if (!ec->hung)
721                {
722                   ec->hung = 1;
723                   evas_object_smart_callback_call(ec->frame, "hung", NULL);
724                   /* FIXME: if below dialog is up - hide it now */
725                }
726              if (ec->delete_requested)
727                {
728                   /* FIXME: pop up dialog saying app is hung - kill client, or pid */
729                   e_client_act_kill_begin(ec);
730                }
731           }
732      }
733    ec->ping_poller = NULL;
734    e_client_ping(ec);
735    return ECORE_CALLBACK_CANCEL;
736 }
737 
738 ///////////////////////////////////////////
739 
740 static int
_e_client_action_input_win_new(void)741 _e_client_action_input_win_new(void)
742 {
743    if (comp_grabbed)
744      {
745         CRI("DOUBLE COMP GRAB! ACK!!!!");
746         return 1;
747      }
748    comp_grabbed = e_comp_grab_input(1, 1);
749    if (!comp_grabbed) _e_client_action_input_win_del();
750    return comp_grabbed;
751 }
752 
753 static void
_e_client_action_event_grabber_mouse_up(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)754 _e_client_action_event_grabber_mouse_up(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
755 {
756    Evas_Event_Mouse_Down *ev = event_info;
757    E_Binding_Event_Mouse_Button ev2;
758 
759    if (!action_client) return;
760    e_bindings_evas_event_mouse_button_convert(ev, &ev2);
761    e_client_mouse_up(action_client, ev->button, &ev->output, &ev2);
762    if (!action_client) return;
763    if (action_client->moving)
764      e_client_act_move_end(action_client, NULL);
765    if (!action_client) return;
766    if (e_client_util_resizing_get(action_client))
767      e_client_act_resize_end(action_client, NULL);
768 }
769 
770 static void
_e_client_action_event_grabber_mouse_move(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)771 _e_client_action_event_grabber_mouse_move(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
772 {
773    Evas_Event_Mouse_Move *ev = event_info;
774    if (action_client)
775      e_client_mouse_move(action_client, &ev->cur.output);
776 }
777 
778 static void
_e_client_action_event_grabber_init(E_Client * ec)779 _e_client_action_event_grabber_init(E_Client *ec)
780 {
781    action_rect = e_comp_canvas_event_grabber_add();
782    evas_object_event_callback_add(action_rect, EVAS_CALLBACK_MOUSE_UP, _e_client_action_event_grabber_mouse_up, NULL);
783    evas_object_event_callback_add(action_rect, EVAS_CALLBACK_MOUSE_MOVE, _e_client_action_event_grabber_mouse_move, NULL);
784    evas_object_smart_member_add(ec->frame, action_rect);
785    evas_object_resize(action_rect, e_comp->w, e_comp->h);
786    evas_object_layer_set(action_rect, EVAS_LAYER_MAX - 100);
787    evas_object_show(action_rect);
788    evas_object_event_grabber_freeze_when_visible_set(action_rect, 1);
789    e_comp_shape_queue();
790 }
791 
792 static void
_e_client_action_init(E_Client * ec)793 _e_client_action_init(E_Client *ec)
794 {
795    action_orig.x = ec->x;
796    action_orig.y = ec->y;
797    action_orig.w = ec->w;
798    action_orig.h = ec->h;
799 
800    if (action_client)
801      {
802         action_client->keyboard_resizing = 0;
803         if (action_client->internal_elm_win)
804           ecore_event_window_ignore_events(elm_win_window_id_get(action_client->internal_elm_win), 0);
805      }
806    action_client = ec;
807    if (ec->internal_elm_win)
808      ecore_event_window_ignore_events(elm_win_window_id_get(ec->internal_elm_win), 1);
809 }
810 
811 static void
_e_client_action_restore_orig(E_Client * ec)812 _e_client_action_restore_orig(E_Client *ec)
813 {
814    if (action_client != ec)
815      return;
816 
817    evas_object_geometry_set(ec->frame, action_orig.x, action_orig.y, action_orig.w, action_orig.h);
818 }
819 
820 static int
_e_client_key_down_modifier_apply(int modifier,int value)821 _e_client_key_down_modifier_apply(int modifier, int value)
822 {
823    if (modifier & ECORE_EVENT_MODIFIER_CTRL) return value * 5;
824    else if (modifier & ECORE_EVENT_MODIFIER_ALT)
825      {
826         value /= 5;
827         if (value) return value;
828         else return 1;
829      }
830 
831    return value;
832 }
833 
834 
835 static int
_e_client_move_begin(E_Client * ec)836 _e_client_move_begin(E_Client *ec)
837 {
838    if ((ec->fullscreen) || (ec->lock_user_location))
839      return 0;
840 
841 /*
842    if (client_grabbed && !e_grabinput_get(e_client_util_pwin_get(ec), 0, e_client_util_pwin_get(ec)))
843      {
844         client_grabbed = 0;
845         return 0;
846      }
847 */
848    if (!_e_client_action_input_win_new()) return 0;
849    ec->moving = 1;
850    ecmove = ec;
851    if (!ec->lock_user_stacking)
852      {
853         if (e_config->border_raise_on_mouse_action)
854           evas_object_raise(ec->frame);
855      }
856 
857    _e_client_hook_call(E_CLIENT_HOOK_MOVE_BEGIN, ec);
858    if (!ec->moving)
859      {
860         if (ecmove == ec) ecmove = NULL;
861         _e_client_action_input_win_del();
862         return 0;
863      }
864    E_FREE_FUNC(ec->raise_timer, ecore_timer_del);
865    _e_client_action_event_grabber_init(ec);
866    return 1;
867 }
868 
869 static int
_e_client_move_end(E_Client * ec)870 _e_client_move_end(E_Client *ec)
871 {
872    //if (client_grabbed)
873      //{
874         //e_grabinput_release(e_client_util_pwin_get(ec), e_client_util_pwin_get(ec));
875         //client_grabbed = 0;
876      //}
877    _e_client_action_input_win_del();
878    e_pointer_mode_pop(ec, E_POINTER_MOVE);
879    ec->moving = 0;
880    _e_client_hook_call(E_CLIENT_HOOK_MOVE_END, ec);
881 
882    ecmove = NULL;
883    return 1;
884 }
885 
886 static Eina_Bool
_e_client_action_move_timeout(void * data EINA_UNUSED)887 _e_client_action_move_timeout(void *data EINA_UNUSED)
888 {
889    _e_client_move_end(action_client);
890    _e_client_action_finish();
891    return ECORE_CALLBACK_CANCEL;
892 }
893 
894 static void
_e_client_action_move_timeout_add(void)895 _e_client_action_move_timeout_add(void)
896 {
897    double timeout = e_config->border_keyboard.timeout;
898    E_FREE_FUNC(action_timer, ecore_timer_del);
899    if (!EINA_DBL_NONZERO(timeout)) timeout = 5.0;
900    action_timer = ecore_timer_loop_add(timeout, _e_client_action_move_timeout, NULL);
901 }
902 
903 static Eina_Bool
_e_client_move_key_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)904 _e_client_move_key_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
905 {
906    Ecore_Event_Key *ev = event;
907    int x, y, dx, dy;
908 
909    if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
910    if (!action_client)
911      {
912         ERR("no action_client!");
913         goto stop;
914      }
915 
916    x = action_client->x;
917    y = action_client->y;
918 
919    dx = e_config->border_keyboard.move.dx;
920    dx = _e_client_key_down_modifier_apply(ev->modifiers, dx);
921    dy = e_config->border_keyboard.move.dy;
922    dy = _e_client_key_down_modifier_apply(ev->modifiers, dy);
923 
924    switch (e_util_key_geometry_action_get(ev->key, &x, &y, dx, dy))
925      {
926       case E_UTIL_ACTION_DONE:
927         goto stop;
928         break;
929       case E_UTIL_ACTION_ABORT:
930         _e_client_action_restore_orig(action_client);
931         goto stop;
932         break;
933       case E_UTIL_ACTION_DO:
934         evas_object_move(action_client->frame, x, y);
935         _e_client_action_move_timeout_add();
936         break;
937       case E_UTIL_ACTION_NONE:
938       default:
939         break;
940      }
941 
942    return ECORE_CALLBACK_PASS_ON;
943 
944 stop:
945    _e_client_move_end(action_client);
946    _e_client_action_finish();
947    return ECORE_CALLBACK_DONE;
948 }
949 
950 static Eina_Bool
_e_client_move_mouse_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event EINA_UNUSED)951 _e_client_move_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
952 {
953    if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
954 
955    if (!action_client)
956      ERR("no action_client!");
957 
958    _e_client_move_end(action_client);
959    _e_client_action_finish();
960    return ECORE_CALLBACK_DONE;
961 }
962 
963 static void
_e_client_moveinfo_gather(E_Client * ec,const char * source)964 _e_client_moveinfo_gather(E_Client *ec, const char *source)
965 {
966    if (e_util_glob_match(source, "mouse,*,1"))
967      ec->moveinfo.down.button = 1;
968    else if (e_util_glob_match(source, "mouse,*,2"))
969      ec->moveinfo.down.button = 2;
970    else if (e_util_glob_match(source, "mouse,*,3"))
971      ec->moveinfo.down.button = 3;
972    else
973      ec->moveinfo.down.button = 0;
974    if ((ec->moveinfo.down.button >= 1) && (ec->moveinfo.down.button <= 3))
975      {
976         ec->moveinfo.down.mx = ec->mouse.last_down[ec->moveinfo.down.button - 1].mx;
977         ec->moveinfo.down.my = ec->mouse.last_down[ec->moveinfo.down.button - 1].my;
978      }
979    else
980      {
981         ec->moveinfo.down.mx = ec->mouse.current.mx;
982         ec->moveinfo.down.my = ec->mouse.current.my;
983      }
984 }
985 
986 static void
_e_client_resize_handle(E_Client * ec)987 _e_client_resize_handle(E_Client *ec)
988 {
989    int x, y, w, h;
990    int new_x, new_y, new_w, new_h;
991    int tw, th;
992    Eina_List *skiplist = NULL;
993 
994    if (e_comp->updating) return;
995    x = ec->x;
996    y = ec->y;
997    w = ec->w;
998    h = ec->h;
999 
1000    if ((ec->resize_mode == E_POINTER_RESIZE_TR) ||
1001        (ec->resize_mode == E_POINTER_RESIZE_R) ||
1002        (ec->resize_mode == E_POINTER_RESIZE_BR))
1003      {
1004         if ((ec->moveinfo.down.button >= 1) &&
1005             (ec->moveinfo.down.button <= 3))
1006           w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w +
1007             (ec->mouse.current.mx - ec->moveinfo.down.mx);
1008         else
1009           w = ec->moveinfo.down.w + (ec->mouse.current.mx - ec->moveinfo.down.mx);
1010      }
1011    else if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1012             (ec->resize_mode == E_POINTER_RESIZE_L) ||
1013             (ec->resize_mode == E_POINTER_RESIZE_BL))
1014      {
1015         if ((ec->moveinfo.down.button >= 1) &&
1016             (ec->moveinfo.down.button <= 3))
1017           w = ec->mouse.last_down[ec->moveinfo.down.button - 1].w -
1018             (ec->mouse.current.mx - ec->moveinfo.down.mx);
1019         else
1020           w = ec->moveinfo.down.w - (ec->mouse.current.mx - ec->moveinfo.down.mx);
1021      }
1022 
1023    if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1024        (ec->resize_mode == E_POINTER_RESIZE_T) ||
1025        (ec->resize_mode == E_POINTER_RESIZE_TR))
1026      {
1027         if ((ec->moveinfo.down.button >= 1) &&
1028             (ec->moveinfo.down.button <= 3))
1029           h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h -
1030             (ec->mouse.current.my - ec->moveinfo.down.my);
1031         else
1032           h = ec->moveinfo.down.h - (ec->mouse.current.my - ec->moveinfo.down.my);
1033      }
1034    else if ((ec->resize_mode == E_POINTER_RESIZE_BL) ||
1035             (ec->resize_mode == E_POINTER_RESIZE_B) ||
1036             (ec->resize_mode == E_POINTER_RESIZE_BR))
1037      {
1038         if ((ec->moveinfo.down.button >= 1) &&
1039             (ec->moveinfo.down.button <= 3))
1040           h = ec->mouse.last_down[ec->moveinfo.down.button - 1].h +
1041             (ec->mouse.current.my - ec->moveinfo.down.my);
1042         else
1043           h = ec->moveinfo.down.h + (ec->mouse.current.my - ec->moveinfo.down.my);
1044      }
1045 
1046    tw = ec->w;
1047    th = ec->h;
1048 
1049    if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1050        (ec->resize_mode == E_POINTER_RESIZE_L) ||
1051        (ec->resize_mode == E_POINTER_RESIZE_BL))
1052      x += (tw - w);
1053    if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1054        (ec->resize_mode == E_POINTER_RESIZE_T) ||
1055        (ec->resize_mode == E_POINTER_RESIZE_TR))
1056      y += (th - h);
1057 
1058    skiplist = eina_list_append(skiplist, ec);
1059    e_resist_client_position(skiplist,
1060                                       ec->x, ec->y, ec->w, ec->h,
1061                                       x, y, w, h,
1062                                       &new_x, &new_y, &new_w, &new_h);
1063    eina_list_free(skiplist);
1064 
1065    w = new_w;
1066    h = new_h;
1067    if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
1068      {
1069         if (ec->zone)
1070           {
1071              w = MIN(w, ec->zone->w);
1072              h = MIN(h, ec->zone->h);
1073           }
1074      }
1075    e_client_resize_limit(ec, &new_w, &new_h);
1076    if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1077        (ec->resize_mode == E_POINTER_RESIZE_L) ||
1078        (ec->resize_mode == E_POINTER_RESIZE_BL))
1079      new_x += (w - new_w);
1080    if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
1081        (ec->resize_mode == E_POINTER_RESIZE_T) ||
1082        (ec->resize_mode == E_POINTER_RESIZE_TR))
1083      new_y += (h - new_h);
1084 
1085    evas_object_geometry_set(ec->frame, new_x, new_y, new_w, new_h);
1086 }
1087 
1088 static int
_e_client_resize_end(E_Client * ec)1089 _e_client_resize_end(E_Client *ec)
1090 {
1091    _e_client_action_input_win_del();
1092    e_pointer_mode_pop(ec, ec->resize_mode);
1093    ec->resize_mode = E_POINTER_RESIZE_NONE;
1094 
1095    /* If this border was maximized, we need to unset Maximized state or
1096     * on restart, E still thinks it's maximized */
1097    if (ec->maximized != E_MAXIMIZE_NONE)
1098      e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL,
1099                                   ec->maximized & E_MAXIMIZE_VERTICAL);
1100 
1101    _e_client_hook_call(E_CLIENT_HOOK_RESIZE_END, ec);
1102 
1103    ecresize = NULL;
1104 
1105    return 1;
1106 }
1107 
1108 
1109 static Eina_Bool
_e_client_action_resize_timeout(void * data EINA_UNUSED)1110 _e_client_action_resize_timeout(void *data EINA_UNUSED)
1111 {
1112    _e_client_resize_end(action_client);
1113    _e_client_action_finish();
1114    return ECORE_CALLBACK_CANCEL;
1115 }
1116 
1117 static void
_e_client_action_resize_timeout_add(void)1118 _e_client_action_resize_timeout_add(void)
1119 {
1120    double timeout = e_config->border_keyboard.timeout;
1121    E_FREE_FUNC(action_timer, ecore_timer_del);
1122    if (!EINA_DBL_NONZERO(timeout)) timeout = 5.0;
1123    action_timer = ecore_timer_loop_add(timeout, _e_client_action_resize_timeout, NULL);
1124 }
1125 
1126 static Eina_Bool
_e_client_resize_key_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)1127 _e_client_resize_key_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1128 {
1129    Ecore_Event_Key *ev = event;
1130    int w, h, dx, dy;
1131 
1132    if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
1133    if (!action_client)
1134      {
1135         ERR("no action_client!");
1136         goto stop;
1137      }
1138 
1139    w = action_client->w;
1140    h = action_client->h;
1141 
1142    dx = e_config->border_keyboard.resize.dx;
1143    if (dx < action_client->icccm.step_w) dx = action_client->icccm.step_w;
1144    dx = _e_client_key_down_modifier_apply(ev->modifiers, dx);
1145    if (dx < action_client->icccm.step_w) dx = action_client->icccm.step_w;
1146 
1147    dy = e_config->border_keyboard.resize.dy;
1148    if (dy < action_client->icccm.step_h) dy = action_client->icccm.step_h;
1149    dy = _e_client_key_down_modifier_apply(ev->modifiers, dy);
1150    if (dy < action_client->icccm.step_h) dy = action_client->icccm.step_h;
1151 
1152    switch (e_util_key_geometry_action_get(ev->key, &w, &h, dx, dy))
1153      {
1154       case E_UTIL_ACTION_DONE:
1155         goto stop;
1156         break;
1157       case E_UTIL_ACTION_ABORT:
1158         _e_client_action_restore_orig(action_client);
1159         goto stop;
1160         break;
1161       case E_UTIL_ACTION_DO:
1162         if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
1163           {
1164              if (action_client->zone)
1165                {
1166                   w = MIN(w, action_client->zone->w);
1167                   h = MIN(h, action_client->zone->h);
1168                }
1169           }
1170         e_client_resize_limit(action_client, &w, &h);
1171         evas_object_resize(action_client->frame, w, h);
1172         _e_client_action_resize_timeout_add();
1173         break;
1174       case E_UTIL_ACTION_NONE:
1175       default:
1176         break;
1177      }
1178 
1179    return ECORE_CALLBACK_PASS_ON;
1180 
1181 stop:
1182    _e_client_resize_end(action_client);
1183    _e_client_action_finish();
1184    return ECORE_CALLBACK_DONE;
1185 }
1186 
1187 static Eina_Bool
_e_client_resize_mouse_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event EINA_UNUSED)1188 _e_client_resize_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
1189 {
1190    if (!comp_grabbed) return ECORE_CALLBACK_RENEW;
1191 
1192    if (!action_client)
1193      ERR("no action_client!");
1194 
1195    _e_client_resize_end(action_client);
1196    _e_client_action_finish();
1197    return ECORE_CALLBACK_DONE;
1198 }
1199 
1200 ////////////////////////////////////////////////
1201 
1202 static E_Client *
_e_client_under_pointer_helper(E_Desk * desk,E_Client * exclude,int x,int y)1203 _e_client_under_pointer_helper(E_Desk *desk, E_Client *exclude, int x, int y)
1204 {
1205    E_Client *ec = NULL, *cec;
1206 
1207    E_CLIENT_REVERSE_FOREACH(cec)
1208      {
1209         /* If a border was specified which should be excluded from the list
1210          * (because it will be closed shortly for example), skip */
1211         if (e_client_util_ignored_get(cec) || (!e_client_util_desk_visible(cec, desk))) continue;
1212         if (!evas_object_visible_get(cec->frame)) continue;
1213         if ((exclude) && (cec == exclude)) continue;
1214         if (!E_INSIDE(x, y, cec->x, cec->y, cec->w, cec->h))
1215           continue;
1216         /* If the layer is higher, the position of the window is higher
1217          * (always on top vs always below) */
1218         if (!ec || (cec->layer > ec->layer))
1219           ec = cec;
1220      }
1221    return ec;
1222 }
1223 
1224 ////////////////////////////////////////////////
1225 
1226 static void
_e_client_zones_layout_calc(E_Client * ec,int * zx,int * zy,int * zw,int * zh)1227 _e_client_zones_layout_calc(E_Client *ec, int *zx, int *zy, int *zw, int *zh)
1228 {
1229    int x, y, w, h;
1230    E_Zone *zone_above, *zone_below, *zone_left, *zone_right;
1231 
1232    if (!ec->zone) return;
1233    x = ec->zone->x;
1234    y = ec->zone->y;
1235    w = ec->zone->w;
1236    h = ec->zone->h;
1237 
1238    if (eina_list_count(e_comp->zones) == 1)
1239      {
1240         if (zx) *zx = x;
1241         if (zy) *zy = y;
1242         if (zw) *zw = w;
1243         if (zh) *zh = h;
1244         return;
1245      }
1246 
1247    zone_left = e_comp_zone_xy_get((x - w + 5), y);
1248    zone_right = e_comp_zone_xy_get((x + w + 5), y);
1249    zone_above = e_comp_zone_xy_get(x, (y - h + 5));
1250    zone_below = e_comp_zone_xy_get(x, (y + h + 5));
1251 
1252    if (!(zone_above) && (y))
1253      zone_above = e_comp_zone_xy_get(x, (h - 5));
1254 
1255    if (!(zone_left) && (x))
1256      zone_left = e_comp_zone_xy_get((x - 5), y);
1257 
1258    if (zone_right)
1259      w = zone_right->x + zone_right->w;
1260 
1261    if (zone_left)
1262      w = ec->zone->x + ec->zone->w;
1263 
1264    if (zone_below)
1265      h = zone_below->y + zone_below->h;
1266 
1267    if (zone_above)
1268      h = ec->zone->y + ec->zone->h;
1269 
1270    if ((zone_left) && (zone_right))
1271      w = ec->zone->w + zone_right->x;
1272 
1273    if ((zone_above) && (zone_below))
1274      h = ec->zone->h + zone_below->y;
1275 
1276    if (x) x -= ec->zone->w;
1277    if (y) y -= ec->zone->h;
1278 
1279    if (zx) *zx = x > 0 ? x : 0;
1280    if (zy) *zy = y > 0 ? y : 0;
1281    if (zw) *zw = w;
1282    if (zh) *zh = h;
1283 }
1284 
1285 static void
_e_client_stay_within_canvas(E_Client * ec,int x,int y,int * new_x,int * new_y)1286 _e_client_stay_within_canvas(E_Client *ec, int x, int y, int *new_x, int *new_y)
1287 {
1288    int new_x_max, new_y_max;
1289    int zw, zh;
1290    Eina_Bool lw, lh;
1291 
1292    if (!ec->zone)
1293      {
1294         if (new_x) *new_x = x;
1295         if (new_y) *new_y = y;
1296         return;
1297      }
1298 
1299    _e_client_zones_layout_calc(ec, NULL, NULL, &zw, &zh);
1300 
1301    new_x_max = zw - ec->w;
1302    new_y_max = zh - ec->h;
1303    lw = ec->w > zw ? EINA_TRUE : EINA_FALSE;
1304    lh = ec->h > zh ? EINA_TRUE : EINA_FALSE;
1305 
1306    if (lw)
1307      {
1308         if (x <= new_x_max)
1309           *new_x = new_x_max;
1310         else if (x >= 0)
1311           *new_x = 0;
1312      }
1313    else
1314      {
1315         if (x >= new_x_max)
1316           *new_x = new_x_max;
1317         else if (x <= 0)
1318           *new_x = 0;
1319      }
1320 
1321    if (lh)
1322      {
1323         if (y <= new_y_max)
1324           *new_y = new_y_max;
1325         else if (y >= 0)
1326           *new_y = 0;
1327      }
1328    else
1329      {
1330         if (y >= new_y_max)
1331           *new_y = new_y_max;
1332         else if (y <= 0)
1333           *new_y = 0;
1334      }
1335 }
1336 
1337 static void
_e_client_reset_lost_window(E_Client * ec)1338 _e_client_reset_lost_window(E_Client *ec)
1339 {
1340    E_OBJECT_CHECK(ec);
1341 
1342    if (ec->during_lost) return;
1343    ec->during_lost = EINA_TRUE;
1344 
1345    if (ec->iconic) e_client_uniconify(ec);
1346    if (!ec->moving) e_comp_object_util_center(ec->frame);
1347 
1348    evas_object_raise(ec->frame);
1349    if (!ec->lock_focus_out)
1350      evas_object_focus_set(ec->frame, 1);
1351 
1352    e_client_pointer_warp_to_center(ec);
1353    ec->during_lost = EINA_FALSE;
1354 }
1355 
1356 static void
_e_client_move_lost_window_to_center(E_Client * ec)1357 _e_client_move_lost_window_to_center(E_Client *ec)
1358 {
1359    int loss_overlap = 5;
1360    int zw, zh, zx, zy;
1361 
1362    if (ec->during_lost) return;
1363    if (!ec->zone) return;
1364 
1365    _e_client_zones_layout_calc(ec, &zx, &zy, &zw, &zh);
1366 
1367    if (!E_INTERSECTS(zx + loss_overlap,
1368                      zy + loss_overlap,
1369                      zw - (2 * loss_overlap),
1370                      zh - (2 * loss_overlap),
1371                      ec->x, ec->y, ec->w, ec->h))
1372      {
1373         if (e_config->edge_flip_dragging)
1374           {
1375              Eina_Bool lf, rf, tf, bf;
1376 
1377              lf = rf = tf = bf = EINA_TRUE;
1378 
1379              if (ec->zone->desk_x_count <= 1) lf = rf = EINA_FALSE;
1380              else if (!e_config->desk_flip_wrap)
1381                {
1382                   if (ec->zone->desk_x_current == 0) lf = EINA_FALSE;
1383                   if (ec->zone->desk_x_current == (ec->zone->desk_x_count - 1)) rf = EINA_FALSE;
1384                }
1385 
1386              if (ec->zone->desk_y_count <= 1) tf = bf = EINA_FALSE;
1387              else if (!e_config->desk_flip_wrap)
1388                {
1389                   if (ec->zone->desk_y_current == 0) tf = EINA_FALSE;
1390                   if (ec->zone->desk_y_current == (ec->zone->desk_y_count - 1)) bf = EINA_FALSE;
1391                }
1392 
1393              if (!(lf) && (ec->x <= loss_overlap) && !(ec->zone->flip.switching))
1394                _e_client_reset_lost_window(ec);
1395 
1396              if (!(rf) && (ec->x >= (ec->zone->w - loss_overlap)) && !(ec->zone->flip.switching))
1397                _e_client_reset_lost_window(ec);
1398 
1399              if (!(tf) && (ec->y <= loss_overlap) && !(ec->zone->flip.switching))
1400                _e_client_reset_lost_window(ec);
1401 
1402              if (!(bf) && (ec->y >= (ec->zone->h - loss_overlap)) && !(ec->zone->flip.switching))
1403                _e_client_reset_lost_window(ec);
1404           }
1405 
1406         if (!e_config->edge_flip_dragging)
1407           _e_client_reset_lost_window(ec);
1408      }
1409 }
1410 
1411 ////////////////////////////////////////////////
1412 static void
_e_client_zone_update(E_Client * ec)1413 _e_client_zone_update(E_Client *ec)
1414 {
1415    Eina_List *l;
1416    E_Zone *zone;
1417 
1418    /* still within old zone - leave it there */
1419    if (ec->zone && E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
1420                     ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h))
1421      return;
1422    /* find a new zone */
1423    EINA_LIST_FOREACH(e_comp->zones, l, zone)
1424      {
1425         if (E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
1426                          zone->x, zone->y, zone->w, zone->h))
1427           {
1428              e_client_zone_set(ec, zone);
1429              return;
1430           }
1431      }
1432 }
1433 
1434 ////////////////////////////////////////////////
1435 
1436 E_API Eina_List *
e_client_stack_list_prepare(E_Client * ec)1437 e_client_stack_list_prepare(E_Client *ec)
1438 {
1439    E_Client *ec2;
1440    Eina_List *list = NULL;
1441 
1442    for (ec2 = ec->stack.prev; ec2; ec2 = ec2->stack.prev)
1443      {
1444         ec2->stack.ignore++;
1445         list = eina_list_prepend(list, ec2);
1446      }
1447    ec->stack.ignore++;
1448    list = eina_list_append(list, ec);
1449    for (ec2 = ec->stack.next; ec2; ec2 = ec2->stack.next)
1450      {
1451         ec2->stack.ignore++;
1452         list = eina_list_append(list, ec2);
1453      }
1454    return list;
1455 }
1456 
1457 E_API void
e_client_stack_list_finish(Eina_List * list)1458 e_client_stack_list_finish(Eina_List *list)
1459 {
1460    E_Client *ec;
1461 
1462    EINA_LIST_FREE(list, ec) ec->stack.ignore--;
1463 }
1464 
1465 E_API E_Client *
e_client_stack_top_get(E_Client * ec)1466 e_client_stack_top_get(E_Client *ec)
1467 {
1468    E_Client *ec2;
1469 
1470    for (ec2 = ec; ec2; ec2 = ec2->stack.next)
1471      {
1472         if (!ec2->stack.next) return ec2;
1473      }
1474    return ec;
1475 }
1476 
1477 E_API E_Client *
e_client_stack_bottom_get(E_Client * ec)1478 e_client_stack_bottom_get(E_Client *ec)
1479 {
1480    E_Client *ec2;
1481 
1482    for (ec2 = ec; ec2; ec2 = ec2->stack.prev)
1483      {
1484         if (!ec2->stack.prev) return ec2;
1485      }
1486    return ec;
1487 }
1488 
1489 E_API E_Client *
e_client_stack_active_adjust(E_Client * ec)1490 e_client_stack_active_adjust(E_Client *ec)
1491 {
1492    E_Client *pec = ec;
1493    if ((!ec->stack.prev) && (!ec->stack.next)) return ec;
1494    ec = e_client_stack_top_get(ec);
1495    for (; ec; ec = ec->stack.prev)
1496      {
1497         if (e_object_is_del(E_OBJECT(ec))) continue;
1498         if (ec->stack.focus_skip) continue;
1499         if (ec->iconic) continue;
1500         if (ec->visible) break;
1501      }
1502    if (!ec) ec = pec;
1503    return ec;
1504 }
1505 
1506 E_API Eina_Bool
e_client_stack_focused_get(E_Client * ec)1507 e_client_stack_focused_get(E_Client *ec)
1508 {
1509   E_Client *ec2;
1510 
1511    ec2 = e_client_stack_bottom_get(ec);
1512    for (; ec2; ec2 = ec2->stack.next)
1513      {
1514         if (ec2->focused) return EINA_TRUE;
1515      }
1516    return EINA_FALSE;
1517 }
1518 
1519 E_API Eina_Bool
e_client_stack_iconified_get(E_Client * ec)1520 e_client_stack_iconified_get(E_Client *ec)
1521 {
1522    E_Client *ec2;
1523 
1524    ec2 = e_client_stack_bottom_get(ec);
1525    for (; ec2; ec2 = ec2->stack.next)
1526      {
1527         if (ec2->iconic) return EINA_TRUE;
1528      }
1529    return EINA_FALSE;
1530 }
1531 
1532 E_API Eina_Bool
e_client_stack_urgent_get(E_Client * ec)1533 e_client_stack_urgent_get(E_Client *ec)
1534 {
1535    E_Client *ec2;
1536 
1537    ec2 = e_client_stack_bottom_get(ec);
1538    for (; ec2; ec2 = ec2->stack.next)
1539      {
1540         if (ec2->urgent) return EINA_TRUE;
1541      }
1542    return EINA_FALSE;
1543 }
1544 
1545 ////////////////////////////////////////////////
1546 
1547 static void
_e_client_cb_evas_hide(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1548 _e_client_cb_evas_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1549 {
1550    E_Client *ec = data;
1551 
1552    if (stopping) return; //ignore all of this if we're shutting down!
1553    if (e_object_is_del(data)) return; //client is about to die
1554    _e_client_mouse_action_end(ec);
1555    if (action_client == ec) _e_client_action_finish();
1556    if (!evas_object_pass_events_get(ec->frame))
1557      e_pointer_type_pop(e_comp->pointer, ec, NULL);
1558 
1559    if (!ec->hidden)
1560      {
1561         if (ec->focused)
1562           _e_client_revert_focus(ec);
1563      }
1564    ec->want_focus = ec->take_focus = 0;
1565 
1566    ec->post_show = 0;
1567 
1568    if (ec->new_client || ec->iconic) return;
1569    _e_client_event_simple(ec, E_EVENT_CLIENT_HIDE);
1570 }
1571 
1572 static void
_e_client_cb_evas_shade_done(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1573 _e_client_cb_evas_shade_done(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1574 {
1575    E_Client *ec = data;
1576 
1577    ec->shading = 0;
1578    ec->shaded = !(ec->shaded);
1579    ec->changes.shaded = 1;
1580    ec->changes.shading = 1;
1581    e_client_comp_hidden_set(ec, ec->shaded);
1582 }
1583 
1584 static void
_e_client_cb_evas_move(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1585 _e_client_cb_evas_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1586 {
1587    E_Client *ec = data;
1588    Evas_Coord x, y;
1589 
1590    ec->pre_res_change.valid = 0;
1591    if (ec->internal_elm_win)
1592      {
1593         EC_CHANGED(ec);
1594         ec->changes.pos = 1;
1595      }
1596 
1597    _e_client_event_simple(ec, E_EVENT_CLIENT_MOVE);
1598 
1599    if (!ec->ignored) _e_client_zone_update(ec);
1600    evas_object_geometry_get(ec->frame, &x, &y, NULL, NULL);
1601    if (ec->stack.prev || ec->stack.next)
1602      {
1603         // do nothing - handled by idle enterer eval
1604      }
1605    else
1606      {
1607         if ((e_config->transient.move) && (ec->transients))
1608           {
1609              Eina_List *list = eina_list_clone(ec->transients);
1610              E_Client *child;
1611 
1612              EINA_LIST_FREE(list, child)
1613                {
1614                   if (child->placed)
1615                     evas_object_move(child->frame,
1616                                      child->x + x - ec->pre_cb.x,
1617                                      child->y + y - ec->pre_cb.y);
1618                }
1619           }
1620      }
1621    if (ec->moving || (ecmove == ec))
1622      _e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec);
1623    e_remember_update(ec);
1624    if (ec->fullscreen || (ec->maximized & E_MAXIMIZE_DIRECTION))
1625      e_hints_window_size_set(ec);
1626    ec->pre_cb.x = x; ec->pre_cb.y = y;
1627 }
1628 
1629 static void
_e_client_cb_evas_resize(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1630 _e_client_cb_evas_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1631 {
1632    E_Client *ec = data;
1633    Evas_Coord x, y, w, h;
1634 
1635    ec->pre_res_change.valid = 0;
1636 
1637    _e_client_event_simple(ec, E_EVENT_CLIENT_RESIZE);
1638 
1639    evas_object_geometry_get(ec->frame, &x, &y, &w, &h);
1640    if (ec->stack.prev || ec->stack.next)
1641      {
1642         // do nothing - handled by idle enterer eval
1643      }
1644    else
1645      {
1646         if ((e_config->transient.resize) && (ec->transients))
1647           {
1648              Eina_List *list = eina_list_clone(ec->transients);
1649              E_Client *child;
1650 
1651              EINA_LIST_FREE(list, child)
1652                {
1653                   Evas_Coord nx, ny, nw, nh;
1654 
1655                   if (!child->placed) continue;
1656 
1657                   if ((ec->pre_cb.w > 0) && (ec->pre_cb.h > 0))
1658                     {
1659                        nx = x + (((child->x - x) * w) / ec->pre_cb.w);
1660                        ny = y + (((child->y - y) * h) / ec->pre_cb.h);
1661                        nw = (child->w * w) / ec->pre_cb.w;
1662                        nh = (child->h * h) / ec->pre_cb.h;
1663                        nx += ((nw - child->w) / 2);
1664                        ny += ((nh - child->h) / 2);
1665                        evas_object_move(child->frame, nx, ny);
1666                     }
1667                }
1668           }
1669      }
1670 
1671    if (e_client_util_resizing_get(ec) || (ecresize == ec))
1672      _e_client_hook_call(E_CLIENT_HOOK_RESIZE_UPDATE, ec);
1673    e_remember_update(ec);
1674    if (ec->fullscreen || (ec->maximized & E_MAXIMIZE_DIRECTION))
1675      e_hints_window_size_set(ec);
1676    ec->pre_cb.w = w; ec->pre_cb.h = h;
1677 }
1678 
1679 static void
_e_client_cb_evas_show(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1680 _e_client_cb_evas_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1681 {
1682    _e_client_event_simple(data, E_EVENT_CLIENT_SHOW);
1683 }
1684 
1685 static void
_e_client_cb_evas_restack(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1686 _e_client_cb_evas_restack(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1687 {
1688    E_Client *ec = data;
1689 
1690    if (ec->layer_block) return;
1691    if (ec->stack.prev || ec->stack.next)
1692      {
1693         if (ec->stack.ignore == 0)
1694           {
1695              Eina_List *l, *list = e_client_stack_list_prepare(ec);
1696              E_Client *child;
1697 
1698              EINA_LIST_FOREACH(list, l, child)
1699                {
1700                   if (child == ec) break;
1701                   evas_object_stack_below(child->frame, ec->frame);
1702                }
1703              EINA_LIST_REVERSE_FOREACH(list, l, child)
1704                {
1705                   if (child == ec) break;
1706                   evas_object_stack_above(child->frame, ec->frame);
1707                }
1708              e_client_stack_list_finish(list);
1709           }
1710      }
1711    else
1712      {
1713         if (e_config->transient.raise && ec->transients)
1714           e_client_transients_restack(ec);
1715      }
1716    if (ec->unredirected_single) return;
1717    e_remember_update(ec);
1718    _e_client_event_simple(ec, E_EVENT_CLIENT_STACK);
1719 }
1720 
1721 ////////////////////////////////////////////////
1722 
1723 static void
_e_client_maximize_done(void * data,E_Efx_Map_Data * emd EINA_UNUSED,Evas_Object * obj)1724 _e_client_maximize_done(void *data, E_Efx_Map_Data *emd EINA_UNUSED, Evas_Object *obj)
1725 {
1726    E_Client *ec = data;
1727    ec->maximize_override = 0;
1728    ec->agent = NULL;
1729    evas_object_del(obj);
1730 }
1731 
1732 static Eina_Bool
_e_client_maximize_run(E_Client * ec,int x,int y,int w,int h)1733 _e_client_maximize_run(E_Client *ec, int x, int y, int w, int h)
1734 {
1735    int pw, ph;
1736    Eina_Bool disabled = EINA_FALSE;
1737    if (e_pixmap_size_get(ec->pixmap, &pw, &ph))
1738       {
1739          e_comp_object_frame_wh_adjust(ec->frame, pw, ph, &pw, &ph);
1740          disabled = (w == pw) && (h == ph);
1741       }
1742    if ((!disabled) && e_config->window_maximize_animate && (!ec->maximize_anims_disabled) &&
1743        (!starting) && (!ec->changes.need_maximize))
1744      {
1745         evas_object_del(ec->agent);
1746         ec->agent = e_comp_object_agent_add(ec->frame);
1747         e_efx_resize(ec->agent, e_config->window_maximize_transition, E_EFX_POINT(x, y),
1748           w, h, e_config->window_maximize_time, _e_client_maximize_done, ec);
1749         return EINA_TRUE;
1750      }
1751    evas_object_geometry_set(ec->frame, x, y, w, h);
1752    return EINA_FALSE;
1753 }
1754 
1755 ////////////////////////////////////////////////
1756 
1757 static void
_e_client_eval(E_Client * ec)1758 _e_client_eval(E_Client *ec)
1759 {
1760    int rem_change = 0;
1761    int send_event = 1;
1762    unsigned int prop = 0;
1763    int zx = 0, zy = 0, zw = 0, zh = 0;
1764 
1765 
1766    if (e_object_is_del(E_OBJECT(ec)))
1767      {
1768         CRI("_e_client_eval(%p) with deleted border! - %d\n", ec, ec->new_client);
1769         ec->changed = 0;
1770         return;
1771      }
1772 
1773    if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_NEW_CLIENT, ec)) return;
1774 
1775    if ((ec->new_client) && (!e_client_util_ignored_get(ec)) && (ec->zone))
1776      {
1777         _e_client_event_simple(ec, E_EVENT_CLIENT_ADD);
1778         e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
1779         /* enforce wm size hints for initial sizing */
1780         if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
1781           {
1782              ec->w = MIN(ec->w, ec->zone->w);
1783              ec->h = MIN(ec->h, ec->zone->h);
1784           }
1785         e_client_resize_limit(ec, &ec->w, &ec->h);
1786 
1787         if (ec->re_manage && e_comp_object_frame_exists(ec->frame))
1788           {
1789              int x = ec->x, y = ec->y;
1790              if (ec->x) e_comp_object_frame_xy_adjust(ec->frame, ec->x, 0, &ec->x, NULL);
1791              if (ec->y) e_comp_object_frame_xy_adjust(ec->frame, 0, ec->y, NULL, &ec->y);
1792              if ((x != ec->x) || (y != ec->y)) ec->changes.pos = 1;
1793              ec->placed = 1;
1794              ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
1795           }
1796 
1797         if ((ec->stack.prev) && (!ec->dialog))
1798           {
1799              E_Client *ec2 = e_client_stack_bottom_get(ec);
1800 
1801              ec->stack.ignore++;
1802              evas_object_move(ec->frame, ec2->x, ec2->y);
1803              evas_object_resize(ec->frame, ec2->w, ec2->h);
1804              ec->stack.ignore--;
1805           }
1806      }
1807    if (ec->new_client && (!ec->override))
1808      e_hints_window_init(ec);
1809    if ((!e_client_util_ignored_get(ec)) && ec->zone && ec->visible && (!ec->placed))
1810      {
1811         e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
1812         if (ec->parent)
1813           {
1814              Eina_Bool centered = EINA_FALSE;
1815              if (ec->parent->zone != e_zone_current_get())
1816                {
1817                   e_client_zone_set(ec, ec->parent->zone);
1818                   e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
1819                }
1820 
1821              if (evas_object_visible_get(ec->parent->frame))
1822                {
1823                   if ((!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh)) ||
1824                      (!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, ec->parent->x, ec->parent->y, ec->parent->w, ec->parent->h)))
1825                     {
1826                        int x, y;
1827 
1828                        e_comp_object_util_center_pos_get(ec->parent->frame, &x, &y);
1829                        if (E_CONTAINS(x, y, ec->w, ec->h, zx, zy, zw, zh))
1830                          {
1831                             ec->x = x, ec->y = y;
1832                          }
1833                        else
1834                          {
1835                             x = ec->parent->x;
1836                             y = ec->parent->y;
1837                             if (!E_CONTAINS(x, y, ec->w, ec->h, zx, zy, zw, zh))
1838                               {
1839                                  e_comp_object_util_center_on(ec->frame,
1840                                                               ec->parent->frame);
1841                                  centered = 1;
1842                               }
1843                          }
1844                        ec->changes.pos = 1;
1845                     }
1846                }
1847              else
1848                {
1849                   e_comp_object_util_center_on(ec->frame,
1850                                                ec->parent->frame);
1851                   centered = 1;
1852                }
1853              if (centered) //test for offscreen
1854                {
1855                   if (!E_CONTAINS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh))
1856                     {
1857                        if (ec->x < zx)
1858                          ec->x = ec->parent->x;
1859                        if (ec->y < zy)
1860                          ec->y = ec->parent->y;
1861                        if (ec->x + ec->w > zx + zw)
1862                          ec->x = ec->parent->x + ec->parent->w - ec->w;
1863                        if (ec->y + ec->h > zy + zh)
1864                          ec->y = ec->parent->y + ec->parent->h - ec->h;
1865                        ec->changes.pos = 1;
1866                     }
1867                }
1868              ec->placed = 1;
1869              ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
1870           }
1871 #if 0
1872         else if ((ec->leader) && (ec->dialog))
1873           {
1874              /* TODO: Place in center of group */
1875           }
1876 #endif
1877         else if (ec->dialog)
1878           {
1879              E_Client *trans_ec = NULL;
1880 
1881              if (ec->icccm.transient_for)
1882                trans_ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ec->icccm.transient_for);
1883              if (trans_ec)
1884                {
1885                   // if transient for a window and not placed, center on
1886                   // transient parent if found
1887                   ec->x = trans_ec->x + ((trans_ec->w - ec->w) / 2);
1888                   ec->y = trans_ec->y + ((trans_ec->h - ec->h) / 2);
1889                }
1890              else
1891                {
1892                   ec->x = zx + ((zw - ec->w) / 2);
1893                   ec->y = zy + ((zh - ec->h) / 2);
1894                }
1895              ec->changes.pos = 1;
1896              ec->placed = 1;
1897              ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
1898           }
1899 
1900         if (!ec->placed)
1901           {
1902              Eina_List *skiplist = NULL;
1903              int new_x, new_y, t = 0;
1904              E_Client *trans_ec = NULL;
1905 
1906              if (zw > ec->w)
1907                new_x = zx + (rand() % (zw - ec->w));
1908              else
1909                new_x = zx;
1910              if (zh > ec->h)
1911                new_y = zy + (rand() % (zh - ec->h));
1912              else
1913                new_y = zy;
1914 
1915              e_comp_object_frame_geometry_get(ec->frame, NULL, NULL, &t, NULL);
1916 
1917              if (ec->icccm.transient_for)
1918                trans_ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ec->icccm.transient_for);
1919              if (trans_ec)
1920                {
1921                   // if transient for a window and not placed, center on
1922                   // transient parent if found
1923                   new_x = trans_ec->x + ((trans_ec->w - ec->w) / 2);
1924                   new_y = trans_ec->y + ((trans_ec->h - ec->h) / 2);
1925                }
1926              else if ((e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART) || (e_config->window_placement_policy == E_WINDOW_PLACEMENT_ANTIGADGET))
1927                {
1928                   skiplist = eina_list_append(skiplist, ec);
1929                   if (ec->transients)
1930                     skiplist = eina_list_merge(skiplist, eina_list_clone(ec->transients));
1931                   if (ec->desk)
1932                     e_place_desk_region_smart(ec->desk, skiplist,
1933                                               ec->x, ec->y, ec->w, ec->h,
1934                                               &new_x, &new_y);
1935                   else
1936                     e_place_zone_region_smart(ec->zone, skiplist,
1937                                               ec->x, ec->y, ec->w, ec->h,
1938                                               &new_x, &new_y);
1939                   eina_list_free(skiplist);
1940                }
1941              else if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL)
1942                {
1943                   e_place_zone_manual(ec->zone, ec->w, t, &new_x, &new_y);
1944                }
1945              else
1946                {
1947                   e_place_zone_cursor(ec->zone, ec->x, ec->y, ec->w, ec->h,
1948                                       t, &new_x, &new_y);
1949                }
1950              ec->x = new_x;
1951              ec->y = new_y;
1952              ec->changes.pos = 1;
1953              ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
1954           }
1955         else if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zx, zy, zw, zh))
1956           {
1957              /* If an ec is placed out of bound, fix it! */
1958              ec->x = zx + ((zw - ec->w) / 2);
1959              ec->y = zy + ((zh - ec->h) / 2);
1960              ec->changes.pos = 1;
1961           }
1962 
1963         /* Recreate state */
1964         if ((ec->e.state.centered) &&
1965             ((!ec->remember) ||
1966              ((ec->remember) && (!(ec->remember->apply & E_REMEMBER_APPLY_POS)))))
1967           {
1968              ec->x = zx + (zw - ec->w) / 2;
1969              ec->y = zy + (zh - ec->h) / 2;
1970              ec->changes.pos = 1;
1971           }
1972 
1973         /* if the explicit geometry request asks for the app to be
1974          * in another zone - well move it there */
1975         {
1976            E_Zone *zone = NULL;
1977            int x, y;
1978 
1979            x = MAX(ec->x, 0);
1980            y = MAX(ec->y, 0);
1981            if ((!ec->re_manage) && ((ec->x != x) || (ec->y != y)))
1982              zone = e_comp_zone_xy_get(x, y);
1983 
1984            if (!zone)
1985              {
1986                 zone = e_comp_zone_xy_get(ec->x + (ec->w / 2), ec->y + (ec->h / 2));
1987                 if (zone)
1988                   {
1989                      E_Zone *z2 = e_comp_zone_xy_get(ec->x, ec->y);
1990 
1991                      if (z2 && (z2 != zone))
1992                        {
1993                           size_t psz = 0;
1994                           E_Zone *zf = z2;
1995                           Eina_List *l;
1996 
1997                           EINA_LIST_FOREACH(e_comp->zones, l, z2)
1998                             {
1999                                 int w, h;
2000 
2001                                 x = ec->x, y = ec->y, w = ec->w, h = ec->h;
2002                                 E_RECTS_CLIP_TO_RECT(x, y, w, h, z2->x, z2->y, z2->w, z2->h);
2003                                 if (w * h == z2->w * z2->h)
2004                                   {
2005                                      /* client fully covering zone */
2006                                      zf = z2;
2007                                      break;
2008                                   }
2009                                 if ((unsigned)(w * h) > psz)
2010                                   {
2011                                      psz = w * h;
2012                                      zf = z2;
2013                                   }
2014                             }
2015                           zone = zf;
2016                        }
2017                   }
2018              }
2019            if (!zone)
2020              zone = e_comp_zone_xy_get(ec->x, ec->y);
2021            if (!zone)
2022              zone = e_comp_zone_xy_get(ec->x + ec->w - 1, ec->y);
2023            if (!zone)
2024              zone = e_comp_zone_xy_get(ec->x + ec->w - 1, ec->y + ec->h - 1);
2025            if (!zone)
2026              zone = e_comp_zone_xy_get(ec->x, ec->y + ec->h - 1);
2027            if ((zone) && (zone != ec->zone))
2028              e_client_zone_set(ec, zone);
2029         }
2030      }
2031 
2032    if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT, ec)) return;
2033 
2034    /* effect changes to the window border itself */
2035    if ((ec->changes.shading))
2036      {
2037         /*  show at start of unshade (but don't hide until end of shade) */
2038         //if (ec->shaded)
2039           //ecore_x_window_raise(ec->win);
2040         ec->changes.shading = 0;
2041         send_event = 0;
2042         rem_change = 1;
2043      }
2044    if (ec->changes.shaded) send_event = 0;
2045    if ((ec->changes.shaded) && (ec->changes.pos) && (ec->changes.size))
2046      {
2047         //if (ec->shaded)
2048           //ecore_x_window_lower(ec->win);
2049         //else
2050           //ecore_x_window_raise(ec->win);
2051         ec->changes.shaded = 0;
2052         rem_change = 1;
2053      }
2054    else if ((ec->changes.shaded) && (ec->changes.pos))
2055      {
2056         //if (ec->shaded)
2057           //ecore_x_window_lower(ec->win);
2058         //else
2059           //ecore_x_window_raise(ec->win);
2060         ec->changes.size = 1;
2061         ec->changes.shaded = 0;
2062         rem_change = 1;
2063      }
2064    else if ((ec->changes.shaded) && (ec->changes.size))
2065      {
2066         //if (ec->shaded)
2067           //ecore_x_window_lower(ec->win);
2068         //else
2069           //ecore_x_window_raise(ec->win);
2070         ec->changes.shaded = 0;
2071         rem_change = 1;
2072      }
2073    else if (ec->changes.shaded)
2074      {
2075         //if (ec->shaded)
2076           //ecore_x_window_lower(ec->win);
2077         //else
2078           //ecore_x_window_raise(ec->win);
2079         ec->changes.shaded = 0;
2080         rem_change = 1;
2081      }
2082 
2083    if (ec->changes.size)
2084      {
2085         ec->changes.size = 0;
2086         if ((!ec->shaded) && (!ec->shading))
2087           evas_object_resize(ec->frame, ec->w, ec->h);
2088 
2089         rem_change = 1;
2090         prop |= E_CLIENT_PROPERTY_SIZE;
2091      }
2092    if (ec->changes.pos)
2093      {
2094         Eina_Bool placed = ec->placed;
2095 
2096         ec->changes.pos = 0;
2097         evas_object_move(ec->frame, ec->x, ec->y);
2098         if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL)
2099           ec->placed = placed;
2100         rem_change = 1;
2101         prop |= E_CLIENT_PROPERTY_POS;
2102      }
2103    if (ec->changes.need_rescale)
2104      {
2105         e_client_rescale(ec);
2106         ec->changes.need_rescale = 0;
2107      }
2108 
2109    if (ec->changes.reset_gravity)
2110      {
2111         ec->changes.reset_gravity = 0;
2112         rem_change = 1;
2113         prop |= E_CLIENT_PROPERTY_GRAVITY;
2114      }
2115 
2116    if ((ec->changes.visible) && (ec->visible) && (ec->new_client) && (!ec->iconic))
2117      {
2118         int x, y;
2119 
2120         ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
2121         if ((!ec->placed) && (!ec->re_manage) &&
2122             (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL) &&
2123             (!((ec->icccm.transient_for != 0) ||
2124                (ec->dialog))) &&
2125             (!ecmove) && (!ecresize))
2126           {
2127              /* Set this window into moving state */
2128 
2129              ec->cur_mouse_action = e_action_find("window_move");
2130              if (ec->next_mouse_action_ignore)
2131                ec->cur_mouse_action = NULL;
2132              if (ec->cur_mouse_action)
2133                {
2134                   if ((!ec->cur_mouse_action->func.end_mouse) &&
2135                       (!ec->cur_mouse_action->func.end))
2136                     ec->cur_mouse_action = NULL;
2137                   if (ec->cur_mouse_action)
2138                     {
2139                        int t;
2140                        ec->x = x - (ec->w >> 1);
2141                        e_comp_object_frame_geometry_get(ec->frame, NULL, NULL, &t, NULL);
2142                        ec->y = y - (t >> 1);
2143                        EC_CHANGED(ec);
2144                        ec->changes.pos = 1;
2145                     }
2146                }
2147           }
2148 
2149         evas_object_show(ec->frame);
2150         if (ec->cur_mouse_action)
2151           {
2152              ec->moveinfo.down.x = ec->x;
2153              ec->moveinfo.down.y = ec->y;
2154              ec->moveinfo.down.w = ec->w;
2155              ec->moveinfo.down.h = ec->h;
2156              ec->mouse.current.mx = x;
2157              ec->mouse.current.my = y;
2158              ec->moveinfo.down.button = 0;
2159              ec->moveinfo.down.mx = x;
2160              ec->moveinfo.down.my = y;
2161 
2162              e_object_ref(E_OBJECT(ec->cur_mouse_action));
2163              ec->cur_mouse_action->func.go(E_OBJECT(ec), NULL);
2164              if (e_config->border_raise_on_mouse_action)
2165                evas_object_raise(ec->frame);
2166              evas_object_focus_set(ec->frame, 1);
2167           }
2168         if (evas_object_visible_get(ec->frame))
2169           ec->changes.visible = 0;
2170      }
2171    else if ((ec->changes.visible) && (ec->new_client))
2172      {
2173         ec->changes.visible = 0;
2174         if (!ec->iconic)
2175           _e_client_event_simple(ec, E_EVENT_CLIENT_HIDE);
2176      }
2177 
2178    if (ec->changes.icon)
2179      {
2180         if (!ec->new_client)
2181           E_FREE_FUNC(ec->desktop, efreet_desktop_free);
2182         if (ec->remember && ec->remember->prop.desktop_file)
2183           {
2184              Efreet_Desktop *d;
2185              const char *desktop = ec->remember->prop.desktop_file;
2186 
2187              d = efreet_desktop_get(desktop);
2188              if (!d)
2189                d = efreet_util_desktop_name_find(desktop);
2190              if (d)
2191                {
2192                   efreet_desktop_free(ec->desktop);
2193                   ec->desktop = d;
2194                }
2195           }
2196         if (!ec->desktop)
2197           {
2198              if (ec->steam.steam_game_id)
2199                {
2200                   Efreet_Desktop *d;
2201                   Eina_List *desks = efreet_util_desktop_name_glob_list("*");
2202                   EINA_LIST_FREE(desks, d)
2203                     {
2204                        if (!d->exec) continue;
2205                        if (!strncmp(d->exec, "steam ", 6))
2206                          {
2207                             const char *st = strstr(d->exec, "steam://rungameid/");
2208                             if (st)
2209                               {
2210                                  st += strlen("steam://rungameid/");
2211                                  unsigned int id = atoi(st);
2212                                  if (id == ec->steam.steam_game_id)
2213                                    ec->desktop = d;
2214                               }
2215                          }
2216                     }
2217                }
2218           }
2219         if (!ec->desktop)
2220           {
2221              E_Exec_Instance *inst;
2222 
2223              inst = e_exec_startup_id_pid_instance_find(ec->netwm.startup_id,
2224                                                         ec->netwm.pid);
2225              if (inst && inst->clients)
2226                {
2227                   E_Client *ec2 = eina_list_data_get(inst->clients);
2228 
2229                   if (ec2->netwm.pid == ec->netwm.pid)
2230                     ec->desktop = inst->desktop;
2231                }
2232              else if (inst)
2233                ec->desktop = inst->desktop;
2234              if (ec->desktop) efreet_desktop_ref(ec->desktop);
2235           }
2236         if (!ec->desktop)
2237           {
2238              if (ec->internal && (ec->icccm.class && (!strncmp(ec->icccm.class, "e_fwin::", 8))))
2239                ec->desktop = efreet_util_desktop_exec_find("enlightenment_filemanager");
2240           }
2241         if (!ec->desktop)
2242           {
2243              if ((ec->icccm.name) || (ec->icccm.class))
2244                ec->desktop = efreet_util_desktop_wm_class_find(ec->icccm.name,
2245                                                                ec->icccm.class);
2246           }
2247         if (!ec->desktop && ec->icccm.command.argv && (ec->icccm.command.argc > 0))
2248           {
2249              ec->desktop = efreet_util_desktop_exec_find(ec->icccm.command.argv[0]);
2250           }
2251         if (!ec->desktop)
2252           {
2253              // special case hacks for specific apps that just don't do things
2254              // right so we have to work around them
2255              if (ec->icccm.class && ec->icccm.name &&
2256                  (!strcmp(ec->icccm.class, "Steam")) &&
2257                  (!strcmp(ec->icccm.name, "Steam")))
2258                {
2259                   ec->desktop = efreet_util_desktop_file_id_find("steam.desktop");
2260                }
2261              /* libreoffice and maybe others match window class
2262                 with .desktop file name */
2263              else if (ec->icccm.class)
2264                {
2265                   char buf[4096] = {0};
2266                   snprintf(buf, sizeof(buf), "%s.desktop", ec->icccm.class);
2267                   ec->desktop = efreet_util_desktop_file_id_find(buf);
2268                   if (!ec->desktop)
2269                     {
2270                        char *s;
2271 
2272                        strncpy(buf, ec->icccm.class, sizeof(buf) - 1);
2273                        s = buf;
2274                        eina_str_tolower(&s);
2275                        if (strcmp(s, ec->icccm.class))
2276                          ec->desktop = efreet_util_desktop_exec_find(s);
2277                     }
2278                }
2279           }
2280         if (!ec->desktop && ec->icccm.name)
2281           {
2282              /* this works for most cases as fallback. useful when app is
2283                 run from a shell  */
2284              ec->desktop = efreet_util_desktop_exec_find(ec->icccm.name);
2285           }
2286         if (!ec->desktop && ec->parent)
2287           {
2288              E_Client *ec2 = ec->parent;
2289              if (ec2->desktop)
2290                {
2291                   efreet_desktop_ref(ec2->desktop);
2292                   ec->desktop = ec2->desktop;
2293                }
2294           }
2295 
2296         if (ec->desktop)
2297           {
2298              if (!ec->exe_inst)
2299                e_exec_phony(ec);
2300              if (!ec->exe_inst->desktop)
2301                {
2302                   efreet_desktop_ref(ec->desktop);
2303                   ec->exe_inst->desktop = ec->desktop;
2304                }
2305           }
2306         ec->changes.icon = !e_comp_object_frame_icon_update(ec->frame);
2307         prop |= E_CLIENT_PROPERTY_ICON;
2308      }
2309 
2310    if (ec->new_client)
2311      e_comp->new_clients--;
2312    ec->new_client = 0;
2313    ec->changed = ec->changes.pos || ec->changes.size ||
2314                  ec->changes.stack || ec->changes.prop || ec->changes.border ||
2315                  ec->changes.reset_gravity || ec->changes.shading || ec->changes.shaded ||
2316                  ec->changes.shape || ec->changes.shape_input || ec->changes.icon ||
2317                  ec->changes.internal_state ||
2318                  ec->changes.need_maximize || ec->changes.need_unmaximize;
2319    ec->changes.stack = 0;
2320 
2321    if ((!ec->input_only) && (!ec->iconic) &&
2322        ((!ec->zone) || e_client_util_desk_visible(ec, e_desk_current_get(ec->zone))) &&
2323        ((ec->take_focus) || (ec->want_focus)))
2324      {
2325         ec->take_focus = 0;
2326         if ((ec->stack.prev) && (!ec->stack.next) &&
2327             (ec->stack.prev == e_client_focused_get()))
2328           {
2329              e_client_focus_set_with_pointer(ec);
2330           }
2331         else if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || (ec->want_focus))
2332           {
2333              ec->want_focus = 0;
2334              e_client_focus_set_with_pointer(ec);
2335           }
2336         else if (ec->dialog)
2337           {
2338              if ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) ||
2339                  ((e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED) &&
2340                   (ec->parent == e_client_focused_get())))
2341                {
2342                   e_client_focus_set_with_pointer(ec);
2343                }
2344           }
2345         else
2346           {
2347              /* focus window by default when it is the only one on desk */
2348              E_Client *ec2 = NULL;
2349              Eina_List *l;
2350              EINA_LIST_FOREACH(focus_stack, l, ec2)
2351                {
2352                   if (ec == ec2) continue;
2353                   if ((!ec2->iconic) && (ec2->visible) &&
2354                       ((ec->desk == ec2->desk) || ec2->sticky))
2355                     break;
2356                }
2357 
2358              if (!ec2)
2359                {
2360                   e_client_focus_set_with_pointer(ec);
2361                }
2362           }
2363      }
2364    else
2365      ec->take_focus = ec->want_focus = 0;
2366 
2367    if (ec->changes.need_maximize)
2368      {
2369         E_Maximize max = ec->maximized;
2370         ec->maximized = E_MAXIMIZE_NONE;
2371         e_client_maximize(ec, max);
2372         ec->changes.need_maximize = 0;
2373      }
2374    else if (ec->changes.need_unmaximize)
2375      {
2376         e_client_unmaximize(ec, ec->maximized);
2377         ec->changes.need_unmaximize = 0;
2378      }
2379 
2380    if (ec->need_fullscreen)
2381      {
2382         e_client_fullscreen(ec, e_config->fullscreen_policy);
2383         ec->need_fullscreen = 0;
2384      }
2385 
2386    if (rem_change)
2387      e_remember_update(ec);
2388 
2389    if (send_event && rem_change && prop)
2390      {
2391         _e_client_event_property(ec, prop);
2392      }
2393    _e_client_hook_call(E_CLIENT_HOOK_EVAL_END, ec);
2394 }
2395 
2396 static void
_e_client_frame_update(E_Client * ec)2397 _e_client_frame_update(E_Client *ec)
2398 {
2399    const char *bordername;
2400 
2401    ec->border.changed = 0;
2402    if ((!e_comp_object_frame_allowed(ec->frame)) && (!e_comp_object_frame_exists(ec->frame)))
2403      return;
2404    if (ec->fullscreen || ec->borderless)
2405      bordername = "borderless";
2406    else if (ec->bordername)
2407      bordername = ec->bordername;
2408    else if (ec->mwm.borderless)
2409      bordername = "borderless";
2410    else if (((ec->icccm.transient_for != 0) || (ec->dialog)) &&
2411             (ec->icccm.min_w == ec->icccm.max_w) &&
2412             (ec->icccm.min_h == ec->icccm.max_h))
2413      bordername = "noresize_dialog";
2414    else if ((ec->icccm.min_w == ec->icccm.max_w) &&
2415             (ec->icccm.min_h == ec->icccm.max_h))
2416      bordername = "noresize";
2417    else if (ec->shaped)
2418      bordername = "shaped";
2419    else if (e_pixmap_is_x(ec->pixmap) &&
2420             ((!ec->icccm.accepts_focus) &&
2421             (!ec->icccm.take_focus)))
2422      bordername = "nofocus";
2423    else if (ec->urgent)
2424      bordername = "urgent";
2425    else if (((ec->icccm.transient_for && (!ec->netwm.type)) || (ec->dialog)) &&
2426             (e_pixmap_is_x(ec->pixmap)))
2427      bordername = "dialog";
2428    else if (ec->netwm.state.modal)
2429      bordername = "modal";
2430    else if ((ec->netwm.state.skip_taskbar) ||
2431             (ec->netwm.state.skip_pager))
2432      bordername = "skipped";
2433   /*
2434    else if ((ec->internal) && (ec->icccm.class) &&
2435             (!strncmp(ec->icccm.class, "e_fwin", 6)))
2436      bordername = "internal_fileman";
2437   */
2438    else
2439      bordername = e_config->theme_default_border_style;
2440    if (!bordername) bordername = "default";
2441 
2442    e_client_border_set(ec, bordername);
2443 }
2444 
2445 ////////////////////////////////////////////////
2446 EINTERN void
e_client_idler_before(void)2447 e_client_idler_before(void)
2448 {
2449    const Eina_List *l;
2450    E_Client *ec;
2451 
2452    if ((!eina_hash_population(clients_hash[0])) && (!eina_hash_population(clients_hash[1]))) return;
2453 
2454    EINA_LIST_FOREACH(e_comp->clients, l, ec)
2455      {
2456         Eina_Stringshare *title;
2457         // pass 1 - eval0. fetch properties on new or on change and
2458         // call hooks to decide what to do - maybe move/resize
2459         if (ec->ignored || (!ec->changed)) continue;
2460 
2461         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_FETCH, ec)) continue;
2462         /* FETCH is hooked by the compositor to get client hints */
2463         title = e_client_util_name_get(ec);
2464         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_FETCH, ec)) continue;
2465         if (title != e_client_util_name_get(ec))
2466           _e_client_event_property(ec, E_CLIENT_PROPERTY_TITLE);
2467         /* PRE_POST_FETCH calls e_remember apply for new client */
2468         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_POST_FETCH, ec)) continue;
2469         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_FETCH, ec)) continue;
2470         if (!_e_client_hook_call(E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN, ec)) continue;
2471 
2472         if ((ec->border.changed) && (!ec->shaded) && (!e_client_is_stacking(ec)) &&
2473             ((!ec->override) || ec->internal) &&
2474             (!(((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN))))
2475           _e_client_frame_update(ec);
2476         ec->border.changed = 0;
2477         _e_client_hook_call(E_CLIENT_HOOK_EVAL_POST_FRAME_ASSIGN, ec);
2478      }
2479 
2480    E_CLIENT_FOREACH(ec)
2481      {
2482         if (ec->ignored) continue;
2483         // pass 2 - show windows needing show
2484         if ((ec->changes.visible) && (ec->visible) &&
2485             (!ec->new_client) && (!ec->changes.pos) &&
2486             (!ec->changes.size))
2487           {
2488              evas_object_show(ec->frame);
2489              ec->changes.visible = !evas_object_visible_get(ec->frame);
2490           }
2491 
2492         if ((!ec->new_client) && (!e_client_util_ignored_get(ec)) &&
2493             (!E_INSIDE(ec->x, ec->y, 0, 0, e_comp->w - 5, e_comp->h - 5)) &&
2494             (!E_INSIDE(ec->x, ec->y, 0 - ec->w + 5, 0 - ec->h + 5, e_comp->w - 5, e_comp->h - 5))
2495             )
2496           {
2497              if (e_config->screen_limits != E_CLIENT_OFFSCREEN_LIMIT_ALLOW_FULL)
2498                {
2499                   if (ec->parent)
2500                     e_comp_object_util_center_on(ec->frame, ec->parent->frame);
2501                   else
2502                     _e_client_move_lost_window_to_center(ec);
2503                }
2504           }
2505         // handle window stack
2506         if (!ec->stack.prev && ec->stack.next)
2507           {
2508              if (ec->stack.ignore == 0)
2509                {
2510                   Eina_List *ll, *list = e_client_stack_list_prepare(ec);
2511                   E_Client *child, *bottom, *moving = NULL, *rel;
2512                   int x, y;
2513 
2514                   bottom = rel = e_client_stack_bottom_get(ec);
2515                   EINA_LIST_FOREACH(list, ll, child)
2516                     {
2517                        if (child->moving)
2518                          {
2519                             moving = child;
2520                             break;
2521                          }
2522                     }
2523                   if (moving)
2524                     {
2525                        Evas_Coord ox, oy;
2526 
2527                        evas_object_geometry_get(ec->frame, &ox, &oy, NULL, NULL);
2528                        rel = moving;
2529                     }
2530                   EINA_LIST_FOREACH(list, ll, child)
2531                     {
2532                        if (moving)
2533                          {
2534                             if (child == moving) continue;
2535                          }
2536                        else if (child == bottom) continue;
2537                        x = rel->x + ((rel->w - child->w) / 2);
2538                        y = rel->y + ((rel->h - child->h) / 2);
2539                        if ((x != child->x)  || (y != child->y))
2540                          {
2541                             child->x = x;
2542                             child->y = y;
2543                             child->pre_cb.x = x;
2544                             child->pre_cb.y = y;
2545                             child->changes.pos = 1;
2546                             child->changed = 1;
2547                          }
2548                     }
2549                   e_client_stack_list_finish(list);
2550                }
2551           }
2552      }
2553 
2554    if (_e_client_layout_cb)
2555      _e_client_layout_cb();
2556 
2557    // pass 3 - hide windows needing hide and eval (main eval)
2558    E_CLIENT_FOREACH(ec)
2559      {
2560         if (ec->ignored || e_object_is_del(E_OBJECT(ec))) continue;
2561 
2562         if ((ec->changes.visible) && (!ec->visible))
2563           {
2564              evas_object_hide(ec->frame);
2565              ec->changes.visible = 0;
2566           }
2567 
2568         if (ec->changed)
2569           _e_client_eval(ec);
2570 
2571         if ((ec->changes.visible) && (ec->visible) && (!ec->changed))
2572           {
2573              evas_object_show(ec->frame);
2574              ec->changes.visible = !evas_object_visible_get(ec->frame);
2575              if (ec->changes.visible) EC_CHANGED(ec);
2576              if (!e_client_util_desk_visible(ec, e_desk_current_get(ec->zone)))
2577                evas_object_hide(ec->frame);
2578           }
2579      }
2580 }
2581 
2582 
2583 EINTERN Eina_Bool
e_client_init(void)2584 e_client_init(void)
2585 {
2586    clients_hash[0] = eina_hash_pointer_new(NULL);
2587    clients_hash[1] = eina_hash_pointer_new(NULL);
2588 
2589    E_LIST_HANDLER_APPEND(handlers, E_EVENT_POINTER_WARP,
2590                          _e_client_cb_pointer_warp, NULL);
2591    E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_DESKTOP_CACHE_UPDATE,
2592                          _e_client_cb_efreet_cache_update, NULL);
2593    E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_ICON_CACHE_UPDATE,
2594                          _e_client_cb_efreet_cache_update, NULL);
2595    E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_ICON_THEME,
2596                          _e_client_cb_config_icon_theme, NULL);
2597    E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_MODE_CHANGED,
2598                          _e_client_cb_config_mode, NULL);
2599    E_LIST_HANDLER_APPEND(handlers, E_EVENT_DESK_WINDOW_PROFILE_CHANGE,
2600                          _e_client_cb_desk_window_profile_change, NULL);
2601 
2602    E_EVENT_CLIENT_ADD = ecore_event_type_new();
2603    E_EVENT_CLIENT_REMOVE = ecore_event_type_new();
2604    E_EVENT_CLIENT_DESK_SET = ecore_event_type_new();
2605    E_EVENT_CLIENT_ZONE_SET = ecore_event_type_new();
2606    E_EVENT_CLIENT_RESIZE = ecore_event_type_new();
2607    E_EVENT_CLIENT_MOVE = ecore_event_type_new();
2608    E_EVENT_CLIENT_SHOW = ecore_event_type_new();
2609    E_EVENT_CLIENT_HIDE = ecore_event_type_new();
2610    E_EVENT_CLIENT_ICONIFY = ecore_event_type_new();
2611    E_EVENT_CLIENT_UNICONIFY = ecore_event_type_new();
2612    E_EVENT_CLIENT_STACK = ecore_event_type_new();
2613    E_EVENT_CLIENT_FOCUS_IN = ecore_event_type_new();
2614    E_EVENT_CLIENT_FOCUS_OUT = ecore_event_type_new();
2615    E_EVENT_CLIENT_PROPERTY = ecore_event_type_new();
2616    E_EVENT_CLIENT_FULLSCREEN = ecore_event_type_new();
2617    E_EVENT_CLIENT_UNFULLSCREEN = ecore_event_type_new();
2618 
2619    return (!!clients_hash[1]);
2620 }
2621 
2622 EINTERN void
e_client_shutdown(void)2623 e_client_shutdown(void)
2624 {
2625    E_FREE_FUNC(clients_hash[0], eina_hash_free);
2626    E_FREE_FUNC(clients_hash[1], eina_hash_free);
2627 
2628    E_FREE_LIST(handlers, ecore_event_handler_del);
2629 
2630    e_int_client_menu_hooks_clear();
2631    E_FREE_FUNC(warp_timer, ecore_timer_del);
2632    warp_client = NULL;
2633 }
2634 
2635 E_API void
e_client_unignore(E_Client * ec)2636 e_client_unignore(E_Client *ec)
2637 {
2638    E_OBJECT_CHECK(ec);
2639    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
2640    if (!ec->ignored) return;
2641 
2642    ec->ignored = 0;
2643    if (!e_client_util_ignored_get(ec))
2644      {
2645         if (starting)
2646           focus_stack = eina_list_prepend(focus_stack, ec);
2647         else
2648           focus_stack = eina_list_append(focus_stack, ec);
2649      }
2650    _e_client_event_simple(ec, E_EVENT_CLIENT_ADD);
2651    _e_client_hook_call(E_CLIENT_HOOK_UNIGNORE, ec);
2652 }
2653 
2654 E_API E_Client *
e_client_new(E_Pixmap * cp,int first_map,int internal)2655 e_client_new(E_Pixmap *cp, int first_map, int internal)
2656 {
2657    E_Client *ec;
2658    E_Pixmap_Type ptype = e_pixmap_type_get(cp);
2659 
2660    if ((ptype != E_PIXMAP_TYPE_X) && (ptype != E_PIXMAP_TYPE_WL)) return NULL;
2661    if (eina_hash_find(clients_hash[ptype], &cp)) return NULL;
2662 
2663    ec = E_OBJECT_ALLOC(E_Client, E_CLIENT_TYPE, _e_client_free);
2664    if (!ec) return NULL;
2665    e_object_del_func_set(E_OBJECT(ec), E_OBJECT_CLEANUP_FUNC(_e_client_del));
2666 
2667    ec->focus_policy_override = E_FOCUS_LAST;
2668    ec->w = 1;
2669    ec->h = 1;
2670    ec->internal = internal;
2671 
2672    ec->pixmap = cp;
2673    e_pixmap_client_set(cp, ec);
2674    ec->resize_mode = E_POINTER_RESIZE_NONE;
2675    ec->layer = E_LAYER_CLIENT_NORMAL;
2676 
2677    /* printf("##- ON MAP CLIENT 0x%x SIZE %ix%i %i:%i\n",
2678     *     ec->win, ec->w, ec->h, att->x, att->y); */
2679 
2680    /* FIXME: if first_map is 1 then we should ignore the first hide event
2681     * or ensure the window is already hidden and events flushed before we
2682     * create a border for it */
2683    if (first_map)
2684      {
2685         // printf("##- FIRST MAP\n");
2686         ec->re_manage = 1;
2687         // needed to be 1 for internal windw and on restart.
2688         // ec->ignore_first_unmap = 2;
2689      }
2690    ec->offer_resistance = 1;
2691    ec->new_client = 1;
2692    e_comp->new_clients++;
2693 
2694    if (!_e_client_hook_call(E_CLIENT_HOOK_NEW_CLIENT, ec))
2695      {
2696         /* delete the above allocated object */
2697         //e_object_del(E_OBJECT(ec));
2698         return NULL;
2699      }
2700 
2701    ec->icccm.title = NULL;
2702    ec->icccm.name = NULL;
2703    ec->icccm.class = NULL;
2704    ec->icccm.icon_name = NULL;
2705    ec->icccm.machine = NULL;
2706    ec->icccm.min_w = 1;
2707    ec->icccm.min_h = 1;
2708    ec->icccm.max_w = 32767;
2709    ec->icccm.max_h = 32767;
2710    ec->icccm.base_w = 0;
2711    ec->icccm.base_h = 0;
2712    ec->icccm.step_w = -1;
2713    ec->icccm.step_h = -1;
2714    ec->icccm.min_aspect = 0.0;
2715    ec->icccm.max_aspect = 0.0;
2716 
2717    ec->netwm.pid = 0;
2718    ec->netwm.name = NULL;
2719    ec->netwm.icon_name = NULL;
2720    ec->netwm.desktop = 0;
2721    ec->netwm.state.modal = 0;
2722    ec->netwm.state.sticky = 0;
2723    ec->netwm.state.shaded = 0;
2724    ec->netwm.state.hidden = 0;
2725    ec->netwm.state.maximized_v = 0;
2726    ec->netwm.state.maximized_h = 0;
2727    ec->netwm.state.skip_taskbar = 0;
2728    ec->netwm.state.skip_pager = 0;
2729    ec->netwm.state.fullscreen = 0;
2730    ec->netwm.state.stacking = E_STACKING_NONE;
2731    ec->netwm.action.move = 0;
2732    ec->netwm.action.resize = 0;
2733    ec->netwm.action.minimize = 0;
2734    ec->netwm.action.shade = 0;
2735    ec->netwm.action.stick = 0;
2736    ec->netwm.action.maximized_h = 0;
2737    ec->netwm.action.maximized_v = 0;
2738    ec->netwm.action.fullscreen = 0;
2739    ec->netwm.action.change_desktop = 0;
2740    ec->netwm.action.close = 0;
2741    ec->netwm.opacity = 255;
2742 
2743    e_comp->clients = eina_list_append(e_comp->clients, ec);
2744    eina_hash_add(clients_hash[ptype], &ec->pixmap, ec);
2745 
2746    if (!ec->ignored) EC_CHANGED(ec);
2747 
2748    e_comp_object_client_add(ec);
2749 
2750    if (ec->override)
2751      _e_client_zone_update(ec);
2752    else if (!ec->desk)
2753      e_client_desk_set(ec, e_desk_current_get(e_zone_current_get()));
2754    if (!ec->re_manage)
2755      ec->placed = ec->changes.pos = 0; //ensure placement is run
2756    if (ec->frame)
2757      {
2758         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW, _e_client_cb_evas_show, ec);
2759         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE, _e_client_cb_evas_hide, ec);
2760         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE, _e_client_cb_evas_move, ec);
2761         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESIZE, _e_client_cb_evas_resize, ec);
2762         evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESTACK, _e_client_cb_evas_restack, ec);
2763         evas_object_smart_callback_add(ec->frame, "shade_done", _e_client_cb_evas_shade_done, ec);
2764         if (ec->override)
2765           evas_object_layer_set(ec->frame, E_LAYER_CLIENT_ABOVE);
2766         else
2767           evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NORMAL);
2768      }
2769    if (!e_client_util_ignored_get(ec))
2770      {
2771         if (starting)
2772           focus_stack = eina_list_prepend(focus_stack, ec);
2773         else
2774           focus_stack = eina_list_append(focus_stack, ec);
2775      }
2776 
2777    e_hints_client_list_set();
2778    return ec;
2779 }
2780 
2781 E_API Eina_Bool
e_client_desk_window_profile_available_check(E_Client * ec,const char * profile)2782 e_client_desk_window_profile_available_check(E_Client *ec, const char *profile)
2783 {
2784    int i;
2785 
2786    E_OBJECT_CHECK_RETURN(ec, EINA_FALSE);
2787    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE);
2788    EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
2789    EINA_SAFETY_ON_FALSE_RETURN_VAL(ec->e.state.profile.use, EINA_FALSE);
2790    if (ec->e.state.profile.num == 0) return EINA_TRUE;
2791 
2792    for (i = 0; i < ec->e.state.profile.num; i++)
2793      {
2794         if (!e_util_strcmp(ec->e.state.profile.available_list[i],
2795                            profile))
2796           return EINA_TRUE;
2797      }
2798 
2799    return EINA_FALSE;
2800 }
2801 
2802 E_API void
e_client_desk_window_profile_wait_desk_set(E_Client * ec,E_Desk * desk)2803 e_client_desk_window_profile_wait_desk_set(E_Client *ec, E_Desk *desk)
2804 {
2805    E_OBJECT_CHECK(ec);
2806    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
2807    E_OBJECT_CHECK(desk);
2808    E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE);
2809 
2810    if (ec->e.state.profile.wait_desk == desk) return;
2811 
2812    if (ec->e.state.profile.wait_desk_delfn)
2813      {
2814         if (ec->e.state.profile.wait_desk)
2815           e_object_delfn_del(E_OBJECT(ec->e.state.profile.wait_desk),
2816                              ec->e.state.profile.wait_desk_delfn);
2817         ec->e.state.profile.wait_desk_delfn = NULL;
2818      }
2819 
2820    if (ec->e.state.profile.wait_desk)
2821      e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk));
2822    ec->e.state.profile.wait_desk = NULL;
2823 
2824    if (desk)
2825      {
2826         ec->e.state.profile.wait_desk_delfn =
2827            e_object_delfn_add(E_OBJECT(desk),
2828                               _e_client_desk_window_profile_wait_desk_delfn,
2829                               ec);
2830      }
2831    ec->e.state.profile.wait_desk = desk;
2832    if (ec->e.state.profile.wait_desk)
2833      e_object_ref(E_OBJECT(ec->e.state.profile.wait_desk));
2834 }
2835 
2836 E_API void
e_client_desk_set(E_Client * ec,E_Desk * desk)2837 e_client_desk_set(E_Client *ec, E_Desk *desk)
2838 {
2839    E_Event_Client_Desk_Set *ev;
2840    E_Desk *old_desk;
2841 
2842    E_OBJECT_CHECK(ec);
2843    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
2844    E_OBJECT_CHECK(desk);
2845    E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE);
2846    if (ec->desk == desk) return;
2847    if (ec->e.state.profile.use)
2848      {
2849         const char *profile = desk->window_profile;
2850 
2851         if (!profile) profile = elm_config_profile_get();
2852         if (!profile) profile = "standard";
2853         if (e_util_strcmp(ec->e.state.profile.name, profile))
2854           {
2855              if (e_client_desk_window_profile_available_check(ec, profile))
2856                {
2857                   eina_stringshare_replace(&ec->e.state.profile.set, profile);
2858                   eina_stringshare_replace(&ec->e.state.profile.wait, NULL);
2859                   ec->e.state.profile.wait_for_done = 0;
2860                   e_client_desk_window_profile_wait_desk_set(ec, desk);
2861                   EC_CHANGED(ec);
2862                }
2863           }
2864      }
2865 
2866    if (ec->fullscreen)
2867      {
2868         if (ec->desk)
2869           ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
2870         desk->fullscreen_clients = eina_list_append(desk->fullscreen_clients, ec);
2871      }
2872    old_desk = ec->desk;
2873    ec->desk = desk;
2874    if (ec->frame)
2875      {
2876         e_comp_object_effect_unclip(ec->frame);
2877         e_comp_object_effect_set(ec->frame, NULL);
2878      }
2879    if (desk->visible || ec->sticky)
2880      {
2881         // force visibility if its a stack window going onto this desktop
2882         if (ec->stack.prev || ec->stack.next) ec->hidden = 0;
2883         if ((!ec->hidden) && (!ec->iconic))
2884           evas_object_show(ec->frame);
2885      }
2886    else
2887      {
2888         ec->hidden = 1;
2889         evas_object_hide(ec->frame);
2890      }
2891    e_client_comp_hidden_set(ec, (!desk->visible) && (!ec->sticky));
2892    e_client_zone_set(ec, desk->zone);
2893 
2894    e_hints_window_desktop_set(ec);
2895 
2896    if (old_desk)
2897      {
2898         ev = E_NEW(E_Event_Client_Desk_Set, 1);
2899         ev->ec = ec;
2900         UNREFD(ec, 4);
2901         e_object_ref(E_OBJECT(ec));
2902         ev->desk = old_desk;
2903         e_object_ref(E_OBJECT(old_desk));
2904         ecore_event_add(E_EVENT_CLIENT_DESK_SET, ev, (Ecore_End_Cb)_e_client_event_desk_set_free, NULL);
2905 
2906         if (old_desk->zone == ec->zone)
2907           {
2908              if (ec->maximized || ec->fullscreen)
2909                e_client_rescale(ec);
2910           }
2911      }
2912 
2913    if (ec->stack.prev || ec->stack.next)
2914      {
2915         if (ec->stack.ignore == 0)
2916           {
2917              Eina_List *l, *list = e_client_stack_list_prepare(ec);
2918              E_Client *child;
2919 
2920              EINA_LIST_FOREACH(list, l, child)
2921                {
2922                   if (child == ec) break;
2923                   e_client_desk_set(child, ec->desk);
2924                   evas_object_stack_below(child->frame, ec->frame);
2925                }
2926              EINA_LIST_REVERSE_FOREACH(list, l, child)
2927                {
2928                   if (child == ec) break;
2929                   e_client_desk_set(child, ec->desk);
2930                   evas_object_stack_above(child->frame, ec->frame);
2931                }
2932              e_client_stack_list_finish(list);
2933           }
2934      }
2935    else
2936      {
2937         if (e_config->transient.desktop)
2938           {
2939              E_Client *child;
2940              const Eina_List *l;
2941 
2942              EINA_LIST_FOREACH(ec->transients, l, child)
2943                e_client_desk_set(child, ec->desk);
2944              e_client_transients_restack(ec);
2945           }
2946      }
2947 
2948    e_remember_update(ec);
2949    _e_client_hook_call(E_CLIENT_HOOK_DESK_SET, ec);
2950    evas_object_smart_callback_call(ec->frame, "desk_change", ec);
2951 }
2952 
2953 E_API Eina_Bool
e_client_comp_grabbed_get(void)2954 e_client_comp_grabbed_get(void)
2955 {
2956    return comp_grabbed;
2957 }
2958 
2959 E_API E_Client *
e_client_action_get(void)2960 e_client_action_get(void)
2961 {
2962    return action_client;
2963 }
2964 
2965 E_API E_Client *
e_client_warping_get(void)2966 e_client_warping_get(void)
2967 {
2968    return warp_client;
2969 }
2970 
2971 
2972 E_API Eina_List *
e_clients_immortal_list(void)2973 e_clients_immortal_list(void)
2974 {
2975    const Eina_List *l;
2976    Eina_List *list = NULL;
2977    E_Client *ec;
2978 
2979    EINA_LIST_FOREACH(e_comp->clients, l, ec)
2980      {
2981         if (ec->lock_life)
2982           list = eina_list_append(list, ec);
2983      }
2984    return list;
2985 }
2986 
2987 //////////////////////////////////////////////////////////
2988 
2989 E_API void
e_client_mouse_in(E_Client * ec,int x,int y)2990 e_client_mouse_in(E_Client *ec, int x, int y)
2991 {
2992    if (comp_grabbed) return;
2993    if (warp_client && (ec != warp_client)) return;
2994    if (e_object_is_del(E_OBJECT(ec))) return;
2995    if (ec->desk && ec->desk->animate_count) return;
2996    ec->mouse.current.mx = x;
2997    ec->mouse.current.my = y;
2998    ec->mouse.in = 1;
2999    if ((!ec->iconic) && (!e_client_util_ignored_get(ec)))
3000      e_focus_event_mouse_in(ec);
3001 }
3002 
3003 E_API void
e_client_mouse_out(E_Client * ec,int x,int y)3004 e_client_mouse_out(E_Client *ec, int x, int y)
3005 {
3006    if (comp_grabbed) return;
3007    if (ec->desk && ec->desk->animate_count) return;
3008    if (e_pixmap_is_x(ec->pixmap) && E_INSIDE(x, y, ec->x, ec->y, ec->w, ec->h)) return;
3009 
3010    ec->mouse.current.mx = x;
3011    ec->mouse.current.my = y;
3012    ec->mouse.in = 0;
3013    if (ec->fullscreen) return;
3014    if (e_object_is_del(E_OBJECT(ec))) return;
3015    if ((!ec->iconic) && (!e_client_util_ignored_get(ec)))
3016      e_focus_event_mouse_out(ec);
3017 }
3018 
3019 E_API void
e_client_mouse_wheel(E_Client * ec,Evas_Point * output,E_Binding_Event_Wheel * ev)3020 e_client_mouse_wheel(E_Client *ec, Evas_Point *output, E_Binding_Event_Wheel *ev)
3021 {
3022    EINA_SAFETY_ON_NULL_RETURN(ec);
3023    if (action_client) return;
3024    ec->mouse.current.mx = output->x;
3025    ec->mouse.current.my = output->y;
3026    if ((!ec->cur_mouse_action) && (!e_client_util_ignored_get(ec)))
3027      e_bindings_wheel_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(ec), ev);
3028 }
3029 
3030 E_API void
e_client_mouse_down(E_Client * ec,int button,Evas_Point * output,E_Binding_Event_Mouse_Button * ev)3031 e_client_mouse_down(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button *ev)
3032 {
3033    Eina_Bool did_act = EINA_FALSE;
3034    E_Client *pfocus;
3035    int player;
3036 
3037    EINA_SAFETY_ON_NULL_RETURN(ec);
3038    if (action_client || ec->iconic || e_client_util_ignored_get(ec)) return;
3039    if ((button >= 1) && (button <= 3))
3040      {
3041         ec->mouse.last_down[button - 1].mx = output->x;
3042         ec->mouse.last_down[button - 1].my = output->y;
3043         ec->mouse.last_down[button - 1].x = ec->x;
3044         ec->mouse.last_down[button - 1].y = ec->y;
3045         ec->mouse.last_down[button - 1].w = ec->w;
3046         ec->mouse.last_down[button - 1].h = ec->h;
3047      }
3048    else
3049      {
3050         ec->moveinfo.down.x = ec->x;
3051         ec->moveinfo.down.y = ec->y;
3052         ec->moveinfo.down.w = ec->w;
3053         ec->moveinfo.down.h = ec->h;
3054      }
3055    ec->mouse.current.mx = output->x;
3056    ec->mouse.current.my = output->y;
3057    pfocus = e_client_focused_get();
3058    player = ec->layer;
3059    if (!ec->cur_mouse_action)
3060      {
3061         ec->cur_mouse_action =
3062           e_bindings_mouse_down_event_handle(E_BINDING_CONTEXT_WINDOW,
3063                                              E_OBJECT(ec), ev);
3064         if (ec->next_mouse_action_ignore)
3065           ec->cur_mouse_action = NULL;
3066         if (ec->cur_mouse_action)
3067           {
3068              did_act = EINA_TRUE;
3069              e_object_ref(E_OBJECT(ec->cur_mouse_action));
3070              if (ec->internal)
3071                {
3072                   int button_mask, i;
3073                   Evas *e;
3074 
3075                   e = evas_object_evas_get(ec->internal_elm_win);
3076                   button_mask = evas_pointer_button_down_mask_get(e);
3077                   for (i = 0; i < 32; i++)
3078                     {
3079                       if ((button_mask & (1 << i)))
3080                         evas_event_feed_mouse_up(e, i + 1, EVAS_BUTTON_NONE, 0, NULL);
3081                     }
3082                   evas_event_feed_mouse_out(e, 0, NULL);
3083                }
3084           }
3085      }
3086    if ((!did_act) || (((pfocus == e_client_focused_get()) || (ec == e_client_focused_get())) && (ec->layer >= player)))
3087      e_focus_event_mouse_down(ec);
3088    if ((button >= 1) && (button <= 3))
3089      {
3090         ec->mouse.last_down[button - 1].mx = output->x;
3091         ec->mouse.last_down[button - 1].my = output->y;
3092         ec->mouse.last_down[button - 1].x = ec->x;
3093         ec->mouse.last_down[button - 1].y = ec->y;
3094         ec->mouse.last_down[button - 1].w = ec->w;
3095         ec->mouse.last_down[button - 1].h = ec->h;
3096      }
3097    else
3098      {
3099         ec->moveinfo.down.x = ec->x;
3100         ec->moveinfo.down.y = ec->y;
3101         ec->moveinfo.down.w = ec->w;
3102         ec->moveinfo.down.h = ec->h;
3103      }
3104    ec->mouse.current.mx = output->x;
3105    ec->mouse.current.my = output->y;
3106 }
3107 
3108 E_API void
e_client_mouse_up(E_Client * ec,int button,Evas_Point * output,E_Binding_Event_Mouse_Button * ev)3109 e_client_mouse_up(E_Client *ec, int button, Evas_Point *output, E_Binding_Event_Mouse_Button* ev)
3110 {
3111    EINA_SAFETY_ON_NULL_RETURN(ec);
3112    if (ec->iconic || e_client_util_ignored_get(ec)) return;
3113    if ((button >= 1) && (button <= 3))
3114      {
3115         ec->mouse.last_up[button - 1].mx = output->x;
3116         ec->mouse.last_up[button - 1].my = output->y;
3117         ec->mouse.last_up[button - 1].x = ec->x;
3118         ec->mouse.last_up[button - 1].y = ec->y;
3119      }
3120    ec->mouse.current.mx = output->x;
3121    ec->mouse.current.my = output->y;
3122    /* also we don't pass the same params that went in - then again that */
3123    /* should be ok as we are just ending the action if it has an end */
3124    if (ec->cur_mouse_action)
3125      _e_client_mouse_action_end(ec);
3126    else
3127      {
3128         if (!e_bindings_mouse_up_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(ec), ev))
3129           e_focus_event_mouse_up(ec);
3130      }
3131    if ((button >= 1) && (button <= 3))
3132      {
3133         ec->mouse.last_up[button - 1].mx = output->x;
3134         ec->mouse.last_up[button - 1].my = output->y;
3135         ec->mouse.last_up[button - 1].x = ec->x;
3136         ec->mouse.last_up[button - 1].y = ec->y;
3137      }
3138 
3139    ec->drag.start = 0;
3140 }
3141 
3142 E_API void
e_client_mouse_move(E_Client * ec,Evas_Point * output)3143 e_client_mouse_move(E_Client *ec, Evas_Point *output)
3144 {
3145    EINA_SAFETY_ON_NULL_RETURN(ec);
3146    if (ec->iconic || e_client_util_ignored_get(ec)) return;
3147    if ((ec->mouse.current.mx == output->x) && (ec->mouse.current.my == output->y)) return;
3148    ec->mouse.current.mx = output->x;
3149    ec->mouse.current.my = output->y;
3150    if (ec->moving)
3151      {
3152         int x, y, new_x, new_y;
3153         int new_w, new_h;
3154         Eina_List *skiplist = NULL;
3155 
3156         if (action_handler_key) return;
3157         if ((ec->moveinfo.down.button >= 1) && (ec->moveinfo.down.button <= 3))
3158           {
3159              x = ec->mouse.last_down[ec->moveinfo.down.button - 1].x +
3160                (ec->mouse.current.mx - ec->moveinfo.down.mx);
3161              y = ec->mouse.last_down[ec->moveinfo.down.button - 1].y +
3162                (ec->mouse.current.my - ec->moveinfo.down.my);
3163           }
3164         else
3165           {
3166              x = ec->moveinfo.down.x +
3167                (ec->mouse.current.mx - ec->moveinfo.down.mx);
3168              y = ec->moveinfo.down.y +
3169                (ec->mouse.current.my - ec->moveinfo.down.my);
3170           }
3171         e_comp_object_frame_xy_adjust(ec->frame, x, y, &new_x, &new_y);
3172 
3173         skiplist = eina_list_append(skiplist, ec);
3174         e_resist_client_position(skiplist,
3175                                  ec->x, ec->y, ec->w, ec->h,
3176                                  x, y, ec->w, ec->h,
3177                                  &new_x, &new_y, &new_w, &new_h);
3178         eina_list_free(skiplist);
3179 
3180         if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
3181           _e_client_stay_within_canvas(ec, x, y, &new_x, &new_y);
3182 
3183         ec->shelf_fix.x = 0;
3184         ec->shelf_fix.y = 0;
3185         ec->shelf_fix.modified = 0;
3186         evas_object_move(ec->frame, new_x, new_y);
3187      }
3188    else if (e_client_util_resizing_get(ec))
3189      {
3190         if (action_handler_key) return;
3191         _e_client_resize_handle(ec);
3192      }
3193    else if (ec->drag.start)
3194      {
3195         if ((ec->drag.x == -1) && (ec->drag.y == -1))
3196           {
3197              ec->drag.x = output->x;
3198              ec->drag.y = output->y;
3199           }
3200         else if (ec->zone)
3201           {
3202              int dx, dy;
3203 
3204              dx = ec->drag.x - output->x;
3205              dy = ec->drag.y - output->y;
3206              if (((dx * dx) + (dy * dy)) >
3207                  (e_config->drag_resist * e_config->drag_resist))
3208                {
3209                   /* start drag! */
3210                   if (
3211 #ifndef HAVE_WAYLAND_ONLY
3212                     ec->netwm.icons ||
3213 #endif
3214                     ec->desktop || ec->internal_icon)
3215                     {
3216                        Evas_Object *o = NULL;
3217                        int x, y, w, h;
3218                        const char *drag_types[] = { "enlightenment/border" };
3219 
3220                        REFD(ec, 1);
3221                        e_object_ref(E_OBJECT(ec));
3222                        e_comp_object_frame_icon_geometry_get(ec->frame, &x, &y, &w, &h);
3223 
3224                        client_drag = e_drag_new(output->x, output->y,
3225                                                 drag_types, 1, ec, -1,
3226                                                 NULL,
3227                                                 _e_client_cb_drag_finished);
3228                        client_drag->button_mask = evas_pointer_button_down_mask_get(e_comp->evas);
3229                        e_drag_resize(client_drag, w, h);
3230 
3231                        o = e_client_icon_add(ec, client_drag->evas);
3232                        if (!o)
3233                          {
3234                             /* FIXME: fallback icon for drag */
3235                             o = evas_object_rectangle_add(client_drag->evas);
3236                             evas_object_color_set(o, 255, 255, 255, 255);
3237                          }
3238 
3239                        e_drag_object_set(client_drag, o);
3240                        e_drag_start(client_drag,
3241                                     output->x + (ec->drag.x - x),
3242                                     output->y + (ec->drag.y - y));
3243                     }
3244                   ec->drag.start = 0;
3245                }
3246           }
3247      }
3248 }
3249 ///////////////////////////////////////////////////////
3250 
3251 E_API void
e_client_res_change_geometry_save(E_Client * ec)3252 e_client_res_change_geometry_save(E_Client *ec)
3253 {
3254    E_OBJECT_CHECK(ec);
3255    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3256 
3257    if (ec->pre_res_change.valid) return;
3258    ec->pre_res_change.valid = 1;
3259    ec->pre_res_change.x = ec->x;
3260    ec->pre_res_change.y = ec->y;
3261    ec->pre_res_change.w = ec->w;
3262    ec->pre_res_change.h = ec->h;
3263    ec->pre_res_change.saved.x = ec->saved.x;
3264    ec->pre_res_change.saved.y = ec->saved.y;
3265    ec->pre_res_change.saved.w = ec->saved.w;
3266    ec->pre_res_change.saved.h = ec->saved.h;
3267 }
3268 
3269 E_API void
e_client_res_change_geometry_restore(E_Client * ec)3270 e_client_res_change_geometry_restore(E_Client *ec)
3271 {
3272    struct
3273    {
3274       unsigned char valid E_BITFIELD;
3275       int           x, y, w, h;
3276       struct
3277       {
3278          int x, y, w, h;
3279       } saved;
3280    } pre_res_change;
3281 
3282    E_OBJECT_CHECK(ec);
3283    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3284    if (!ec->pre_res_change.valid) return;
3285    if (ec->new_client) return;
3286    if (!ec->zone) return;
3287 
3288    memcpy(&pre_res_change, &ec->pre_res_change, sizeof(pre_res_change));
3289 
3290    if (ec->fullscreen)
3291      {
3292         if ((eina_list_count(e_comp->zones) > 1) ||
3293             (e_config->fullscreen_policy == E_FULLSCREEN_RESIZE))
3294           evas_object_geometry_set(ec->frame, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h);
3295         else
3296           {
3297              e_client_unfullscreen(ec);
3298              e_client_fullscreen(ec, e_config->fullscreen_policy);
3299           }
3300      }
3301    else if (ec->maximized != E_MAXIMIZE_NONE)
3302      {
3303         int x, y, w, h;
3304 
3305         if (e_client_maximize_geometry_get(ec, ec->maximized, &x, &y, &w, &h))
3306           {
3307              Eina_Bool override = ec->maximize_override;
3308              ec->maximize_override = 1;
3309              evas_object_geometry_set(ec->frame, x, y, w, h);
3310              ec->maximize_override = override;
3311           }
3312         else
3313           {
3314              E_Maximize max = ec->maximized;
3315              e_client_unmaximize(ec, E_MAXIMIZE_BOTH);
3316              e_client_maximize(ec, max);
3317           }
3318      }
3319    else
3320      {
3321         int x, y, w, h, zx, zy, zw, zh;
3322 
3323         ec->saved.x = ec->pre_res_change.saved.x;
3324         ec->saved.y = ec->pre_res_change.saved.y;
3325         ec->saved.w = ec->pre_res_change.saved.w;
3326         ec->saved.h = ec->pre_res_change.saved.h;
3327 
3328         e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
3329 
3330         if (ec->saved.w > zw)
3331           ec->saved.w = zw;
3332         if ((ec->saved.x + ec->saved.w) > (zx + zw))
3333           ec->saved.x = zx + zw - ec->saved.w;
3334 
3335         if (ec->saved.h > zh)
3336           ec->saved.h = zh;
3337         if ((ec->saved.y + ec->saved.h) > (zy + zh))
3338           ec->saved.y = zy + zh - ec->saved.h;
3339 
3340         x = ec->pre_res_change.x;
3341         y = ec->pre_res_change.y;
3342         w = ec->pre_res_change.w;
3343         h = ec->pre_res_change.h;
3344         if (w > zw)
3345           w = zw;
3346         if (h > zh)
3347           h = zh;
3348         if ((x + w) > (zx + zw))
3349           x = zx + zw - w;
3350         if ((y + h) > (zy + zh))
3351           y = zy + zh - h;
3352         evas_object_move(ec->frame, x, y);
3353         if (w && h)
3354           {
3355              e_client_resize_limit(ec, &w, &h);
3356              evas_object_resize(ec->frame, w, h);
3357           }
3358      }
3359    memcpy(&ec->pre_res_change, &pre_res_change, sizeof(pre_res_change));
3360 }
3361 
3362 E_API void
e_client_rescale(E_Client * ec)3363 e_client_rescale(E_Client *ec)
3364 {
3365    Eina_Bool shaded;
3366    int shade_dir;
3367 
3368    if (stopping) return;
3369    E_OBJECT_CHECK(ec);
3370    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3371 
3372    if (e_comp->updating)
3373      {
3374         ec->changes.need_rescale = 1;
3375         EC_CHANGED(ec);
3376         return;
3377      }
3378    ec->changes.need_rescale = 0;
3379 
3380    shaded = ec->shaded;
3381    shade_dir = ec->shade_dir;
3382    if (shaded) e_client_unshade(ec, shade_dir);
3383    ec->pre_res_change.valid = 0;
3384    e_client_res_change_geometry_save(ec);
3385    e_client_res_change_geometry_restore(ec);
3386    if (shaded) e_client_shade(ec, shade_dir);
3387 }
3388 
3389 E_API void
e_client_zone_set(E_Client * ec,E_Zone * zone)3390 e_client_zone_set(E_Client *ec, E_Zone *zone)
3391 {
3392    E_Event_Client_Zone_Set *ev;
3393 
3394    E_OBJECT_CHECK(ec);
3395    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3396    E_OBJECT_CHECK(zone);
3397    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
3398    if (ec->zone == zone) return;
3399 
3400    /* if the window does not lie in the new zone, move it so that it does */
3401    if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h, zone->x, zone->y, zone->w, zone->h))
3402      {
3403         int x, y;
3404 
3405         if (ec->zone)
3406           {
3407              /* first guess -- get offset from old zone, and apply to new zone */
3408              x = zone->x + (ec->x - ec->zone->x);
3409              y = zone->y + (ec->y - ec->zone->y);
3410           }
3411         else
3412           x = ec->x, y = ec->y;
3413 
3414         /* keep window from hanging off bottom and left */
3415         if (x + ec->w > zone->x + zone->w) x += (zone->x + zone->w) - (x + ec->w);
3416         if (y + ec->h > zone->y + zone->h) y += (zone->y + zone->h) - (y + ec->h);
3417 
3418         /* make sure to and left are on screen (if the window is larger than the zone, it will hang off the bottom / right) */
3419         if (x < zone->x) x = zone->x;
3420         if (y < zone->y) y = zone->y;
3421 
3422         if (!E_INTERSECTS(x, y, ec->w, ec->h, zone->x, zone->y, zone->w, zone->h))
3423           {
3424              /* still not in zone at all, so just move it to closest edge */
3425              if (x < zone->x) x = zone->x;
3426              if (x >= zone->x + zone->w) x = zone->x + zone->w - ec->w;
3427              if (y < zone->y) y = zone->y;
3428              if (y >= zone->y + zone->h) y = zone->y + zone->h - ec->h;
3429           }
3430         evas_object_move(ec->frame, x, y);
3431      }
3432 
3433    ec->zone = zone;
3434 
3435    if ((!ec->desk) || (ec->desk->zone != ec->zone))
3436      e_client_desk_set(ec, e_desk_current_get(ec->zone));
3437 
3438    ev = E_NEW(E_Event_Client_Zone_Set, 1);
3439    ev->ec = ec;
3440    REFD(ec, 5);
3441    e_object_ref(E_OBJECT(ec));
3442    ev->zone = zone;
3443    e_object_ref(E_OBJECT(zone));
3444 
3445    ecore_event_add(E_EVENT_CLIENT_ZONE_SET, ev, (Ecore_End_Cb)_e_client_event_zone_set_free, NULL);
3446 
3447    e_remember_update(ec);
3448    if (ec->maximized || ec->fullscreen)
3449      e_client_rescale(ec);
3450 }
3451 
3452 E_API void
e_client_geometry_get(E_Client * ec,int * x,int * y,int * w,int * h)3453 e_client_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h)
3454 {
3455    E_OBJECT_CHECK(ec);
3456    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3457 
3458    if (ec->frame)
3459      evas_object_geometry_get(ec->frame, x, y, w, h);
3460    else
3461      {
3462         if (x) *x = ec->x;
3463         if (y) *y = ec->y;
3464         if (w) *w = ec->w;
3465         if (h) *h = ec->h;
3466      }
3467 }
3468 
3469 E_API E_Client *
e_client_above_get(const E_Client * ec)3470 e_client_above_get(const E_Client *ec)
3471 {
3472    unsigned int x;
3473    E_Client *ec2;
3474 
3475    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
3476    if (EINA_INLIST_GET(ec)->next) //check current layer
3477      {
3478         EINA_INLIST_FOREACH(EINA_INLIST_GET(ec)->next, ec2)
3479           if (!e_object_is_del(E_OBJECT(ec2)))
3480             return ec2;
3481      }
3482    if (ec->layer == E_LAYER_CLIENT_PRIO) return NULL;
3483    if (e_comp_canvas_client_layer_map(ec->layer) == 9999) return NULL;
3484 
3485    /* go up the layers until we find one */
3486    for (x = e_comp_canvas_layer_map(ec->layer) + 1; x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); x++)
3487      {
3488         if (!e_comp->layers[x].clients) continue;
3489         EINA_INLIST_FOREACH(e_comp->layers[x].clients, ec2)
3490           if (!e_object_is_del(E_OBJECT(ec2)))
3491             return ec2;
3492      }
3493    return NULL;
3494 }
3495 
3496 E_API E_Client *
e_client_below_get(const E_Client * ec)3497 e_client_below_get(const E_Client *ec)
3498 {
3499    unsigned int x;
3500    E_Client *ec2;
3501    Eina_Inlist *l;
3502 
3503    E_OBJECT_CHECK_RETURN(ec, NULL);
3504    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
3505 
3506    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
3507    if (EINA_INLIST_GET(ec)->prev) //check current layer
3508      {
3509         for (l = EINA_INLIST_GET(ec)->prev; l; l = l->prev)
3510           {
3511              ec2 = EINA_INLIST_CONTAINER_GET(l, E_Client);;
3512              if (!e_object_is_del(E_OBJECT(ec2)))
3513                return ec2;
3514           }
3515      }
3516    if (ec->layer == E_LAYER_CLIENT_DESKTOP) return NULL;
3517    if (e_comp_canvas_client_layer_map(ec->layer) == 9999) return NULL;
3518 
3519    /* go down the layers until we find one */
3520    x = e_comp_canvas_layer_map(ec->layer);
3521    if (x > 0) x--;
3522 
3523    for (; x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
3524      {
3525         if (!e_comp->layers[x].clients) continue;
3526         EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2)
3527           if (!e_object_is_del(E_OBJECT(ec2)))
3528             return ec2;
3529      }
3530    return NULL;
3531 }
3532 
3533 E_API E_Client *
e_client_bottom_get(void)3534 e_client_bottom_get(void)
3535 {
3536    unsigned int x;
3537 
3538    for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x <= e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); x++)
3539      {
3540         E_Client *ec2;
3541 
3542         if (!e_comp->layers[x].clients) continue;
3543         EINA_INLIST_FOREACH(e_comp->layers[x].clients, ec2)
3544           if (!e_object_is_del(E_OBJECT(ec2)))
3545             return ec2;
3546      }
3547    return NULL;
3548 }
3549 
3550 E_API E_Client *
e_client_top_get(void)3551 e_client_top_get(void)
3552 {
3553    unsigned int x;
3554 
3555    for (x = e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); x >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); x--)
3556      {
3557         E_Client *ec2;
3558 
3559         if (!e_comp->layers[x].clients) continue;
3560         EINA_INLIST_REVERSE_FOREACH(e_comp->layers[x].clients, ec2)
3561           if (!e_object_is_del(E_OBJECT(ec2)))
3562             return ec2;
3563      }
3564    return NULL;
3565 }
3566 
3567 E_API unsigned int
e_clients_count(void)3568 e_clients_count(void)
3569 {
3570    return eina_list_count(e_comp->clients);
3571 }
3572 
3573 
3574 /**
3575  * Set a callback which will be called just prior to updating the
3576  * move coordinates for a border
3577  */
3578 E_API void
e_client_move_intercept_cb_set(E_Client * ec,E_Client_Move_Intercept_Cb cb)3579 e_client_move_intercept_cb_set(E_Client *ec, E_Client_Move_Intercept_Cb cb)
3580 {
3581    ec->move_intercept_cb = cb;
3582 }
3583 
3584 ///////////////////////////////////////
3585 
3586 E_API E_Client_Hook *
e_client_hook_add(E_Client_Hook_Point hookpoint,E_Client_Hook_Cb func,const void * data)3587 e_client_hook_add(E_Client_Hook_Point hookpoint, E_Client_Hook_Cb func, const void *data)
3588 {
3589    E_Client_Hook *ch;
3590 
3591    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_CLIENT_HOOK_LAST, NULL);
3592    ch = E_NEW(E_Client_Hook, 1);
3593    if (!ch) return NULL;
3594    ch->hookpoint = hookpoint;
3595    ch->func = func;
3596    ch->data = (void*)data;
3597    _e_client_hooks[hookpoint] = eina_inlist_append(_e_client_hooks[hookpoint], EINA_INLIST_GET(ch));
3598    return ch;
3599 }
3600 
3601 E_API void
e_client_hook_del(E_Client_Hook * ch)3602 e_client_hook_del(E_Client_Hook *ch)
3603 {
3604    ch->delete_me = 1;
3605    if (_e_client_hooks_walking == 0)
3606      {
3607         _e_client_hooks[ch->hookpoint] = eina_inlist_remove(_e_client_hooks[ch->hookpoint], EINA_INLIST_GET(ch));
3608         free(ch);
3609      }
3610    else
3611      _e_client_hooks_delete++;
3612 }
3613 
3614 ///////////////////////////////////////
3615 
3616 E_API void
e_client_focus_latest_set(E_Client * ec)3617 e_client_focus_latest_set(E_Client *ec)
3618 {
3619    if (!ec) CRI("ACK");
3620    if (focus_track_frozen > 0) return;
3621    focus_stack = eina_list_remove(focus_stack, ec);
3622    focus_stack = eina_list_prepend(focus_stack, ec);
3623 }
3624 
3625 E_API void
e_client_raise_latest_set(E_Client * ec)3626 e_client_raise_latest_set(E_Client *ec)
3627 {
3628    if (!ec) CRI("ACK");
3629    raise_stack = eina_list_remove(raise_stack, ec);
3630    raise_stack = eina_list_prepend(raise_stack, ec);
3631 }
3632 
3633 E_API Eina_Bool
e_client_focus_track_enabled(void)3634 e_client_focus_track_enabled(void)
3635 {
3636    return !focus_track_frozen;
3637 }
3638 
3639 E_API void
e_client_focus_track_freeze(void)3640 e_client_focus_track_freeze(void)
3641 {
3642    focus_track_frozen++;
3643 }
3644 
3645 E_API void
e_client_focus_track_thaw(void)3646 e_client_focus_track_thaw(void)
3647 {
3648    if (focus_track_frozen)
3649      focus_track_frozen--;
3650 }
3651 
3652 E_API void
e_client_refocus(void)3653 e_client_refocus(void)
3654 {
3655    E_Client *ec;
3656    const Eina_List *l;
3657 
3658    EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec)
3659      if (ec->desk && ec->desk->visible && (!ec->iconic))
3660        {
3661           if (e_comp->input_key_grabs || e_comp->input_mouse_grabs) break;
3662           evas_object_focus_set(ec->frame, 1);
3663           break;
3664        }
3665 }
3666 
3667 
3668 /*
3669  * Sets the focus to the given client if necessary
3670  * There are 3 cases of different focus_policy-configurations:
3671  *
3672  * - E_FOCUS_CLICK: just set the focus, the most simple one
3673  *
3674  * - E_FOCUS_MOUSE: focus is where the mouse is, so try to
3675  *   warp the pointer to the window. If this fails (because
3676  *   the pointer is already in the window), just set the focus.
3677  *
3678  * - E_FOCUS_SLOPPY: focus is where the mouse is or on the
3679  *   last window which was focused, if the mouse is on the
3680  *   desktop. So, we need to look if there is another window
3681  *   under the pointer and warp to pointer to the right
3682  *   one if so (also, we set the focus afterwards). In case
3683  *   there is no window under pointer, the pointer is on the
3684  *   desktop and so we just set the focus.
3685  *
3686  *
3687  * This function is to be called when setting the focus was not
3688  * explicitly triggered by the user (by moving the mouse or
3689  * clicking for example), but implicitly (by closing a window,
3690  * the last focused window should get focus).
3691  *
3692  */
3693 E_API void
e_client_focus_set_with_pointer(E_Client * ec)3694 e_client_focus_set_with_pointer(E_Client *ec)
3695 {
3696    E_OBJECT_CHECK(ec);
3697    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3698    /* note: this is here as it seems there are enough apps that do not even
3699     * expect us to emulate a look of focus but not actually set x input
3700     * focus as we do - so simply abort any focuse set on such windows */
3701    if (e_pixmap_is_x(ec->pixmap))
3702      {
3703         /* be strict about accepting focus hint */
3704         if ((!ec->icccm.accepts_focus) &&
3705             (!ec->icccm.take_focus)) return;
3706      }
3707    ec = e_client_stack_active_adjust(ec);
3708    if (ec->lock_focus_out) return;
3709    if (ec == focused) return;
3710    evas_object_focus_set(ec->frame, 1);
3711 
3712    if (e_config->focus_policy == E_FOCUS_CLICK) return;
3713    if (!ec->visible) return;
3714 
3715    if (e_config->focus_policy == E_FOCUS_SLOPPY)
3716      {
3717         E_Client *pec;
3718         pec = e_client_under_pointer_get(ec->desk, ec);
3719         /* Do not slide pointer when disabled (probably breaks focus
3720          * on sloppy/mouse focus but requested by users). */
3721         if (e_config->pointer_slide && pec && (pec != ec))
3722           e_client_pointer_warp_to_center(ec);
3723      }
3724    else
3725      {
3726         if (e_config->pointer_slide)
3727           e_client_pointer_warp_to_center(ec);
3728      }
3729 }
3730 
3731 static Eina_Bool
_e_client_is_in_parents(E_Client * ec,E_Client * ec_find)3732 _e_client_is_in_parents(E_Client *ec, E_Client *ec_find)
3733 {
3734    if (ec == ec_find) return EINA_TRUE;
3735    if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
3736    if (ec->parent) return _e_client_is_in_parents(ec->parent, ec_find);
3737    return EINA_FALSE;
3738 }
3739 
3740 EINTERN void
e_client_focused_set(E_Client * ec)3741 e_client_focused_set(E_Client *ec)
3742 {
3743    E_Client *ec2, *ec_unfocus = focused;
3744    Eina_List *l, *ll;
3745 
3746    if (ec == focused) return;
3747    focused = ec;
3748    if ((ec) && (ec->zone))
3749      {
3750         ec->focused = 1;
3751         e_client_urgent_set(ec, 0);
3752         if (!e_config->allow_above_fullscreen)
3753           {
3754              int x, total = ec->zone->desk_x_count * ec->zone->desk_y_count;
3755 
3756              for (x = 0; x < total; x++)
3757                {
3758                   E_Desk *desk = ec->zone->desks[x];
3759                   /* if there's any fullscreen non-parents on this desk, unfullscreen them */
3760                   EINA_LIST_FOREACH_SAFE(desk->fullscreen_clients, l, ll, ec2)
3761                     {
3762                        if (ec2 == ec) continue;
3763                        if (e_object_is_del(E_OBJECT(ec2))) continue;
3764                        /* but only if it's the same desk or one of the clients is sticky */
3765                        if ((desk == ec->desk) || (ec->sticky || ec2->sticky))
3766                          {
3767                             if (!_e_client_is_in_parents(ec, ec2))
3768                               e_client_unfullscreen(ec2);
3769                          }
3770                     }
3771                }
3772           }
3773      }
3774 
3775    while ((ec_unfocus) && (ec_unfocus->zone))
3776      {
3777         Eina_Bool is_popup, is_child;
3778 
3779         ec_unfocus->want_focus = ec_unfocus->focused = 0;
3780         if (!e_object_is_del(E_OBJECT(ec_unfocus)))
3781           e_focus_event_focus_out(ec_unfocus);
3782         if (ec_unfocus->mouse.in && ec && (!e_client_util_is_popup(ec)) &&
3783             (e_config->focus_policy != E_FOCUS_CLICK) && e_config->pointer_slide)
3784           e_client_mouse_out(ec_unfocus, ec_unfocus->x - 1, ec_unfocus->y - 1);
3785 
3786         E_FREE_FUNC(ec_unfocus->raise_timer, ecore_timer_del);
3787 
3788         is_popup = EINA_FALSE;
3789         is_child = EINA_FALSE;
3790         if ((ec) &&
3791             ((ec->netwm.type == E_WINDOW_TYPE_MENU) ||
3792              (ec->netwm.type == E_WINDOW_TYPE_TOOLBAR) ||
3793              (ec->netwm.type == E_WINDOW_TYPE_DOCK) ||
3794              (ec->netwm.type == E_WINDOW_TYPE_SPLASH) ||
3795              (ec->netwm.type == E_WINDOW_TYPE_TOOLTIP) ||
3796              (ec->netwm.type == E_WINDOW_TYPE_DROPDOWN_MENU) ||
3797              (ec->netwm.type == E_WINDOW_TYPE_POPUP_MENU) ||
3798              (ec->netwm.type == E_WINDOW_TYPE_COMBO) ||
3799              (ec->netwm.type == E_WINDOW_TYPE_DND) ||
3800              (ec->netwm.type == E_WINDOW_TYPE_NOTIFICATION)))
3801           is_popup = EINA_TRUE;
3802         if ((ec) && _e_client_is_in_parents(ec, ec_unfocus))
3803           is_child = EINA_TRUE;
3804 
3805         /* if there unfocus client is fullscreen and visible */
3806         if ((!is_popup) && (!is_child) &&
3807             (!e_config->allow_above_fullscreen) &&
3808             (ec_unfocus->fullscreen) && (!ec_unfocus->iconic) && (!ec_unfocus->hidden) &&
3809             (ec_unfocus->zone == e_zone_current_get()) &&
3810             ((ec_unfocus->desk == e_desk_current_get(ec_unfocus->zone)) || (ec_unfocus->sticky)))
3811           {
3812              Eina_Bool have_vis_child = EINA_FALSE;
3813 
3814              /* if any of its children are visible */
3815              EINA_LIST_FOREACH(ec_unfocus->transients, l, ec2)
3816                {
3817                   if ((ec2->zone == ec_unfocus->zone) &&
3818                       ((ec2->desk == ec_unfocus->desk) ||
3819                        (ec2->sticky) || (ec_unfocus->sticky)))
3820                     {
3821                        have_vis_child = EINA_TRUE;
3822                        break;
3823                     }
3824                }
3825              /* if no children are visible, unfullscreen */
3826              if ((!e_object_is_del(E_OBJECT(ec_unfocus))) && (!have_vis_child))
3827                e_client_unfullscreen(ec_unfocus);
3828           }
3829 
3830         _e_client_hook_call(E_CLIENT_HOOK_FOCUS_UNSET, ec_unfocus);
3831         /* only send event here if we're not being deleted */
3832         if ((!e_object_is_del(E_OBJECT(ec_unfocus))) &&
3833            (e_object_ref_get(E_OBJECT(ec_unfocus)) > 0))
3834           {
3835              _e_client_event_simple(ec_unfocus, E_EVENT_CLIENT_FOCUS_OUT);
3836              e_client_urgent_set(ec_unfocus, ec_unfocus->icccm.urgent);
3837           }
3838         break;
3839      }
3840    if (!ec) return;
3841 
3842    _e_client_hook_call(E_CLIENT_HOOK_FOCUS_SET, ec);
3843    e_focus_event_focus_in(ec);
3844 
3845    if (!focus_track_frozen)
3846      e_client_focus_latest_set(ec);
3847 
3848    e_hints_active_window_set(ec);
3849    _e_client_event_simple(ec, E_EVENT_CLIENT_FOCUS_IN);
3850    if (ec->sticky && ec->desk && (!ec->desk->visible))
3851      e_client_desk_set(ec, e_desk_current_get(ec->zone));
3852 }
3853 
3854 E_API void
e_client_activate(E_Client * ec,Eina_Bool just_do_it)3855 e_client_activate(E_Client *ec, Eina_Bool just_do_it)
3856 {
3857    E_OBJECT_CHECK(ec);
3858    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3859    ec = e_client_stack_active_adjust(ec);
3860    if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) ||
3861        ((ec->parent) &&
3862         ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) ||
3863          ((ec->parent->focused) &&
3864           (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))) ||
3865        (just_do_it))
3866      {
3867         if (ec->iconic)
3868           {
3869              if (e_config->clientlist_warp_to_iconified_desktop == 1)
3870                e_desk_show(ec->desk);
3871 
3872              if (!ec->lock_user_iconify)
3873                e_client_uniconify(ec);
3874           }
3875         if ((!ec->iconic) && ((!ec->sticky) || e_config->focus_revert_allow_sticky))
3876           {
3877              int val = e_config->focus_last_focused_per_desktop;
3878 
3879              /* prevent infinite focus loops during refocus */
3880              if (!ec->lock_focus_out)
3881                e_config->focus_last_focused_per_desktop = 0;
3882              e_desk_show(ec->desk);
3883              e_config->focus_last_focused_per_desktop = val;
3884           }
3885         if (!ec->lock_user_stacking)
3886           evas_object_raise(ec->frame);
3887         if (ec->shaded || ec->shading)
3888           e_client_unshade(ec, ec->shade_dir);
3889         if (!ec->lock_focus_out)
3890           {
3891              /* XXX ooffice does send this request for
3892                 config dialogs when the main window gets focus.
3893                 causing the pointer to jump back and forth.  */
3894              if ((e_config->focus_policy != E_FOCUS_CLICK) && (!ec->new_client) &&
3895                  (!e_config->disable_all_pointer_warps) &&
3896                  (!e_util_strcmp(ec->icccm.name, "VCLSalFrame")))
3897                ecore_evas_pointer_warp(e_comp->ee,
3898                                     ec->x + (ec->w / 2), ec->y + (ec->h / 2));
3899              evas_object_focus_set(ec->frame, 1);
3900           }
3901      }
3902 }
3903 
3904 E_API E_Client *
e_client_focused_get(void)3905 e_client_focused_get(void)
3906 {
3907    return focused;
3908 }
3909 
3910 E_API Eina_List *
e_client_focus_stack_get(void)3911 e_client_focus_stack_get(void)
3912 {
3913    return focus_stack;
3914 }
3915 
3916 YOLO E_API void
e_client_focus_stack_set(Eina_List * l)3917 e_client_focus_stack_set(Eina_List *l)
3918 {
3919    focus_stack = l;
3920 }
3921 
3922 E_API Eina_List *
e_client_raise_stack_get(void)3923 e_client_raise_stack_get(void)
3924 {
3925    return raise_stack;
3926 }
3927 
3928 E_API Eina_List *
e_client_lost_windows_get(E_Zone * zone)3929 e_client_lost_windows_get(E_Zone *zone)
3930 {
3931    Eina_List *list = NULL;
3932    const Eina_List *l;
3933    E_Client *ec;
3934    int loss_overlap = 5;
3935 
3936    E_OBJECT_CHECK_RETURN(zone, NULL);
3937    E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, NULL);
3938    EINA_LIST_FOREACH(e_comp->clients, l, ec)
3939      {
3940         if (ec->zone != zone) continue;
3941         if (e_client_util_ignored_get(ec)) continue;
3942 
3943         if (!E_INTERSECTS(ec->zone->x + loss_overlap,
3944                           ec->zone->y + loss_overlap,
3945                           ec->zone->w - (2 * loss_overlap),
3946                           ec->zone->h - (2 * loss_overlap),
3947                           ec->x, ec->y, ec->w, ec->h))
3948           {
3949              list = eina_list_append(list, ec);
3950           }
3951      }
3952    return list;
3953 }
3954 
3955 ///////////////////////////////////////
3956 
3957 E_API void
e_client_shade(E_Client * ec,E_Direction dir)3958 e_client_shade(E_Client *ec, E_Direction dir)
3959 {
3960    E_OBJECT_CHECK(ec);
3961    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3962    if (((!ec->shaded) && ec->shading) || (ec->shaded && (!ec->shading)) || (ec->fullscreen) ||
3963        ((ec->maximized) && (!e_config->allow_manip))) return;
3964    if (!e_util_strcmp("borderless", ec->bordername)) return;
3965    if (!e_comp_object_frame_allowed(ec->frame)) return;
3966 
3967    e_hints_window_shaded_set(ec, 1);
3968    e_hints_window_shade_direction_set(ec, dir);
3969    ec->take_focus = 0;
3970    ec->shading = 1;
3971    ec->shade_dir = dir;
3972 
3973    if (e_config->border_shade_animate && (!ec->new_client))
3974      {
3975         ec->changes.shading = 1;
3976         EC_CHANGED(ec);
3977 
3978         evas_object_smart_callback_call(ec->frame, "shading", (uintptr_t*)dir);
3979      }
3980    else
3981      evas_object_smart_callback_call(ec->frame, "shaded", (uintptr_t*)dir);
3982 
3983    e_remember_update(ec);
3984 }
3985 
3986 E_API void
e_client_unshade(E_Client * ec,E_Direction dir)3987 e_client_unshade(E_Client *ec, E_Direction dir)
3988 {
3989    E_OBJECT_CHECK(ec);
3990    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
3991    if ((!ec->shaded) || (ec->shading))
3992      return;
3993 
3994    e_hints_window_shaded_set(ec, 0);
3995    e_hints_window_shade_direction_set(ec, dir);
3996    ec->shading = 1;
3997    ec->shade_dir = 0;
3998 
3999    if (e_config->border_shade_animate)
4000      {
4001         ec->changes.shading = 1;
4002         EC_CHANGED(ec);
4003 
4004         evas_object_smart_callback_call(ec->frame, "unshading", (uintptr_t*)dir);
4005      }
4006    else
4007      evas_object_smart_callback_call(ec->frame, "unshaded", (uintptr_t*)dir);
4008 
4009    e_remember_update(ec);
4010 }
4011 
4012 ///////////////////////////////////////
4013 
4014 E_API Eina_Bool
e_client_maximize_geometry_get(const E_Client * ec,E_Maximize max,int * mx,int * my,int * mw,int * mh)4015 e_client_maximize_geometry_get(const E_Client *ec, E_Maximize max, int *mx, int *my, int *mw, int *mh)
4016 {
4017    int x1, yy1, x2, y2;
4018    int x = 0, y = 0, w, h, pw, ph;
4019    int zx, zy, zw, zh;
4020    int ecx, ecy, ecw, ech;
4021 
4022    if (e_client_util_ignored_get(ec)) return EINA_FALSE;
4023    zx = zy = zw = zh = 0;
4024 
4025    switch (max & E_MAXIMIZE_TYPE)
4026      {
4027       case E_MAXIMIZE_FULLSCREEN:
4028         w = ec->zone->w;
4029         h = ec->zone->h;
4030 
4031         e_client_resize_limit(ec, &w, &h);
4032         /* center x-direction */
4033         x1 = ec->zone->x + (ec->zone->w - w) / 2;
4034         /* center y-direction */
4035         yy1 = ec->zone->y + (ec->zone->h - h) / 2;
4036 
4037         switch (max & E_MAXIMIZE_DIRECTION)
4038           {
4039            case E_MAXIMIZE_BOTH:
4040              x = x1, y = yy1;
4041              break;
4042 
4043            case E_MAXIMIZE_VERTICAL:
4044              x = ec->x, y = yy1, w = ec->w;
4045              break;
4046 
4047            case E_MAXIMIZE_HORIZONTAL:
4048              x = x1, y = ec->y, h = ec->h;
4049              break;
4050 
4051            case E_MAXIMIZE_LEFT:
4052              x = ec->zone->x, y = ec->zone->y, w /= 2;
4053              break;
4054 
4055            case E_MAXIMIZE_RIGHT:
4056              x = x1, y = ec->zone->y, w /= 2;
4057              break;
4058           }
4059         if (mx) *mx = x;
4060         if (my) *my = y;
4061         if (mw) *mw = w;
4062         if (mh) *mh = h;
4063         break;
4064 
4065       case E_MAXIMIZE_SMART:
4066       case E_MAXIMIZE_EXPAND:
4067         e_zone_desk_useful_geometry_get(ec->zone, ec->desk, &zx, &zy, &zw, &zh);
4068         w = zw, h = zh;
4069 
4070         e_comp_object_frame_xy_unadjust(ec->frame, ec->x, ec->y, &ecx, &ecy);
4071         e_comp_object_frame_wh_unadjust(ec->frame, ec->w, ec->h, &ecw, &ech);
4072 
4073         if (ecw < zw)
4074           w = ecw;
4075 
4076         if (ech < zh)
4077           h = ech;
4078 
4079         if (ecx < zx) // window left not useful coordinates
4080           x1 = zx;
4081         else if (ecx + ecw > zx + zw) // window right not useful coordinates
4082           x1 = zx + zw - ecw;
4083         else // window normal position
4084           x1 = ecx;
4085 
4086         if (ecy < zy) // window top not useful coordinates
4087           yy1 = zy;
4088         else if (ecy + ech > zy + zh) // window bottom not useful coordinates
4089           yy1 = zy + zh - ech;
4090         else // window normal position
4091           yy1 = ecy;
4092 
4093         switch (max & E_MAXIMIZE_DIRECTION)
4094           {
4095            case E_MAXIMIZE_BOTH:
4096              x = zx, y = zy, w = zw, h = zh;
4097              break;
4098 
4099            case E_MAXIMIZE_VERTICAL:
4100              x = ec->x, y = zy, w = ec->w, h = zh;
4101              break;
4102 
4103            case E_MAXIMIZE_HORIZONTAL:
4104              x = zx, y = ec->y, w = zw, h = ec->h;
4105              break;
4106 
4107            case E_MAXIMIZE_LEFT:
4108              x = zx, y = zy, w = zw / 2, h = zh;
4109              break;
4110 
4111            case E_MAXIMIZE_RIGHT:
4112              x = zx + zw / 2, y = zy, w = zw / 2, h = zh;
4113              break;
4114           }
4115         break;
4116 
4117       case E_MAXIMIZE_FILL:
4118         x1 = ec->zone->x;
4119         yy1 = ec->zone->y;
4120         x2 = ec->zone->x + ec->zone->w;
4121         y2 = ec->zone->y + ec->zone->h;
4122 
4123         e_zone_desk_useful_geometry_get(ec->zone, ec->desk, &zx, &zy, &zw, &zh);
4124         x1 = zx, yy1 = zy, x2 = x1 + zw, y2 = yy1 + zh;
4125 
4126         w = x2 - x1;
4127         h = y2 - yy1;
4128         pw = w;
4129         ph = h;
4130         e_client_resize_limit(ec, &w, &h);
4131         /* center x-direction */
4132         x1 = x1 + (pw - w) / 2;
4133         /* center y-direction */
4134         yy1 = yy1 + (ph - h) / 2;
4135 
4136         switch (max & E_MAXIMIZE_DIRECTION)
4137           {
4138            case E_MAXIMIZE_BOTH:
4139              x = x1, y = yy1;
4140              break;
4141 
4142            case E_MAXIMIZE_VERTICAL:
4143              x = ec->x, y = yy1, w = ec->w;
4144              break;
4145 
4146            case E_MAXIMIZE_HORIZONTAL:
4147              x = x1, y = ec->y, h = ec->h;
4148              break;
4149 
4150            case E_MAXIMIZE_LEFT:
4151              x = ec->zone->x, y = ec->zone->y, w /= 2;
4152              break;
4153 
4154            case E_MAXIMIZE_RIGHT:
4155              x = x1, y = ec->zone->y, w /= 2;
4156              break;
4157           }
4158         break;
4159       default:
4160         return EINA_FALSE;
4161      }
4162    if (mx) *mx = x;
4163    if (my) *my = y;
4164    if (mw) *mw = w;
4165    if (mh) *mh = h;
4166    return EINA_TRUE;
4167 }
4168 
4169 E_API void
e_client_maximize(E_Client * ec,E_Maximize max)4170 e_client_maximize(E_Client *ec, E_Maximize max)
4171 {
4172    Eina_Bool override;
4173    E_OBJECT_CHECK(ec);
4174    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4175 
4176    if (!ec->zone) return;
4177    if (ec->maximized == max) return;
4178    if (!(max & E_MAXIMIZE_DIRECTION)) max |= E_MAXIMIZE_BOTH;
4179 
4180    if ((ec->shaded) || (ec->shading)) return;
4181 
4182    /* Only allow changes in vertical/ horizontal maximization */
4183    if (((ec->maximized & E_MAXIMIZE_DIRECTION) == (max & E_MAXIMIZE_DIRECTION)) ||
4184        ((ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_BOTH)) return;
4185    if (ec->new_client)
4186      {
4187         ec->changes.need_maximize = 1;
4188         ec->maximized &= ~E_MAXIMIZE_TYPE;
4189         ec->maximized |= max;
4190         EC_CHANGED(ec);
4191         if (ec->re_manage) ec->changes.pos = 0;
4192         return;
4193      }
4194    if ((max & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)
4195      evas_object_smart_callback_call(ec->frame, "fullscreen", NULL);
4196    else
4197      evas_object_smart_callback_call(ec->frame, "maximize", NULL);
4198    evas_object_smart_callback_call(ec->frame, "maximize_pre", &max);
4199    if (!max) return;
4200    if (ec->moving)
4201      {
4202         if (ec == action_client)
4203           e_comp_canvas_feed_mouse_up(0); //triggers event grabber cb
4204      }
4205    override = ec->maximize_override;
4206    if (ec->fullscreen)
4207      e_client_unfullscreen(ec);
4208    ec->pre_res_change.valid = 0;
4209    if (!ec->saved.set)
4210      {
4211         if (!(ec->maximized & E_MAXIMIZE_HORIZONTAL))
4212           {
4213              /* Horizontal hasn't been set */
4214              if (ec->changes.pos)
4215                e_comp_object_frame_xy_adjust(ec->frame, ec->x, 0, &ec->saved.x, NULL);
4216              else
4217                ec->saved.x = ec->client.x;
4218              ec->saved.x -= ec->zone->x;
4219              if (ec->visible)
4220                ec->saved.w = ec->client.w;
4221           }
4222         if (!(ec->maximized & E_MAXIMIZE_VERTICAL))
4223           {
4224              /* Vertical hasn't been set */
4225              if (ec->changes.pos)
4226                e_comp_object_frame_xy_adjust(ec->frame, 0, ec->y, NULL, &ec->saved.y);
4227              else
4228                ec->saved.y = ec->client.y;
4229              ec->saved.y -= ec->zone->y;
4230              if (ec->visible)
4231                ec->saved.h = ec->client.h;
4232           }
4233         ec->saved.zone = ec->zone->num;
4234         ec->saved.frame = e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame));
4235      }
4236 
4237    ec->maximize_override = 1;
4238 
4239    {
4240       int x, y, w, h;
4241       e_client_maximize_geometry_get(ec, max, &x, &y, &w, &h);
4242       if (!_e_client_maximize_run(ec, x, y, w, h))
4243         ec->maximize_override = override;
4244    }
4245 
4246    /* Remove previous type */
4247    ec->maximized &= ~E_MAXIMIZE_TYPE;
4248    /* Add new maximization. It must be added, so that VERTICAL + HORIZONTAL == BOTH */
4249    ec->maximized |= max;
4250    ec->changes.need_unmaximize = 0;
4251 
4252    if ((ec->maximized & E_MAXIMIZE_DIRECTION) > E_MAXIMIZE_BOTH)
4253      /* left/right maximize */
4254      e_hints_window_maximized_set(ec, 0,
4255                                   ((ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_LEFT) ||
4256                                   ((ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_RIGHT));
4257    else
4258      e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL,
4259                                   ec->maximized & E_MAXIMIZE_VERTICAL);
4260    e_remember_update(ec);
4261    evas_object_smart_callback_call(ec->frame, "maximize_done", NULL);
4262 }
4263 
4264 E_API Eina_Bool
e_client_unmaximize_geometry_get(const E_Client * ec,E_Maximize max,int * mx,int * my,int * mw,int * mh)4265 e_client_unmaximize_geometry_get(const E_Client *ec, E_Maximize max, int *mx, int *my, int *mw, int *mh)
4266 {
4267    int w, h, x, y;
4268 
4269    if (e_client_util_ignored_get(ec)) return EINA_FALSE;
4270    if (!(ec->maximized & E_MAXIMIZE_TYPE)) return EINA_FALSE;
4271    if ((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)
4272      {
4273         if (mx) *mx = ec->saved.x + ec->zone->x;
4274         if (my) *my = ec->saved.y + ec->zone->y;
4275         if (mw) *mw = ec->saved.w;
4276         if (mh) *mh = ec->saved.h;
4277         return EINA_TRUE;
4278      }
4279 
4280    w = ec->client.w;
4281    h = ec->client.h;
4282    x = ec->client.x;
4283    y = ec->client.y;
4284    max &= (ec->maximized & E_MAXIMIZE_DIRECTION);
4285 
4286    if (max & E_MAXIMIZE_VERTICAL)
4287      {
4288         /* Remove vertical */
4289         h = ec->saved.h;
4290         y = ec->saved.y + ec->zone->y;
4291      }
4292    if (max & E_MAXIMIZE_HORIZONTAL)
4293      {
4294         /* Remove horizontal */
4295         w = ec->saved.w;
4296         x = ec->saved.x + ec->zone->x;
4297      }
4298    if (mx) *mx = x;
4299    if (my) *my = y;
4300    if (mw) *mw = w;
4301    if (mh) *mh = h;
4302    return EINA_TRUE;
4303 }
4304 
4305 E_API void
e_client_unmaximize(E_Client * ec,E_Maximize max)4306 e_client_unmaximize(E_Client *ec, E_Maximize max)
4307 {
4308    E_Maximize unmax = max;
4309    E_OBJECT_CHECK(ec);
4310    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4311    if (!ec->zone) return;
4312    if (!(max & E_MAXIMIZE_DIRECTION))
4313      {
4314         CRI("BUG: Unmaximize call without direction!");
4315         return;
4316      }
4317    if (ec->new_client)
4318      {
4319         ec->changes.need_unmaximize = 1;
4320         EC_CHANGED(ec);
4321         return;
4322      }
4323 
4324    if ((ec->shaded) || (ec->shading)) return;
4325 
4326    /* Remove directions not used */
4327    unmax &= (ec->maximized & E_MAXIMIZE_DIRECTION);
4328    evas_object_smart_callback_call(ec->frame, "unmaximize_pre", &unmax);
4329    /* Can only remove existing maximization directions */
4330    if ((!unmax) && (!ec->need_fullscreen)) return;
4331    if (!unmax) unmax = max & (ec->maximized & E_MAXIMIZE_DIRECTION);
4332    if (ec->maximized & E_MAXIMIZE_TYPE)
4333      {
4334         ec->pre_res_change.valid = 0;
4335         ec->changes.need_maximize = 0;
4336 
4337         if ((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)
4338           {
4339              E_Maximize tmp_max = ec->maximized;
4340 
4341              //un-set maximized state for updating frame.
4342              ec->maximized = E_MAXIMIZE_NONE;
4343              _e_client_frame_update(ec);
4344              // re-set maximized state for unmaximize smart callback.
4345              ec->maximized = tmp_max;
4346              evas_object_smart_callback_call(ec->frame, "unfullscreen", NULL);
4347              // un-set maximized state.
4348              ec->maximized = E_MAXIMIZE_NONE;
4349              e_client_util_move_resize_without_frame(ec,
4350                                                      ec->saved.x + ec->zone->x,
4351                                                      ec->saved.y + ec->zone->y,
4352                                                      ec->saved.w, ec->saved.h);
4353              ec->saved.x = ec->saved.y = ec->saved.w = ec->saved.h = 0;
4354              ec->saved.set = 0;
4355              e_hints_window_size_unset(ec);
4356           }
4357         else
4358           {
4359              int w, h, x, y;
4360              Eina_Bool horiz = EINA_FALSE, vert = EINA_FALSE;
4361              Eina_Bool fullscreen = !!eina_list_data_find(ec->desk->fullscreen_clients, ec);
4362 
4363              e_client_unmaximize_geometry_get(ec, unmax, &x, &y, &w, &h);
4364              if (unmax & E_MAXIMIZE_VERTICAL)
4365                {
4366                   /* Remove vertical */
4367                   vert = EINA_TRUE;
4368                   if ((unmax & E_MAXIMIZE_VERTICAL) == E_MAXIMIZE_VERTICAL)
4369                     {
4370                        if ((ec->maximized & E_MAXIMIZE_LEFT) == E_MAXIMIZE_LEFT)
4371                          ec->maximized &= ~E_MAXIMIZE_LEFT;
4372                        if ((ec->maximized & E_MAXIMIZE_RIGHT) == E_MAXIMIZE_RIGHT)
4373                          ec->maximized &= ~E_MAXIMIZE_RIGHT;
4374                        ec->maximized &= ~E_MAXIMIZE_VERTICAL;
4375                     }
4376                   if ((unmax & E_MAXIMIZE_LEFT) == E_MAXIMIZE_LEFT)
4377                     ec->maximized &= ~E_MAXIMIZE_LEFT;
4378                   if ((unmax & E_MAXIMIZE_RIGHT) == E_MAXIMIZE_RIGHT)
4379                     ec->maximized &= ~E_MAXIMIZE_RIGHT;
4380                }
4381              if (unmax & E_MAXIMIZE_HORIZONTAL)
4382                {
4383                   /* Remove horizontal */
4384                   horiz = EINA_TRUE;
4385                   ec->maximized &= ~E_MAXIMIZE_HORIZONTAL;
4386                }
4387 
4388              if (!(ec->maximized & E_MAXIMIZE_DIRECTION))
4389                {
4390                   ec->maximized = E_MAXIMIZE_NONE;
4391                   _e_client_frame_update(ec);
4392                   e_hints_window_size_unset(ec);
4393                }
4394              if (e_config->window_maximize_animate && (!ec->maximize_anims_disabled))
4395                ec->maximize_override = 1;
4396              if (!fullscreen)
4397                evas_object_smart_callback_call(ec->frame, "unmaximize", NULL);
4398              if (ec->saved.frame &&
4399                (e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame))))
4400                {
4401                   e_comp_object_frame_xy_adjust(ec->frame, x, y, &x, &y);
4402                   e_comp_object_frame_wh_adjust(ec->frame, w, h, &w, &h);
4403                }
4404              e_client_resize_limit(ec, &w, &h);
4405              if (fullscreen)
4406                evas_object_smart_callback_call(ec->frame, "unmaximize", NULL);
4407              if (!_e_client_maximize_run(ec, x, y, w, h))
4408                ec->maximize_override = 0;
4409              if (vert)
4410                ec->saved.h = ec->saved.y = 0;
4411              if (horiz)
4412                ec->saved.w = ec->saved.x = 0;
4413              if (vert && horiz)
4414                ec->saved.set = ec->saved.frame = 0;
4415           }
4416         e_hints_window_maximized_set(ec, ec->maximized & E_MAXIMIZE_HORIZONTAL,
4417                                      ec->maximized & E_MAXIMIZE_VERTICAL);
4418      }
4419    e_remember_update(ec);
4420    evas_object_smart_callback_call(ec->frame, "unmaximize_done", NULL);
4421    ec->changes.need_unmaximize = 0;
4422 }
4423 
4424 E_API void
e_client_fullscreen(E_Client * ec,E_Fullscreen policy)4425 e_client_fullscreen(E_Client *ec, E_Fullscreen policy)
4426 {
4427    int x = 0, y = 0, w = 0, h = 0;
4428 
4429    E_OBJECT_CHECK(ec);
4430    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4431    if (!ec->zone) return;
4432 
4433    if ((ec->shaded) || (ec->shading) || ec->fullscreen) return;
4434    if ((!e_config->allow_above_fullscreen) && (!ec->desk->visible)) return;
4435    ec->need_fullscreen = 1;
4436    if (ec->new_client) return;
4437    if (e_comp->nocomp_ec && (ec->desk == e_comp->nocomp_ec->desk))
4438      {
4439         e_object_unref(E_OBJECT(e_comp->nocomp_ec));
4440         e_object_ref(E_OBJECT(ec));
4441         e_comp->nocomp_ec = ec;
4442      }
4443    ec->desk->fullscreen_clients = eina_list_append(ec->desk->fullscreen_clients, ec);
4444    ec->pre_res_change.valid = 0;
4445 
4446    if (ec->maximized)
4447      {
4448         x = ec->saved.x;
4449         y = ec->saved.y;
4450         w = ec->saved.w;
4451         h = ec->saved.h;
4452      }
4453    else
4454      {
4455         if (ec->changes.pos)
4456           e_comp_object_frame_xy_adjust(ec->frame, ec->x, ec->y, &ec->saved.x, &ec->saved.y);
4457         else
4458           {
4459              ec->saved.x = ec->client.x;
4460              ec->saved.y = ec->client.y;
4461           }
4462         ec->saved.x -= ec->zone->x;
4463         ec->saved.y -= ec->zone->y;
4464 
4465         if (ec->visible)
4466           {
4467              ec->saved.w = ec->client.w;
4468              ec->saved.h = ec->client.h;
4469           }
4470      }
4471    E_FREE_FUNC(ec->agent, evas_object_del);
4472    ec->saved.maximized = ec->maximized;
4473    ec->saved.zone = ec->zone->num;
4474    ec->saved.frame = e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame));
4475 
4476    if (ec->maximized)
4477      {
4478         Eina_Bool maximize_anims_disabled = ec->maximize_anims_disabled;
4479 
4480         ec->maximize_anims_disabled = 1;
4481         e_client_unmaximize(ec, E_MAXIMIZE_BOTH);
4482         ec->maximize_anims_disabled = maximize_anims_disabled;
4483         ec->saved.x = x;
4484         ec->saved.y = y;
4485         ec->saved.w = w;
4486         ec->saved.h = h;
4487         ec->saved.frame = e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame));
4488      }
4489 
4490    ec->saved.layer = ec->layer;
4491    ec->saved.set = 1;
4492    if (!e_config->allow_above_fullscreen)
4493      evas_object_layer_set(ec->frame, E_LAYER_CLIENT_FULLSCREEN);
4494    else if (e_config->mode.presentation)
4495      evas_object_layer_set(ec->frame, E_LAYER_CLIENT_TOP);
4496 
4497    ec->fullscreen = 1;
4498 #ifndef HAVE_WAYLAND_ONLY
4499    if ((eina_list_count(e_comp->zones) > 1) ||
4500        (policy == E_FULLSCREEN_RESIZE) || (!ecore_x_randr_query()))
4501 #else
4502    if ((eina_list_count(e_comp->zones) > 1) ||
4503        (policy == E_FULLSCREEN_RESIZE))
4504 #endif
4505      {
4506         evas_object_geometry_set(ec->frame, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h);
4507      }
4508    else if (policy == E_FULLSCREEN_ZOOM)
4509      {
4510         /* compositor backends! */
4511         evas_object_smart_callback_call(ec->frame, "fullscreen_zoom", NULL);
4512      }
4513 
4514    e_hints_window_fullscreen_set(ec, 1);
4515    e_hints_window_size_unset(ec);
4516    if (!e_client_util_ignored_get(ec))
4517      _e_client_frame_update(ec);
4518    ec->fullscreen_policy = policy;
4519    evas_object_smart_callback_call(ec->frame, "fullscreen", NULL);
4520 
4521    _e_client_event_simple(ec, E_EVENT_CLIENT_FULLSCREEN);
4522 
4523    e_remember_update(ec);
4524    ec->need_fullscreen = 0;
4525 }
4526 
4527 E_API void
e_client_unfullscreen(E_Client * ec)4528 e_client_unfullscreen(E_Client *ec)
4529 {
4530    E_OBJECT_CHECK(ec);
4531    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4532    if (!ec->zone) return;
4533    if ((ec->shaded) || (ec->shading)) return;
4534    if (!ec->fullscreen) return;
4535    ec->pre_res_change.valid = 0;
4536    ec->fullscreen = 0;
4537    ec->need_fullscreen = 0;
4538    ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
4539 
4540    if (ec->fullscreen_policy == E_FULLSCREEN_ZOOM)
4541      evas_object_smart_callback_call(ec->frame, "unfullscreen_zoom", NULL);
4542 
4543    if (!e_client_util_ignored_get(ec))
4544      _e_client_frame_update(ec);
4545    ec->fullscreen_policy = 0;
4546    evas_object_smart_callback_call(ec->frame, "unfullscreen", NULL);
4547 
4548    if (ec->saved.maximized)
4549      {
4550         Eina_Bool maximize_anims_disabled = ec->maximize_anims_disabled;
4551         ec->changes.pos = ec->changes.size = 0;
4552         ec->maximize_anims_disabled = 1;
4553         e_client_maximize(ec,
4554           (e_config->maximize_policy & E_MAXIMIZE_TYPE) | ec->saved.maximized);
4555         ec->maximize_anims_disabled = maximize_anims_disabled;
4556      }
4557    else
4558      {
4559         if (ec->saved.frame &&
4560           (e_comp_object_frame_exists(ec->frame) || (!e_comp_object_frame_allowed(ec->frame))))
4561           e_client_util_move_resize_without_frame(ec, ec->zone->x + ec->saved.x,
4562                                                   ec->zone->y + ec->saved.y,
4563                                                   ec->saved.w, ec->saved.h);
4564         else
4565            evas_object_geometry_set(ec->frame, ec->zone->x + ec->saved.x,
4566                                                    ec->zone->y + ec->saved.y,
4567                                                    ec->saved.w, ec->saved.h);
4568         ec->saved.w = ec->saved.x = ec->saved.h = ec->saved.y = 0;
4569         ec->saved.set = ec->saved.frame = 0;
4570      }
4571 
4572    evas_object_layer_set(ec->frame, ec->saved.layer);
4573 
4574    e_hints_window_fullscreen_set(ec, 0);
4575    _e_client_event_simple(ec, E_EVENT_CLIENT_UNFULLSCREEN);
4576 
4577    e_remember_update(ec);
4578    if (!ec->desk->fullscreen_clients)
4579      e_comp_render_queue();
4580 }
4581 
4582 ///////////////////////////////////////
4583 
4584 
4585 E_API void
e_client_iconify(E_Client * ec)4586 e_client_iconify(E_Client *ec)
4587 {
4588    E_OBJECT_CHECK(ec);
4589    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4590    if (!ec->zone) return;
4591    if (ec->shading || ec->iconic) return;
4592    if (((ec->stack.prev || ec->stack.next)) && (!ec->stack.ignore))
4593      {
4594         Eina_List *l, *list = e_client_stack_list_prepare(ec);
4595         E_Client *child;
4596 
4597         EINA_LIST_FOREACH(list, l, child)
4598           {
4599              e_client_iconify(child);
4600           }
4601         e_client_stack_list_finish(list);
4602         E_Desk *desk;
4603 
4604         desk = e_desk_current_get(ec->zone);
4605         e_desk_last_focused_focus(desk);
4606         return;
4607      }
4608    ec->iconic = 1;
4609    ec->want_focus = ec->take_focus = 0;
4610    ec->changes.visible = 0;
4611    if (ec->fullscreen)
4612      ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
4613    e_client_comp_hidden_set(ec, 1);
4614    if (!ec->stack.ignore)
4615      {
4616         if (!ec->new_client)
4617           {
4618              _e_client_revert_focus(ec);
4619              evas_object_hide(ec->frame);
4620           }
4621         e_client_urgent_set(ec, ec->icccm.urgent);
4622      }
4623    else
4624      {
4625         if (!ec->new_client)
4626           evas_object_hide(ec->frame);
4627         e_client_urgent_set(ec, ec->icccm.urgent);
4628         if (ec->focused)
4629           evas_object_focus_set(ec->frame, 0);
4630      }
4631 
4632    _e_client_event_simple(ec, E_EVENT_CLIENT_ICONIFY);
4633 
4634    if (!ec->stack.prev && !ec->stack.next)
4635      {
4636         if (e_config->transient.iconify)
4637           {
4638              E_Client *child;
4639              Eina_List *list = eina_list_clone(ec->transients);
4640 
4641              EINA_LIST_FREE(list, child)
4642                e_client_iconify(child);
4643           }
4644      }
4645    e_remember_update(ec);
4646 }
4647 
4648 E_API void
e_client_uniconify(E_Client * ec)4649 e_client_uniconify(E_Client *ec)
4650 {
4651    E_Desk *desk;
4652 
4653    E_OBJECT_CHECK(ec);
4654    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4655    if (!ec->zone) return;
4656    if (ec->shading || (!ec->iconic)) return;
4657 
4658    if (((ec->stack.prev || ec->stack.next)) && (!ec->stack.ignore))
4659      {
4660         Eina_List *l, *list = e_client_stack_list_prepare(ec);
4661         E_Client *child, *ec_focus = NULL;
4662 
4663         EINA_LIST_FOREACH(list, l, child)
4664           {
4665              e_client_uniconify(child);
4666              if (!l->next) ec_focus = child;
4667           }
4668         e_client_stack_list_finish(list);
4669         evas_object_raise(ec_focus->frame);
4670         evas_object_focus_set(ec_focus->frame, 1);
4671         return;
4672      }
4673    desk = e_desk_current_get(ec->desk->zone);
4674    e_client_desk_set(ec, desk);
4675    if (!ec->stack.ignore)
4676      evas_object_raise(ec->frame);
4677    evas_object_show(ec->frame);
4678    e_client_comp_hidden_set(ec, 0);
4679    ec->deskshow = ec->iconic = 0;
4680    if (!ec->stack.ignore)
4681      evas_object_focus_set(ec->frame, 1);
4682 
4683    _e_client_event_simple(ec, E_EVENT_CLIENT_UNICONIFY);
4684 
4685    if (!ec->stack.prev && !ec->stack.next)
4686      {
4687         if (e_config->transient.iconify)
4688           {
4689              E_Client *child;
4690              Eina_List *list = eina_list_clone(ec->transients);
4691 
4692              EINA_LIST_FREE(list, child)
4693                e_client_uniconify(child);
4694           }
4695      }
4696    e_remember_update(ec);
4697 }
4698 
4699 ///////////////////////////////////////
4700 
4701 E_API void
e_client_urgent_set(E_Client * ec,Eina_Bool urgent)4702 e_client_urgent_set(E_Client *ec, Eina_Bool urgent)
4703 {
4704    E_OBJECT_CHECK(ec);
4705    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4706 
4707    if (urgent && e_screensaver_on_get() && e_config->screensaver_wake_on_urgent)
4708      {
4709         int x, y;
4710         ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
4711         ecore_evas_pointer_warp(e_comp->ee, x, y);
4712         e_comp_canvas_notidle();
4713      }
4714    if (!ec->zone) return;
4715 
4716    urgent = !!urgent;
4717    if (urgent == ec->urgent) return;
4718    _e_client_event_property(ec, E_CLIENT_PROPERTY_URGENCY);
4719    if (urgent && (!ec->focused) && (!ec->want_focus))
4720      {
4721         e_comp_object_signal_emit(ec->frame, "e,state,urgent", "e");
4722         ec->urgent = urgent;
4723      }
4724    else
4725      {
4726         e_comp_object_signal_emit(ec->frame, "e,state,not_urgent", "e");
4727         ec->urgent = 0;
4728      }
4729 }
4730 
4731 ///////////////////////////////////////
4732 
4733 E_API void
e_client_stick(E_Client * ec)4734 e_client_stick(E_Client *ec)
4735 {
4736    E_Desk *desk;
4737 
4738    E_OBJECT_CHECK(ec);
4739    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4740    if (!ec->zone) return;
4741    if (ec->sticky) return;
4742    desk = ec->desk;
4743    ec->desk = NULL;
4744    if (desk && ec->fullscreen)
4745      desk->fullscreen_clients = eina_list_remove(desk->fullscreen_clients, ec);
4746    ec->sticky = 1;
4747    ec->hidden = 0;
4748    e_hints_window_sticky_set(ec, 1);
4749    e_client_desk_set(ec, desk);
4750    evas_object_smart_callback_call(ec->frame, "stick", NULL);
4751 
4752    if (ec->stack.prev || ec->stack.next)
4753      {
4754         if (ec->stack.ignore == 0)
4755           {
4756              Eina_List *l, *list = e_client_stack_list_prepare(ec);
4757              E_Client *child;
4758 
4759              EINA_LIST_FOREACH(list, l, child)
4760                {
4761                   if (child == ec) continue;
4762                   child->sticky = 1;
4763                   e_hints_window_sticky_set(child, 1);
4764                   evas_object_show(ec->frame);
4765                }
4766              e_client_stack_list_finish(list);
4767           }
4768      }
4769    else
4770      {
4771         if (e_config->transient.desktop)
4772           {
4773              E_Client *child;
4774              Eina_List *list = eina_list_clone(ec->transients);
4775 
4776              EINA_LIST_FREE(list, child)
4777                {
4778                   child->sticky = 1;
4779                   e_hints_window_sticky_set(child, 1);
4780                   evas_object_show(ec->frame);
4781                }
4782           }
4783      }
4784 
4785    _e_client_event_property(ec, E_CLIENT_PROPERTY_STICKY);
4786    e_remember_update(ec);
4787 }
4788 
4789 E_API void
e_client_unstick(E_Client * ec)4790 e_client_unstick(E_Client *ec)
4791 {
4792    E_Desk *desk;
4793 
4794    E_OBJECT_CHECK(ec);
4795    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4796    if (!ec->zone) return;
4797    /* Set the desk before we unstick the client */
4798    if (!ec->sticky) return;
4799    desk = e_desk_current_get(ec->zone);
4800    if (ec->desk && ec->fullscreen)
4801      ec->desk->fullscreen_clients = eina_list_remove(ec->desk->fullscreen_clients, ec);
4802    ec->desk = NULL;
4803    ec->hidden = ec->sticky = 0;
4804    e_hints_window_sticky_set(ec, 0);
4805    e_client_desk_set(ec, desk);
4806    evas_object_smart_callback_call(ec->frame, "unstick", NULL);
4807 
4808    if (ec->stack.prev || ec->stack.next)
4809      {
4810         if (ec->stack.ignore == 0)
4811           {
4812              Eina_List *l, *list = e_client_stack_list_prepare(ec);
4813              E_Client *child;
4814 
4815              EINA_LIST_FOREACH(list, l, child)
4816                {
4817                   if (child == ec) continue;
4818                   child->sticky = 1;
4819                   e_hints_window_sticky_set(child, 0);
4820                }
4821              e_client_stack_list_finish(list);
4822           }
4823      }
4824    else
4825      {
4826         if (e_config->transient.desktop)
4827           {
4828              E_Client *child;
4829              Eina_List *list = eina_list_clone(ec->transients);
4830 
4831              EINA_LIST_FREE(list, child)
4832                {
4833                   child->sticky = 0;
4834                   e_hints_window_sticky_set(child, 0);
4835                }
4836           }
4837      }
4838 
4839    _e_client_event_property(ec, E_CLIENT_PROPERTY_STICKY);
4840 
4841    e_client_desk_set(ec, e_desk_current_get(ec->zone));
4842    e_remember_update(ec);
4843 }
4844 
4845 E_API void
e_client_pinned_set(E_Client * ec,Eina_Bool set)4846 e_client_pinned_set(E_Client *ec, Eina_Bool set)
4847 {
4848    E_Layer layer;
4849 
4850    EINA_SAFETY_ON_NULL_RETURN(ec);
4851    ec->borderless = !!set;
4852    ec->user_skip_winlist = !!set;
4853    if (set)
4854      layer = E_LAYER_CLIENT_BELOW;
4855    else
4856      layer = E_LAYER_CLIENT_NORMAL;
4857 
4858    evas_object_layer_set(ec->frame, layer);
4859 
4860    ec->border.changed = 1;
4861    EC_CHANGED(ec);
4862 }
4863 
4864 E_API void
e_client_prop_misc_changed(E_Client * ec)4865 e_client_prop_misc_changed(E_Client *ec)
4866 {
4867    EINA_SAFETY_ON_NULL_RETURN(ec);
4868    _e_client_event_property(ec, E_CLIENT_PROPERTY_MISC);
4869 }
4870 
4871 ///////////////////////////////////////
4872 
4873 E_API Eina_Bool
e_client_border_set(E_Client * ec,const char * name)4874 e_client_border_set(E_Client *ec, const char *name)
4875 {
4876    Eina_Stringshare *pborder;
4877 
4878    E_OBJECT_CHECK_RETURN(ec, EINA_FALSE);
4879    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE);
4880    if ((!e_comp_object_frame_allowed(ec->frame)) && (!e_comp_object_frame_exists(ec->frame)))
4881      return EINA_FALSE;
4882    if (ec->border.changed)
4883      CRI("CALLING WHEN border.changed SET!");
4884 
4885    if (eina_streq(ec->border.name, name)) return EINA_TRUE;
4886    if (ec->mwm.borderless && (!eina_streq(name, "borderless")))
4887      {
4888         e_util_dialog_show(_("Client Error!"), _("Something has attempted to set a border when it shouldn't! Report this!"));
4889         CRI("border change attempted for MWM borderless client!");
4890      }
4891    if ((!ec->border.name) && eina_streq(name, "borderless")) return EINA_TRUE;
4892    pborder = ec->border.name;
4893    ec->border.name = eina_stringshare_add(name);
4894    if (e_comp_object_frame_theme_set(ec->frame, name))
4895      {
4896         eina_stringshare_del(pborder);
4897         return EINA_TRUE;
4898      }
4899    eina_stringshare_del(ec->border.name);
4900    ec->border.name = pborder;
4901    return EINA_FALSE;
4902 }
4903 
4904 ///////////////////////////////////////
4905 
4906 E_API void
e_client_comp_hidden_set(E_Client * ec,Eina_Bool hidden)4907 e_client_comp_hidden_set(E_Client *ec, Eina_Bool hidden)
4908 {
4909    E_OBJECT_CHECK(ec);
4910    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4911    if (!ec->zone) return;
4912 
4913    hidden = !!hidden;
4914    if (ec->comp_hidden == hidden) return;
4915    ec->comp_hidden = hidden;
4916    evas_object_smart_callback_call(ec->frame, "comp_hidden", NULL);
4917 }
4918 
4919 ///////////////////////////////////////
4920 
4921 E_API void
e_client_act_move_keyboard(E_Client * ec)4922 e_client_act_move_keyboard(E_Client *ec)
4923 {
4924    EINA_SAFETY_ON_NULL_RETURN(ec);
4925    if (!ec->zone) return;
4926 
4927    if (!_e_client_move_begin(ec))
4928      return;
4929    _e_client_action_init(ec);
4930    if (!_e_client_hook_call(E_CLIENT_HOOK_MOVE_UPDATE, ec)) return;
4931 
4932    if (!action_handler_key)
4933      action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_client_move_key_down, NULL);
4934 
4935    if (!action_handler_mouse)
4936      action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_client_move_mouse_down, NULL);
4937    _e_client_action_move_timeout_add();
4938 }
4939 
4940 E_API void
e_client_act_resize_keyboard(E_Client * ec)4941 e_client_act_resize_keyboard(E_Client *ec)
4942 {
4943    EINA_SAFETY_ON_NULL_RETURN(ec);
4944    if (!ec->zone) return;
4945 
4946    ec->resize_mode = E_POINTER_RESIZE_BR;
4947    ec->keyboard_resizing = 1;
4948    if (!e_client_resize_begin(ec))
4949      {
4950         ec->keyboard_resizing = 0;
4951         return;
4952      }
4953    _e_client_action_init(ec);
4954 
4955    if (!action_handler_key)
4956      action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_client_resize_key_down, NULL);
4957 
4958    if (!action_handler_mouse)
4959      action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_client_resize_mouse_down, NULL);
4960    _e_client_action_resize_timeout_add();
4961 }
4962 
4963 E_API void
e_client_act_move_begin(E_Client * ec,E_Binding_Event_Mouse_Button * ev)4964 e_client_act_move_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev)
4965 {
4966    E_OBJECT_CHECK(ec);
4967    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4968    if (!ec->zone) return;
4969    if (e_client_util_resizing_get(ec) || (ec->moving)) return;
4970    if (ev)
4971      {
4972         char source[256];
4973 
4974         snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button);
4975         _e_client_moveinfo_gather(ec, source);
4976      }
4977    if (!_e_client_move_begin(ec))
4978      return;
4979 
4980    _e_client_action_init(ec);
4981    e_pointer_mode_push(ec, E_POINTER_MOVE);
4982 }
4983 
4984 E_API void
e_client_act_move_end(E_Client * ec,E_Binding_Event_Mouse_Button * ev EINA_UNUSED)4985 e_client_act_move_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED)
4986 {
4987    E_OBJECT_CHECK(ec);
4988    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
4989    if (!ec->zone) return;
4990    if (!ec->moving) return;
4991    e_zone_edge_enable();
4992    _e_client_move_end(ec);
4993    e_zone_flip_coords_handle(ec->zone, -1, -1);
4994    _e_client_action_finish();
4995 }
4996 
4997 E_API void
e_client_act_resize_begin(E_Client * ec,E_Binding_Event_Mouse_Button * ev)4998 e_client_act_resize_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev)
4999 {
5000    E_OBJECT_CHECK(ec);
5001    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5002    if (!ec->zone) return;
5003    if (ec->lock_user_size || ec->shaded || ec->shading) return;
5004    if (e_client_util_resizing_get(ec) || (ec->moving)) return;
5005    if (ev)
5006      {
5007         char source[256];
5008 
5009         snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button);
5010         _e_client_moveinfo_gather(ec, source);
5011      }
5012    if ((ec->mouse.current.mx > (ec->x + ec->w / 5)) &&
5013        (ec->mouse.current.mx < (ec->x + ec->w * 4 / 5)))
5014      {
5015         if (ec->mouse.current.my < (ec->y + ec->h / 2))
5016           {
5017              ec->resize_mode = E_POINTER_RESIZE_T;
5018           }
5019         else
5020           {
5021              ec->resize_mode = E_POINTER_RESIZE_B;
5022           }
5023      }
5024    else if (ec->mouse.current.mx < (ec->x + ec->w / 2))
5025      {
5026         if ((ec->mouse.current.my > (ec->y + ec->h / 5)) &&
5027             (ec->mouse.current.my < (ec->y + ec->h * 4 / 5)))
5028           {
5029              ec->resize_mode = E_POINTER_RESIZE_L;
5030           }
5031         else if (ec->mouse.current.my < (ec->y + ec->h / 2))
5032           {
5033              ec->resize_mode = E_POINTER_RESIZE_TL;
5034           }
5035         else
5036           {
5037              ec->resize_mode = E_POINTER_RESIZE_BL;
5038           }
5039      }
5040    else
5041      {
5042         if ((ec->mouse.current.my > (ec->y + ec->h / 5)) &&
5043             (ec->mouse.current.my < (ec->y + ec->h * 4 / 5)))
5044           {
5045              ec->resize_mode = E_POINTER_RESIZE_R;
5046           }
5047         else if (ec->mouse.current.my < (ec->y + ec->h / 2))
5048           {
5049              ec->resize_mode = E_POINTER_RESIZE_TR;
5050           }
5051         else
5052           {
5053              ec->resize_mode = E_POINTER_RESIZE_BR;
5054           }
5055      }
5056    if (!e_client_resize_begin(ec))
5057      return;
5058    _e_client_action_init(ec);
5059    e_pointer_mode_push(ec, ec->resize_mode);
5060 }
5061 
5062 E_API void
e_client_act_resize_end(E_Client * ec,E_Binding_Event_Mouse_Button * ev EINA_UNUSED)5063 e_client_act_resize_end(E_Client *ec, E_Binding_Event_Mouse_Button *ev EINA_UNUSED)
5064 {
5065    E_OBJECT_CHECK(ec);
5066    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5067    if (!ec->zone) return;
5068    if (e_client_util_resizing_get(ec))
5069      {
5070         _e_client_resize_end(ec);
5071         ec->changes.reset_gravity = 1;
5072         if (!e_object_is_del(E_OBJECT(ec)))
5073           EC_CHANGED(ec);
5074      }
5075    _e_client_action_finish();
5076 }
5077 
5078 E_API void
e_client_act_menu_begin(E_Client * ec,E_Binding_Event_Mouse_Button * ev,int key)5079 e_client_act_menu_begin(E_Client *ec, E_Binding_Event_Mouse_Button *ev, int key)
5080 {
5081    E_OBJECT_CHECK(ec);
5082    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5083    if (!ec->zone) return;
5084    if (ec->border_menu) return;
5085    if (ev)
5086      e_int_client_menu_show(ec, ev->canvas.x, ev->canvas.y, key, ev->timestamp);
5087    else
5088      {
5089         int x, y;
5090 
5091         evas_pointer_canvas_xy_get(e_comp->evas, &x, &y);
5092         e_int_client_menu_show(ec, x, y, key, 0);
5093      }
5094 }
5095 
5096 E_API void
e_client_act_close_begin(E_Client * ec)5097 e_client_act_close_begin(E_Client *ec)
5098 {
5099    E_OBJECT_CHECK(ec);
5100    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5101    if (!ec->zone) return;
5102    if (ec->lock_close) return;
5103    if (ec->icccm.delete_request)
5104      {
5105         ec->delete_requested = 1;
5106         evas_object_smart_callback_call(ec->frame, "delete_request", NULL);
5107      }
5108    else if (e_config->kill_if_close_not_possible)
5109      {
5110         e_client_act_kill_begin(ec);
5111      }
5112 }
5113 
5114 E_API void
e_client_act_kill_begin(E_Client * ec)5115 e_client_act_kill_begin(E_Client *ec)
5116 {
5117    E_OBJECT_CHECK(ec);
5118    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5119    if (!ec->zone) return;
5120    if (ec->internal) return;
5121    if (ec->lock_close) return;
5122    if (ec->netwm.pid == getpid()) return;
5123    if ((ec->netwm.pid > 1) && (e_config->kill_process))
5124      {
5125         kill(ec->netwm.pid, SIGINT);
5126         ec->kill_timer = ecore_timer_loop_add(e_config->kill_timer_wait,
5127                                          _e_client_cb_kill_timer, ec);
5128      }
5129    else
5130      evas_object_smart_callback_call(ec->frame, "kill_request", NULL);
5131 }
5132 
5133 ////////////////////////////////////////////////
5134 
5135 
5136 E_API Evas_Object *
e_client_icon_add(E_Client * ec,Evas * evas)5137 e_client_icon_add(E_Client *ec, Evas *evas)
5138 {
5139    Evas_Object *o;
5140 
5141    E_OBJECT_CHECK_RETURN(ec, NULL);
5142    E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, NULL);
5143 
5144    o = NULL;
5145    if (ec->internal)
5146      {
5147         if (!ec->internal_icon)
5148           {
5149              o = e_icon_add(evas);
5150              e_util_icon_theme_set(o, "enlightenment");
5151           }
5152         else
5153           {
5154              if (!ec->internal_icon_key)
5155                {
5156                   char *ext;
5157 
5158                   ext = strrchr(ec->internal_icon, '.');
5159                   if ((ext) && ((!strcmp(ext, ".edj"))))
5160                     {
5161                        o = edje_object_add(evas);
5162                        if (!edje_object_file_set(o, ec->internal_icon, "icon"))
5163                          e_util_icon_theme_set(o, "enlightenment");
5164                     }
5165                   else if (ext)
5166                     {
5167                        o = e_icon_add(evas);
5168                        e_icon_file_set(o, ec->internal_icon);
5169                     }
5170                   else
5171                     {
5172                        o = e_icon_add(evas);
5173                        if (!e_util_icon_theme_set(o, ec->internal_icon))
5174                          e_util_icon_theme_set(o, "enlightenment");
5175                     }
5176                }
5177              else
5178                {
5179                   o = edje_object_add(evas);
5180                   edje_object_file_set(o, ec->internal_icon,
5181                                        ec->internal_icon_key);
5182                }
5183           }
5184         return o;
5185      }
5186 #ifndef HAVE_WAYLAND_ONLY
5187    if ((e_config->use_app_icon) && (ec->icon_preference != E_ICON_PREF_USER))
5188      {
5189         if (ec->netwm.icons)
5190           {
5191              o = e_icon_add(evas);
5192              e_icon_data_set(o, ec->netwm.icons[0].data,
5193                              ec->netwm.icons[0].width,
5194                              ec->netwm.icons[0].height);
5195              e_icon_alpha_set(o, 1);
5196              return o;
5197           }
5198      }
5199 #endif
5200    if (!o)
5201      {
5202         if ((ec->desktop) && (ec->icon_preference != E_ICON_PREF_NETWM))
5203           {
5204              o = e_util_desktop_icon_add(ec->desktop, 64, evas);
5205              if (o)
5206                return o;
5207           }
5208 #ifndef HAVE_WAYLAND_ONLY
5209         else if (ec->netwm.icons)
5210           {
5211              o = e_icon_add(evas);
5212              e_icon_data_set(o, ec->netwm.icons[0].data,
5213                              ec->netwm.icons[0].width,
5214                              ec->netwm.icons[0].height);
5215              e_icon_alpha_set(o, 1);
5216              return o;
5217           }
5218 #endif
5219      }
5220 
5221    o = e_icon_add(evas);
5222    e_util_icon_theme_set(o, "unknown");
5223    return o;
5224 }
5225 
5226 ////////////////////////////////////////////
5227 
5228 E_API void
e_client_ping(E_Client * ec)5229 e_client_ping(E_Client *ec)
5230 {
5231    E_OBJECT_CHECK(ec);
5232    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5233    if (!e_config->ping_clients) return;
5234    ec->ping_ok = 0;
5235    evas_object_smart_callback_call(ec->frame, "ping", NULL);
5236    ec->ping = ecore_loop_time_get();
5237    if (ec->ping_poller) ecore_poller_del(ec->ping_poller);
5238    ec->ping_poller = ecore_poller_add(ECORE_POLLER_CORE,
5239                                       e_config->ping_clients_interval,
5240                                       _e_client_cb_ping_poller, ec);
5241 }
5242 
5243 ////////////////////////////////////////////
5244 
5245 E_API void
e_client_move_cancel(void)5246 e_client_move_cancel(void)
5247 {
5248    if (!ecmove) return;
5249    if (ecmove->cur_mouse_action)
5250      {
5251         E_Client *ec;
5252 
5253         ec = ecmove;
5254         e_object_ref(E_OBJECT(ec));
5255         _e_client_mouse_action_end(ec);
5256         e_object_unref(E_OBJECT(ec));
5257      }
5258    else
5259      _e_client_move_end(ecmove);
5260 }
5261 
5262 E_API void
e_client_resize_cancel(void)5263 e_client_resize_cancel(void)
5264 {
5265    if (!ecresize) return;
5266    if (ecresize->cur_mouse_action)
5267      {
5268         E_Client *ec;
5269 
5270         ec = ecresize;
5271         e_object_ref(E_OBJECT(ec));
5272         _e_client_mouse_action_end(ec);
5273         e_object_unref(E_OBJECT(ec));
5274      }
5275    else
5276      _e_client_resize_end(ecresize);
5277 }
5278 
5279 E_API Eina_Bool
e_client_resize_begin(E_Client * ec)5280 e_client_resize_begin(E_Client *ec)
5281 {
5282    if ((ec->shaded) || (ec->shading) ||
5283        (ec->fullscreen) || (ec->lock_user_size))
5284      goto error;
5285    if (!_e_client_action_input_win_new()) goto error;
5286    if (!ec->lock_user_stacking)
5287      {
5288         if (e_config->border_raise_on_mouse_action)
5289           evas_object_raise(ec->frame);
5290      }
5291    ecresize = ec;
5292    _e_client_hook_call(E_CLIENT_HOOK_RESIZE_BEGIN, ec);
5293    if (!e_client_util_resizing_get(ec))
5294      {
5295         if (ecresize == ec) ecresize = NULL;
5296         _e_client_action_input_win_del();
5297         return EINA_FALSE;
5298      }
5299    E_FREE_FUNC(ec->raise_timer, ecore_timer_del);
5300    _e_client_action_event_grabber_init(ec);
5301    return EINA_TRUE;
5302 error:
5303    ec->resize_mode = E_POINTER_RESIZE_NONE;
5304    return EINA_FALSE;
5305 }
5306 
5307 
5308 ////////////////////////////////////////////
5309 
5310 E_API void
e_client_frame_recalc(E_Client * ec)5311 e_client_frame_recalc(E_Client *ec)
5312 {
5313    EINA_SAFETY_ON_NULL_RETURN(ec);
5314    if (!ec->frame) return;
5315    evas_object_smart_callback_call(ec->frame, "frame_recalc", NULL);
5316 }
5317 
5318 ////////////////////////////////////////////
5319 
5320 E_API void
e_client_signal_move_begin(E_Client * ec,const char * sig,const char * src EINA_UNUSED)5321 e_client_signal_move_begin(E_Client *ec, const char *sig, const char *src EINA_UNUSED)
5322 {
5323    E_OBJECT_CHECK(ec);
5324    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5325    if (!ec->zone) return;
5326 
5327    if (e_client_util_resizing_get(ec) || (ec->moving)) return;
5328    _e_client_moveinfo_gather(ec, sig);
5329    if (!_e_client_move_begin(ec)) return;
5330    _e_client_action_init(ec);
5331    e_pointer_mode_push(ec, E_POINTER_MOVE);
5332 }
5333 
5334 E_API void
e_client_signal_move_end(E_Client * ec,const char * sig EINA_UNUSED,const char * src EINA_UNUSED)5335 e_client_signal_move_end(E_Client *ec, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
5336 {
5337    E_OBJECT_CHECK(ec);
5338    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5339    if (!ec->zone) return;
5340    if (!ec->moving) return;
5341    _e_client_move_end(ec);
5342    e_zone_edge_enable();
5343    e_zone_flip_coords_handle(ec->zone, -1, -1);
5344    _e_client_action_finish();
5345 }
5346 
5347 E_API void
e_client_signal_resize_begin(E_Client * ec,const char * dir,const char * sig,const char * src EINA_UNUSED)5348 e_client_signal_resize_begin(E_Client *ec, const char *dir, const char *sig, const char *src EINA_UNUSED)
5349 {
5350    int resize_mode = E_POINTER_RESIZE_BR;
5351 
5352    E_OBJECT_CHECK(ec);
5353    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5354 
5355    if (e_client_util_resizing_get(ec) || (ec->moving)) return;
5356    if (!strcmp(dir, "tl"))
5357      {
5358         resize_mode = E_POINTER_RESIZE_TL;
5359      }
5360    else if (!strcmp(dir, "t"))
5361      {
5362         resize_mode = E_POINTER_RESIZE_T;
5363      }
5364    else if (!strcmp(dir, "tr"))
5365      {
5366         resize_mode = E_POINTER_RESIZE_TR;
5367      }
5368    else if (!strcmp(dir, "r"))
5369      {
5370         resize_mode = E_POINTER_RESIZE_R;
5371      }
5372    else if (!strcmp(dir, "br"))
5373      {
5374         resize_mode = E_POINTER_RESIZE_BR;
5375      }
5376    else if (!strcmp(dir, "b"))
5377      {
5378         resize_mode = E_POINTER_RESIZE_B;
5379      }
5380    else if (!strcmp(dir, "bl"))
5381      {
5382         resize_mode = E_POINTER_RESIZE_BL;
5383      }
5384    else if (!strcmp(dir, "l"))
5385      {
5386         resize_mode = E_POINTER_RESIZE_L;
5387      }
5388    ec->resize_mode = resize_mode;
5389    _e_client_moveinfo_gather(ec, sig);
5390    if (!e_client_resize_begin(ec))
5391      return;
5392    _e_client_action_init(ec);
5393    e_pointer_mode_push(ec, ec->resize_mode);
5394 }
5395 
5396 E_API void
e_client_signal_resize_end(E_Client * ec,const char * dir EINA_UNUSED,const char * sig EINA_UNUSED,const char * src EINA_UNUSED)5397 e_client_signal_resize_end(E_Client *ec, const char *dir EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
5398 {
5399    E_OBJECT_CHECK(ec);
5400    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5401    if (!e_client_util_resizing_get(ec)) return;
5402    _e_client_resize_handle(ec);
5403    _e_client_resize_end(ec);
5404    ec->changes.reset_gravity = 1;
5405    EC_CHANGED(ec);
5406    _e_client_action_finish();
5407 }
5408 
5409 ////////////////////////////////////////////
5410 
5411 E_API void
e_client_resize_limit(const E_Client * ec,int * w,int * h)5412 e_client_resize_limit(const E_Client *ec, int *w, int *h)
5413 {
5414    int l = 0, r = 0, t = 0, b = 0;
5415    int dw = 0, dh = 0;
5416    E_OBJECT_CHECK(ec);
5417    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5418 
5419    e_comp_object_frame_geometry_get(ec->frame, &l, &r, &t, &b);
5420    if ((ec->frame) && e_comp_object_frame_allowed(ec->frame))
5421      {
5422         e_comp_object_frame_wh_unadjust(ec->frame, ec->w, ec->h, &dw, &dh);
5423         e_comp_object_frame_wh_unadjust(ec->frame, *w, *h, w, h);
5424      }
5425    else
5426      {
5427         *w -= l + r;
5428         *h -= t + b;
5429         dw = ec->w;
5430         dh = ec->h;
5431      }
5432    dw = abs(*w - dw);
5433    dh = abs(*h - dh);
5434    if (*h < 1) *h = 1;
5435    if (*w < 1) *w = 1;
5436 
5437    if ((ec->icccm.max_w > 0) && (*w > ec->icccm.max_w)) *w = ec->icccm.max_w;
5438    else if (*w < ec->icccm.min_w)
5439      *w = ec->icccm.min_w;
5440    if ((ec->icccm.max_h > 0) && (*h > ec->icccm.max_h)) *h = ec->icccm.max_h;
5441    else if (*h < ec->icccm.min_h)
5442      *h = ec->icccm.min_h;
5443 
5444    if (ec->icccm.step_w > 0)
5445      {
5446         int bw = ec->icccm.base_w ?: ec->icccm.min_w;
5447 
5448         bw = bw + (((*w - bw) / ec->icccm.step_w) * ec->icccm.step_w);
5449         if ((bw > ec->icccm.min_w) && ((ec->icccm.max_w < 1) || (bw < ec->icccm.max_w)))
5450           *w = bw;
5451      }
5452    if (ec->icccm.step_h > 0)
5453      {
5454         int bh = ec->icccm.base_h ?: ec->icccm.min_h;
5455 
5456         bh = bh + (((*h - bh) / ec->icccm.step_h) * ec->icccm.step_h);
5457         if ((bh > ec->icccm.min_h) && ((ec->icccm.max_h < 1) || (bh < ec->icccm.max_h)))
5458           *h = bh;
5459      }
5460 
5461    if (EINA_DBL_NONZERO(ec->icccm.min_aspect) ||
5462        EINA_DBL_NONZERO(ec->icccm.max_aspect))
5463      {
5464         double a = (double)*w / *h;
5465         Evas_Aspect_Control aspect;
5466         int aw, ah;
5467         double val;
5468 
5469         if (a < ec->icccm.min_aspect)
5470           {
5471              if (dw)
5472                aspect = EVAS_ASPECT_CONTROL_HORIZONTAL;
5473              else if (dh)
5474                aspect = EVAS_ASPECT_CONTROL_VERTICAL;
5475              else
5476                aspect = EVAS_ASPECT_CONTROL_BOTH;
5477              switch (aspect)
5478                {
5479                 case EVAS_ASPECT_CONTROL_HORIZONTAL:
5480                   val = ((*h - (*w / ec->icccm.min_aspect)) * ec->icccm.step_h) / ec->icccm.step_h;
5481                   if (val > 0)
5482                     ah = ceil(val);
5483                   else
5484                     ah = floor(val);
5485                   if (*h - ah > ec->icccm.min_h)
5486                     {
5487                        *h -= ah;
5488                        break;
5489                     }
5490                   EINA_FALLTHROUGH;
5491                   /* No break */
5492                 default:
5493                   val = (((*h * ec->icccm.min_aspect) - *w) * ec->icccm.step_w) / ec->icccm.step_w;
5494                   if (val > 0)
5495                     aw = ceil(val);
5496                   else
5497                     aw = floor(val);
5498                   if (*w + aw < ec->icccm.max_w)
5499                     *w += aw;
5500                   break;
5501                }
5502           }
5503         a = (double)*w / *h;
5504         if (a < ec->icccm.min_aspect) abort();
5505         if (a > ec->icccm.max_aspect)
5506           {
5507              if (dw)
5508                aspect = EVAS_ASPECT_CONTROL_HORIZONTAL;
5509              else if (dh)
5510                aspect = EVAS_ASPECT_CONTROL_VERTICAL;
5511              else
5512                aspect = EVAS_ASPECT_CONTROL_BOTH;
5513              switch (aspect)
5514                {
5515                 case EVAS_ASPECT_CONTROL_HORIZONTAL:
5516                   val = (((*w / ec->icccm.max_aspect) - *h) * ec->icccm.step_h) / ec->icccm.step_h;
5517                   if (val > 0)
5518                     ah = ceil(val);
5519                   else
5520                     ah = floor(val);
5521                   if (*h + ah > ec->icccm.max_h)
5522                     {
5523                        *h += ah;
5524                        break;
5525                     }
5526                   EINA_FALLTHROUGH;
5527                   /* No break */
5528                 default:
5529                   val = ((*w - (*h * ec->icccm.max_aspect)) * ec->icccm.step_w) / ec->icccm.step_w;
5530                   if (val > 0)
5531                     aw = ceil(val);
5532                   else
5533                     aw = floor(val);
5534                   if (*w - aw > ec->icccm.min_w)
5535                     *w -= aw;
5536                   break;
5537                }
5538           }
5539      }
5540 
5541    if (*h < 1) *h = 1;
5542    if (*w < 1) *w = 1;
5543 
5544    if ((ec->frame) && e_comp_object_frame_allowed(ec->frame))
5545      {
5546         if (ec->frame)
5547           e_comp_object_frame_wh_adjust(ec->frame, *w, *h, w, h);
5548      }
5549    else
5550      {
5551         *w += l + r;
5552         *h += t + b;
5553      }
5554 }
5555 
5556 ////////////////////////////////////////////
5557 
5558 
5559 
5560 E_API E_Client *
e_client_under_pointer_get(E_Desk * desk,E_Client * exclude)5561 e_client_under_pointer_get(E_Desk *desk, E_Client *exclude)
5562 {
5563    int x, y;
5564 
5565    /* We need to ensure that we can get the comp window for the
5566     * zone of either the given desk or the desk of the excluded
5567     * window, so return if neither is given */
5568    if (desk)
5569      ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
5570    else if (exclude)
5571      ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
5572    else
5573      return NULL;
5574 
5575    if (!desk)
5576      {
5577         desk = exclude->desk;
5578         if (!desk)
5579           {
5580              if (exclude->zone)
5581                desk = e_desk_current_get(exclude->zone);
5582              else
5583                desk = e_desk_current_get(e_zone_current_get());
5584           }
5585      }
5586 
5587    return _e_client_under_pointer_helper(desk, exclude, x, y);
5588 }
5589 
5590 ////////////////////////////////////////////
5591 
5592 E_API int
e_client_pointer_warp_to_center_now(E_Client * ec)5593 e_client_pointer_warp_to_center_now(E_Client *ec)
5594 {
5595    if (e_config->disable_all_pointer_warps) return 0;
5596    if (warp_client == ec)
5597      {
5598         ecore_evas_pointer_warp(e_comp->ee, warp_to_x, warp_to_y);
5599         warp_to = 0;
5600         _e_client_pointer_warp_to_center_timer(NULL);
5601      }
5602    else
5603      {
5604         if (e_client_pointer_warp_to_center(ec))
5605           e_client_pointer_warp_to_center_now(ec);
5606      }
5607    return 1;
5608 }
5609 
5610 E_API int
e_client_pointer_warp_to_center(E_Client * ec)5611 e_client_pointer_warp_to_center(E_Client *ec)
5612 {
5613    int x, y;
5614    E_Client *cec = NULL;
5615 
5616    ec = e_client_stack_active_adjust(ec);
5617    if (ec->override) return 0;
5618    if (!ec->zone) return 0;
5619    if (e_config->disable_all_pointer_warps) return 0;
5620    /* Only warp the pointer if it is not already in the area of
5621     * the given border */
5622    ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
5623    if ((x >= ec->x) && (x <= (ec->x + ec->w)) &&
5624        (y >= ec->y) && (y <= (ec->y + ec->h)))
5625      {
5626         cec = _e_client_under_pointer_helper(ec->desk, ec, x, y);
5627         if (cec) cec = e_client_stack_active_adjust(cec);
5628         if (cec == ec) return 0;
5629      }
5630 
5631    warp_to_x = ec->x + (ec->w / 2);
5632    if (warp_to_x < (ec->zone->x + 1))
5633      warp_to_x = ec->zone->x + ((ec->x + ec->w - ec->zone->x) / 2);
5634    else if (warp_to_x > (ec->zone->x + ec->zone->w))
5635      warp_to_x = (ec->zone->x + ec->zone->w + ec->x) / 2;
5636 
5637    warp_to_y = ec->y + (ec->h / 2);
5638    if (warp_to_y < (ec->zone->y + 1))
5639      warp_to_y = ec->zone->y + ((ec->y + ec->h - ec->zone->y) / 2);
5640    else if (warp_to_y > (ec->zone->y + ec->zone->h))
5641      warp_to_y = (ec->zone->y + ec->zone->h + ec->y) / 2;
5642 
5643    /* TODO: handle case where another border is over the exact center,
5644     * find a place where the requested border is not overlapped?
5645     *
5646    if (!cec) cec = _e_client_under_pointer_helper(ec->desk, ec, x, y);
5647    if (cec != ec)
5648      {
5649      }
5650    */
5651 
5652    warp_to = 1;
5653    warp_client = ec;
5654    ecore_evas_pointer_xy_get(e_comp->ee, &warp_x[0], &warp_y[0]);
5655    if (warp_timer) ecore_timer_del(warp_timer);
5656    warp_timer = ecore_timer_loop_add(0.01, _e_client_pointer_warp_to_center_timer, ec);
5657    return 1;
5658 }
5659 
5660 ////////////////////////////////////////////
5661 
5662 E_API void
e_client_redirected_set(E_Client * ec,Eina_Bool set)5663 e_client_redirected_set(E_Client *ec, Eina_Bool set)
5664 {
5665    EINA_SAFETY_ON_NULL_RETURN(ec);
5666    if (ec->input_only) return;
5667    set = !!set;
5668    if (ec->redirected == set) return;
5669    if (set)
5670      {
5671         e_client_frame_recalc(ec);
5672         if (!_e_client_hook_call(E_CLIENT_HOOK_REDIRECT, ec)) return;
5673      }
5674    else
5675      {
5676         if (!_e_client_hook_call(E_CLIENT_HOOK_UNREDIRECT, ec)) return;
5677      }
5678    e_comp_object_redirected_set(ec->frame, set);
5679    ec->redirected = !!set;
5680 }
5681 
5682 ////////////////////////////////////////////
5683 
5684 E_API void
e_client_next_mouse_action_ignore(E_Client * ec)5685 e_client_next_mouse_action_ignore(E_Client *ec)
5686 {
5687    EINA_SAFETY_ON_NULL_RETURN(ec);
5688    ec->next_mouse_action_ignore = EINA_TRUE;
5689 }
5690 
5691 ////////////////////////////////////////////
5692 
5693 E_API Eina_Bool
e_client_is_stacking(const E_Client * ec)5694 e_client_is_stacking(const E_Client *ec)
5695 {
5696    return e_comp->layers[e_comp_canvas_layer_map(ec->layer)].obj == ec->frame;
5697 }
5698 
5699 E_API Eina_Bool
e_client_has_xwindow(const E_Client * ec)5700 e_client_has_xwindow(const E_Client *ec)
5701 {
5702 #ifdef HAVE_WAYLAND_ONLY
5703    (void)ec;
5704    return EINA_FALSE;
5705 #else
5706 # ifdef HAVE_WAYLAND
5707    if (!e_pixmap_is_x(ec->pixmap))
5708      return !!e_comp_wl_client_xwayland_pixmap(ec);
5709 # endif
5710    return e_pixmap_is_x(ec->pixmap);
5711 #endif
5712 }
5713 
5714 ////////////////////////////////////////////
5715 
5716 E_API void
e_client_layout_cb_set(E_Client_Layout_Cb cb)5717 e_client_layout_cb_set(E_Client_Layout_Cb cb)
5718 {
5719    if (_e_client_layout_cb && cb)
5720      CRI("ATTEMPTING TO OVERWRITE EXISTING CLIENT LAYOUT HOOK!!!");
5721    _e_client_layout_cb = cb;
5722 }
5723 
5724 ////////////////////////////////////////////
5725 
5726 E_API void
e_client_parent_set(E_Client * ec,E_Client * parent)5727 e_client_parent_set(E_Client *ec, E_Client *parent)
5728 {
5729 //   E_Client *prev;
5730 
5731    E_OBJECT_CHECK(ec);
5732    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5733    if (parent)
5734      {
5735         E_OBJECT_CHECK(parent);
5736         E_OBJECT_TYPE_CHECK(parent, E_CLIENT_TYPE);
5737      }
5738 
5739    if (ec == parent)
5740      {
5741         ERR("refusing to set client as its own parent");
5742         return;
5743      }
5744 
5745    if (parent && (parent->parent == ec))
5746      {
5747         ERR("refusing to set client as its parent's parent");
5748         return;
5749      }
5750 
5751    if (ec->parent == parent) return;
5752 
5753    /* If we already have a parent, remove it */
5754    if (ec->parent)
5755      {
5756         ec->parent->transients = eina_list_remove(ec->parent->transients, ec);
5757         if (ec->parent->modal == ec) ec->parent->modal = NULL;
5758         ec->parent = NULL;
5759      }
5760    if (parent)
5761      {
5762 //        prev = eina_list_last_data_get(parent->transients);
5763         parent->transients = eina_list_append(parent->transients, ec);
5764         ec->parent = parent;
5765      }
5766    if (ec->parent)
5767      {
5768         evas_object_layer_set(ec->frame, ec->parent->layer);
5769 
5770 /* complex stacking right above one dialog after the other hurts the
5771  * simple assumptions that the window should be on top by clients so
5772  * be dumber and disable this
5773         if (prev)
5774           evas_object_stack_above(ec->frame, prev->frame);
5775         else
5776           evas_object_stack_above(ec->frame, parent->frame);
5777  */
5778         evas_object_raise(ec->frame);
5779 
5780         if (e_client_util_ignored_get(ec)) return;
5781         if (e_pixmap_usable_get(ec->pixmap) && (!ec->lock_user_location))
5782           e_comp_object_util_center_on(ec->frame, parent->frame);
5783 
5784         if ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) ||
5785             (ec->parent->focused && (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))
5786           ec->take_focus = 1;
5787      }
5788 }
5789 
5790 static void
_e_client_stack_top(E_Client * ec_base EINA_UNUSED,E_Client * ec_stack,E_Client * ec_above)5791 _e_client_stack_top(E_Client *ec_base EINA_UNUSED,
5792                     E_Client *ec_stack, E_Client *ec_above)
5793 {
5794 /* complex stacking right above one dialog after the other hurts the
5795  * simple assumptions that the window should be on top by clients so
5796  * be dumber and disable this
5797    if (!ec_above)
5798      {
5799         evas_object_raise(ec_stack->frame);
5800         evas_object_stack_above(ec_base->frame, ec_stack->frame);
5801      }
5802    else
5803      {
5804         if (ec_above->transients)
5805           {
5806              e_client_transients_restack(ec_above);
5807              E_Client *ec_last = eina_list_last_data_get(ec_above->transients);
5808              if (ec_last)
5809                evas_object_stack_above(ec_stack->frame, ec_last->frame);
5810              else
5811                evas_object_stack_above(ec_stack->frame, ec_above->frame);
5812           }
5813         else
5814           evas_object_stack_above(ec_stack->frame, ec_above->frame);
5815      }
5816  */
5817    if (!ec_above) evas_object_raise(ec_stack->frame);
5818    else
5819      {
5820         if (ec_above->transients) e_client_transients_restack(ec_above);
5821         evas_object_raise(ec_stack->frame);
5822      }
5823 }
5824 
5825 E_API void
e_client_transients_restack(E_Client * ec)5826 e_client_transients_restack(E_Client *ec)
5827 {
5828    E_Client *child, *below = NULL;
5829    Eina_List *list;
5830 
5831    E_OBJECT_CHECK(ec);
5832    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
5833    if (!ec->transients) return;
5834 
5835    list = eina_list_clone(ec->transients);
5836    EINA_LIST_FREE(list, child)
5837      {
5838         // Don't stack iconic transients. If the user wants these shown,
5839         // that's another option.
5840         if (child->iconic) continue;
5841         _e_client_stack_top(ec, child, below);
5842         below = child;
5843      }
5844 }
5845