support modal feature 10/308810/1
authorDoyoun Kang <doyoun.kang@samsung.com>
Mon, 1 Apr 2024 10:20:31 +0000 (19:20 +0900)
committerDoyoun Kang <doyoun.kang@samsung.com>
Mon, 1 Apr 2024 10:20:31 +0000 (19:20 +0900)
We add the modal feature for transient_for child.
If the child set the modal state, then the parent of it cannot get focus and input event.

FYI, this feature is supported since tizen_policy version 13.

Change-Id: Ibedf7aeb32dc55533de518500aa2a8c81e14ed25

src/bin/e_client.c
src/bin/e_client.h
src/bin/e_comp_object.c
src/bin/e_comp_wl.c
src/bin/e_focus_policy_history.c
src/bin/e_info_server.c
src/bin/e_info_shared_types.h
src/bin/e_policy_stack.c
src/bin/e_policy_wl.c

index 694ed491cd0dffc29822750f28050b1621aa0f91..a5bd8a6bea84ab5ead069e69d39fb73be9cb38dd 100644 (file)
@@ -80,6 +80,8 @@ struct _E_Client_Private
 
    Eina_Bool hide_by_request;
    Eina_Bool focus_check;
+
+   E_Client *modal;
 };
 
 static int _e_client_hooks_delete = 0;
@@ -1063,6 +1065,8 @@ _e_client_del(E_Client *ec)
 
    if (ec->parent)
      {
+        if (e_client_modal_child_get(ec->parent) == ec)
+          e_client_modal_child_set(ec->parent, NULL);
         ec->parent->transients = eina_list_remove(ec->parent->transients, ec);
         ec->parent = NULL;
      }
@@ -3012,6 +3016,49 @@ e_client_mapped_set(E_Client *ec, Eina_Bool set)
    cdata->mapped = set;
 }
 
+EINTERN void
+e_client_modal_child_set(E_Client *ec, E_Client *modal)
+{
+   API_ENTRY;
+
+   E_Client *old_modal = priv->modal;
+   if (old_modal == modal) return;
+
+   ELOGF("E_CLIENT", "SET modal. new(ec:%p, win:0x%08zx), old(ec:%p, win:0x%08zx)", ec,
+         modal, e_client_util_win_get(modal), old_modal, e_client_util_win_get(old_modal));
+
+   // TODO: if ec has a modal window already, then how does we do?
+   priv->modal = modal;
+}
+
+EINTERN E_Client *
+e_client_modal_child_get(E_Client *ec)
+{
+   API_ENTRY_VAL(NULL);
+   return priv->modal;
+}
+
+EINTERN void
+e_client_modal_state_set(E_Client *ec, Eina_Bool modal)
+{
+   if (!ec) return;
+   ec->netwm.state.modal = modal;
+
+   if (ec->parent)
+     {
+        if (ec->netwm.state.modal)
+          e_client_modal_child_set(ec->parent, ec);
+        else
+          e_client_modal_child_set(ec->parent, NULL);
+     }
+}
+
+EINTERN Eina_Bool
+e_client_is_modal_state(E_Client *ec)
+{
+   if (!ec) return EINA_FALSE;
+   return ec->netwm.state.modal;
+}
 
 ////////////////////////////////////////////////
 EINTERN Eina_Bool
