From 25b7146d278ab3ce7c3e30f37daa577b6e67f971 Mon Sep 17 00:00:00 2001 From: MinJeong Kim Date: Mon, 22 Jul 2019 19:06:42 +0900 Subject: [PATCH] e_service_launcher : supports multiple launchers Enlightenment has to handle multiple launchers to support not only home-to-app but also app-to-app launching animation. This patch includes below features to support that. 1. E_Service_Launcher_Handler object added - provides 'launcher_hansh' to store multiple launcher data - manages hooks and event handlers. - manages runner, pre_runner launchers. 2. runner/pre_runner - 'runner' is a pointer of launcher object currently proccessed by enlightenment now. - 'pre_runner' is a pointer of launcher object previously proccessed by enlightenment. - runner and pre_runner are able to exist as only single instance(or no instance) - A launcher that send the latest 'launch' request is 'runner'. If there is 'runner' already. the 'runner' is changed to 'pre_runner'. - TODO: grouping runner and pre-runner to support multiple launchers running animation. Change-Id: Ic54d073b9d42ac6e65782f73ddbf99e3d2867cb7 Signed-off-by: MinJeong Kim --- src/bin/services/e_service_launcher.c | 1407 ++++++++++++++++++++++----------- 1 file changed, 928 insertions(+), 479 deletions(-) diff --git a/src/bin/services/e_service_launcher.c b/src/bin/services/e_service_launcher.c index dbe68b9..eab9caf 100644 --- a/src/bin/services/e_service_launcher.c +++ b/src/bin/services/e_service_launcher.c @@ -2,7 +2,8 @@ #include #include "services/e_service_launcher.h" -typedef struct _E_Service_Launcher E_Service_Launcher; +typedef struct _E_Service_Launcher E_Service_Launcher; +typedef struct _E_Service_Launcher_Handler E_Service_Launcher_Handler; typedef enum { @@ -17,35 +18,65 @@ typedef enum struct _E_Service_Launcher { - struct wl_resource *res; //tizen_window_transition_launcher resource - Launcher_State state; //current state of launcher + 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 wl_resource *res; //tizen_window_transition_launcher resource + 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 + 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 + E_Object_Delfn *delfn; //del callback of target E_Client } target; //target window information for transition - E_Client *launched_ec; //E_Client was launched by launcher + E_Client *launched_ec; //E_Client was launched by launcher + E_Object_Delfn *launched_delfn; //del callback of launched_ec + + Ecore_Event_Handler *buff_attach; //event handler for BUFFER_CHANGE +}; + +struct _E_Service_Launcher_Handler +{ + Eina_Hash *launcher_hash; //hash key:launcher_ec, data:E_Service_Launcher + unsigned int launcher_count; //count of launcher object + + Eina_List *hooks_ec; //hook list for E_CLIENT_HOOK_* + Eina_List *hooks_vis; //hook list for E_POL_VIS_HOOK_TYPE_* + Eina_List *hooks_co; //hook list for E_COMP_OBJECT_INTERCEPT_HOOK_* + Eina_List *hdlrs_ev; //handler list for ecore events - 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 + E_Service_Launcher *runner; //current runner(running launcher) + E_Service_Launcher *pre_runner; //previous runner }; + //////////////////////////////////////////////////////////////////// -static E_Service_Launcher *_e_srv_launcher = NULL; //only one instance is allowed +static E_Service_Launcher_Handler *_laundler = NULL; + +static void _launcher_launched_ec_set(E_Service_Launcher *lc, E_Client *launched_ec); +static void _launcher_target_ec_set(E_Service_Launcher *lc, E_Client *target_ec); + +static E_Service_Launcher *_launcher_handler_launcher_find(E_Client *ec); +static Eina_Bool _launcher_handler_launcher_add(E_Service_Launcher *lc); +static Eina_Bool _launcher_handler_launcher_del(E_Service_Launcher *lc); + +static E_Service_Launcher *_launcher_handler_launcher_runner_get(void); +static void _launcher_handler_launcher_runner_set(E_Service_Launcher *lc); +static void _launcher_handler_launcher_runner_unset(E_Service_Launcher *lc); +static E_Service_Launcher *_launcher_handler_launcher_pre_runner_get(void); +static void _launcher_handler_launcher_pre_runner_set(E_Service_Launcher *lc); +static void _launcher_handler_launcher_pre_runner_unset(E_Service_Launcher *lc); + //////////////////////////////////////////////////////////////////// static Eina_List * -_e_srv_launcher_clients_find_by_pid(pid_t pid) +_launcher_clients_find_by_pid(pid_t pid) { E_Client *ec; Eina_List *clients = NULL, *l; @@ -61,7 +92,7 @@ _e_srv_launcher_clients_find_by_pid(pid_t pid) } static const char* -_e_srv_launcher_state_to_str(Launcher_State state) +_launcher_state_to_str(Launcher_State state) { switch (state) { @@ -84,7 +115,7 @@ _e_srv_launcher_state_to_str(Launcher_State state) } static void -_e_srv_launcher_state_set(E_Service_Launcher *lc, +_launcher_state_set(E_Service_Launcher *lc, Launcher_State state) { EINA_SAFETY_ON_NULL_RETURN(lc); @@ -93,14 +124,99 @@ _e_srv_launcher_state_set(E_Service_Launcher *lc, ELOGF("LAUNCHER_SRV", "Set state %s --> %s", lc->ec, - _e_srv_launcher_state_to_str(lc->state), - _e_srv_launcher_state_to_str(state)); + _launcher_state_to_str(lc->state), + _launcher_state_to_str(state)); lc->state = state; } static void -_e_srv_launcher_stop_send(E_Service_Launcher *lc) +_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; + + _launcher_target_ec_set(lc, NULL); + + lc->serial = 0; + 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) + _launcher_launched_ec_set(lc, 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 +_launcher_post_backward(E_Service_Launcher *lc, Eina_Bool success) +{ + E_Client *target_ec = NULL; + + target_ec = lc->target.ec; + _launcher_target_ec_set(lc, NULL); + + lc->serial = 0; + lc->target.pid = -1; + lc->direction = 0; + + E_FREE_FUNC(lc->buff_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); +} + +static void +_launcher_stop_send(E_Service_Launcher *lc) { EINA_SAFETY_ON_NULL_RETURN(lc); @@ -111,7 +227,7 @@ _e_srv_launcher_stop_send(E_Service_Launcher *lc) } static Eina_Bool -_e_srv_launcher_prepare_send(E_Service_Launcher *lc, +_launcher_prepare_send(E_Service_Launcher *lc, E_Client *target_ec, int x, int y) { @@ -119,12 +235,18 @@ _e_srv_launcher_prepare_send(E_Service_Launcher *lc, E_Comp_Object_Content_Type content_type = 0; enum tws_service_launcher_target_type target_type = 0; - const char *target_path = NULL; + const char *target_path = NULL, *target_group = NULL; Evas_Object *content = NULL; + struct wl_array info_array; + + int len; + char *p_char; + uint32_t *p_u32; EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(target_ec, EINA_FALSE); + wl_array_init(&info_array); if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD) { content_type = e_comp_object_content_type_get(target_ec->frame); @@ -132,31 +254,59 @@ _e_srv_launcher_prepare_send(E_Service_Launcher *lc, { case E_COMP_OBJECT_CONTENT_TYPE_EXT_IMAGE: content = e_comp_object_content_get(target_ec->frame); - EINA_SAFETY_ON_NULL_RETURN_VAL(content, EINA_FALSE); + EINA_SAFETY_ON_NULL_GOTO(content, fail); target_type = TWS_SERVICE_LAUNCHER_TARGET_TYPE_IMAGE; evas_object_image_file_get(content, &target_path, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(target_path, EINA_FALSE); + EINA_SAFETY_ON_NULL_GOTO(target_path, fail); + len = strlen(target_path) + 1; + p_char = wl_array_add(&info_array, len); + EINA_SAFETY_ON_NULL_GOTO(p_char, fail); + + strncpy(p_char, target_path, len); break; case E_COMP_OBJECT_CONTENT_TYPE_EXT_EDJE: content = e_comp_object_content_get(target_ec->frame); - EINA_SAFETY_ON_NULL_RETURN_VAL(content, EINA_FALSE); + EINA_SAFETY_ON_NULL_GOTO(content, fail); target_type = TWS_SERVICE_LAUNCHER_TARGET_TYPE_EDJE; - edje_object_file_get(content, &target_path, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(target_path, EINA_FALSE); + edje_object_file_get(content, &target_path, &target_group); + EINA_SAFETY_ON_NULL_GOTO(target_path, fail); + EINA_SAFETY_ON_NULL_GOTO(target_group, fail); + + len = strlen(target_path) + 1; + p_char = wl_array_add(&info_array, len); + EINA_SAFETY_ON_NULL_GOTO(p_char, fail); + + strncpy(p_char, target_path, len); + + len = strlen(target_group) + 1; + p_char = wl_array_add(&info_array, len); + EINA_SAFETY_ON_NULL_GOTO(p_char, fail); + + strncpy(p_char, target_group, len); break; default: target_type = TWS_SERVICE_LAUNCHER_TARGET_TYPE_REMOTE_SURFACE; res_id = e_pixmap_res_id_get(target_ec->pixmap); + + p_u32 = wl_array_add(&info_array, sizeof(uint32_t)); + EINA_SAFETY_ON_NULL_GOTO(p_u32, fail); + + *p_u32 = res_id; } } else { target_type = TWS_SERVICE_LAUNCHER_TARGET_TYPE_REMOTE_SURFACE; res_id = e_pixmap_res_id_get(target_ec->pixmap); + + p_u32 = wl_array_add(&info_array, sizeof(uint32_t)); + EINA_SAFETY_ON_NULL_GOTO(p_u32, fail); + + *p_u32 = res_id; } @@ -165,15 +315,19 @@ _e_srv_launcher_prepare_send(E_Service_Launcher *lc, tws_service_launcher_send_prepare(lc->res, target_type, - res_id, target_path, + &info_array, lc->direction, x, y, lc->serial); + wl_array_release(&info_array); return EINA_TRUE; +fail: + wl_array_release(&info_array); + return EINA_FALSE; } static Eina_Bool -_e_srv_launcher_prepare_forward_send(E_Service_Launcher *lc, +_launcher_prepare_forward_send(E_Service_Launcher *lc, E_Client *target_ec) { Eina_Bool sent = EINA_FALSE; @@ -194,37 +348,27 @@ _e_srv_launcher_prepare_forward_send(E_Service_Launcher *lc, 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); + _launcher_launched_ec_set(lc, NULL); + _launcher_target_ec_set(lc, 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); - sent = _e_srv_launcher_prepare_send(lc, target_ec, x, y); + sent = _launcher_prepare_send(lc, target_ec, x, y); + //fail to send protocol event if (!sent) { ELOGF("LAUNCHER_SRV", "Failed to send event(PREPARE:FORWARD)", lc->ec); - - lc->launched_ec = NULL; - lc->target.ec = NULL; - lc->direction = 0; - lc->serial = 0; - - if (lc->target.vis_grab) - e_policy_visibility_client_grab_release(lc->target.vis_grab); - lc->target.vis_grab = NULL; - - e_comp_client_override_del(target_ec); - e_policy_animatable_lock(target_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 0); + _launcher_post_forward(lc, EINA_FALSE); } return sent; } static Eina_Bool -_e_srv_launcher_prepare_backward_send(E_Service_Launcher *lc, +_launcher_prepare_backward_send(E_Service_Launcher *lc, E_Client *activity, E_Client *target_ec, E_Vis_Job_Type job_type) @@ -259,224 +403,551 @@ _e_srv_launcher_prepare_backward_send(E_Service_Launcher *lc, 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; + _launcher_launched_ec_set(lc, NULL); + _launcher_target_ec_set(lc, 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); - sent = _e_srv_launcher_prepare_send(lc, target_ec, x, y); + sent = _launcher_prepare_send(lc, target_ec, x, y); + //fail to send protocol event if (!sent) { ELOGF("LAUNCHER_SRV", "Failed to send event(PREPARE:BACKWARD)", lc->ec); - - lc->launched_ec = NULL; - lc->target.ec = NULL; - lc->serial = 0; - lc->direction = 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); - - e_comp_client_override_del(target_ec); - e_policy_animatable_lock(target_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 0); - - e_object_delay_del_unref(E_OBJECT(target_ec)); - lc->target.delay_del = EINA_FALSE; + _launcher_post_backward(lc, EINA_FALSE); } return sent; } +/* Reset lc data */ static void -_e_srv_launcher_post_forward(E_Service_Launcher *lc, - Eina_Bool success) +_launcher_data_reset(E_Service_Launcher *lc) { - E_Client *target_ec = NULL; + EINA_SAFETY_ON_NULL_RETURN(lc); - if ((lc->target.ec) && (!e_object_is_del(E_OBJECT(lc->target.ec)))) - target_ec = lc->target.ec; + ELOGF("LAUNCHER_SRV", "Reset Launcher Data", lc->ec); - lc->serial = 0; - lc->target.ec = NULL; - lc->target.pid = -1; + //clear resource and send 'DISQUALIFIED' msg + if (lc->res) + { + tws_service_launcher_send_error(lc->res, TWS_SERVICE_LAUNCHER_ERROR_DISQUALIFIED, lc->serial); + wl_resource_set_user_data(lc->res, NULL); + lc->res = NULL; + } - //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->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD) + _launcher_post_forward(lc, EINA_FALSE); + else if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD) + _launcher_post_backward(lc, EINA_FALSE); - 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); + _launcher_state_set(lc, LAUNCHER_STATE_IDLE); + _launcher_launched_ec_set(lc, NULL); - lc->vis_grab = NULL; - lc->target.vis_grab = NULL; + _launcher_handler_launcher_runner_unset(lc); + _launcher_handler_launcher_pre_runner_unset(lc); - if (!target_ec) return; + lc->direction = 0; +} - 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); +static Eina_Bool +_launcher_cb_event_buff_attach(void *data, int type EINA_UNUSED, void *event) +{ + E_Service_Launcher *lc; + E_Client *ec; + E_Event_Client *ev; - e_comp_client_override_del(target_ec); -} + lc = (E_Service_Launcher*)data; + EINA_SAFETY_ON_NULL_RETURN_VAL(lc, ECORE_CALLBACK_PASS_ON); -static void -_e_srv_launcher_post_backward(E_Service_Launcher *lc, - Eina_Bool success) -{ - E_Client *target_ec = NULL; + 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); - target_ec = lc->target.ec; + ec = ev->ec; + if (ec != lc->ec) return ECORE_CALLBACK_PASS_ON; - lc->serial = 0; - lc->target.ec = NULL; - lc->target.pid = -1; + ELOGF("LAUNCHER_SRV", "Event cb(BUFFER_CHANGE)", ec); - E_FREE_FUNC(lc->buf_attach, ecore_event_handler_del); + if (lc->state == LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER) + _launcher_state_set(lc, LAUNCHER_STATE_LAUNCHING); - if (target_ec) + if (lc->vis_grab) { - 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; + e_policy_visibility_client_grab_release(lc->vis_grab); + lc->vis_grab = 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); + { + e_policy_visibility_client_grab_release(lc->target.vis_grab); + lc->target.vis_grab = NULL; + } - lc->vis_grab = NULL; - lc->target.vis_grab = NULL; + E_FREE_FUNC(lc->buff_attach, ecore_event_handler_del); - if (!target_ec) return; + return ECORE_CALLBACK_PASS_ON; +} - if (success) - e_policy_animatable_lock(target_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 0); +static void +_launcher_cb_launched_ec_del(void *data, void *obj) +{ + E_Service_Launcher *lc = (E_Service_Launcher *)data; + E_Client *launched_ec = (E_Client *)obj; - e_comp_client_override_del(target_ec); + EINA_SAFETY_ON_NULL_RETURN(launched_ec); + EINA_SAFETY_ON_NULL_RETURN(lc); + EINA_SAFETY_ON_TRUE_RETURN(lc->launched_ec != launched_ec); + + lc->launched_ec = NULL; + lc->launched_delfn = NULL; } -/* Reset lc data except for reusable hooks and handlers. */ static void -_e_srv_launcher_data_reset(E_Service_Launcher *lc) +_launcher_cb_target_ec_del(void *data, void *obj) { + E_Service_Launcher *lc = (E_Service_Launcher *)data; + E_Client *target_ec = (E_Client *)obj; + + EINA_SAFETY_ON_NULL_RETURN(target_ec); EINA_SAFETY_ON_NULL_RETURN(lc); + EINA_SAFETY_ON_TRUE_RETURN(lc->target.ec != target_ec); - ELOGF("LAUNCHER_SRV", "Reset Launcher Data", lc->ec); + lc->target.ec = NULL; + lc->target.delfn = NULL; - //clear resource and send 'DISQUALIFIED' msg - if (lc->res) + switch (lc->state) { - tws_service_launcher_send_error(lc->res, TWS_SERVICE_LAUNCHER_ERROR_DISQUALIFIED); - wl_resource_set_user_data(lc->res, NULL); - lc->res = NULL; - } + case LAUNCHER_STATE_PREPARING: + case LAUNCHER_STATE_LAUNCHING: + case LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER: + _launcher_stop_send(lc); + if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD) + _launcher_post_forward(lc, EINA_FALSE); + else if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD) + _launcher_post_backward(lc, EINA_FALSE); - 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); + _launcher_handler_launcher_runner_unset(lc); + _launcher_handler_launcher_pre_runner_unset(lc); - _e_srv_launcher_state_set(lc, LAUNCHER_STATE_IDLE); - lc->direction = 0; - lc->launched_ec = NULL; + _launcher_state_set(lc, LAUNCHER_STATE_IDLE); + break; + default: + break; + } } static void -_e_srv_launcher_data_free(E_Service_Launcher *lc) +_launcher_launched_ec_set(E_Service_Launcher *lc, E_Client *launched_ec) { EINA_SAFETY_ON_NULL_RETURN(lc); + if (lc->launched_ec == launched_ec) return; - 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); + if (lc->launched_ec) + { + e_object_delfn_del(E_OBJECT(lc->launched_ec), lc->launched_delfn); + lc->launched_ec = NULL; + lc->launched_delfn = NULL; + } - E_FREE(lc); + if (launched_ec) + { + lc->launched_ec = launched_ec; + lc->launched_delfn = e_object_delfn_add(E_OBJECT(launched_ec), + _launcher_cb_launched_ec_del, lc); + } } -static Eina_Bool -_e_srv_launcher_cb_hook_intercept_show_helper(void *data, E_Client *ec) +static void +_launcher_target_ec_set(E_Service_Launcher *lc, E_Client *target_ec) { - E_Service_Launcher *lc; - Eina_Bool sent = EINA_FALSE; - - lc = (E_Service_Launcher*)data; - - EINA_SAFETY_ON_NULL_GOTO(lc, show_allow); - EINA_SAFETY_ON_NULL_GOTO(ec, show_allow); + EINA_SAFETY_ON_NULL_RETURN(lc); + if (lc->target.ec == target_ec) return; - if (ec->new_client) goto show_allow; + if (lc->target.ec) + { + e_object_delfn_del(E_OBJECT(lc->target.ec), lc->target.delfn); + lc->target.ec = NULL; + lc->target.delfn = NULL; + } - switch (lc->state) + if (target_ec) { - 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; + lc->target.ec = target_ec; + lc->target.delfn = e_object_delfn_add(E_OBJECT(target_ec), + _launcher_cb_target_ec_del, lc); + } +} - sent = _e_srv_launcher_prepare_forward_send(lc, ec); - EINA_SAFETY_ON_FALSE_GOTO(sent, send_stop); +static void +_launcher_cb_resource_destroy(struct wl_resource *res_tws_lc) +{ + E_Service_Launcher *lc; - _e_srv_launcher_state_set(lc, LAUNCHER_STATE_PREPARING); - goto show_deny; - default: - goto show_allow; + lc = wl_resource_get_user_data(res_tws_lc); + if (!lc) return; + + ELOGF("LAUNCHER_SRV", "Start Resource Destroy tws_service_launcher", lc->ec); + + _launcher_handler_launcher_del(lc); + + lc->res = NULL; + _launcher_data_reset(lc); + + E_FREE(lc); + + ELOGF("LAUNCHER_SRV", "End Resource Destroy tws_service_launcher", NULL); +} + +static void +_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 +_launcher_cb_launch(struct wl_client *client EINA_UNUSED, + struct wl_resource *res_tws_lc, + const char *app_id, + const char *instance_id, + int32_t pid) +{ + E_Service_Launcher *lc; + E_Service_Launcher *runner, *pre_runner; + E_Client *target_ec; + Eina_List *ecs, *l; + Eina_Bool sent = EINA_FALSE; + + 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 instance id:%s pid:%d", + lc->ec, app_id?:"NONE", instance_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); + + //check current state of lc + runner = _launcher_handler_launcher_runner_get(); + if (runner == lc) + { + ELOGF("LAUNCHER_SRV", + "Launcher(%s) requests LAUNCH again without cancel, ignore this.", + lc->ec, _launcher_state_to_str(lc->state)); + + tws_service_launcher_send_error(lc->res, TWS_SERVICE_LAUNCHER_ERROR_WRONG_REQUEST, lc->serial); + return; } -show_allow: - return EINA_TRUE; -show_deny: - return EINA_FALSE; + pre_runner = _launcher_handler_launcher_pre_runner_get(); + if (pre_runner == lc) + { + _launcher_handler_launcher_pre_runner_set(NULL); + _launcher_launched_ec_set(lc, NULL); + } + + lc->target.pid = pid; + + ecs = _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); + + sent = _launcher_prepare_forward_send(lc, target_ec); + EINA_SAFETY_ON_FALSE_GOTO(sent, send_stop); + + _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); + _launcher_state_set(lc, LAUNCHER_STATE_MONITORING); + } + + _launcher_handler_launcher_runner_set(lc); + + return; + send_stop: - lc->target.pid = -1; - _e_srv_launcher_stop_send(lc); - _e_srv_launcher_state_set(lc, LAUNCHER_STATE_IDLE); - return EINA_TRUE; + ELOGF("LAUNCHER_SRV", "can't process request(launcher_launch)", lc->ec); + _launcher_stop_send(lc); } -static Eina_Bool -_e_srv_launcher_cb_hook_vis_uniconify_render_running(void *data EINA_UNUSED, E_Client *ec) +static void +_launcher_cb_launching(struct wl_client *client EINA_UNUSED, + struct wl_resource *res_tws_lc, + uint32_t serial) +{ + E_Service_Launcher *lc; + E_Service_Launcher *runner; + + 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"); + + //check current state of lc + runner = _launcher_handler_launcher_runner_get(); + if (runner != lc) + { + ELOGF("LAUNCHER_SRV", "lc(%p) runner(%p), lc is not runner, ignore LAUNCHING", + lc->ec, lc, runner); + tws_service_launcher_send_error(lc->res, TWS_SERVICE_LAUNCHER_ERROR_WRONG_REQUEST, lc->serial); + return; + } + + _launcher_state_set(lc, LAUNCHER_STATE_LAUNCHING); + + if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD) + { + _launcher_state_set(lc, LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER); + lc->buff_attach = ecore_event_handler_add(E_EVENT_CLIENT_BUFFER_CHANGE, + _launcher_cb_event_buff_attach, lc); + } +} + +static void +_launcher_cb_launch_done(struct wl_client *client EINA_UNUSED, + struct wl_resource *res_tws_lc, + uint32_t serial) +{ + E_Service_Launcher *lc; + E_Service_Launcher *runner; + + 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); + + //check current state of lc + runner = _launcher_handler_launcher_runner_get(); + if (runner != lc) + { + ELOGF("LAUNCHER_SRV", "lc(%p) runner(%p), lc is not runner, ignore LAUNCH_DONE", + lc->ec, lc, runner); + tws_service_launcher_send_error(lc->res, TWS_SERVICE_LAUNCHER_ERROR_WRONG_REQUEST, lc->serial); + return; + } + + if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD) + _launcher_post_forward(lc, EINA_TRUE); + else if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD) + _launcher_post_backward(lc, EINA_TRUE); + + _launcher_handler_launcher_runner_unset(lc); + _launcher_handler_launcher_pre_runner_set(lc); + _launcher_state_set(lc, LAUNCHER_STATE_DONE); +} + +static void +_launcher_cb_launch_cancel(struct wl_client *client EINA_UNUSED, + struct wl_resource *res_tws_lc, + uint32_t serial) { E_Service_Launcher *lc; + E_Service_Launcher *runner; + + 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); + + //check state of lc + runner = _launcher_handler_launcher_runner_get(); + if (runner != lc) + { + ELOGF("LAUNCHER_SRV", "lc(%p) runner(%p), lc is not runner, ignore LAUNCH_CANCEL", + lc->ec, lc, runner); + tws_service_launcher_send_error(lc->res, TWS_SERVICE_LAUNCHER_ERROR_WRONG_REQUEST, lc->serial); + return; + } + + if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD) + _launcher_post_forward(lc, EINA_FALSE); + else if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD) + _launcher_post_backward(lc, EINA_FALSE); + + _launcher_handler_launcher_runner_unset(lc); + _launcher_handler_launcher_pre_runner_set(lc); + _launcher_state_set(lc, LAUNCHER_STATE_CANCELED); +} + +static const struct tws_service_launcher_interface _launcher_iface = +{ + _launcher_cb_destroy, + _launcher_cb_launch, + _launcher_cb_launching, + _launcher_cb_launch_done, + _launcher_cb_launch_cancel, +}; + +static E_Service_Launcher * +_launcher_handler_launcher_find(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(_laundler, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(_laundler->launcher_hash, NULL); + + return eina_hash_find(_laundler->launcher_hash, &ec); +} + +static Eina_Bool +_launcher_handler_launcher_add(E_Service_Launcher *lc) +{ + Eina_Bool ret; + + EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(lc->ec, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(_laundler, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(_laundler->launcher_hash, EINA_FALSE); + + ret = eina_hash_add(_laundler->launcher_hash, &lc->ec, lc); + if (ret) + _laundler->launcher_count++; + + return ret; +} + +static Eina_Bool +_launcher_handler_launcher_del(E_Service_Launcher *lc) +{ + Eina_Bool ret; + + EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(lc->ec, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(_laundler, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(_laundler->launcher_hash, EINA_FALSE); + + ret = eina_hash_del(_laundler->launcher_hash, &lc->ec, lc); + if (ret) _laundler->launcher_count--; + + return ret; +} + +static void +_launcher_handler_launcher_runner_set(E_Service_Launcher *lc) +{ + E_Service_Launcher *runner = NULL; + + EINA_SAFETY_ON_NULL_RETURN(_laundler); + if (_laundler->runner == lc) return; + + //reset previous runner + runner = _laundler->runner; + if (runner) + { + switch (runner->state) + { + case LAUNCHER_STATE_PREPARING: + case LAUNCHER_STATE_LAUNCHING: + case LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER: + _launcher_state_set(runner, LAUNCHER_STATE_CANCELED); + _launcher_stop_send(runner); + if (runner->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD) + _launcher_post_forward(runner, EINA_FALSE); + else if (runner->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD) + _launcher_post_backward(runner, EINA_FALSE); + break; + case LAUNCHER_STATE_MONITORING: + _launcher_state_set(runner, LAUNCHER_STATE_CANCELED); + _launcher_stop_send(runner); + runner->target.pid = -1; + break; + default: + break; + } + _launcher_handler_launcher_pre_runner_set(runner); + } + + ELOGF("LAUNCHER_SRV", "runner change %p(ec:%p) to %p(ec:%p)", + NULL, runner, runner?runner->ec:NULL, lc, lc?lc->ec:NULL); + + _laundler->runner = lc; +} + +static void +_launcher_handler_launcher_runner_unset(E_Service_Launcher *lc) +{ + EINA_SAFETY_ON_NULL_RETURN(_laundler); + if (_laundler->runner != lc) return; + + _laundler->runner = NULL; + + ELOGF("LAUNCHER_SRV", "runner unset %p(ec:%p)", + NULL, lc, lc?lc->ec:NULL); +} + +static E_Service_Launcher * +_launcher_handler_launcher_runner_get(void) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(_laundler, NULL); + return _laundler->runner; +} + +static void +_launcher_handler_launcher_pre_runner_set(E_Service_Launcher *lc) +{ + E_Service_Launcher *pre_runner = NULL; + + EINA_SAFETY_ON_NULL_RETURN(_laundler); + + pre_runner = _laundler->pre_runner; + if (pre_runner == lc) return; + if (pre_runner) + { + if (pre_runner->launched_ec) + e_policy_animatable_lock(pre_runner->launched_ec, E_POLICY_ANIMATABLE_CUSTOMIZED, 0); + _launcher_state_set(pre_runner, LAUNCHER_STATE_IDLE); + } + + _laundler->pre_runner = lc; + + ELOGF("LAUNCHER_SRV", "pre_runner change %p(ec:%p) to %p(ec:%p)", + NULL, pre_runner, pre_runner?pre_runner->ec:NULL, lc, lc?lc->ec:NULL); +} + +static void +_launcher_handler_launcher_pre_runner_unset(E_Service_Launcher *lc) +{ + EINA_SAFETY_ON_NULL_RETURN(_laundler); + if (_laundler->pre_runner != lc) return; + + _laundler->pre_runner = NULL; + + ELOGF("LAUNCHER_SRV", "pre_runner unset %p(ec:%p)", + NULL, lc, lc?lc->ec:NULL); +} + +static E_Service_Launcher * +_launcher_handler_launcher_pre_runner_get(void) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(_laundler, NULL); + return _laundler->pre_runner; +} + +static Eina_Bool +_launcher_handler_cb_hook_vis_uniconify_render_running(void *data EINA_UNUSED, E_Client *ec) +{ + E_Service_Launcher *lc = NULL; + E_Service_Launcher *runner, *pre_runner = NULL; E_Client *activity = NULL; - lc = (E_Service_Launcher*)data; + lc = _launcher_handler_launcher_find(ec); EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_TRUE); activity = e_policy_visibility_main_activity_get(); @@ -494,11 +965,29 @@ _e_srv_launcher_cb_hook_vis_uniconify_render_running(void *data EINA_UNUSED, E_C 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, + //check state of lc + runner = _launcher_handler_launcher_runner_get(); + if (runner == lc) + { + ELOGF("LAUNCHER_SRV", + "Launcher(%s) is already runner, do nothing", + lc->ec, _launcher_state_to_str(lc->state)); + return EINA_TRUE; + } + + pre_runner = _launcher_handler_launcher_pre_runner_get(); + if (pre_runner == lc) + { + _launcher_handler_launcher_pre_runner_set(NULL); + } + + sent = _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); + + _launcher_state_set(lc, LAUNCHER_STATE_PREPARING); + _launcher_handler_launcher_runner_set(lc); } } @@ -506,19 +995,18 @@ _e_srv_launcher_cb_hook_vis_uniconify_render_running(void *data EINA_UNUSED, E_C } static Eina_Bool -_e_srv_launcher_cb_hook_vis_lower(void *data, E_Client *ec) +_launcher_handler_cb_hook_vis_lower(void *data EINA_UNUSED, E_Client *ec) { - E_Service_Launcher *lc; + E_Service_Launcher *lc = NULL; + E_Service_Launcher *runner, *pre_runner; 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; + lc = _launcher_handler_launcher_find(activity); + EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_FALSE); + if (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED) return EINA_FALSE; if (ec == lc->launched_ec) @@ -526,29 +1014,44 @@ _e_srv_launcher_cb_hook_vis_lower(void *data, E_Client *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); + //check state of lc + runner = _launcher_handler_launcher_runner_get(); + if (runner == lc) + { + ELOGF("LAUNCHER_SRV", + "Launcher(%s) is already runner, do nothing", + lc->ec, _launcher_state_to_str(lc->state)); + return EINA_FALSE; + } + + pre_runner = _launcher_handler_launcher_pre_runner_get(); + if (pre_runner == lc) + { + _launcher_handler_launcher_pre_runner_set(NULL); + } + + sent = _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); + _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) +_launcher_handler_cb_hook_vis_hide(void *data EINA_UNUSED, E_Client *ec) { - E_Service_Launcher *lc; + E_Service_Launcher *lc = NULL; + E_Service_Launcher *runner, *pre_runner; 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; + lc = _launcher_handler_launcher_find(activity); + EINA_SAFETY_ON_NULL_RETURN_VAL(lc, EINA_FALSE); + if (ec->visibility.obscured != E_VISIBILITY_UNOBSCURED) return EINA_FALSE; if (ec == lc->launched_ec) @@ -556,305 +1059,251 @@ _e_srv_launcher_cb_hook_vis_hide(void *data, E_Client *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); + //check state of lc + runner = _launcher_handler_launcher_runner_get(); + if (runner == lc) + { + ELOGF("LAUNCHER_SRV", + "Launcher(%s) is already runner, do nothing", + lc->ec, _launcher_state_to_str(lc->state)); + return EINA_FALSE; + } + + pre_runner = _launcher_handler_launcher_pre_runner_get(); + if (pre_runner == lc) + { + _launcher_handler_launcher_pre_runner_set(NULL); + } + + sent = _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); + _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) +static void +_launcher_handler_cb_hook_client_del(void *data EINA_UNUSED, E_Client *ec) { 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); + EINA_SAFETY_ON_NULL_RETURN(ec); - 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); + lc = _launcher_handler_launcher_find(ec); + EINA_SAFETY_ON_NULL_RETURN(lc); - ec = ev->ec; - if (ec != lc->ec) return ECORE_CALLBACK_PASS_ON; + if (lc->ec == ec) //launcher surface is gone. + { + _launcher_handler_launcher_del(lc); + _launcher_data_reset(lc); + E_FREE(lc); + } +} - ELOGF("LAUNCHER_SRV", "Event cb(BUFFER_CHANGE)", ec); +static Eina_Bool +_launcher_handler_cb_hook_intercept_show_helper(void *data, E_Client *ec) +{ + E_Service_Launcher *runner; + Eina_Bool sent = EINA_FALSE; - if (lc->state == LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER) - _e_srv_launcher_state_set(lc, LAUNCHER_STATE_LAUNCHING); + runner = _launcher_handler_launcher_runner_get(); - if (lc->vis_grab) - { - e_policy_visibility_client_grab_release(lc->vis_grab); - lc->vis_grab = NULL; - } + EINA_SAFETY_ON_NULL_GOTO(runner, show_allow); + EINA_SAFETY_ON_NULL_GOTO(ec, show_allow); - if (lc->target.vis_grab) + if (ec->new_client) goto show_allow; + + switch (runner->state) { - e_policy_visibility_client_grab_release(lc->target.vis_grab); - lc->target.vis_grab = NULL; - } + case LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER: //waiting buffer change + if (ec == runner->ec) + goto show_deny; + case LAUNCHER_STATE_PREPARING: //waiting launcher client's preparation + if (ec == runner->target.ec) goto show_deny; + break; + case LAUNCHER_STATE_LAUNCHING: //doing animation + if (ec == runner->target.ec) goto show_deny; //don't show launched app window + else if (ec == runner->ec) goto show_allow; //show launcher + break; + case LAUNCHER_STATE_MONITORING: //waiting creation of target window + if (ec->netwm.pid != runner->target.pid) goto show_allow; + if (e_object_is_del(E_OBJECT(ec))) goto show_allow; - E_FREE_FUNC(lc->buf_attach, ecore_event_handler_del); + sent = _launcher_prepare_forward_send(runner, ec); + EINA_SAFETY_ON_FALSE_GOTO(sent, send_stop); - return ECORE_CALLBACK_PASS_ON; + _launcher_state_set(runner, LAUNCHER_STATE_PREPARING); + goto show_deny; + default: + goto show_allow; + } + +show_allow: + return EINA_TRUE; +show_deny: + return EINA_FALSE; +send_stop: + runner->target.pid = -1; + _launcher_stop_send(runner); + _launcher_state_set(runner, LAUNCHER_STATE_IDLE); + _launcher_handler_launcher_runner_unset(runner); + return EINA_TRUE; } static Eina_Bool -_e_srv_launcher_cb_event_client_show(void *data, int type EINA_UNUSED, void *event) +_launcher_handler_cb_event_client_show(void *data, int type EINA_UNUSED, void *event) { - E_Service_Launcher *lc; + E_Service_Launcher *runner, *pre_runner; 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; + runner = _launcher_handler_launcher_runner_get(); + EINA_SAFETY_ON_NULL_RETURN_VAL(runner, 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) + switch (runner->state) { - _e_srv_launcher_stop_send(lc); - if (lc->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD) - _e_srv_launcher_post_backward(lc, EINA_FALSE); + case LAUNCHER_STATE_MONITORING: + if (ec->netwm.pid == runner->target.pid) + goto send_stop; + break; + case LAUNCHER_STATE_PREPARING: + if (runner->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD) + { + if (ec == runner->target.ec) goto send_stop; + } + else if (runner->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD) + { + if (ec == runner->ec) goto send_stop; + } + break; + case LAUNCHER_STATE_LAUNCHING: + if (runner->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD) + { + if (ec == runner->target.ec) goto send_stop; + } + break; + default: + break; } - _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. + pre_runner = _launcher_handler_launcher_pre_runner_get(); + if (pre_runner) { - 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) + switch (pre_runner->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); + case LAUNCHER_STATE_DONE: + if (ec == pre_runner->launched_ec) + _launcher_handler_launcher_pre_runner_set(NULL); + break; + case LAUNCHER_STATE_CANCELED: + _launcher_handler_launcher_pre_runner_set(NULL); 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; + return ECORE_CALLBACK_PASS_ON; - ELOGF("LAUNCHER_SRV", "Start Resource Destroy tws_service_launcher", lc->ec); +send_stop: + ELOGF("LAUNCHER_SRV", "CLIENT SHOW: Failure Case runner:%p", ec, runner); - if (_e_srv_launcher == lc) - _e_srv_launcher = NULL; + _launcher_stop_send(runner); - lc->res = NULL; - _e_srv_launcher_data_free(lc); + if (runner->state == LAUNCHER_STATE_MONITORING) + runner->target.pid = -1; + else if (runner->direction == TWS_SERVICE_LAUNCHER_DIRECTION_FORWARD) + _launcher_post_forward(runner, EINA_FALSE); + else if (runner->direction == TWS_SERVICE_LAUNCHER_DIRECTION_BACKWARD) + _launcher_post_backward(runner, EINA_FALSE); - ELOGF("LAUNCHER_SRV", "End Resource Destroy tws_service_launcher", NULL); -} + _launcher_state_set(runner, LAUNCHER_STATE_IDLE); + _launcher_handler_launcher_runner_unset(runner); -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); + return ECORE_CALLBACK_PASS_ON; } -static void -_e_srv_launcher_cb_launch(struct wl_client *client EINA_UNUSED, - struct wl_resource *res_tws_lc, - const char *app_id, - const char *instance_id, - int32_t pid) -{ - E_Service_Launcher *lc; - E_Client *target_ec; - Eina_List *ecs, *l; - Eina_Bool sent = EINA_FALSE; - - 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 instance id:%s pid:%d", - lc->ec, app_id?:"NONE", instance_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); - - sent = _e_srv_launcher_prepare_forward_send(lc, target_ec); - EINA_SAFETY_ON_FALSE_GOTO(sent, send_stop); - - _e_srv_launcher_state_set(lc, LAUNCHER_STATE_PREPARING); - break; - } - eina_list_free(ecs); +#undef LAUNCHER_HANDLER_CB_ADD +#define LAUNCHER_HANDLER_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) - 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; +static E_Service_Launcher_Handler * +_launcher_handler_create(void) +{ + E_Service_Launcher_Handler *laundler = NULL; -send_stop: - ELOGF("LAUNCHER_SRV", "can't process request(launcher_launch)", lc->ec); - _e_srv_launcher_stop_send(lc); -} + laundler = E_NEW(E_Service_Launcher_Handler, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(laundler, NULL); -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; + laundler->launcher_count = 0; + laundler->launcher_hash = eina_hash_pointer_new(NULL); - lc = wl_resource_get_user_data(res_tws_lc); - EINA_SAFETY_ON_NULL_RETURN(lc); + LAUNCHER_HANDLER_CB_ADD(laundler->hooks_vis, + e_policy_visibility_hook_add, + E_POL_VIS_HOOK_TYPE_UNICONIFY_RENDER_RUNNING, + _launcher_handler_cb_hook_vis_uniconify_render_running, NULL); - ELOGF("LAUNCHER_SRV", "LAUNCHING(%d) %s", - lc->ec, serial, lc->direction?"backward":"forward"); + LAUNCHER_HANDLER_CB_ADD(laundler->hooks_vis, + e_policy_visibility_hook_add, + E_POL_VIS_HOOK_TYPE_LOWER, + _launcher_handler_cb_hook_vis_lower, NULL); - _e_srv_launcher_state_set(lc, LAUNCHER_STATE_LAUNCHING); + LAUNCHER_HANDLER_CB_ADD(laundler->hooks_vis, + e_policy_visibility_hook_add, + E_POL_VIS_HOOK_TYPE_HIDE, + _launcher_handler_cb_hook_vis_hide, NULL); - 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); - } -} + LAUNCHER_HANDLER_CB_ADD(laundler->hooks_ec, + e_client_hook_add, + E_CLIENT_HOOK_DEL, + _launcher_handler_cb_hook_client_del, NULL); -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; + LAUNCHER_HANDLER_CB_ADD(laundler->hooks_co, + e_comp_object_intercept_hook_add, + E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER, + _launcher_handler_cb_hook_intercept_show_helper, NULL); - 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); + LAUNCHER_HANDLER_CB_ADD(laundler->hdlrs_ev, + ecore_event_handler_add, + E_EVENT_CLIENT_SHOW, + _launcher_handler_cb_event_client_show, NULL); - 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); + ELOGF("LAUNCHER_SRV", "new launcher handler(%p) created", NULL, laundler); - if ((lc->state == LAUNCHER_STATE_LAUNCHING) || - (lc->state == LAUNCHER_STATE_LAUNCHING_WAIT_BUFFER)) - _e_srv_launcher_state_set(lc, LAUNCHER_STATE_DONE); + return laundler; } static void -_e_srv_launcher_cb_launch_cancel(struct wl_client *client EINA_UNUSED, - struct wl_resource *res_tws_lc, - uint32_t serial) +_launcher_handler_destroy(E_Service_Launcher_Handler *laundler) { - E_Service_Launcher *lc; - - lc = wl_resource_get_user_data(res_tws_lc); - EINA_SAFETY_ON_NULL_RETURN(lc); + EINA_SAFETY_ON_NULL_RETURN(laundler); - ELOGF("LAUNCHER_SRV", "LAUNCH_CANCEL(%d) target_ec:%p", - lc->ec, serial, lc->target.ec); + E_FREE_LIST(laundler->hdlrs_ev, ecore_event_handler_del); + E_FREE_LIST(laundler->hooks_co, e_comp_object_intercept_hook_del); + E_FREE_LIST(laundler->hooks_ec, e_client_hook_del); + E_FREE_LIST(laundler->hooks_vis, e_policy_visibility_hook_del); - 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); + E_FREE_FUNC(laundler->launcher_hash, eina_hash_free); + E_FREE(laundler); } -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) { @@ -863,26 +1312,15 @@ e_service_launcher_resource_set(E_Client *ec, struct wl_resource *res_tws_lc) EINA_SAFETY_ON_NULL_RETURN(ec); EINA_SAFETY_ON_NULL_RETURN(res_tws_lc); - lc = _e_srv_launcher; + lc = _launcher_handler_launcher_find(ec); 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) + &_launcher_iface, lc, + _launcher_cb_resource_destroy); +} EINTERN void e_service_launcher_client_set(E_Client *ec) @@ -892,32 +1330,32 @@ e_service_launcher_client_set(E_Client *ec) EINA_SAFETY_ON_NULL_RETURN(ec); EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(ec))); - if (_e_srv_launcher) + if ((lc = _launcher_handler_launcher_find(ec))) { - lc = _e_srv_launcher; - _e_srv_launcher_data_reset(lc); + ELOGF("LAUNCHER_SRV", "ec(%p) is already set as launcher(%p)", + ec, ec, lc); + return; } - if (!lc) + if (!_laundler) { - - 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; + _laundler = _launcher_handler_create(); + EINA_SAFETY_ON_NULL_RETURN(_laundler); } + lc = E_NEW(E_Service_Launcher, 1); + EINA_SAFETY_ON_NULL_RETURN(lc); + lc->ec = ec; + if (!_launcher_handler_launcher_add(lc)) + { + E_FREE(lc); + ELOGF("LAUNCHER_SRV", "Fail to add launcher", ec); + return; + } ELOGF("LAUNCHER_SRV", "client set|Created New Launcher(%p)", ec, lc); + _launcher_state_set(lc, LAUNCHER_STATE_IDLE); return; } @@ -928,11 +1366,22 @@ 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); + lc = _launcher_handler_launcher_find(ec); + EINA_SAFETY_ON_NULL_RETURN(lc); + + _launcher_handler_launcher_del(lc); + _launcher_data_reset(lc); + E_FREE(lc); ELOGF("LAUNCHER_SRV", "client unset", ec); + + if ((_laundler) && (_laundler->launcher_count == 0)) + { + ELOGF("LAUNCHER_SRV", "No launcher available, Destroy Launcher Handler(%p)", + NULL, _laundler); + + _launcher_handler_destroy(_laundler); + _laundler = NULL; + } } -- 2.7.4