From: Doyoun Kang Date: Tue, 16 Aug 2016 04:05:37 +0000 (+0900) Subject: e_process: added feature to handle process status X-Git-Tag: accepted/tizen/common/20160817.133000~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F53%2F83953%2F3;p=platform%2Fupstream%2Fenlightenment.git e_process: added feature to handle process status Change-Id: Ie12d0603367116977c5b923cf86727ba305e1af6 --- diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index 37fe0c1..9c3d11a 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -102,7 +102,8 @@ src/bin/e_policy.h \ src/bin/e_policy_keyboard.h \ src/bin/e_policy_private_data.h \ src/bin/e_policy_wl.h \ -src/bin/e_policy_wl_display.h +src/bin/e_policy_wl_display.h \ +src/bin/e_process.h enlightenment_src = \ src/bin/e_actions.c \ @@ -189,7 +190,8 @@ src/bin/e_policy_softkey.c \ src/bin/e_policy_stack.c \ src/bin/e_policy_visibility.c \ src/bin/e_policy_wl.c \ -src/bin/e_policy_wl_display.c +src/bin/e_policy_wl_display.c \ +src/bin/e_process.c src_bin_enlightenment_CPPFLAGS = $(E_CPPFLAGS) -DEFL_BETA_API_SUPPORT -DEFL_EO_API_SUPPORT -DE_LOGGING=1 @WAYLAND_CFLAGS@ $(TTRACE_CFLAGS) $(DLOG_CFLAGS) $(POLICY_CFLAGS) if HAVE_WAYLAND_TBM diff --git a/src/bin/e_includes.h b/src/bin/e_includes.h index 77f1ef9..5681cde 100644 --- a/src/bin/e_includes.h +++ b/src/bin/e_includes.h @@ -59,3 +59,4 @@ # include "e_comp_wl_tbm.h" #endif #include "e_policy.h" +#include "e_process.h" diff --git a/src/bin/e_main.c b/src/bin/e_main.c index eda6612..d926de5 100644 --- a/src/bin/e_main.c +++ b/src/bin/e_main.c @@ -683,6 +683,15 @@ main(int argc, char **argv) _e_main_shutdown_push(e_policy_shutdown); } + TS("E_Process Init"); + if (!e_process_init()) + { + e_error_message_show(_("Enlightenment cannot setup process managing system!\n")); + _e_main_shutdown(-1); + } + TS("E_Process Init Done"); + _e_main_shutdown_push(e_process_shutdown); + TS("Load Modules"); _e_main_modules_load(safe_mode); TS("Load Modules Done"); diff --git a/src/bin/e_process.c b/src/bin/e_process.c new file mode 100644 index 0000000..8825ab6 --- /dev/null +++ b/src/bin/e_process.c @@ -0,0 +1,547 @@ +#include "e.h" + +static E_Process *_e_process_find(E_Process_Manager *pm, pid_t pid); +static E_Process *_e_process_new(pid_t pid); +static void _e_process_del(E_Process *pinfo); + +static Eina_Bool _e_process_client_info_add(E_Client *ec); +static void _e_process_client_info_del(E_Client *ec); + +static Eina_Bool _e_process_cb_client_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_process_cb_client_remove(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_process_cb_client_iconify(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_process_cb_client_uniconify(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_process_cb_client_visibility_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_process_cb_client_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); + +static void _e_process_cb_hook_visibility(void *d EINA_UNUSED, E_Client *ec); + +static Eina_Bool _e_process_freeze_condition_check(pid_t pid); +static Eina_Bool _e_process_freeze(pid_t pid); +static Eina_Bool _e_process_thaw(pid_t pid); + +static void _e_process_action_change(E_Process *epro, E_Process_Action act); +static void _e_process_state_change(E_Process *epro, E_Process_State state); + + +static void _e_process_hooks_clean(void); +static void _e_process_hook_call(E_Process_Hook_Point hookpoint, E_Process *epro, void *user_data); + + +static Eina_Inlist *_e_process_hooks[] = +{ + [E_PROCESS_HOOK_STATE_CHANGE] = NULL, + [E_PROCESS_HOOK_ACTION_CHANGE] = NULL, +}; + +static int _e_process_hooks_delete = 0; +static int _e_process_hooks_walking = 0; + +static Eina_List *_e_process_ec_handlers = NULL; +static Eina_List *_e_process_ec_hooks = NULL; + +E_Process_Manager *_e_process_manager; + + +static E_Process * +_e_process_find(E_Process_Manager *pm, pid_t pid) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL); + return eina_hash_find(pm->pids_hash, &pid); +} + +static E_Process * +_e_process_new(pid_t pid) +{ + E_Process *pinfo = NULL; + + if (pid <= 0) return NULL; + + pinfo = E_NEW(E_Process, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(pinfo, NULL); + + pinfo->pid = pid; + pinfo->state = E_PROCESS_STATE_UNKNOWN; + + eina_hash_add(_e_process_manager->pids_hash, &pid, pinfo); + _e_process_manager->process_list = eina_inlist_append(_e_process_manager->process_list, EINA_INLIST_GET(pinfo)); + + return pinfo; +} + +static void +_e_process_del(E_Process *pinfo) +{ + pid_t pid; + + EINA_SAFETY_ON_NULL_RETURN(pinfo); + + pid = pinfo->pid; + + _e_process_manager->process_list = eina_inlist_remove(_e_process_manager->process_list, EINA_INLIST_GET(pinfo)); + eina_hash_del_by_key(_e_process_manager->pids_hash, &pid); + + E_FREE(pinfo); +} + +static Eina_Bool +_e_process_client_info_add(E_Client *ec) +{ + E_Process *pinfo = NULL; + pid_t pid; + + if (!ec) return EINA_FALSE; + + pid = ec->netwm.pid; + if (pid <= 0) return EINA_FALSE; + + pinfo = _e_process_find(_e_process_manager, pid); + if (!pinfo) + { + pinfo = _e_process_new(pid); + EINA_SAFETY_ON_NULL_RETURN_VAL(pinfo, EINA_FALSE); + } + + if (!eina_list_data_find(pinfo->ec_list, ec)) + pinfo->ec_list = eina_list_append(pinfo->ec_list, ec); + + return EINA_TRUE; +} + +static void +_e_process_client_info_del(E_Client *ec) +{ + E_Process *pinfo = NULL; + pid_t pid; + + if (!ec) return; + + pid = ec->netwm.pid; + if (pid <=0) return; + + pinfo = _e_process_find(_e_process_manager, pid); + EINA_SAFETY_ON_NULL_RETURN(pinfo); + + if (_e_process_manager->active_win == ec) + { + _e_process_manager->active_win = NULL; + ELOGF("PROCESS", "ACTION DEACTIVATE. PID:%d", NULL, NULL, pid); + _e_process_action_change(pinfo, E_PROCESS_ACT_DEACTIVATE); + } + + pinfo->ec_list = eina_list_remove(pinfo->ec_list, ec); + + if (!pinfo->ec_list) + _e_process_del(pinfo); + + return; +} + +static Eina_Bool +_e_process_cb_client_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + E_Client *ec; + + ev = event; + if (!ev) return ECORE_CALLBACK_PASS_ON; + + ec = ev->ec; + _e_process_client_info_add(ec); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_process_cb_client_remove(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + E_Client *ec; + + ev = event; + if (!ev) return ECORE_CALLBACK_PASS_ON; + + ec = ev->ec; + _e_process_client_info_del(ec); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_process_cb_client_iconify(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + E_Client *ec; + pid_t pid; + + ev = event; + if (!ev) return ECORE_CALLBACK_PASS_ON; + + ec = ev->ec; + if (!ec) return ECORE_CALLBACK_PASS_ON; + + pid = ec->netwm.pid; + + // check all ECs of its pid, if yes, freeze + if (_e_process_freeze_condition_check(pid)) + _e_process_freeze(pid); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_process_cb_client_uniconify(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + E_Client *ec; + pid_t pid; + + ev = event; + if (!ev) return ECORE_CALLBACK_PASS_ON; + + ec = ev->ec; + if (!ec) return ECORE_CALLBACK_PASS_ON; + + pid = ec->netwm.pid; + _e_process_thaw(pid); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_process_cb_client_visibility_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + E_Client *ec; + pid_t pid; + + ev = event; + if (!ev) return ECORE_CALLBACK_PASS_ON; + + ec = ev->ec; + if (!ec) return ECORE_CALLBACK_PASS_ON; + + pid = ec->netwm.pid; + if (ec->visibility.obscured == E_VISIBILITY_UNOBSCURED) + _e_process_thaw(pid); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_process_cb_client_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + E_Client *ec; + E_Client *ec_deactive; + E_Process *pinfo = NULL; + E_Process *pinfo_deactive = NULL; + Eina_Bool change_active = EINA_FALSE; + pid_t pid = -1; + pid_t pid_deactivate = -1; + + ev = event; + if (!ev) return ECORE_CALLBACK_PASS_ON; + + ec = ev->ec; + if (!ec) return ECORE_CALLBACK_PASS_ON; + + pid = ec->netwm.pid; + if (pid <= 0) return EINA_FALSE; + + pinfo = _e_process_find(_e_process_manager, pid); + if (!pinfo) return EINA_FALSE; + + ec_deactive = _e_process_manager->active_win; + _e_process_manager->active_win = ec; + + if (!ec_deactive) + { + change_active = EINA_TRUE; + } + else + { + pid_deactivate = ec_deactive->netwm.pid; + if (pid_deactivate != pid) + { + change_active = EINA_TRUE; + } + } + + if (change_active) + { + ELOGF("PROCESS", "ACTION ACTIVATE. PID:%d", NULL, NULL, pid); + _e_process_action_change(pinfo, E_PROCESS_ACT_ACTIVATE); + + if (ec_deactive) + { + pinfo_deactive = _e_process_find(_e_process_manager, ec_deactive->netwm.pid); + if (pinfo_deactive) + { + ELOGF("PROCESS", "ACTION DEACTIVATE. PID:%d", NULL, NULL, pinfo_deactive->pid); + _e_process_action_change(pinfo_deactive, E_PROCESS_ACT_DEACTIVATE); + } + } + } + + return ECORE_CALLBACK_PASS_ON; +} + +static void +_e_process_cb_hook_visibility(void *d EINA_UNUSED, E_Client *ec) +{ + if (ec->visibility.changed) + { + if (ec->visibility.obscured == E_VISIBILITY_UNOBSCURED) + { + _e_process_thaw(ec->netwm.pid); + } + } +} + +static Eina_Bool +_e_process_freeze_condition_check(pid_t pid) +{ + E_Process *pinfo = NULL; + E_Client *ec = NULL; + Eina_Bool freeze = EINA_TRUE; + Eina_List *l; + + if (pid <= 0) return EINA_FALSE; + + pinfo = _e_process_find(_e_process_manager, pid); + EINA_SAFETY_ON_NULL_RETURN_VAL(pinfo, EINA_FALSE); + + if (pinfo->state == E_PROCESS_STATE_BACKGROUND) return EINA_FALSE; + if (!pinfo->ec_list) return EINA_FALSE; + + EINA_LIST_FOREACH(pinfo->ec_list, l, ec) + { + if (!ec->iconic) + { + freeze = EINA_FALSE; + break; + } + } + + return freeze; +} + +static Eina_Bool +_e_process_freeze(pid_t pid) +{ + E_Process *pinfo = NULL; + + if (pid <= 0) return EINA_FALSE; + + pinfo = _e_process_find(_e_process_manager, pid); + EINA_SAFETY_ON_NULL_RETURN_VAL(pinfo, EINA_FALSE); + + if (pinfo->state != E_PROCESS_STATE_BACKGROUND) + { + ELOGF("PROCESS", "STATE BACKGROUND. PID:%d", NULL, NULL, pid); + _e_process_state_change(pinfo, E_PROCESS_STATE_BACKGROUND); + } + + return EINA_TRUE; +} + +static Eina_Bool +_e_process_thaw(pid_t pid) +{ + E_Process *pinfo = NULL; + + if (pid <= 0) return EINA_FALSE; + + pinfo = _e_process_find(_e_process_manager, pid); + EINA_SAFETY_ON_NULL_RETURN_VAL(pinfo, EINA_FALSE); + + if (pinfo->state != E_PROCESS_STATE_FOREGROUND) + { + ELOGF("PROCESS", "STATE FOREGROUND. PID:%d", NULL, NULL, pid); + _e_process_state_change(pinfo, E_PROCESS_STATE_FOREGROUND); + } + + return EINA_TRUE; +} + +static void +_e_process_action_change(E_Process *epro, E_Process_Action act) +{ + EINA_SAFETY_ON_NULL_RETURN(epro); + + _e_process_hook_call(E_PROCESS_HOOK_ACTION_CHANGE, epro, (E_Process_Action *)&act); +} + +static void +_e_process_state_change(E_Process *epro, E_Process_State state) +{ + EINA_SAFETY_ON_NULL_RETURN(epro); + + if (epro->state != state) + { + epro->state = state; + _e_process_hook_call(E_PROCESS_HOOK_STATE_CHANGE, epro, NULL); + + if (state == E_PROCESS_STATE_FOREGROUND) + { + ELOGF("PROCESS", "ACTION FOREGROUND. PID:%d", NULL, NULL, epro->pid); + _e_process_action_change(epro, E_PROCESS_ACT_FOREGROUND); + } + else if (state == E_PROCESS_STATE_BACKGROUND) + { + ELOGF("PROCESS", "ACTION BACKGROUND. PID:%d", NULL, NULL, epro->pid); + _e_process_action_change(epro, E_PROCESS_ACT_BACKGROUND); + } + } +} + +static void +_e_process_hooks_clean(void) +{ + Eina_Inlist *l; + E_Process_Hook *ph; + unsigned int x; + + for (x = 0; x < E_PROCESS_HOOK_LAST; x++) + EINA_INLIST_FOREACH_SAFE(_e_process_hooks[x], l, ph) + { + if (!ph->delete_me) continue; + _e_process_hooks[x] = eina_inlist_remove(_e_process_hooks[x], + EINA_INLIST_GET(ph)); + free(ph); + } +} + +static void +_e_process_hook_call(E_Process_Hook_Point hookpoint, E_Process *epro, void *user_data) +{ + E_Process_Hook *ph; + + _e_process_hooks_walking++; + EINA_INLIST_FOREACH(_e_process_hooks[hookpoint], ph) + { + if (ph->delete_me) continue; + ph->func(ph->data, epro, user_data); + } + _e_process_hooks_walking--; + if ((_e_process_hooks_walking == 0) && (_e_process_hooks_delete > 0)) + _e_process_hooks_clean(); +} + + +static E_Process_Manager * +_e_process_manager_new(void) +{ + E_Process_Manager *pm; + + pm = E_NEW(E_Process_Manager, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL); + + pm->pids_hash = eina_hash_pointer_new(NULL); + if (!pm->pids_hash) goto error; + + return pm; + +error: + + E_FREE(pm); + return NULL; + +} + +static void +_e_process_manager_del(E_Process_Manager *pm) +{ + E_Process *pinfo = NULL; + + if (!pm) return; + + EINA_INLIST_FREE(pm->process_list, pinfo) + { + eina_list_free(pinfo->ec_list); + eina_hash_del_by_key(pm->pids_hash, &pinfo->pid); + E_FREE(pinfo); + } + + if (pm->pids_hash) + { + eina_hash_free(pm->pids_hash); + pm->pids_hash = NULL; + } + + E_FREE(pm); +} + + +E_API Eina_Bool +e_process_init(void) +{ + E_Process_Manager *e_pm; + E_Client_Hook *hook; + + e_pm = _e_process_manager_new(); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_pm, EINA_FALSE); + + E_LIST_HANDLER_APPEND(_e_process_ec_handlers, E_EVENT_CLIENT_ADD, _e_process_cb_client_add, NULL); + E_LIST_HANDLER_APPEND(_e_process_ec_handlers, E_EVENT_CLIENT_REMOVE, _e_process_cb_client_remove, NULL); + E_LIST_HANDLER_APPEND(_e_process_ec_handlers, E_EVENT_CLIENT_ICONIFY, _e_process_cb_client_iconify, NULL); + E_LIST_HANDLER_APPEND(_e_process_ec_handlers, E_EVENT_CLIENT_UNICONIFY, _e_process_cb_client_uniconify, NULL); + E_LIST_HANDLER_APPEND(_e_process_ec_handlers, E_EVENT_CLIENT_VISIBILITY_CHANGE, _e_process_cb_client_visibility_change, NULL); + E_LIST_HANDLER_APPEND(_e_process_ec_handlers, E_EVENT_CLIENT_FOCUS_IN, _e_process_cb_client_focus_in, NULL); + + hook = e_client_hook_add(E_CLIENT_HOOK_EVAL_VISIBILITY, _e_process_cb_hook_visibility, NULL); + if (hook) _e_process_ec_hooks = eina_list_append(_e_process_ec_hooks, hook); + + _e_process_manager = e_pm; + + return EINA_TRUE; +} + +E_API int +e_process_shutdown(void) +{ + E_Client_Hook *hook; + + if (!_e_process_manager) return 0; + + E_FREE_LIST(_e_process_ec_handlers, ecore_event_handler_del); + EINA_LIST_FREE(_e_process_ec_hooks, hook) + e_client_hook_del(hook); + + _e_process_manager_del(_e_process_manager); + _e_process_manager = NULL; + + return 1; +} + +E_API E_Process_Hook * +e_process_hook_add(E_Process_Hook_Point hookpoint, E_Process_Hook_Cb func, const void *data) +{ + E_Process_Hook *ph; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_PROCESS_HOOK_LAST, NULL); + + ph = E_NEW(E_Process_Hook, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(ph, NULL); + + ph->hookpoint = hookpoint; + ph->func = func; + ph->data = (void*)data; + + _e_process_hooks[hookpoint] = eina_inlist_append(_e_process_hooks[hookpoint], EINA_INLIST_GET(ph)); + return ph; +} + +E_API void +e_process_hook_del(E_Process_Hook *ph) +{ + ph->delete_me = 1; + if (_e_process_hooks_walking == 0) + { + _e_process_hooks[ph->hookpoint] = eina_inlist_remove(_e_process_hooks[ph->hookpoint], EINA_INLIST_GET(ph)); + free(ph); + } + else + _e_process_hooks_delete++; +} diff --git a/src/bin/e_process.h b/src/bin/e_process.h new file mode 100644 index 0000000..bd3a084 --- /dev/null +++ b/src/bin/e_process.h @@ -0,0 +1,74 @@ +# ifdef E_TYPEDEFS + +typedef enum _E_Process_Action +{ + E_PROCESS_ACT_LAUNCH = 0, + E_PROCESS_ACT_RESUME = 1, + E_PROCESS_ACT_TERMINATE = 2, + E_PROCESS_ACT_FOREGROUND = 3, + E_PROCESS_ACT_BACKGROUND = 4, + E_PROCESS_ACT_ACTIVATE = 5, + E_PROCESS_ACT_DEACTIVATE = 6, +} E_Process_Action; + +typedef enum _E_Process_State +{ + E_PROCESS_STATE_UNKNOWN, + E_PROCESS_STATE_BACKGROUND, + E_PROCESS_STATE_FOREGROUND, +} E_Process_State; + +typedef enum _E_Process_Hook_Point +{ + E_PROCESS_HOOK_STATE_CHANGE, + E_PROCESS_HOOK_ACTION_CHANGE, + E_PROCESS_HOOK_LAST +} E_Process_Hook_Point; + +typedef struct _E_Process_Manager E_Process_Manager; +typedef struct _E_Process E_Process; + +typedef struct _E_Process_Hook E_Process_Hook; + +typedef void (*E_Process_Hook_Cb)(void *data, E_Process *epro, void *user); + + +# else + +# ifndef E_PROCESSMGR_H +# define E_PROCESSMGR_H + +struct _E_Process_Hook +{ + EINA_INLIST; + E_Process_Hook_Point hookpoint; + E_Process_Hook_Cb func; + void *data; + unsigned char delete_me : 1; +}; + +struct _E_Process_Manager +{ + Eina_Hash *pids_hash; + Eina_Inlist *process_list; + E_Client *active_win; +}; + +struct _E_Process +{ + EINA_INLIST; + pid_t pid; + Eina_List *ec_list; + E_Process_State state; +}; + +E_API Eina_Bool e_process_init(void); +E_API int e_process_shutdown(void); + +E_API E_Process_Hook *e_process_hook_add(E_Process_Hook_Point hookpoint, E_Process_Hook_Cb func, const void *data); +E_API void e_process_hook_del(E_Process_Hook *ph); + + +#endif +#endif +