e_serivce_launcher : support launcher service 60/207960/6 accepted/tizen/unified/20190627.115212 submit/tizen/20190627.023120
authorMinJeong Kim <minjjj.kim@samsung.com>
Wed, 12 Jun 2019 11:02:16 +0000 (20:02 +0900)
committerGwanglim Lee <gl77.lee@samsung.com>
Thu, 27 Jun 2019 11:19:07 +0000 (11:19 +0000)
e_serivce_launcher supports a launcher application who proccesses launching
animation. The launcher application should be privileged to be assigned
a role of launcher service and if the launcher is passed the privilege test,
enlightenment would accepts connection of tws_launcher_service from the launcher.
The launcher application and enlightenment are able to control launching
animation with those connection.

Change-Id: I86366ee188dc8f431a2405f4f2c2f3b6fae308ab
Signed-off-by: MinJeong Kim <minjjj.kim@samsung.com>
src/bin/Makefile.mk
src/bin/e_policy_wl.c
src/bin/e_privilege.c
src/bin/e_privilege.h
src/bin/services/e_service_launcher.c [new file with mode: 0644]
src/bin/services/e_service_launcher.h [new file with mode: 0644]

index 5573eb2..3497674 100644 (file)
@@ -122,6 +122,7 @@ src/bin/services/e_service_indicator.h \
 src/bin/services/e_service_cbhm.h \
 src/bin/services/e_service_scrsaver.h \
 src/bin/services/e_service_softkey.h \
+src/bin/services/e_service_launcher.h \
 src/bin/e_policy.h \
 src/bin/e_policy_conformant.h \
 src/bin/e_policy_visibility.h \
@@ -244,6 +245,7 @@ src/bin/services/e_service_indicator.c \
 src/bin/services/e_service_cbhm.c \
 src/bin/services/e_service_scrsaver.c \
 src/bin/services/e_service_softkey.c \
+src/bin/services/e_service_launcher.c \
 src/bin/e_policy.c \
 src/bin/e_policy_conformant.c \
 src/bin/e_policy_softkey.c \
index 979b9bc..0f20936 100644 (file)
@@ -7,6 +7,7 @@
 #include "services/e_service_cbhm.h"
 #include "services/e_service_scrsaver.h"
 #include "services/e_service_softkey.h"
+#include "services/e_service_launcher.h"
 #include "e_policy_wl_display.h"
 #include "e_policy_conformant_internal.h"
 #include "e_policy_visibility.h"
@@ -35,6 +36,7 @@ typedef enum _Tzsh_Srv_Role
    TZSH_SRV_ROLE_CBHM,
    TZSH_SRV_ROLE_SOFTKEY,
    TZSH_SRV_ROLE_MAGNIFIER,
+   TZSH_SRV_ROLE_LAUNCHER,
    TZSH_SRV_ROLE_MAX
 } Tzsh_Srv_Role;
 
@@ -710,6 +712,16 @@ _e_policy_wl_tzsh_srv_del(E_Policy_Wl_Tzsh_Srv *tzsh_srv)
              e_magnifier_del();
           }
      }
+   else if (tzsh_srv->role == TZSH_SRV_ROLE_LAUNCHER)
+     {
+        E_Client *launcher_ec = NULL;
+
+        launcher_ec = tzsh_srv->tzsh->ec;
+        if (launcher_ec)
+          {
+             e_service_launcher_client_unset(launcher_ec);
+          }
+     }
 
    memset(tzsh_srv, 0x0, sizeof(E_Policy_Wl_Tzsh_Srv));
    E_FREE(tzsh_srv);
@@ -732,6 +744,7 @@ _e_policy_wl_tzsh_srv_role_get(const char *name)
    else if (!e_util_strcmp(name, "cbhm"                     )) role = TZSH_SRV_ROLE_CBHM;
    else if (!e_util_strcmp(name, "softkey"                  )) role = TZSH_SRV_ROLE_SOFTKEY;
    else if (!e_util_strcmp(name, "magnifier"                )) role = TZSH_SRV_ROLE_MAGNIFIER;
+   else if (!e_util_strcmp(name, "launcher"                 )) role = TZSH_SRV_ROLE_LAUNCHER;
 
    return role;
 }
@@ -4086,6 +4099,30 @@ _tzsh_srv_iface_cb_cbhm_get(struct wl_client *client, struct wl_resource *res_tz
    wl_resource_set_implementation(res, &_tzsh_srv_cbhm_iface, tzsh_srv, NULL);
 }
 
