1 #include "e_focus_policy_iface.h"
2 #include "e_zone_intern.h"
3 #include "e_client_intern.h"
4 #include "e_desk_intern.h"
5 #include "e_config_intern.h"
7 typedef struct _E_Focus_Policy_Topmost_Impl E_Focus_Policy_Topmost;
8 typedef struct _E_Focus_Policy_Topmost_Client E_Focus_Policy_Topmost_Client;
10 struct _E_Focus_Policy_Topmost_Impl
17 struct wl_signal focused_ec_changed;
20 struct wl_listener zone_client_add;
21 struct wl_listener zone_client_remove;
22 struct wl_listener zone_focus_clear;
25 struct _E_Focus_Policy_Topmost_Client
28 E_Focus_Policy_Topmost *topmost_policy;
30 struct wl_listener client_destroy;
31 struct wl_listener client_mouse_in;
32 struct wl_listener client_mouse_out;
33 struct wl_listener client_mouse_down;
34 struct wl_listener client_focus_set;
35 struct wl_listener client_focus_unset;
36 struct wl_listener client_lower;
37 struct wl_listener client_move;
38 struct wl_listener client_eval_end;
41 // Trace the focus topmost
42 //#define FOCUS_TOPMOST_TRACE
43 #ifdef FOCUS_TOPMOST_TRACE
44 #define E_FOCUS_TOPMOST_TRACE(topmost_policy, ec) \
48 "FOCUS_TOPMOST", "[FOCUS][Trace][%s]:(%p, %d) focused_ec:%p", ec, \
49 __FUNCTION__, topmost_policy, topmost_policy->zone->id, topmost_policy->focused_ec)\
54 #define E_FOCUS_TOPMOST_TRACE(topmost_policy, ec)
58 _e_focus_policy_topmost_focus_can_take_by_vis_obscured(E_Client *ec)
60 switch (e_client_visibility_get(ec))
62 case E_VISIBILITY_UNKNOWN:
63 case E_VISIBILITY_FULLY_OBSCURED:
64 if (e_client_check_really_iconified(ec))
67 case E_VISIBILITY_UNOBSCURED:
68 case E_VISIBILITY_PARTIALLY_OBSCURED:
69 case E_VISIBILITY_PRE_UNOBSCURED:
77 _e_focus_policy_topmost_focus_can_take(E_Client *ec)
80 E_Client *child_ec, *above_ec;
81 int x = 0, y = 0, w = 0, h = 0;
83 if (!ec) return EINA_FALSE;
84 if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
85 if (e_client_util_ignored_get(ec)) return EINA_FALSE;
87 if (!(ec->icccm.accepts_focus || ec->icccm.take_focus)) return EINA_FALSE;
88 if (ec->lock_focus_in || ec->lock_focus_out) return EINA_FALSE;
90 if (!ec->visible) return EINA_FALSE;
91 if (ec->bg_state) return EINA_FALSE;
92 if (ec->visibility.force_obscured) return EINA_FALSE;
93 if (!_e_focus_policy_topmost_focus_can_take_by_vis_obscured(ec)) return EINA_FALSE;
95 zone = e_comp_zone_find_by_ec(ec);
98 e_client_geometry_get(ec, &x, &y, &w, &h);
99 if (!E_INTERSECTS(zone->x, zone->y, zone->w, zone->h, x, y, w, h))
103 above_ec = e_client_check_fully_contain_by_above(ec, EINA_FALSE);
106 if (!evas_object_visible_get(above_ec->frame))
109 child_ec = e_client_check_obscured_by_children_group(ec);
110 if (!child_ec) return EINA_FALSE;
111 if (above_ec != child_ec) return EINA_FALSE;
113 if (_e_focus_policy_topmost_focus_can_take(child_ec))
115 else if (e_client_check_fully_contain_by_above(child_ec, EINA_FALSE))
123 _e_focus_policy_topmost_focusable_get(void)
127 E_CLIENT_REVERSE_FOREACH(ec)
129 if (_e_focus_policy_topmost_focus_can_take(ec))
137 _focus_policy_topmost_next_focus_set(E_Focus_Policy_Topmost *topmost_policy)
139 E_Client *focusable_ec, *focused_ec;
141 // current focused ec
142 focused_ec = topmost_policy->focused_ec;
145 focusable_ec = _e_focus_policy_topmost_focusable_get();
146 if (focusable_ec == focused_ec) return;
150 if (!focusable_ec->iconic || focusable_ec->exp_iconify.buffer_flush)
152 ELOGF("FOCUS_TOPMOST", "focus set | topmost_focus", focusable_ec);
155 e_client_frame_focus_set(focused_ec, EINA_FALSE);
157 e_client_frame_focus_set(focusable_ec, EINA_TRUE);
162 ELOGF("FOCUS_TOPMOST", "focus unset | No focusable ec", focused_ec);
164 e_client_frame_focus_set(focused_ec, EINA_FALSE);
169 _focus_policy_topmost_cb_client_destroy(struct wl_listener *listener, void *data)
171 E_Focus_Policy_Topmost_Client *topmost_client;
172 E_Focus_Policy_Topmost *topmost_policy;
175 topmost_client = wl_container_of(listener, topmost_client, client_destroy);
177 topmost_policy = topmost_client->topmost_policy;
178 EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
180 ec = topmost_client->ec;
181 EINA_SAFETY_ON_NULL_RETURN(ec);
183 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
185 wl_list_remove(&topmost_client->client_eval_end.link);
186 wl_list_remove(&topmost_client->client_move.link);
187 wl_list_remove(&topmost_client->client_lower.link);
188 wl_list_remove(&topmost_client->client_focus_unset.link);
189 wl_list_remove(&topmost_client->client_focus_set.link);
190 wl_list_remove(&topmost_client->client_mouse_down.link);
191 wl_list_remove(&topmost_client->client_mouse_out.link);
192 wl_list_remove(&topmost_client->client_mouse_in.link);
193 wl_list_remove(&topmost_client->client_destroy.link);
195 E_FREE(topmost_client);
199 _focus_policy_topmost_cb_client_mouse_in(struct wl_listener *listener, void *data)
201 E_Focus_Policy_Topmost_Client *topmost_client;
202 E_Focus_Policy_Topmost *topmost_policy;
205 topmost_client = wl_container_of(listener, topmost_client, client_mouse_in);
207 topmost_policy = topmost_client->topmost_policy;
208 EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
210 ec = topmost_client->ec;
211 EINA_SAFETY_ON_NULL_RETURN(ec);
213 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
215 if ((!ec->iconic) && (!e_client_util_ignored_get(ec)))
217 if (e_config->use_auto_raise)
219 if (!ec->lock_user_stacking)
226 _focus_policy_topmost_cb_client_mouse_out(struct wl_listener *listener, void *data)
232 _focus_policy_topmost_cb_client_mouse_down(struct wl_listener *listener, void *data)
234 E_Focus_Policy_Topmost_Client *topmost_client;
235 E_Focus_Policy_Topmost *topmost_policy;
236 E_Client *focused_ec, *ec;
238 topmost_client = wl_container_of(listener, topmost_client, client_mouse_down);
240 topmost_policy = topmost_client->topmost_policy;
241 EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
243 ec = topmost_client->ec;
244 EINA_SAFETY_ON_NULL_RETURN(ec);
246 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
248 if (e_object_is_del(E_OBJECT(ec))) return;
250 focused_ec = topmost_policy->focused_ec;
251 if ((focused_ec) && (ec != focused_ec))
253 if (e_client_focus_policy_click(ec) ||
254 e_config->always_click_to_focus)
260 if (e_config->always_click_to_raise)
262 if (!ec->lock_user_stacking)
265 if (ec->parent && e_client_is_belong_to_parent(ec))
267 if (!ec->parent->lock_user_stacking)
268 e_client_raise(ec->parent);
274 static void set_focused_ec(E_Focus_Policy_Topmost *topmost_policy, E_Client *ec)
276 atomic_store(&topmost_policy->focused_ec, ec);
278 wl_signal_emit(&topmost_policy->events.focused_ec_changed, ec);
282 _focus_policy_topmost_cb_client_focus_set(struct wl_listener *listener, void *data)
284 E_Focus_Policy_Topmost_Client *topmost_client;
285 E_Focus_Policy_Topmost *topmost_policy;
286 #ifdef REFACTOR_DESK_AREA
287 E_Client *focused_ec, *ec;
289 E_Client *focused_ec, *ec, *ec2;
294 topmost_client = wl_container_of(listener, topmost_client, client_focus_set);
296 topmost_policy = topmost_client->topmost_policy;
297 EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
299 ec = topmost_client->ec;
300 EINA_SAFETY_ON_NULL_RETURN(ec);
302 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
304 focused_ec = topmost_policy->focused_ec;
305 if (ec == focused_ec) return;
307 #ifdef REFACTOR_DESK_AREA
309 zone = topmost_policy->zone;
314 #ifdef REFACTOR_DESK_AREA
316 // TODO: This is not for focus policy, but for fullscreen(Window State) policy.
317 // Move this code to the better place.
318 int x, total = zone->desk_x_count * zone->desk_y_count;
319 for (x = 0; x < total; x++)
321 E_Desk *desk = zone->desks[x];
322 /* if there's any fullscreen non-parents on this desk, unfullscreen them */
323 EINA_LIST_FOREACH_SAFE(desk->fullscreen_clients, l, ll, ec2)
325 if (ec2 == ec) continue;
326 if (e_object_is_del(E_OBJECT(ec2))) continue;
327 /* but only if it's the same desk or one of the clients is sticky */
328 if ((e_desk_has_ec(desk, ec2)) || (ec->sticky || ec2->sticky))
330 if (!eina_list_data_find(ec->transients, ec2))
331 e_client_unfullscreen(ec2);
337 // assign the focused_ec
338 set_focused_ec(topmost_policy, ec);
340 ELOGF("FOCUS_TOPMOST", "focus_set | focused_ec SET", ec);
344 _focus_policy_topmost_cb_client_focus_unset(struct wl_listener *listener, void *data)
346 E_Focus_Policy_Topmost_Client *topmost_client;
347 E_Focus_Policy_Topmost *topmost_policy;
350 E_Desk *desk, *desk2;
353 topmost_client = wl_container_of(listener, topmost_client, client_focus_unset);
355 topmost_policy = topmost_client->topmost_policy;
356 EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
358 ec = topmost_client->ec;
359 EINA_SAFETY_ON_NULL_RETURN(ec);
361 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
363 zone = topmost_policy->zone;
365 ec->want_focus = ec->focused = 0;
366 if (ec->mouse.in && ec && (!e_client_util_is_popup(ec)) &&
367 (e_config->focus_policy != E_FOCUS_CLICK))
368 e_client_mouse_out(ec, ec->x - 1, ec->y - 1);
370 desk = e_zone_desk_find_by_ec(zone, ec);
371 /* if there unfocus client is fullscreen and visible */
372 if ((ec->fullscreen) && (!ec->iconic) && (!ec->hidden) &&
373 ((desk == e_desk_current_get(zone)) || (ec->sticky)))
375 Eina_Bool have_vis_child = EINA_FALSE;
377 /* if any of its children are visible */
378 EINA_LIST_FOREACH(ec->transients, l, ec2)
380 desk2 = e_zone_desk_find_by_ec(zone, ec2);
381 if (((desk2 == desk) ||
382 (ec2->sticky) || (ec->sticky)))
384 have_vis_child = EINA_TRUE;
388 /* if no children are visible, unfullscreen */
389 if ((!e_object_is_del(E_OBJECT(ec))) && (!have_vis_child))
390 e_client_unfullscreen(ec);
393 // assign the focused_ec
394 set_focused_ec(topmost_policy, NULL);
396 ELOGF("FOCUS_TOPMOST", "focus_unset | focused_ec UNSET", NULL);
400 _focus_policy_topmost_cb_client_lower(struct wl_listener *listener, void *data)
402 E_Focus_Policy_Topmost_Client *topmost_client;
403 E_Focus_Policy_Topmost *topmost_policy;
406 topmost_client = wl_container_of(listener, topmost_client, client_lower);
408 topmost_policy = topmost_client->topmost_policy;
409 EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
411 ec = topmost_client->ec;
412 EINA_SAFETY_ON_NULL_RETURN(ec);
414 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
416 // no need to change the focused ec when ec is not focused.
417 if (!ec->focused) return;
419 // no need to change the focused ec when calc_vis_without_effect is not set.
420 if (e_config->calc_vis_without_effect) return;
422 // find the next focus and set it
423 _focus_policy_topmost_next_focus_set(topmost_policy);
427 _focus_policy_topmost_cb_client_move(struct wl_listener *listener, void *data)
429 E_Focus_Policy_Topmost_Client *topmost_client;
430 E_Focus_Policy_Topmost *topmost_policy;
434 topmost_client = wl_container_of(listener, topmost_client, client_move);
436 topmost_policy = topmost_client->topmost_policy;
437 EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
439 ec = topmost_client->ec;
440 EINA_SAFETY_ON_NULL_RETURN(ec);
442 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
444 zone = e_comp_zone_find_by_ec(ec);
447 // no need to change the focused ec when ec is not focused.
448 if (!ec->focused) return;
450 // no need to change the focused ec when ec is in the area of a zone.
451 if (!E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
452 zone->x, zone->y, zone->w, zone->h))
454 // find the next focus and set it
455 _focus_policy_topmost_next_focus_set(topmost_policy);
460 _focus_policy_topmost_cb_client_eval_end(struct wl_listener *listener, void *data)
462 E_Focus_Policy_Topmost_Client *topmost_client;
463 E_Focus_Policy_Topmost *topmost_policy;
466 topmost_client = wl_container_of(listener, topmost_client, client_eval_end);
468 topmost_policy = topmost_client->topmost_policy;
469 EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
471 ec = topmost_client->ec;
472 EINA_SAFETY_ON_NULL_RETURN(ec);
474 if (e_object_is_del(E_OBJECT(ec))) return;
476 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
478 ec->take_focus = ec->want_focus = 0;
482 _focus_policy_topmost_cb_zone_client_add(struct wl_listener *listener, void *data)
484 E_Focus_Policy_Topmost *topmost_policy;
485 E_Focus_Policy_Topmost_Client *topmost_client;
488 topmost_policy = wl_container_of(listener, topmost_policy, zone_client_add);
490 ec = (E_Client *)data;
491 EINA_SAFETY_ON_NULL_RETURN(ec);
493 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
495 topmost_client = E_NEW(E_Focus_Policy_Topmost_Client, 1);
496 EINA_SAFETY_ON_NULL_RETURN(topmost_client);
498 topmost_client->ec = ec;
499 topmost_client->topmost_policy = topmost_policy;
501 // e_client listeners
502 topmost_client->client_destroy.notify = _focus_policy_topmost_cb_client_destroy;
503 e_client_destroy_listener_add(ec, &topmost_client->client_destroy);
504 topmost_client->client_mouse_in.notify = _focus_policy_topmost_cb_client_mouse_in;
505 e_client_mouse_in_listener_add(ec, &topmost_client->client_mouse_in);
506 topmost_client->client_mouse_out.notify = _focus_policy_topmost_cb_client_mouse_out;
507 e_client_mouse_out_listener_add(ec, &topmost_client->client_mouse_out);
508 topmost_client->client_mouse_down.notify = _focus_policy_topmost_cb_client_mouse_down;
509 e_client_mouse_down_listener_add(ec, &topmost_client->client_mouse_down);
510 topmost_client->client_focus_set.notify = _focus_policy_topmost_cb_client_focus_set;
511 e_client_focus_set_listener_add(ec, &topmost_client->client_focus_set);
512 topmost_client->client_focus_unset.notify = _focus_policy_topmost_cb_client_focus_unset;
513 e_client_focus_unset_listener_add(ec, &topmost_client->client_focus_unset);
514 topmost_client->client_lower.notify = _focus_policy_topmost_cb_client_lower;
515 e_client_lower_listener_add(ec, &topmost_client->client_lower);
516 topmost_client->client_move.notify = _focus_policy_topmost_cb_client_move;
517 e_client_move_listener_add(ec, &topmost_client->client_move);
518 topmost_client->client_eval_end.notify = _focus_policy_topmost_cb_client_eval_end;
519 e_client_eval_end_listener_add(ec, &topmost_client->client_eval_end);
521 ELOGF("FOCUS_TOPMOST", "zone_client_add | ", ec);
525 _focus_policy_topmost_cb_zone_client_remove(struct wl_listener *listener, void *data)
527 E_Focus_Policy_Topmost *topmost_policy;
530 topmost_policy = wl_container_of(listener, topmost_policy, zone_client_remove);
532 ec = (E_Client *)data;
533 EINA_SAFETY_ON_NULL_RETURN(ec);
535 E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
537 ELOGF("FOCUS_TOPMOST", "zone_client_remove | ", ec);
539 // find the next focus and set it when ec is focused.
542 _focus_policy_topmost_next_focus_set(topmost_policy);
544 // check the critical case
545 if (topmost_policy->focused_ec == ec)
547 ELOGF("FOCUS_TOPMOST", "CRITICAL. focused is deleted ec.", ec);
548 ELOGF("FOCUS_TOPMOST", "CLIENT FOCUS_SET", NULL);
549 set_focused_ec(topmost_policy, NULL);
555 _focus_policy_topmost_cb_zone_focus_clear(struct wl_listener *listener, void *data)
557 E_Focus_Policy_Topmost *topmost_policy;
560 topmost_policy = wl_container_of(listener, topmost_policy, zone_focus_clear);
562 zone = (E_Zone *)data;
563 if (topmost_policy->zone != zone) return;
565 // make focused_ec be NULL
566 set_focused_ec(topmost_policy, NULL);
568 ELOGF("FOCUS_TOPMOST", "focus_clear | focused_ec UNSET", NULL);
572 _focus_policy_topmost_del(E_Focus_Policy_Impl *impl)
574 E_Focus_Policy_Topmost *topmost_policy = (E_Focus_Policy_Topmost *)impl;
576 if (!topmost_policy) return;
578 wl_list_remove(&topmost_policy->zone_focus_clear.link);
579 wl_list_remove(&topmost_policy->zone_client_remove.link);
580 wl_list_remove(&topmost_policy->zone_client_add.link);
582 E_FREE(topmost_policy);
586 _focus_policy_topmost_focused_ec_get(E_Focus_Policy_Impl *impl)
588 E_Focus_Policy_Topmost *topmost_policy;
589 E_Client *focused_ec = NULL;
591 topmost_policy = (E_Focus_Policy_Topmost *)impl;
592 EINA_SAFETY_ON_NULL_RETURN_VAL(topmost_policy, NULL);
594 focused_ec = atomic_load(&topmost_policy->focused_ec);
600 _focus_policy_topmost_update(E_Focus_Policy_Impl *impl)
602 E_Focus_Policy_Topmost *topmost_policy;
604 E_Client *focusable_ec, *focused_ec;
606 topmost_policy = (E_Focus_Policy_Topmost *)impl;
607 EINA_SAFETY_ON_NULL_RETURN_VAL(topmost_policy, EINA_FALSE);
609 zone = topmost_policy->zone;
610 EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
612 // no need to update the focused ec when zone is not displaying
613 if (!e_zone_is_displaying(zone)) return EINA_FALSE;
615 // current focused ec
616 focused_ec = topmost_policy->focused_ec;
619 focusable_ec = _e_focus_policy_topmost_focusable_get();
620 if (focusable_ec == focused_ec) return EINA_TRUE;
622 e_client_frame_focus_set(focused_ec, EINA_FALSE);
626 ELOGF("FOCUS_TOPMOST", "focus set | topmost focus calculate Zone(%d)", focusable_ec, zone->id);
627 e_client_frame_focus_set(focusable_ec, EINA_TRUE);
631 ELOGF("FOCUS_TOPMOST", "focus unset | No focusable ec Zone(%d)", focused_ec, zone->id);
638 _focus_policy_topmost_focused_ec_changed_listener_add(E_Focus_Policy_Impl *impl, struct wl_listener *listener)
640 E_Focus_Policy_Topmost *topmost_policy;
642 topmost_policy = (E_Focus_Policy_Topmost *)impl;
643 EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
645 wl_signal_add(&topmost_policy->events.focused_ec_changed, listener);
648 EINTERN E_Focus_Policy_Iface *
649 e_focus_policy_iface_topmost_new(E_Zone* zone)
651 E_Focus_Policy_Iface *policy_iface;
652 E_Focus_Policy_Topmost *topmost_policy;
654 EINA_SAFETY_ON_NULL_RETURN_VAL(zone, NULL);
656 policy_iface = E_NEW(E_Focus_Policy_Iface, 1);
657 EINA_SAFETY_ON_NULL_RETURN_VAL(policy_iface, NULL);
659 topmost_policy = E_NEW(E_Focus_Policy_Topmost, 1);
660 EINA_SAFETY_ON_NULL_GOTO(topmost_policy, fail);
662 topmost_policy->zone = zone;
664 wl_signal_init(&topmost_policy->events.focused_ec_changed);
666 policy_iface->impl = (E_Focus_Policy_Impl *)topmost_policy;
667 policy_iface->del = _focus_policy_topmost_del;
668 policy_iface->focused_ec_get = _focus_policy_topmost_focused_ec_get;
669 policy_iface->update = _focus_policy_topmost_update;
670 policy_iface->focused_ec_changed_listener_add = _focus_policy_topmost_focused_ec_changed_listener_add;
673 topmost_policy->zone_client_add.notify = _focus_policy_topmost_cb_zone_client_add;
674 e_zone_client_add_listener_add(zone, &topmost_policy->zone_client_add);
675 topmost_policy->zone_client_remove.notify = _focus_policy_topmost_cb_zone_client_remove;
676 e_zone_client_remove_listener_add(zone, &topmost_policy->zone_client_remove);
677 topmost_policy->zone_focus_clear.notify = _focus_policy_topmost_cb_zone_focus_clear;
678 e_zone_focus_clear_listener_add(zone, &topmost_policy->zone_focus_clear);
683 _focus_policy_topmost_del(topmost_policy);
685 E_FREE(policy_iface);