e_focus_policy_topmost: Use wl_listener instead of Hooks 71/300371/2
authorSooChan Lim <sc1.lim@samsung.com>
Wed, 4 Oct 2023 08:43:56 +0000 (17:43 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 23 Oct 2023 06:22:31 +0000 (06:22 +0000)
Change-Id: Ib5157a6c9bae5df6737275f4707d19d334d2f05b

src/bin/e_focus_policy_topmost.c

index 5fc1dc1..75edc33 100644 (file)
@@ -1,8 +1,11 @@
 #include "e.h"
+#include "e_zone_intern.h"
+#include "e_client_intern.h"
 
 #ifdef REFACTOR_FOCUS_POLICY
 
 typedef struct _E_Focus_Policy_Topmost_Impl E_Focus_Policy_Topmost;
+typedef struct _E_Focus_Policy_Topmost_Client E_Focus_Policy_Topmost_Client;
 
 struct _E_Focus_Policy_Topmost_Impl
 {
@@ -11,10 +14,43 @@ struct _E_Focus_Policy_Topmost_Impl
 
    GMutex focused_ec_mutex;
 
-   Eina_List *ec_hooks;
-   Eina_List *zone_hooks;
+   struct wl_listener zone_client_add;
+   struct wl_listener zone_client_remove;
+   struct wl_listener zone_focus_clear;
 };
 
+struct _E_Focus_Policy_Topmost_Client
+{
+   E_Client *ec;
+   E_Focus_Policy_Topmost *topmost_policy;
+
+   struct wl_listener client_destroy;
+   struct wl_listener client_mouse_in;
+   struct wl_listener client_mouse_out;
+   struct wl_listener client_mouse_down;
+   struct wl_listener client_focus_set;
+   struct wl_listener client_focus_unset;
+   struct wl_listener client_lower;
+   struct wl_listener client_move;
+   struct wl_listener client_eval_end;
+};
+
+// Trace the focus topmost
+//#define FOCUS_TOPMOST_TRACE
+#ifdef FOCUS_TOPMOST_TRACE
+#define E_FOCUS_TOPMOST_TRACE(topmost_policy, ec) \
+  do \
+    { \
+       ELOGF( \
+             "FOCUS_TOPMOST", "[FOCUS][Trace][%s]:(%p, %d) focused_ec:%p", ec, \
+             __FUNCTION__, topmost_policy, topmost_policy->zone->id, topmost_policy->focused_ec)\
+            ); \
+    } \
+  while (0)
+#else
+#define E_FOCUS_TOPMOST_TRACE(topmost_policy, ec)
+#endif
+
 static Eina_Bool
 _e_focus_policy_topmost_focus_can_take_by_vis_obscured(E_Client *ec)
 {
@@ -127,37 +163,51 @@ _focus_policy_topmost_next_focus_set(E_Focus_Policy_Topmost *topmost_policy)
 }
 
 static void
-_focus_policy_topmost_hook_cb_client_del(void *data, E_Client *ec)
+_focus_policy_topmost_cb_client_destroy(struct wl_listener *listener, void *data)
 {
+   E_Focus_Policy_Topmost_Client *topmost_client;
    E_Focus_Policy_Topmost *topmost_policy;
+   E_Client *ec;
 
-   topmost_policy = (E_Focus_Policy_Topmost *)data;
-   if (!topmost_policy) return;
+   topmost_client = wl_container_of(listener, topmost_client, client_destroy);
 
-   // find the next focus and set it when ec is focused.
-   if (ec->focused)
-     {
-        _focus_policy_topmost_next_focus_set(topmost_policy);
+   topmost_policy = topmost_client->topmost_policy;
+   EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
 
-        // check the critical case
-        if (topmost_policy->focused_ec == ec)
-          {
-             ELOGF("FOCUS_TOPMOST", "CRITICAL. focused is deleted ec.", ec);
-             ELOGF("FOCUS_TOPMOST", "CLIENT FOCUS_SET", NULL);
-             g_mutex_lock(&topmost_policy->focused_ec_mutex);
-             topmost_policy->focused_ec = NULL;
-             g_mutex_unlock(&topmost_policy->focused_ec_mutex);
-          }
-     }
+   ec = topmost_client->ec;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
+
+   wl_list_remove(&topmost_client->client_eval_end.link);
+   wl_list_remove(&topmost_client->client_move.link);
+   wl_list_remove(&topmost_client->client_lower.link);
+   wl_list_remove(&topmost_client->client_focus_unset.link);
+   wl_list_remove(&topmost_client->client_focus_set.link);
+   wl_list_remove(&topmost_client->client_mouse_down.link);
+   wl_list_remove(&topmost_client->client_mouse_out.link);
+   wl_list_remove(&topmost_client->client_mouse_in.link);
+   wl_list_remove(&topmost_client->client_destroy.link);
+
+   E_FREE(topmost_client);
 }
 
 static void
