support modal feature 89/309389/1
authorDoyoun Kang <doyoun.kang@samsung.com>
Mon, 8 Apr 2024 08:24:27 +0000 (17:24 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Tue, 9 Apr 2024 08:52:28 +0000 (17:52 +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: Ibd8cee7134515b62c7dcd191fc47482e7297496c

src/bin/e_client.c
src/bin/e_client_intern.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_policy_stack.c
src/bin/e_policy_wl.c
src/include/e_client.h
src/include/e_info_shared_types.h

index a0b62d7..12c3843 100644 (file)
@@ -108,6 +108,8 @@ struct _E_Client_Private
 
    Eina_Bool hide_by_request;
    Eina_Bool focus_check;
+
+   E_Client *modal;
 };
 
 static int _e_client_hooks_delete = 0;
@@ -1105,6 +1107,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;
      }
@@ -3046,6 +3050,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 f93fbf3..7b2eb55 100644 (file)
@@ -151,6 +151,11 @@ EINTERN E_Client *e_client_transient_child_top_get(E_Client *ec, Eina_Bool consi
 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);
+
 EINTERN void      e_client_transform_apply(E_Client *ec, double degree, double zoom, int cx, int cy);
 EINTERN void      e_client_transform_clear(E_Client *ec);
 EINTERN void      e_client_transform_core_input_inv_rect_transform(E_Client *ec, int x, int y, int *out_x, int *out_y);
index 6306feb..de74523 100644 (file)
@@ -2796,6 +2796,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 89dbd37..2158d64 100644 (file)
@@ -1286,6 +1286,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)
 {
@@ -1421,6 +1437,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;
 
@@ -1469,6 +1487,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;
 
@@ -1631,6 +1651,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);
@@ -1689,6 +1710,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)
      {
@@ -1825,6 +1847,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;
 
@@ -1869,6 +1893,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 241af48..3f856e3 100644 (file)
@@ -605,6 +605,12 @@ _focus_policy_history_cb_client_focus_set(struct wl_listener *listener, void *da
      }
 #endif
 
+   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 33759a9..21123cd 100644 (file)
@@ -7464,6 +7464,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 3c205eb..d567bcd 100644 (file)
@@ -340,6 +340,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;
@@ -367,6 +369,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;
      }
 
@@ -378,6 +382,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 54201a2..3422f74 100644 (file)
@@ -3733,6 +3733,34 @@ _tzpol_iface_cb_set_layout(struct wl_client *client EINA_UNUSED, struct wl_resou
      e_client_shell_configure_send(ec, 0, w, h);
 }
 
+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
 // --------------------------------------------------------
@@ -3785,7 +3813,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
@@ -8768,7 +8798,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);
index b328153..fdeceb4 100644 (file)
@@ -541,7 +541,7 @@ struct _E_Client
       /* NetWM Window state */
       struct
       {
-         EINA_DEPRECATED unsigned char modal : 1;
+         unsigned char modal : 1;
          EINA_DEPRECATED unsigned char sticky : 1;
          EINA_DEPRECATED unsigned char maximized_v : 1;
          EINA_DEPRECATED unsigned char maximized_h : 1;
index d18eb2d..b70f26c 100644 (file)
@@ -338,9 +338,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                                                         */