+
+static void
+_tzsh_srv_iface_cb_launcher_get(struct wl_client *client, struct wl_resource *res_tzsh_srv, uint32_t id)
+{
+   E_Policy_Wl_Tzsh_Srv *tzsh_srv;
+   struct wl_resource *res;
+
+   tzsh_srv = wl_resource_get_user_data(res_tzsh_srv);
+   EINA_SAFETY_ON_NULL_RETURN(tzsh_srv);
+   EINA_SAFETY_ON_NULL_RETURN(tzsh_srv->tzsh);
+
+   if (!eina_list_data_find(polwl->tzsh_srvs, tzsh_srv))
+     return;
+
+   res = wl_resource_create(client, &tws_service_launcher_interface, 1, id);
+   if (!res)
+     {
+        wl_client_post_no_memory(client);
+        return;
+     }
+
+   e_service_launcher_resource_set(tzsh_srv->tzsh->ec, res);
+}
+
 static const struct tws_service_interface _tzsh_srv_iface =
 {
    _tzsh_srv_iface_cb_destroy,
@@ -4097,6 +4134,7 @@ static const struct tws_service_interface _tzsh_srv_iface =
    _tzsh_srv_iface_cb_cbhm_get,
    _tzsh_srv_iface_cb_softkey_get,
    _tzsh_srv_iface_cb_magnifier_get,
+   _tzsh_srv_iface_cb_launcher_get,
 };
 
 static void
@@ -4151,6 +4189,19 @@ _tzsh_iface_cb_srv_create(struct wl_client *client, struct wl_resource *res_tzsh
              return;
           }
      }