index 5013769585202bdc50a0ad5bad8eab4da1e72452..c19da87b6c87e23949996c93e7bf1d7f2d193bc9 100644 (file)
@@ -1180,6 +1180,10 @@ E_API void      e_client_post_raise_lower_set(E_Client *ec, Eina_Bool raise_set,
 E_API Eina_Bool e_client_first_mapped_get(E_Client *ec);
 EINTERN Eina_Bool e_client_mapped_get(E_Client *ec);
 EINTERN void      e_client_mapped_set(E_Client *ec, Eina_Bool set);
+EINTERN void      e_client_modal_child_set(E_Client *ec, E_Client *modal_child);
+EINTERN E_Client *e_client_modal_child_get(E_Client *ec);
+EINTERN void      e_client_modal_state_set(E_Client *ec, Eina_Bool modal);
+EINTERN Eina_Bool e_client_is_modal_state(E_Client *ec);
 
 E_API void e_client_transform_update(E_Client *ec);
 EINTERN void e_client_transform_apply(E_Client *ec, double degree, double zoom, int cx, int cy);
index 902b53de26c8ef72e372fc77acd7f3e20c1218df..d0b2e82da1328d4c734428fa6455eb897de6e40a 100644 (file)
@@ -2793,6 +2793,20 @@ _e_comp_intercept_focus(void *data, Evas_Object *obj, Eina_Bool focus)
 
    if (focus)
      {
+        /* check for modal child and set focus to modal child */
+        E_Client *modal_child = e_client_modal_child_get(ec);
+        if ((modal_child) && (modal_child != ec) &&
+            (!e_client_is_iconified_by_client(modal_child)) &&
+            (modal_child->visible) && (!e_object_is_del(E_OBJECT(modal_child))))
+          {
+             // add ec to latest focus stack
+             e_client_focus_latest_set(ec);
+
+             ELOGF("FOCUS", "FOCUS SET to MODAL (ec:%p, win:0x%08zx, frame:%p)", ec, modal_child, e_client_util_win_get(modal_child), modal_child->frame);
+             //e_client_focused_set(modal_child);
+             evas_object_focus_set(modal_child->frame, focus);
+             return;
+          }
         if (!cw->visible)
           {
              /* not yet visible, wait till the next time... */
index 7728a6a042a2693db3b23af5690cbce9cf4bee4f..fe04a78000158e9b00f58dd3a7dd6bca1a41cb91 100644 (file)
@@ -1244,6 +1244,22 @@ _e_comp_wl_check_cursor_timer_needed(E_Client *ec)
    return EINA_TRUE;
 }
 
+static Eina_Bool
+_e_comp_wl_check_block_input(E_Client *ec)
+{
+   E_Client *modal_child = e_client_modal_child_get(ec);
+   if (modal_child)
+     {
+        if (modal_child->visible && !modal_child->iconic && (modal_child->visibility.obscured == E_VISIBILITY_UNOBSCURED))
+          {
+             ELOGF("Touch", "Block touch by Modal child(ec:%p, win:0x%08zx)", ec, modal_child, e_client_util_win_get(modal_child));
+             return EINA_TRUE;
+          }
+     }
+
+   return EINA_FALSE;
+}
+
 static void
 _e_comp_wl_evas_cb_mouse_in(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
 {
@@ -1374,6 +1390,8 @@ _e_comp_wl_send_touch(E_Client *ec, int idx, int canvas_x, int canvas_y, uint32_
 
    if (!ec) return;
    if (e_object_is_del(E_OBJECT(ec))) return;
+   if (_e_comp_wl_check_block_input(ec)) return;
+
    struct wl_resource *surface = e_comp_wl_client_surface_get(ec);
    if (!surface) return;
 
@@ -1422,6 +1440,8 @@ _e_comp_wl_send_touch_move(E_Client *ec, int idx, int canvas_x, int canvas_y, ui
    if (!ec) return;
    if (ec->cur_mouse_action) return;
    if (e_object_is_del(E_OBJECT(ec))) return;
+   if (_e_comp_wl_check_block_input(ec)) return;
+
    struct wl_resource *surface = e_comp_wl_client_surface_get(ec);
    if (!surface) return;
 
@@ -1584,6 +1604,7 @@ _e_comp_wl_evas_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *o
 
    if (!ec) return;
    if (e_object_is_del(E_OBJECT(ec))) return;
+   if (_e_comp_wl_check_block_input(ec)) return;
 
    dev = ev->dev;
    dev_name = evas_device_description_get(dev);
@@ -1642,6 +1663,7 @@ _e_comp_wl_evas_cb_mouse_up(void *data, Evas *evas, Evas_Object *obj, void *even
    if (!ec) return;
    if (ec->cur_mouse_action) return;
    if (e_object_is_del(E_OBJECT(ec))) return;
+   if (_e_comp_wl_check_block_input(ec)) return;
 
    if (!need_send_released)
      {
@@ -1778,6 +1800,8 @@ _e_comp_wl_evas_cb_multi_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *o
 
    if (!ec) return;
    if (e_object_is_del(E_OBJECT(ec))) return;
+   if (_e_comp_wl_check_block_input(ec)) return;
+
    struct wl_resource *surface = e_comp_wl_client_surface_get(ec);
    if (!surface) return;
 
@@ -1822,6 +1846,8 @@ _e_comp_wl_evas_cb_multi_up(void *data, Evas *evas, Evas_Object *obj EINA_UNUSED
 
    if (!ec) return;
    if (e_object_is_del(E_OBJECT(ec))) return;
+   if (_e_comp_wl_check_block_input(ec)) return;
+
    struct wl_resource *surface = e_comp_wl_client_surface_get(ec);
    if (!surface) return;
 
index 82fbbe7b47eab57b7b35ecd2997134ea77b43fc5..594a05cfe56949b3d72dcec5c2f169b560a8d417 100644 (file)
@@ -577,6 +577,12 @@ _focus_policy_history_cb_client_focus_set(struct wl_listener *listener, void *da
           }
      }
 
+   if (ec->parent && !e_object_is_del(E_OBJECT(ec->parent)))
+     {
+        if (e_client_modal_child_get(ec->parent) == ec)
+          _focus_policy_history_focus_stack_latest_set(history_policy, ec->parent);
+     }
+
    _focus_policy_history_focus_stack_latest_set(history_policy, ec);
 
    // assign the focused_ec
index d021d0c1afb751ff2eb07152b0c173bcb6cfa9cb..d63a343a3fc1844d0a2cbfb60e747f7672aa9747 100644 (file)
@@ -7511,6 +7511,10 @@ _e_info_server_prop_set(E_Client *ec, const char *property, int set)
      {
         e_client_pinned_set(ec, set);
      }
+   else if (!e_util_strcmp("modal", property))
+     {
+        e_client_modal_state_set(ec, set);
+     }
    else
      {
         ERR("Not supported operation (%s)", property);
index ea93cd1b55443b550d323cc0fbca135fae470a88..488ffe01834de7af5e81be6ad4a1ded5729cb6c4 100644 (file)
@@ -334,9 +334,10 @@ typedef enum
 /* PROPERTY_SET                                                               */
 /* -------------------------------------------------------------------------- */
 #define USAGE_PROPERTY_SET                                                    \
-   "-prop_set {window id} ( pin ) ( 1 | 0) \n"                                \
+   "-prop_set {window id} ( pin | modal ) ( 1 | 0) \n"                        \
    "Example:\n"                                                               \
-   "\twinfo -prop_set 0x12345678 pin 1\n"
+   "\twinfo -prop_set 0x12345678 pin 1\n"                                     \
+   "\twinfo -prop_set 0x12345678 modal 1\n"
 
 /* -------------------------------------------------------------------------- */
 /* QUICKPANEL CONTROL                                                         */
index 9b7fc77248a99d6ff9a0e276f593e9475551b419..378d3547b3a27ba8699e87d410ccc40034dcb5e5 100644 (file)
@@ -313,6 +313,8 @@ _e_policy_stack_transient_for_set(E_Client *ec, E_Client *parent, Eina_Bool tran
           {
              ec->parent->transients =
                 eina_list_remove(ec->parent->transients, ec);
+             if (e_client_modal_child_get(ec->parent) == ec)
+               e_client_modal_child_set(ec->parent, NULL);
              ec->parent = NULL;
 
              ec->icccm.fetch.transient_for = EINA_TRUE;
@@ -340,6 +342,8 @@ _e_policy_stack_transient_for_set(E_Client *ec, E_Client *parent, Eina_Bool tran
      {
         ec->parent->transients =
            eina_list_remove(ec->parent->transients, ec);
+        if (e_client_modal_child_get(ec->parent) == ec)
+          e_client_modal_child_set(ec->parent, NULL);
         ec->parent = NULL;
      }
 
@@ -351,6 +355,8 @@ _e_policy_stack_transient_for_set(E_Client *ec, E_Client *parent, Eina_Bool tran
         else
           parent->transients = eina_list_append(parent->transients, ec);
         ec->parent = parent;
+        if (e_client_is_modal_state(ec))
+          e_client_modal_child_set(ec->parent, ec);
      }
 
    if (ec->parent)
index 554f0e68c989fd9ab88bddee3b9b5279a6bed723..fef1f5116e5de0d0a1ff05da20b61aae3d19aac4 100644 (file)
@@ -3704,6 +3704,34 @@ _tzpol_iface_cb_set_layout(struct wl_client *client EINA_UNUSED, struct wl_resou
      }
 }
 
+static void
+_e_policy_set_modal(E_Client *ec, Eina_Bool modal)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+   EINA_SAFETY_ON_NULL_RETURN(ec->frame);
+
+   ELOGF("TZPOL", "Set modal to %d", ec, modal);
+   e_client_modal_state_set(ec, modal);
+}
+
+static void
+_tzpol_iface_cb_set_modal(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf)
+{
+   E_Client *ec;
+
+   ec = e_client_from_surface_resource(surf);
+   _e_policy_set_modal(ec, EINA_TRUE);
+}
+
+static void
+_tzpol_iface_cb_unset_modal(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf)
+{
+   E_Client *ec;
+
+   ec = e_client_from_surface_resource(surf);
+   _e_policy_set_modal(ec, EINA_FALSE);
+}
+
 // --------------------------------------------------------
 // tizen_policy_interface
 // --------------------------------------------------------
@@ -3756,7 +3784,9 @@ static const struct tizen_policy_interface _tzpol_iface =
    _tzpol_iface_cb_set_maximize_direction,
    _tzpol_iface_cb_set_pin_mode,
    _tzpol_iface_cb_unset_pin_mode,
-   _tzpol_iface_cb_set_layout
+   _tzpol_iface_cb_set_layout,
+   _tzpol_iface_cb_set_modal,
+   _tzpol_iface_cb_unset_modal,
 };
 
 static void
@@ -8745,7 +8775,7 @@ e_policy_wl_init(void)
    /* create globals */
    global = wl_global_create(e_comp_wl->wl.disp,
                              &tizen_policy_interface,
-                             12,
+                             13,
                              NULL,
                              _tzpol_cb_bind);
    EINA_SAFETY_ON_NULL_GOTO(global, err);