-_focus_policy_topmost_hook_cb_client_mouse_in(void *data, E_Client *ec)
+_focus_policy_topmost_cb_client_mouse_in(struct wl_listener *listener, void *data)
 {
+   E_Focus_Policy_Topmost_Client *topmost_client;
    E_Focus_Policy_Topmost *topmost_policy;
+   E_Client *ec;
 
-   topmost_policy = (E_Focus_Policy_Topmost *)data;
-   if (!topmost_policy) return;
+   topmost_client = wl_container_of(listener, topmost_client, client_mouse_in);
+
+   topmost_policy = topmost_client->topmost_policy;
+   EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
+
+   ec = topmost_client->ec;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
 
    if ((!ec->iconic) && (!e_client_util_ignored_get(ec)))
      {
@@ -170,19 +220,27 @@ _focus_policy_topmost_hook_cb_client_mouse_in(void *data, E_Client *ec)
 }
 
 static void
-_focus_policy_topmost_hook_cb_client_mouse_out(void *data, E_Client *ec)
+_focus_policy_topmost_cb_client_mouse_out(struct wl_listener *listener, void *data)
 {
    // nothing to do
 }
 
 static void
-_focus_policy_topmost_hook_cb_client_mouse_down(void *data, E_Client *ec)
+_focus_policy_topmost_cb_client_mouse_down(struct wl_listener *listener, void *data)
 {
+   E_Focus_Policy_Topmost_Client *topmost_client;
    E_Focus_Policy_Topmost *topmost_policy;
-   E_Client *focused_ec;
+   E_Client *focused_ec, *ec;
 
-   topmost_policy = (E_Focus_Policy_Topmost *)data;
-   if (!topmost_policy) return;
+   topmost_client = wl_container_of(listener, topmost_client, client_mouse_down);
+
+   topmost_policy = topmost_client->topmost_policy;
+   EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
+
+   ec = topmost_client->ec;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
 
    if (e_object_is_del(E_OBJECT(ec))) return;
 
@@ -211,15 +269,23 @@ _focus_policy_topmost_hook_cb_client_mouse_down(void *data, E_Client *ec)
 }
 
 static void
-_focus_policy_topmost_hook_cb_client_focus_set(void *data, E_Client *ec)
+_focus_policy_topmost_cb_client_focus_set(struct wl_listener *listener, void *data)
 {
+   E_Focus_Policy_Topmost_Client *topmost_client;
    E_Focus_Policy_Topmost *topmost_policy;
+   E_Client *focused_ec, *ec, *ec2;
    E_Zone *zone;
-   E_Client *focused_ec, *ec2;
    Eina_List *l, *ll;
 
-   topmost_policy = (E_Focus_Policy_Topmost *)data;
-   if (!topmost_policy) return;
+   topmost_client = wl_container_of(listener, topmost_client, client_focus_set);
+
+   topmost_policy = topmost_client->topmost_policy;
+   EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
+
+   ec = topmost_client->ec;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
 
    focused_ec = topmost_policy->focused_ec;
    if (ec == focused_ec) return;
@@ -258,19 +324,25 @@ _focus_policy_topmost_hook_cb_client_focus_set(void *data, E_Client *ec)
 }
 
 static void
-_focus_policy_topmost_hook_cb_client_focus_unset(void *data, E_Client *ec)
+_focus_policy_topmost_cb_client_focus_unset(struct wl_listener *listener, void *data)
 {
+   E_Focus_Policy_Topmost_Client *topmost_client;
    E_Focus_Policy_Topmost *topmost_policy;
+   E_Client *ec, *ec2;
    E_Zone *zone;
    E_Desk *desk, *desk2;
-   E_Client *ec2;
    Eina_List *l;
 
-   topmost_policy = (E_Focus_Policy_Topmost *)data;
-   if (!topmost_policy) return;
+   topmost_client = wl_container_of(listener, topmost_client, client_focus_unset);
+
+   topmost_policy = topmost_client->topmost_policy;
+   EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
 
+   ec = topmost_client->ec;
    EINA_SAFETY_ON_NULL_RETURN(ec);
 
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
+
    zone = topmost_policy->zone;
 
    ec->want_focus = ec->focused = 0;
@@ -310,12 +382,21 @@ _focus_policy_topmost_hook_cb_client_focus_unset(void *data, E_Client *ec)
 }
 
 static void
-_focus_policy_topmost_hook_cb_client_lower(void *data, E_Client *ec)
+_focus_policy_topmost_cb_client_lower(struct wl_listener *listener, void *data)
 {
+   E_Focus_Policy_Topmost_Client *topmost_client;
    E_Focus_Policy_Topmost *topmost_policy;
+   E_Client *ec;
 
-   topmost_policy = (E_Focus_Policy_Topmost *)data;
-   if (!topmost_policy) return;
+   topmost_client = wl_container_of(listener, topmost_client, client_lower);
+
+   topmost_policy = topmost_client->topmost_policy;
+   EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
+
+   ec = topmost_client->ec;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
 
    // no need to change the focused ec when ec is not focused.
    if (!ec->focused) return;
@@ -328,13 +409,22 @@ _focus_policy_topmost_hook_cb_client_lower(void *data, E_Client *ec)
 }
 
 static void
-_focus_policy_topmost_hook_cb_client_move(void *data, E_Client *ec)
+_focus_policy_topmost_cb_client_move(struct wl_listener *listener, void *data)
 {
+   E_Focus_Policy_Topmost_Client *topmost_client;
    E_Focus_Policy_Topmost *topmost_policy;
+   E_Client *ec;
    E_Zone *zone;
 
-   topmost_policy = (E_Focus_Policy_Topmost *)data;
-   if (!topmost_policy) return;
+   topmost_client = wl_container_of(listener, topmost_client, client_move);
+
+   topmost_policy = topmost_client->topmost_policy;
+   EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
+
+   ec = topmost_client->ec;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
 
    zone = e_comp_zone_find_by_ec(ec);
    if (!zone) return;
@@ -352,26 +442,111 @@ _focus_policy_topmost_hook_cb_client_move(void *data, E_Client *ec)
 }
 
 static void
-_focus_policy_topmost_hook_cb_client_eval_end(void *data, E_Client *ec)
+_focus_policy_topmost_cb_client_eval_end(struct wl_listener *listener, void *data)
 {
+   E_Focus_Policy_Topmost_Client *topmost_client;
    E_Focus_Policy_Topmost *topmost_policy;
+   E_Client *ec;
 
-   topmost_policy = (E_Focus_Policy_Topmost *)data;
-   if (!topmost_policy) return;
+   topmost_client = wl_container_of(listener, topmost_client, client_eval_end);
+
+   topmost_policy = topmost_client->topmost_policy;
+   EINA_SAFETY_ON_NULL_RETURN(topmost_policy);
+
+   ec = topmost_client->ec;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
 
    if (e_object_is_del(E_OBJECT(ec))) return;
 
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
+
    ec->take_focus = ec->want_focus = 0;
 }
 
 static void
-_focus_policy_topmost_hook_cb_zone_focus_clear(void *data, E_Zone *zone)
+_focus_policy_topmost_cb_zone_client_add(struct wl_listener *listener, void *data)
 {
    E_Focus_Policy_Topmost *topmost_policy;
+   E_Focus_Policy_Topmost_Client *topmost_client;
+   E_Client *ec;
 
-   topmost_policy = (E_Focus_Policy_Topmost *)data;
-   if (!topmost_policy) return;
+   topmost_policy = wl_container_of(listener, topmost_policy, zone_client_add);
+
+   ec = (E_Client *)data;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
+
+   topmost_client = E_NEW(E_Focus_Policy_Topmost_Client, 1);
+   EINA_SAFETY_ON_NULL_RETURN(topmost_client);
+
+   topmost_client->ec = ec;
+   topmost_client->topmost_policy = topmost_policy;
+
+   // e_client listeners
+   topmost_client->client_destroy.notify = _focus_policy_topmost_cb_client_destroy;
+   e_client_destroy_listener_add(ec, &topmost_client->client_destroy);
+   topmost_client->client_mouse_in.notify = _focus_policy_topmost_cb_client_mouse_in;
+   e_client_mouse_in_listener_add(ec, &topmost_client->client_mouse_in);
+   topmost_client->client_mouse_out.notify = _focus_policy_topmost_cb_client_mouse_out;
+   e_client_mouse_out_listener_add(ec, &topmost_client->client_mouse_out);
+   topmost_client->client_mouse_down.notify = _focus_policy_topmost_cb_client_mouse_down;
+   e_client_mouse_down_listener_add(ec, &topmost_client->client_mouse_down);
+   topmost_client->client_focus_set.notify = _focus_policy_topmost_cb_client_focus_set;
+   e_client_focus_set_listener_add(ec, &topmost_client->client_focus_set);
+   topmost_client->client_focus_unset.notify = _focus_policy_topmost_cb_client_focus_unset;
+   e_client_focus_unset_listener_add(ec, &topmost_client->client_focus_unset);
+   topmost_client->client_lower.notify = _focus_policy_topmost_cb_client_lower;
+   e_client_lower_listener_add(ec, &topmost_client->client_lower);
+   topmost_client->client_move.notify = _focus_policy_topmost_cb_client_move;
+   e_client_move_listener_add(ec, &topmost_client->client_move);
+   topmost_client->client_eval_end.notify = _focus_policy_topmost_cb_client_eval_end;
+   e_client_eval_end_listener_add(ec, &topmost_client->client_eval_end);
+
+   ELOGF("FOCUS_TOPMOST", "zone_client_add | ", ec);
+}
+
+static void
+_focus_policy_topmost_cb_zone_client_remove(struct wl_listener *listener, void *data)
+{
+   E_Focus_Policy_Topmost *topmost_policy;
+   E_Client *ec;
+
+   topmost_policy = wl_container_of(listener, topmost_policy, zone_client_remove);
+
+   ec = (E_Client *)data;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   E_FOCUS_TOPMOST_TRACE(topmost_policy, ec);
+
+   ELOGF("FOCUS_TOPMOST", "zone_client_remove | ", ec);
+
+   // find the next focus and set it when ec is focused.
+   if (ec->focused)
+     {
+        _focus_policy_topmost_next_focus_set(topmost_policy);
+
+        // check the critical case
+        if (topmost_policy->focused_ec == ec)
+          {
+             ELOGF("FOCUS_TOPMOST", "CRITICAL. focused is deleted ec.", ec);
+             ELOGF("FOCUS_TOPMOST", "CLIENT FOCUS_SET", NULL);
+             g_mutex_lock(&topmost_policy->focused_ec_mutex);
+             topmost_policy->focused_ec = NULL;
+             g_mutex_unlock(&topmost_policy->focused_ec_mutex);
+          }
+     }
+}
+
+static void
+_focus_policy_topmost_cb_zone_focus_clear(struct wl_listener *listener, void *data)
+{
+   E_Focus_Policy_Topmost *topmost_policy;
+   E_Zone *zone;
+
+   topmost_policy = wl_container_of(listener, topmost_policy, zone_focus_clear);
 
+   zone = (E_Zone *)data;
    if (topmost_policy->zone != zone) return;
 
    // make focused_ec be NULL
@@ -389,8 +564,9 @@ _focus_policy_topmost_del(E_Focus_Policy_Impl *impl)
 
    if (!topmost_policy) return;
 
-   E_FREE_LIST(topmost_policy->zone_hooks, e_zone_hook_del);
-   E_FREE_LIST(topmost_policy->ec_hooks, e_client_hook_del);
+   wl_list_remove(&topmost_policy->zone_focus_clear.link);
+   wl_list_remove(&topmost_policy->zone_client_remove.link);
+   wl_list_remove(&topmost_policy->zone_client_add.link);
 
    g_mutex_clear(&topmost_policy->focused_ec_mutex);
 
@@ -451,7 +627,6 @@ e_focus_policy_iface_topmost_new(E_Zone* zone)
 {
    E_Focus_Policy_Iface *policy_iface;
    E_Focus_Policy_Topmost *topmost_policy;
-   E_Zone_Hook *zone_hook;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(zone, NULL);
 
@@ -469,20 +644,13 @@ e_focus_policy_iface_topmost_new(E_Zone* zone)
    policy_iface->focused_ec_get = _focus_policy_topmost_focused_ec_get;
    policy_iface->update = _focus_policy_topmost_update;
 
-   // e_client hooks
-   E_LIST_HOOK_APPEND(topmost_policy->ec_hooks, E_CLIENT_HOOK_DEL, _focus_policy_topmost_hook_cb_client_del, topmost_policy);
-   E_LIST_HOOK_APPEND(topmost_policy->ec_hooks, E_CLIENT_HOOK_MOUSE_IN, _focus_policy_topmost_hook_cb_client_mouse_in, topmost_policy);
-   E_LIST_HOOK_APPEND(topmost_policy->ec_hooks, E_CLIENT_HOOK_MOUSE_OUT, _focus_policy_topmost_hook_cb_client_mouse_out, topmost_policy);
-   E_LIST_HOOK_APPEND(topmost_policy->ec_hooks, E_CLIENT_HOOK_MOUSE_DOWN, _focus_policy_topmost_hook_cb_client_mouse_down, topmost_policy);
-   E_LIST_HOOK_APPEND(topmost_policy->ec_hooks, E_CLIENT_HOOK_FOCUS_SET, _focus_policy_topmost_hook_cb_client_focus_set, topmost_policy);
-   E_LIST_HOOK_APPEND(topmost_policy->ec_hooks, E_CLIENT_HOOK_FOCUS_UNSET, _focus_policy_topmost_hook_cb_client_focus_unset, topmost_policy);
-   E_LIST_HOOK_APPEND(topmost_policy->ec_hooks, E_CLIENT_HOOK_LOWER, _focus_policy_topmost_hook_cb_client_lower, topmost_policy);
-   E_LIST_HOOK_APPEND(topmost_policy->ec_hooks, E_CLIENT_HOOK_MOVE, _focus_policy_topmost_hook_cb_client_move, topmost_policy);
-   E_LIST_HOOK_APPEND(topmost_policy->ec_hooks, E_CLIENT_HOOK_EVAL_END, _focus_policy_topmost_hook_cb_client_eval_end, topmost_policy);
-
-   // e_zone hooks
-   zone_hook = e_zone_hook_add(E_ZONE_HOOK_FOCUS_CLEAR, _focus_policy_topmost_hook_cb_zone_focus_clear, topmost_policy);
-   if (zone_hook) topmost_policy->zone_hooks = eina_list_append(topmost_policy->zone_hooks, zone_hook);
+   // zone listeners
+   topmost_policy->zone_client_add.notify = _focus_policy_topmost_cb_zone_client_add;
+   e_zone_client_add_listener_add(zone, &topmost_policy->zone_client_add);
+   topmost_policy->zone_client_remove.notify = _focus_policy_topmost_cb_zone_client_remove;
+   e_zone_client_remove_listener_add(zone, &topmost_policy->zone_client_remove);
+   topmost_policy->zone_focus_clear.notify = _focus_policy_topmost_cb_zone_focus_clear;
+   e_zone_focus_clear_listener_add(zone, &topmost_policy->zone_focus_clear);
 
    return policy_iface;