+   else if (role == TZSH_SRV_ROLE_LAUNCHER)
+     {
+        wl_client_get_credentials(client, &pid, &uid, NULL);
+        res = e_security_privilege_check(pid, uid,
+                                         E_PRIVILEGE_LAUNCHER_SERVICE);
+        if (!res)
+          {
+             ERR("Could not get privilege of resource: %m");
+             tizen_ws_shell_send_error(res_tzsh,
+                                       TIZEN_WS_SHELL_ERROR_PERMISSION_DENIED);
+             return;
+          }
+     }
 
    /* to avoid sending a wayland error after tzsh ERROR_NONE for every cases
     * such as invalid object or no memory error, tzsh ERROR_NONE should be sent
@@ -4220,9 +4271,9 @@ _tzsh_iface_cb_srv_create(struct wl_client *client, struct wl_resource *res_tzsh
    _e_policy_wl_tzsh_data_set(tzsh, TZSH_TYPE_SRV, cp, ec);
 
    tzsh_srv = _e_policy_wl_tzsh_srv_add(tzsh,
-                                   role,
-                                   res_tzsh_srv,
-                                   name);
+                                        role,
+                                        res_tzsh_srv,
+                                        name);
    if (!tzsh_srv)
      {
         ERR("Could not create WS_Shell_Service");
@@ -4259,6 +4310,8 @@ _tzsh_iface_cb_srv_create(struct wl_client *client, struct wl_resource *res_tzsh
         e_magnifier_new();
         e_magnifier_owner_set(tzsh->ec);
      }
+   else if (role == TZSH_SRV_ROLE_LAUNCHER)
+     e_service_launcher_client_set(tzsh->ec);
 }
 
 // --------------------------------------------------------
index be0bcca..c1836ea 100644 (file)
@@ -9,3 +9,4 @@ EINTERN const char *E_PRIVILEGE_INTERNAL_DEFAULT_PLATFORM = "http://tizen.org/pr
 EINTERN const char *E_PRIVILEGE_SCREENSHOT                = "http://tizen.org/privilege/screenshot";
 EINTERN const char *E_PRIVILEGE_SOFTKEY                   = "http://tizen.org/privilege/windowsystem.admin";
 EINTERN const char *E_PRIVILEGE_MAGNIFIER_SERVICE         = "http://tizen.org/privilege/internal/default/platform";
+EINTERN const char *E_PRIVILEGE_LAUNCHER_SERVICE          = "http://tizen.org/privilege/internal/default/platform";
index 87a4fc1..f906f99 100644 (file)
@@ -12,6 +12,7 @@ extern EINTERN const char *E_PRIVILEGE_INTERNAL_DEFAULT_PLATFORM;
 extern EINTERN const char *E_PRIVILEGE_SCREENSHOT;
 extern EINTERN const char *E_PRIVILEGE_SOFTKEY;
 extern EINTERN const char *E_PRIVILEGE_MAGNIFIER_SERVICE;
+extern EINTERN const char *E_PRIVILEGE_LAUNCHER_SERVICE;
 
 #endif
 #endif
diff --git a/src/bin/services/e_service_launcher.c b/src/bin/services/e_service_launcher.c
new file mode 100644 (file)
index 0000000..9af2a9c
--- /dev/null
@@ -0,0 +1,842 @@
+#include "e.h"
+#include <tzsh_server.h>
+#include "services/e_service_launcher.h"
+
+typedef struct _E_Service_Launcher E_Service_Launcher;
+
+typedef enum
+{
+   LAUNCHER_STATE_IDLE,
+   LAUNCHER_STATE_MONITORING,
+   LAUNCHER_STATE_PREPARING,
+   LAUNCHER_STATE_LAUNCHING,
+   LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER,
+   LAUNCHER_STATE_DONE,
+   LAUNCHER_STATE_CANCELED,
+} Launcher_State;
+
+struct _E_Service_Launcher
+{
+   struct wl_resource *res;      //tizen_window_transition_launcher resource
+   Launcher_State      state;    //current state of launcher
+
+   E_Client           *ec;       //launcher E_Client
+   E_Vis_Grab         *vis_grab; //grab of launcher visibility
+   uint32_t            serial;   //identifier
+   enum tws_service_launcher_direction direction; //direction of transition
+
+   struct
+     {
+        E_Client   *ec;        //target E_Client
+        pid_t       pid;       //pid
+        E_Vis_Grab *vis_grab;  //grab of target client's visibility
+        Eina_Bool   delay_del; //refered delay_del
+     } target; //target window information for transition
+
+   E_Client            *launched_ec;     //E_Client was launched by launcher
+
+   Ecore_Event_Handler *buf_attach;      //event handler for BUFFER_CHANGE
+   Eina_List           *hooks_ec;        //hook list for E_CLIENT_HOOK_*
+   Eina_List           *hooks_co;        //hook list for E_COMP_OBJECT_INTERCEPT_*
+   Eina_List           *hooks_vis;       //hook list for E_POL_VIS_HOOK_TYPE_*
+   Eina_List           *handlers;        //ecore event handlers
+};
+////////////////////////////////////////////////////////////////////
+static E_Service_Launcher  *_e_srv_launcher = NULL; //only one instance is allowed
+////////////////////////////////////////////////////////////////////
+static Eina_List *
+_e_srv_launcher_clients_find_by_pid(pid_t pid)
+{
+   E_Client *ec;
+   Eina_List *clients = NULL, *l;
+
+   EINA_LIST_FOREACH(e_comp->clients, l, ec)
+     {
+        if (e_object_is_del(E_OBJECT(ec))) continue;
+        if (ec->netwm.pid != pid) continue;
+        clients = eina_list_append(clients, ec);
+     }
+
+   return clients;
+}
+
+static const char*
+_e_srv_launcher_state_to_str(Launcher_State state)
+{
+   switch (state)
+     {
+      case LAUNCHER_STATE_IDLE:
+         return "IDLE";
+      case LAUNCHER_STATE_MONITORING:
+         return "PID_MONITORING";
+      case LAUNCHER_STATE_PREPARING:
+         return "PREPARING";
+      case LAUNCHER_STATE_LAUNCHING:
+         return "LAUNCHING";
+      case LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER:
+         return "LAUNCHING_BUT_WATING_BUFFER";
+      case LAUNCHER_STATE_DONE:
+         return "LAUNCH_DONE";
+      case LAUNCHER_STATE_CANCELED:
+         return "LAUNCH_CANCELED";
+     }
+   return "UNKNOWN";
+}
+
+static void
+_e_srv_launcher_state_set(E_Service_Launcher *lc,
+                          Launcher_State state)
+{
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+
+   if (state == lc->state) return;
+
+   ELOGF("LAUNCHER_SRV", "Set state  %s --> %s",
+         lc->ec,
+         _e_srv_launcher_state_to_str(lc->state),
+         _e_srv_launcher_state_to_str(state));
+
+   lc->state = state;
+}
+
+static void
+_e_srv_launcher_stop_send(E_Service_Launcher *lc)
+{
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+
+   ELOGF("LAUNCHER_SRV", "Send STOP event(%d) target(ec:%p)",
+         lc->ec, lc->serial, lc->target.ec);
+
+   tws_service_launcher_send_stop(lc->res, lc->serial);
+}
+
+static void
+_e_srv_launcher_prepare_send(E_Service_Launcher *lc,
+                             E_Client *target_ec,
+                             int x, int y)
+{
+   uint32_t res_id;
+
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+   EINA_SAFETY_ON_NULL_RETURN(target_ec);
+
+   res_id = e_pixmap_res_id_get(target_ec->pixmap);
+
+   ELOGF("LAUNCHER_SRV", "Send PREPARE event(%d) direction:%s target(ec:%p res:%d pos(%d,%d))",
+         lc->ec, lc->serial, lc->direction?"BACKWARD":"FORWARD", target_ec, res_id, x, y);
+
+   tws_service_launcher_send_prepare(lc->res,
+                                     res_id, lc->direction,
+                                     x, y, lc->serial);
+}
+
+static void
+_e_srv_launcher_prepare_forward_send(E_Service_Launcher *lc,
+                                     E_Client *target_ec)
+{
+   int x, y;
+
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+   EINA_SAFETY_ON_NULL_RETURN(target_ec);
+
+   if(e_object_is_del(E_OBJECT(target_ec))) return;
+
+   e_policy_animatable_lock(target_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 1);
+   e_comp_client_override_add(target_ec);
+
+   //grab uniconify job of target_ec
+   if (target_ec->iconic)
+     lc->target.vis_grab = e_policy_visibility_client_filtered_grab_get(target_ec,
+                                                                        (E_VIS_JOB_TYPE_UNICONIFY |
+                                                                         E_VIS_JOB_TYPE_UNICONIFY_BY_VISIBILITY),
+                                                                        __func__);
+
+   lc->launched_ec = NULL;
+   lc->target.ec = target_ec;
+   lc->direction = TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD;
+   lc->serial = wl_display_next_serial(e_comp_wl->wl.disp);
+
+   e_client_pos_get(target_ec, &x, &y);
+
+   _e_srv_launcher_prepare_send(lc, target_ec, x, y);
+}
+
+static Eina_Bool
+_e_srv_launcher_prepare_backward_send(E_Service_Launcher *lc,
+                                      E_Client *activity,
+                                      E_Client *target_ec,
+                                      E_Vis_Job_Type job_type)
+{
+   int x, y;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(activity, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(target_ec, EINA_FALSE);
+
+   if (e_object_is_del(E_OBJECT(target_ec)))
+     {
+        //can't do nothing if ec is deleted and there's no delay_del_ref as well.
+        if (!e_object_delay_del_ref_get(E_OBJECT(target_ec)))
+          return EINA_FALSE;
+     }
+
+   e_object_delay_del_ref(E_OBJECT(target_ec));
+   lc->target.delay_del = EINA_TRUE;
+
+   e_policy_animatable_lock(target_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 1);
+   e_comp_client_override_add(target_ec);
+
+   if (activity == target_ec)
+     {
+        lc->vis_grab = e_policy_visibility_client_filtered_grab_get(lc->ec, job_type, __func__);
+        lc->target.vis_grab = e_policy_visibility_client_filtered_grab_get(target_ec, E_VIS_JOB_TYPE_ALL, __func__);
+     }
+   else
+     {
+        lc->target.vis_grab = e_policy_visibility_client_filtered_grab_get(target_ec, job_type, __func__);
+     }
+
+   lc->launched_ec = NULL;
+   lc->target.ec = target_ec;
+   lc->serial = wl_display_next_serial(e_comp_wl->wl.disp);
+   lc->direction = TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD;
+   e_client_pos_get(target_ec, &x, &y);
+
+   _e_srv_launcher_prepare_send(lc, target_ec, x, y);
+
+   return EINA_TRUE;
+}
+
+static void
+_e_srv_launcher_post_forward(E_Service_Launcher *lc,
+                             Eina_Bool success)
+{
+   E_Client *target_ec = NULL;
+
+   if ((lc->target.ec) && (!e_object_is_del(E_OBJECT(lc->target.ec))))
+     target_ec = lc->target.ec;
+
+   lc->serial = 0;
+   lc->target.ec = NULL;
+   lc->target.pid = -1;
+
+   //if forward animation is failed, enlightenment can run animation instead.
+   if ((!success) && (target_ec))
+     e_policy_animatable_lock(target_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 0);
+
+   if (lc->vis_grab)
+     e_policy_visibility_client_grab_release(lc->vis_grab);
+   if (lc->target.vis_grab)
+     e_policy_visibility_client_grab_release(lc->target.vis_grab);
+
+   lc->vis_grab = NULL;
+   lc->target.vis_grab = NULL;
+
+   if (!target_ec) return;
+
+   if (success)
+     lc->launched_ec = target_ec;
+
+   //show target_ec
+   e_comp_object_damage(target_ec->frame, 0, 0, target_ec->w, target_ec->h);
+   e_comp_object_dirty(target_ec->frame);
+   e_comp_object_render(target_ec->frame);
+   evas_object_show(target_ec->frame);
+
+   e_comp_client_override_del(target_ec);
+}
+
+static void
+_e_srv_launcher_post_backward(E_Service_Launcher *lc,
+                              Eina_Bool success)
+{
+   E_Client *target_ec = NULL;
+
+   target_ec = lc->target.ec;
+
+   lc->serial = 0;
+   lc->target.ec = NULL;
+   lc->target.pid = -1;
+
+   E_FREE_FUNC(lc->buf_attach, ecore_event_handler_del);
+
+   if (target_ec)
+     {
+        Eina_Bool is_del;
+        is_del = e_object_is_del(E_OBJECT(target_ec));
+        if (lc->target.delay_del)
+          e_object_delay_del_unref(E_OBJECT(target_ec));
+
+        if (is_del)
+          target_ec = NULL;
+     }
+   lc->target.delay_del = EINA_FALSE;
+
+   //if forward animation is failed, enlightenment can run animation instead.
+   if ((!success) && (target_ec))
+     e_policy_animatable_lock(target_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 0);
+
+   if (lc->vis_grab)
+     e_policy_visibility_client_grab_release(lc->vis_grab);
+   if (lc->target.vis_grab)
+     e_policy_visibility_client_grab_release(lc->target.vis_grab);
+
+   lc->vis_grab = NULL;
+   lc->target.vis_grab = NULL;
+
+   if (!target_ec) return;
+
+   if (success)
+     e_policy_animatable_lock(target_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 0);
+
+   e_comp_client_override_del(target_ec);
+}
+
+/* Reset lc data except for reusable hooks and handlers. */
+static void
+_e_srv_launcher_data_reset(E_Service_Launcher *lc)
+{
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+
+   ELOGF("LAUNCHER_SRV", "Reset Launcher Data", lc->ec);
+
+   //clear resource and send 'DISQUALIFIED' msg
+   if (lc->res)
+     {
+        tws_service_launcher_send_error(lc->res, TWS_SERVICE_LAUNCHER_ERROR_DISQUALIFIED);
+        wl_resource_set_user_data(lc->res, NULL);
+        lc->res = NULL;
+     }
+
+   if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD)
+     _e_srv_launcher_post_forward(lc, EINA_FALSE);
+   else if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD)
+     _e_srv_launcher_post_backward(lc, EINA_FALSE);
+
+   _e_srv_launcher_state_set(lc, LAUNCHER_STATE_IDLE);
+   lc->direction = 0;
+   lc->launched_ec = NULL;
+}
+
+static void
+_e_srv_launcher_data_free(E_Service_Launcher *lc)
+{
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+
+   E_FREE_FUNC(lc->buf_attach, ecore_event_handler_del);
+   E_FREE_LIST(lc->handlers,   ecore_event_handler_del);
+   E_FREE_LIST(lc->hooks_ec,   e_client_hook_del);
+   E_FREE_LIST(lc->hooks_co,   e_comp_object_intercept_hook_del);
+   E_FREE_LIST(lc->hooks_vis,  e_policy_visibility_hook_del);
+
+   _e_srv_launcher_data_reset(lc);
+
+   E_FREE(lc);
+}
+
+static Eina_Bool
+_e_srv_launcher_cb_hook_intercept_show_helper(void *data, E_Client *ec)
+{
+   E_Service_Launcher *lc;
+
+   lc = (E_Service_Launcher*)data;
+
+   EINA_SAFETY_ON_NULL_GOTO(lc, show_allow);
+   EINA_SAFETY_ON_NULL_GOTO(ec, show_allow);
+
+   if (ec->new_client) goto show_allow;
+
+   switch (lc->state)
+     {
+      case LAUNCHER_STATE_IDLE:
+      case LAUNCHER_STATE_DONE:
+      case LAUNCHER_STATE_CANCELED:               //animation ended or didn't start
+         goto show_allow;
+      case LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER:  //waiting buffer change
+         goto show_deny;
+      case LAUNCHER_STATE_PREPARING:              //waiting launcher client's preparation
+         if (ec == lc->target.ec) goto show_deny;
+         break;
+      case LAUNCHER_STATE_LAUNCHING:              //doing animation
+         if (ec == lc->target.ec) goto show_deny; //don't show launched app window
+         else if (ec == lc->ec) goto show_allow;  //show launcher
+         break;
+      case LAUNCHER_STATE_MONITORING:             //waiting creation of target window
+         if (lc->target.pid != ec->netwm.pid) goto show_allow;
+         if (e_object_is_del(E_OBJECT(ec))) goto show_allow;
+
+         _e_srv_launcher_prepare_forward_send(lc, ec);
+         _e_srv_launcher_state_set(lc, LAUNCHER_STATE_PREPARING);
+         goto show_deny;
+      default:
+         goto show_allow;
+     }
+
+show_allow:
+   return EINA_TRUE;
+show_deny:
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_e_srv_launcher_cb_hook_vis_uniconify_render_running(void *data EINA_UNUSED, E_Client *ec)
+{
+   E_Service_Launcher *lc;
+   E_Client *activity = NULL;
+
+   lc = (E_Service_Launcher*)data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_TRUE);
+
+   activity = e_policy_visibility_main_activity_get();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(activity, EINA_TRUE);
+
+   if (ec == lc->ec)
+     {
+        ELOGF("LAUNCHER_SRV", "Hook uniconify render begin target.ec:%p activity:%p launched_ec:%p",
+              ec, lc->target.ec, activity, lc->launched_ec);
+
+        if (activity == lc->launched_ec)
+          {
+             int sent = EINA_FALSE;
+
+             ELOGF("LAUNCHER_SRV", "Current activity(%p, is_del:%d) was launched by launcher.",
+                   ec, activity, e_object_is_del(E_OBJECT(activity)));
+
+             sent = _e_srv_launcher_prepare_backward_send(lc, activity, activity,
+                                                          (E_VIS_JOB_TYPE_UNICONIFY |
+                                                           E_VIS_JOB_TYPE_UNICONIFY_BY_VISIBILITY));
+             if (!sent) return EINA_FALSE;
+             _e_srv_launcher_state_set(lc, LAUNCHER_STATE_PREPARING);
+          }
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_srv_launcher_cb_hook_vis_lower(void *data, E_Client *ec)
+{
+   E_Service_Launcher *lc;
+   E_Client *activity = NULL;
+
+   lc = (E_Service_Launcher*)data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+   activity = e_policy_visibility_main_activity_get();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(activity, EINA_FALSE);
+
+   if (activity != lc->ec) return EINA_FALSE;
+   if (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED) return EINA_FALSE;
+
+   if (ec == lc->launched_ec)
+     {
+        Eina_Bool sent = EINA_FALSE;
+        ELOGF("LAUNCHER_SRV", "Lower hook of launched_ec(%p)", lc->ec, ec);
+
+        sent = _e_srv_launcher_prepare_backward_send(lc, activity, ec, E_VIS_JOB_TYPE_LOWER);
+        if (!sent) return EINA_FALSE;
+
+        _e_srv_launcher_state_set(lc, LAUNCHER_STATE_PREPARING);
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_srv_launcher_cb_hook_vis_hide(void *data, E_Client *ec)
+{
+   E_Service_Launcher *lc;
+   E_Client *activity = NULL;
+
+   lc = (E_Service_Launcher*)data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+   activity = e_policy_visibility_main_activity_get();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(activity, EINA_FALSE);
+
+   if (activity != lc->ec) return EINA_FALSE;
+   if (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED) return EINA_FALSE;
+
+   if (ec == lc->launched_ec)
+     {
+        Eina_Bool sent = EINA_FALSE;
+        ELOGF("LAUNCHER_SRV", "Hide hook of launched_ec(%p)", lc->ec, ec);
+
+        sent = _e_srv_launcher_prepare_backward_send(lc, activity, ec, E_VIS_JOB_TYPE_HIDE);
+        if (!sent) return EINA_FALSE;
+
+        _e_srv_launcher_state_set(lc, LAUNCHER_STATE_PREPARING);
+     }
+
+   return EINA_TRUE;
+}
+
+
+static Eina_Bool
+_e_srv_launcher_cb_event_buff_attach(void *data, int type EINA_UNUSED, void *event)
+{
+   E_Service_Launcher *lc;
+   E_Client *ec;
+   E_Event_Client *ev;
+
+   lc = (E_Service_Launcher*)data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(lc, ECORE_CALLBACK_PASS_ON);
+
+   ev = (E_Event_Client *)event;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
+
+   ec = ev->ec;
+   if (ec != lc->ec) return ECORE_CALLBACK_PASS_ON;
+
+   ELOGF("LAUNCHER_SRV", "Event cb(BUFFER_CHANGE)", ec);
+
+   if (lc->state == LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER)
+     _e_srv_launcher_state_set(lc, LAUNCHER_STATE_LAUNCHING);
+
+   if (lc->vis_grab)
+     {
+        e_policy_visibility_client_grab_release(lc->vis_grab);
+        lc->vis_grab = NULL;
+     }
+
+   if (lc->target.vis_grab)
+     {
+        e_policy_visibility_client_grab_release(lc->target.vis_grab);
+        lc->target.vis_grab = NULL;
+     }
+
+   E_FREE_FUNC(lc->buf_attach, ecore_event_handler_del);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_srv_launcher_cb_event_client_show(void *data, int type EINA_UNUSED, void *event)
+{
+   E_Service_Launcher *lc;
+   E_Client *ec;
+   E_Event_Client *ev;
+
+   lc = (E_Service_Launcher*)data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(lc, ECORE_CALLBACK_PASS_ON);
+
+   if ((lc->state == LAUNCHER_STATE_IDLE) ||
+       (lc->state == LAUNCHER_STATE_MONITORING) ||
+       (lc->state == LAUNCHER_STATE_LAUNCHING) ||
+       (lc->state == LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER))
+     return ECORE_CALLBACK_PASS_ON;
+
+   ev = (E_Event_Client *)event;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
+
+   ec = ev->ec;
+   if ((ec != lc->launched_ec) && (ec != lc->ec)) return ECORE_CALLBACK_PASS_ON;
+
+   ELOGF("LAUNCHER_SRV", "Event cb(CLIENT_SHOW)", ec);
+
+   if (ec == lc->launched_ec)
+     e_policy_animatable_lock(ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 0);
+
+   //failure case
+   if (lc->state == LAUNCHER_STATE_PREPARING)
+     {
+        _e_srv_launcher_stop_send(lc);
+        if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD)
+          _e_srv_launcher_post_backward(lc, EINA_FALSE);
+     }
+
+   _e_srv_launcher_state_set(lc, LAUNCHER_STATE_IDLE);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_e_srv_launcher_cb_hook_client_del(void *data, E_Client *ec)
+{
+   E_Service_Launcher *lc;
+
+   lc = (E_Service_Launcher*)data;
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   if (lc->launched_ec == ec)
+     lc->launched_ec = NULL;
+   else if (lc->ec == ec) //launcher surface is gone.
+     {
+        if (_e_srv_launcher == lc)
+          _e_srv_launcher = NULL;
+
+        _e_srv_launcher_data_free(lc);
+     }
+   else if (lc->target.ec == ec) //target surface is gone.
+     {
+        switch (lc->state)
+          {
+           case LAUNCHER_STATE_PREPARING:
+           case LAUNCHER_STATE_LAUNCHING:
+           case LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER:
+              _e_srv_launcher_stop_send(lc);
+              if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD)
+                _e_srv_launcher_post_forward(lc, EINA_FALSE);
+              else if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD)
+                _e_srv_launcher_post_backward(lc, EINA_FALSE);
+              break;
+           default:
+              break;
+          }
+     }
+}
+
+static void
+_e_srv_launcher_cb_resource_destroy(struct wl_resource *res_tws_lc)
+{
+   E_Service_Launcher *lc;
+
+   lc = wl_resource_get_user_data(res_tws_lc);
+   if (!lc) return;
+
+   ELOGF("LAUNCHER_SRV", "Start Resource Destroy tws_service_launcher", lc->ec);
+
+   if (_e_srv_launcher == lc)
+     _e_srv_launcher = NULL;
+
+   lc->res = NULL;
+   _e_srv_launcher_data_free(lc);
+
+   ELOGF("LAUNCHER_SRV", "End Resource Destroy tws_service_launcher", NULL);
+}
+
+static void
+_e_srv_launcher_cb_destroy(struct wl_client *client EINA_UNUSED,
+                           struct wl_resource *res_tws_lc)
+{
+   ELOGF("LAUNCHER_SRV", "Received request(launcher_destroy)", NULL);
+   wl_resource_destroy(res_tws_lc);
+}
+
+static void
+_e_srv_launcher_cb_launch(struct wl_client *client EINA_UNUSED,
+                          struct wl_resource *res_tws_lc,
+                          const char *app_id,
+                          int32_t pid)
+{
+   E_Service_Launcher *lc;
+   E_Client *target_ec;
+   Eina_List *ecs, *l;
+
+   lc = wl_resource_get_user_data(res_tws_lc);
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+   EINA_SAFETY_ON_NULL_RETURN(lc->ec);
+
+   ELOGF("LAUNCHER_SRV",
+         "Recieved request(launcher_launch) appid:%s pid:%d",
+         lc->ec, app_id?:"NONE", pid);
+
+   EINA_SAFETY_ON_TRUE_GOTO(lc->ec->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED, send_stop);
+   EINA_SAFETY_ON_TRUE_GOTO(pid < 0, send_stop);
+
+   lc->target.pid = pid;
+
+   //if we received launch without idle state
+   if ((lc->state == LAUNCHER_STATE_DONE) ||
+       (lc->state == LAUNCHER_STATE_CANCELED))
+     {
+        if (lc->launched_ec)
+          {
+             e_policy_animatable_lock(lc->launched_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 0);
+             lc->launched_ec = NULL;
+          }
+
+        _e_srv_launcher_state_set(lc, LAUNCHER_STATE_IDLE);
+     }
+
+   ecs = _e_srv_launcher_clients_find_by_pid(pid);
+   EINA_LIST_FOREACH(ecs, l, target_ec)
+     {
+        if (e_object_is_del(E_OBJECT(target_ec))) continue;
+        if (e_client_util_ignored_get(target_ec)) continue;
+
+        ELOGF("LAUNCHER_SRV", "Found target_ec:%p", lc->ec, target_ec);
+
+        _e_srv_launcher_prepare_forward_send(lc, target_ec);
+        _e_srv_launcher_state_set(lc, LAUNCHER_STATE_PREPARING);
+        break;
+     }
+   eina_list_free(ecs);
+
+   if (!lc->target.ec)
+     {
+        ELOGF("LAUNCHER_SRV", "Can't find target_ec, Start Monitoring", lc->ec);
+        _e_srv_launcher_state_set(lc, LAUNCHER_STATE_MONITORING);
+     }
+
+   return;
+
+send_stop:
+   ELOGF("LAUNCHER_SRV", "can't process request(launcher_launch)", lc->ec);
+   _e_srv_launcher_stop_send(lc);
+}
+
+static void
+_e_srv_launcher_cb_launching(struct wl_client *client EINA_UNUSED,
+                             struct wl_resource *res_tws_lc,
+                             uint32_t serial)
+{
+   E_Service_Launcher *lc;
+
+   lc = wl_resource_get_user_data(res_tws_lc);
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+
+   ELOGF("LAUNCHER_SRV", "LAUNCHING(%d) %s",
+         lc->ec, serial, lc->direction?"backward":"forward");
+
+   _e_srv_launcher_state_set(lc, LAUNCHER_STATE_LAUNCHING);
+
+   if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD)
+     {
+        _e_srv_launcher_state_set(lc, LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER);
+        lc->buf_attach = ecore_event_handler_add(E_EVENT_CLIENT_BUFFER_CHANGE,
+                                                 _e_srv_launcher_cb_event_buff_attach, lc);
+     }
+}
+
+static void
+_e_srv_launcher_cb_launch_done(struct wl_client *client EINA_UNUSED,
+                               struct wl_resource *res_tws_lc,
+                               uint32_t serial)
+{
+   E_Service_Launcher *lc;
+
+   lc = wl_resource_get_user_data(res_tws_lc);
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+
+   ELOGF("LAUNCHER_SRV", "LAUNCH_DONE(%d) target:%p", lc->ec, serial, lc->target.ec);
+
+   if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD)
+     _e_srv_launcher_post_forward(lc, EINA_TRUE);
+   else if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD)
+     _e_srv_launcher_post_backward(lc, EINA_TRUE);
+
+   if ((lc->state == LAUNCHER_STATE_LAUNCHING) ||
+       (lc->state == LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER))
+     _e_srv_launcher_state_set(lc, LAUNCHER_STATE_DONE);
+}
+
+static void
+_e_srv_launcher_cb_launch_cancel(struct wl_client *client EINA_UNUSED,
+                                 struct wl_resource *res_tws_lc,
+                                 uint32_t serial)
+{
+   E_Service_Launcher *lc;
+
+   lc = wl_resource_get_user_data(res_tws_lc);
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+
+   ELOGF("LAUNCHER_SRV", "LAUNCH_CANCEL(%d) target_ec:%p",
+         lc->ec, serial, lc->target.ec);
+
+   if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD)
+     _e_srv_launcher_post_forward(lc, EINA_FALSE);
+   else if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD)
+     _e_srv_launcher_post_backward(lc, EINA_FALSE);
+
+   if ((lc->state == LAUNCHER_STATE_PREPARING) ||
+       (lc->state == LAUNCHER_STATE_LAUNCHING) ||
+       (lc->state == LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER))
+     _e_srv_launcher_state_set(lc, LAUNCHER_STATE_CANCELED);
+}
+
+static const struct tws_service_launcher_interface _e_srv_launcher_iface =
+{
+   _e_srv_launcher_cb_destroy,
+   _e_srv_launcher_cb_launch,
+   _e_srv_launcher_cb_launching,
+   _e_srv_launcher_cb_launch_done,
+   _e_srv_launcher_cb_launch_cancel,
+};
+
+EINTERN void
+e_service_launcher_resource_set(E_Client *ec, struct wl_resource *res_tws_lc)
+{
+   E_Service_Launcher *lc;
+
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+   EINA_SAFETY_ON_NULL_RETURN(res_tws_lc);
+
+   lc = _e_srv_launcher;
+   EINA_SAFETY_ON_NULL_RETURN(lc);
+   EINA_SAFETY_ON_TRUE_RETURN(lc->ec != ec);
+
+   lc->res = res_tws_lc;
+   wl_resource_set_implementation(res_tws_lc,
+                                  &_e_srv_launcher_iface, lc,
+                                  _e_srv_launcher_cb_resource_destroy);
+}
+
+#undef  LAUNCHER_CB_ADD
+#define LAUNCHER_CB_ADD(l, appender, event_type, cb, data)  \
+  do                                                        \
+    {                                                       \
+       void *_h;                                            \
+       _h = appender(event_type, cb, data);                 \
+       assert(_h);                                          \
+       l = eina_list_append(l, _h);                         \
+    }                                                       \
+  while (0)
+
+EINTERN void
+e_service_launcher_client_set(E_Client *ec)
+{
+   E_Service_Launcher *lc = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+   EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(ec)));
+
+   if (_e_srv_launcher)
+     {
+        lc = _e_srv_launcher;
+        _e_srv_launcher_data_reset(lc);
+     }
+
+   if (!lc)
+     {
+
+        lc = E_NEW(E_Service_Launcher, 1);
+        EINA_SAFETY_ON_NULL_RETURN(lc);
+
+        /* hook, event handler add */
+        LAUNCHER_CB_ADD(lc->hooks_co,  e_comp_object_intercept_hook_add, E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER, _e_srv_launcher_cb_hook_intercept_show_helper, lc);
+        LAUNCHER_CB_ADD(lc->hooks_vis, e_policy_visibility_hook_add, E_POL_VIS_HOOK_TYPE_UNICONIFY_RENDER_RUNNING, _e_srv_launcher_cb_hook_vis_uniconify_render_running, lc);
+        LAUNCHER_CB_ADD(lc->hooks_vis, e_policy_visibility_hook_add, E_POL_VIS_HOOK_TYPE_LOWER, _e_srv_launcher_cb_hook_vis_lower, lc);
+        LAUNCHER_CB_ADD(lc->hooks_vis, e_policy_visibility_hook_add, E_POL_VIS_HOOK_TYPE_HIDE, _e_srv_launcher_cb_hook_vis_hide, lc);
+        LAUNCHER_CB_ADD(lc->hooks_ec,  e_client_hook_add, E_CLIENT_HOOK_DEL, _e_srv_launcher_cb_hook_client_del, lc);
+        LAUNCHER_CB_ADD(lc->handlers,  ecore_event_handler_add, E_EVENT_CLIENT_SHOW, _e_srv_launcher_cb_event_client_show, lc);
+
+        _e_srv_launcher = lc;
+     }
+
+   lc->ec = ec;
+
+   ELOGF("LAUNCHER_SRV", "client set|Created New Launcher(%p)", ec, lc);
+
+   return;
+}
+
+EINTERN void
+e_service_launcher_client_unset(E_Client *ec)
+{
+   E_Service_Launcher *lc;
+
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+   EINA_SAFETY_ON_NULL_RETURN(_e_srv_launcher);
+   EINA_SAFETY_ON_TRUE_RETURN(_e_srv_launcher->ec != ec);
+
+   lc = _e_srv_launcher;
+   _e_srv_launcher_data_reset(lc);
+
+   ELOGF("LAUNCHER_SRV", "client unset", ec);
+}
diff --git a/src/bin/services/e_service_launcher.h b/src/bin/services/e_service_launcher.h
new file mode 100644 (file)
index 0000000..8f085c1
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef E_SERVICE_LAUNCHER_H
+#define E_SERVICE_LAUNCHER_H
+
+#include "e_policy_private_data.h"
+#include <tzsh_server.h>
+
+EINTERN void              e_service_launcher_resource_set(E_Client *ec, struct wl_resource *res_tws_lc);
+EINTERN void              e_service_launcher_client_set(E_Client *ec);
+EINTERN void              e_service_launcher_client_unset(E_Client *ec);
+
+#endif