From: MinJeong Kim Date: Fri, 22 Jul 2016 07:31:07 +0000 (+0900) Subject: e_policy/e_service: added policy system and tizen_ws_shell interfaces X-Git-Tag: submit/tizen/20160803.115336~21 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8ea090222cee86b57e54f1444c5b63252380fba5;p=platform%2Fupstream%2Fenlightenment.git e_policy/e_service: added policy system and tizen_ws_shell interfaces Change-Id: Iad5fb635573d4d65aa2cd357be23a93794496833 Signed-off-by: MinJeong Kim --- diff --git a/configure.ac b/configure.ac index 0d5ff97e93..74f7776b79 100755 --- a/configure.ac +++ b/configure.ac @@ -460,6 +460,27 @@ AM_CONDITIONAL([HAVE_WAYLAND], [test "x${have_wayland}" = "xyes"]) AM_CONDITIONAL([HAVE_WAYLAND_TBM], [test "x${have_wayland_tbm}" = "xyes"]) AM_CONDITIONAL([HAVE_HWC], [test "x${have_hwc}" = "xyes"]) +#capi-system-device +PKG_CHECK_MODULES([CAPI_SYSTEM_DEVICE], + [capi-system-device]) +#cynara +PKG_CHECK_MODULES(CYNARA, + [cynara-client, cynara-creds-socket, cynara-session], + [have_cynara="yes"], [have_cynara="no"]) +if test "x${have_cynara}" = "xyes"; then + AC_DEFINE([HAVE_CYNARA], [1], [Define to 1 if you have cynara]) +fi + +#tzsh-server +PKG_CHECK_MODULES(TZSH, + [tzsh-server], + [have_tzsh="yes"]) + +POLICY_CFLAGS="${CAPI_SYSTEM_DEVICE_CFLAGS} ${CYNARA_CFLAGS} ${TZSH_CFLAGS}" +POLICY_LIBS="${CAPI_SYSTEM_DEVICE_LIBS} ${CYNARA_LIBS} ${TZSH_LIBS}" +AC_SUBST(POLICY_CFLAGS) +AC_SUBST(POLICY_LIBS) + WL_DESKTOP_SHELL=false define([CHECK_MODULE_WL_DESKTOP_SHELL], [ diff --git a/packaging/enlightenment.spec b/packaging/enlightenment.spec index 266e0bacca..75a8ff933b 100755 --- a/packaging/enlightenment.spec +++ b/packaging/enlightenment.spec @@ -34,6 +34,10 @@ BuildRequires: pkgconfig(wayland-tbm-server) BuildRequires: pkgconfig(ecore-drm) BuildRequires: pkgconfig(libtdm) BuildRequires: pkgconfig(gbm) +BuildRequires: pkgconfig(capi-system-device) +BuildRequires: pkgconfig(tzsh-server) +BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(cynara-creds-socket) Requires: libwayland-extension-server %description diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index da260f1dc2..a4b8000f97 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -93,6 +93,19 @@ ENLIGHTENMENTHEADERS += \ src/bin/e_comp_wl_tbm.h endif +ENLIGHTENMENTHEADERS += \ +src/bin/services/e_service_gesture.h \ +src/bin/services/e_service_lockscreen.h \ +src/bin/services/e_service_quickpanel.h \ +src/bin/services/e_service_region.h \ +src/bin/services/e_service_volume.h \ +src/bin/e_policy.h \ +src/bin/e_policy_keyboard.h \ +src/bin/e_policy_private_data.h \ +src/bin/e_policy_transform_mode.h \ +src/bin/e_policy_wl.h \ +src/bin/e_policy_wl_display.h + enlightenment_src = \ src/bin/e_actions.c \ src/bin/e_bg.c \ @@ -166,7 +179,23 @@ enlightenment_src += \ src/bin/e_comp_wl_tbm.c endif -src_bin_enlightenment_CPPFLAGS = $(E_CPPFLAGS) -DEFL_BETA_API_SUPPORT -DEFL_EO_API_SUPPORT -DE_LOGGING=1 @WAYLAND_CFLAGS@ $(TTRACE_CFLAGS) $(DLOG_CFLAGS) +enlightenment_src += \ +src/bin/services/e_service_gesture.c \ +src/bin/services/e_service_lockscreen.c \ +src/bin/services/e_service_quickpanel.c \ +src/bin/services/e_service_region.c \ +src/bin/services/e_service_volume.c \ +src/bin/e_policy.c \ +src/bin/e_policy_conformant.c \ +src/bin/e_policy_keyboard.c \ +src/bin/e_policy_softkey.c \ +src/bin/e_policy_stack.c \ +src/bin/e_policy_transform_mode.c \ +src/bin/e_policy_visibility.c \ +src/bin/e_policy_wl.c \ +src/bin/e_policy_wl_display.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 src_bin_enlightenment_CPPFLAGS += @WAYLAND_TBM_CFLAGS@ @ECORE_DRM_CFLAGS@ endif @@ -179,7 +208,7 @@ src/bin/e_main.c \ $(enlightenment_src) src_bin_enlightenment_LDFLAGS = -export-dynamic -src_bin_enlightenment_LDADD = @e_libs@ @dlopen_libs@ @cf_libs@ @VALGRIND_LIBS@ @WAYLAND_LIBS@ -lm @SHM_OPEN_LIBS@ $(TTRACE_LIBS) $(DLOG_LIBS) +src_bin_enlightenment_LDADD = @e_libs@ @dlopen_libs@ @cf_libs@ @VALGRIND_LIBS@ @WAYLAND_LIBS@ -lm @SHM_OPEN_LIBS@ $(TTRACE_LIBS) $(DLOG_LIBS) $(POLICY_LIBS) if HAVE_WAYLAND_TBM src_bin_enlightenment_LDADD += @WAYLAND_TBM_LIBS@ @ECORE_DRM_LIBS@ endif diff --git a/src/bin/e_includes.h b/src/bin/e_includes.h index b890392644..775228144a 100644 --- a/src/bin/e_includes.h +++ b/src/bin/e_includes.h @@ -60,3 +60,4 @@ #ifdef HAVE_WAYLAND_TBM # include "e_comp_wl_tbm.h" #endif +#include "e_policy.h" diff --git a/src/bin/e_main.c b/src/bin/e_main.c index bd7acf15a0..4dd01f7b7f 100644 --- a/src/bin/e_main.c +++ b/src/bin/e_main.c @@ -281,6 +281,16 @@ _e_main_subsystem_defer(void *data EINA_UNUSED) TS("[DEFERRED] Compositor's deferred job Done"); TRACE_DS_END(); + if (e_config->use_e_policy) + { + TRACE_DS_BEGIN(MAIN:DEFERRED POLICY JOB); + + TS("[DEFERRED] E_Policy's deferred job"); + e_policy_deferred_job(); + TS("[DEFERRED] E_Policy's deferred job Done"); + + TRACE_DS_END(); + } TRACE_DS_BEGIN(MAIN:DEFERRED MODULE JOB); TS("[DEFERRED] E_Module's deferred job"); @@ -661,6 +671,18 @@ main(int argc, char **argv) TS("E_Icon Init Done"); _e_main_shutdown_push(e_icon_shutdown); + if (e_config->use_e_policy) + { + TS("E_Policy Init"); + if (!e_policy_init()) + { + e_error_message_show(_("Enlightenment cannot setup policy system!\n")); + _e_main_shutdown(-1); + } + TS("E_Policy Init Done"); + _e_main_shutdown_push(e_policy_shutdown); + } + TS("Load Modules"); _e_main_modules_load(safe_mode); TS("Load Modules Done"); diff --git a/src/bin/e_policy.c b/src/bin/e_policy.c new file mode 100644 index 0000000000..382b1a0071 --- /dev/null +++ b/src/bin/e_policy.c @@ -0,0 +1,1409 @@ +#include "e.h" +#include "e_policy_keyboard.h" +#include "e_policy_transform_mode.h" +#include "e_policy_conformant.h" +#include "e_policy_wl.h" + +E_Policy *e_policy = NULL; +Eina_Hash *hash_policy_desks = NULL; +Eina_Hash *hash_policy_clients = NULL; +E_Policy_System_Info e_policy_system_info = +{ + {NULL, EINA_FALSE}, + { -1, -1, EINA_FALSE} +}; + +static Eina_List *handlers = NULL; +static Eina_List *hooks_ec = NULL; +static Eina_List *hooks_cp = NULL; + +static E_Policy_Client *_e_policy_client_add(E_Client *ec); +static void _e_policy_client_del(E_Policy_Client *pc); +static Eina_Bool _e_policy_client_normal_check(E_Client *ec); +static Eina_Bool _e_policy_client_maximize_policy_apply(E_Policy_Client *pc); +static void _e_policy_client_maximize_policy_cancel(E_Policy_Client *pc); +static void _e_policy_client_floating_policy_apply(E_Policy_Client *pc); +static void _e_policy_client_floating_policy_cancel(E_Policy_Client *pc); +static void _e_policy_client_launcher_set(E_Policy_Client *pc); + +static void _e_policy_cb_hook_client_eval_pre_new_client(void *d EINA_UNUSED, E_Client *ec); +static void _e_policy_cb_hook_client_eval_pre_fetch(void *d EINA_UNUSED, E_Client *ec); +static void _e_policy_cb_hook_client_eval_pre_post_fetch(void *d EINA_UNUSED, E_Client *ec); +static void _e_policy_cb_hook_client_eval_post_fetch(void *d EINA_UNUSED, E_Client *ec); +static void _e_policy_cb_hook_client_eval_post_new_client(void *d EINA_UNUSED, E_Client *ec); +static void _e_policy_cb_hook_client_desk_set(void *d EINA_UNUSED, E_Client *ec); +static void _e_policy_cb_hook_client_fullscreen_pre(void *data EINA_UNUSED, E_Client *ec); + +static void _e_policy_cb_hook_pixmap_del(void *data EINA_UNUSED, E_Pixmap *cp); +static void _e_policy_cb_hook_pixmap_unusable(void *data EINA_UNUSED, E_Pixmap *cp); + +static void _e_policy_cb_desk_data_free(void *data); +static void _e_policy_cb_client_data_free(void *data); +static Eina_Bool _e_policy_cb_zone_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_policy_cb_zone_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_policy_cb_zone_move_resize(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_policy_cb_zone_desk_count_set(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_policy_cb_zone_display_state_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_policy_cb_desk_show(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_policy_cb_client_add(void *data EINA_UNUSED, int type, void *event); +static Eina_Bool _e_policy_cb_client_move(void *data EINA_UNUSED, int type, void *event); +static Eina_Bool _e_policy_cb_client_resize(void *data EINA_UNUSED, int type, void *event); +static Eina_Bool _e_policy_cb_client_stack(void *data EINA_UNUSED, int type, void *event); +static Eina_Bool _e_policy_cb_client_property(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _e_policy_cb_client_vis_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED); + +static void +_e_policy_client_launcher_set(E_Policy_Client *pc) +{ + E_Policy_Client *pc2; + + pc2 = e_policy_client_launcher_get(pc->ec->zone); + if (pc2) return; + + if (pc->ec->netwm.type != e_config->launcher.type) + return; + + if (e_util_strcmp(pc->ec->icccm.class, + e_config->launcher.clas)) + return; + + + if (e_util_strcmp(pc->ec->icccm.title, + e_config->launcher.title)) + { + /* check netwm name instead, because comp_x had ignored + * icccm name when fetching */ + if (e_util_strcmp(pc->ec->netwm.name, + e_config->launcher.title)) + { + return; + } + } + + e_policy->launchers = eina_list_append(e_policy->launchers, pc); +} + +static E_Policy_Client * +_e_policy_client_add(E_Client *ec) +{ + E_Policy_Client *pc; + + if (e_object_is_del(E_OBJECT(ec))) return NULL; + + pc = eina_hash_find(hash_policy_clients, &ec); + if (pc) return NULL; + + pc = E_NEW(E_Policy_Client, 1); + pc->ec = ec; + + eina_hash_add(hash_policy_clients, &ec, pc); + + return pc; +} + +static void +_e_policy_client_del(E_Policy_Client *pc) +{ + eina_hash_del_by_key(hash_policy_clients, &pc->ec); +} + +static Eina_Bool +_e_policy_client_normal_check(E_Client *ec) +{ + E_Policy_Client *pc; + + if ((e_client_util_ignored_get(ec)) || + (!ec->pixmap)) + { + return EINA_FALSE; + } + + if (e_policy_client_is_quickpanel(ec)) + { + return EINA_FALSE; + } + + if (e_policy_client_is_keyboard(ec) || + e_policy_client_is_keyboard_sub(ec)) + { + e_policy_keyboard_layout_apply(ec); + goto cancel_max; + } + else if (e_policy_client_is_volume_tv(ec)) + goto cancel_max; + else if (!e_util_strcmp("e_demo", ec->icccm.window_role)) + goto cancel_max; + else if (e_policy_client_is_floating(ec)) + { + pc = eina_hash_find(hash_policy_clients, &ec); + _e_policy_client_maximize_policy_cancel(pc); + _e_policy_client_floating_policy_apply(pc); + return EINA_FALSE; + } + else if (e_policy_client_is_subsurface(ec)) + goto cancel_max; + + if ((ec->netwm.type == E_WINDOW_TYPE_NORMAL) || + (ec->netwm.type == E_WINDOW_TYPE_UNKNOWN) || + (ec->netwm.type == E_WINDOW_TYPE_NOTIFICATION)) + { + return EINA_TRUE; + } + + return EINA_FALSE; + +cancel_max: + pc = eina_hash_find(hash_policy_clients, &ec); + _e_policy_client_maximize_policy_cancel(pc); + + return EINA_FALSE; +} + +static void +_e_policy_client_maximize_pre(E_Policy_Client *pc) +{ + E_Client *ec; + int zx, zy, zw, zh; + + ec = pc->ec; + + if (ec->desk->visible) + e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh); + else + { + zx = ec->zone->x; + zy = ec->zone->y; + zw = ec->zone->w; + zh = ec->zone->h; + } + + ec->x = ec->client.x = zx; + ec->y = ec->client.y = zy; + ec->w = ec->client.w = zw; + ec->h = ec->client.h = zh; + + EC_CHANGED(ec); +} + +static Eina_Bool +_e_policy_client_maximize_policy_apply(E_Policy_Client *pc) +{ + E_Client *ec; + + if (!pc) return EINA_FALSE; + if (pc->max_policy_state) return EINA_FALSE; + if (pc->allow_user_geom) return EINA_FALSE; + + ec = pc->ec; + if (ec->netwm.type == E_WINDOW_TYPE_UTILITY) return EINA_FALSE; + + pc->max_policy_state = EINA_TRUE; + +#undef _SET +# define _SET(a) pc->orig.a = pc->ec->a + _SET(borderless); + _SET(fullscreen); + _SET(maximized); + _SET(lock_user_location); + _SET(lock_client_location); + _SET(lock_user_size); + _SET(lock_client_size); + _SET(lock_client_stacking); + _SET(lock_user_shade); + _SET(lock_client_shade); + _SET(lock_user_maximize); + _SET(lock_client_maximize); + _SET(lock_user_fullscreen); + _SET(lock_client_fullscreen); +#undef _SET + + _e_policy_client_launcher_set(pc); + + if (ec->remember) + { + e_remember_del(ec->remember); + ec->remember = NULL; + } + + /* skip hooks of e_remeber for eval_pre_post_fetch and eval_post_new_client */ + ec->internal_no_remember = 1; + + if (!ec->borderless) + { + ec->borderless = 1; + ec->border.changed = 1; + EC_CHANGED(pc->ec); + } + + if (!ec->maximized) + { + e_client_maximize(ec, E_MAXIMIZE_EXPAND | E_MAXIMIZE_BOTH); + + if (ec->changes.need_maximize) + _e_policy_client_maximize_pre(pc); + } + + /* do not allow client to change these properties */ + ec->lock_user_location = 1; + ec->lock_client_location = 1; + ec->lock_user_size = 1; + ec->lock_client_size = 1; + ec->lock_user_shade = 1; + ec->lock_client_shade = 1; + ec->lock_user_maximize = 1; + ec->lock_client_maximize = 1; + ec->lock_user_fullscreen = 1; + ec->lock_client_fullscreen = 1; + ec->skip_fullscreen = 1; + + if (!e_policy_client_is_home_screen(ec)) + ec->lock_client_stacking = 1; + + return EINA_TRUE; +} + +static void +_e_policy_client_maximize_policy_cancel(E_Policy_Client *pc) +{ + E_Client *ec; + Eina_Bool changed = EINA_FALSE; + + if (!pc) return; + if (!pc->max_policy_state) return; + + pc->max_policy_state = EINA_FALSE; + + ec = pc->ec; + + if (pc->orig.borderless != ec->borderless) + { + ec->border.changed = 1; + changed = EINA_TRUE; + } + + if ((pc->orig.fullscreen != ec->fullscreen) && + (pc->orig.fullscreen)) + { + ec->need_fullscreen = 1; + changed = EINA_TRUE; + } + + if (pc->orig.maximized != ec->maximized) + { + if (pc->orig.maximized) + ec->changes.need_maximize = 1; + else + e_client_unmaximize(ec, ec->maximized); + + changed = EINA_TRUE; + } + +#undef _SET +# define _SET(a) ec->a = pc->orig.a + _SET(borderless); + _SET(fullscreen); + _SET(maximized); + _SET(lock_user_location); + _SET(lock_client_location); + _SET(lock_user_size); + _SET(lock_client_size); + _SET(lock_client_stacking); + _SET(lock_user_shade); + _SET(lock_client_shade); + _SET(lock_user_maximize); + _SET(lock_client_maximize); + _SET(lock_user_fullscreen); + _SET(lock_client_fullscreen); +#undef _SET + + ec->skip_fullscreen = 0; + + /* only set it if the border is changed or fullscreen/maximize has changed */ + if (changed) + EC_CHANGED(pc->ec); + + e_policy->launchers = eina_list_remove(e_policy->launchers, pc); +} + +static void +_e_policy_client_floating_policy_apply(E_Policy_Client *pc) +{ + E_Client *ec; + + if (!pc) return; + if (pc->flt_policy_state) return; + + pc->flt_policy_state = EINA_TRUE; + ec = pc->ec; + +#undef _SET +# define _SET(a) pc->orig.a = pc->ec->a + _SET(fullscreen); + _SET(lock_client_stacking); + _SET(lock_user_shade); + _SET(lock_client_shade); + _SET(lock_user_maximize); + _SET(lock_client_maximize); + _SET(lock_user_fullscreen); + _SET(lock_client_fullscreen); +#undef _SET + + ec->skip_fullscreen = 1; + ec->lock_client_stacking = 1; + ec->lock_user_shade = 1; + ec->lock_client_shade = 1; + ec->lock_user_maximize = 1; + ec->lock_client_maximize = 1; + ec->lock_user_fullscreen = 1; + ec->lock_client_fullscreen = 1; +} + +static void +_e_policy_client_floating_policy_cancel(E_Policy_Client *pc) +{ + E_Client *ec; + Eina_Bool changed = EINA_FALSE; + + if (!pc) return; + if (!pc->flt_policy_state) return; + + pc->flt_policy_state = EINA_FALSE; + ec = pc->ec; + + if ((pc->orig.fullscreen != ec->fullscreen) && + (pc->orig.fullscreen)) + { + ec->need_fullscreen = 1; + changed = EINA_TRUE; + } + + if (pc->orig.maximized != ec->maximized) + { + if (pc->orig.maximized) + ec->changes.need_maximize = 1; + else + e_client_unmaximize(ec, ec->maximized); + + changed = EINA_TRUE; + } + + ec->skip_fullscreen = 0; + +#undef _SET +# define _SET(a) ec->a = pc->orig.a + _SET(fullscreen); + _SET(lock_client_stacking); + _SET(lock_user_shade); + _SET(lock_client_shade); + _SET(lock_user_maximize); + _SET(lock_client_maximize); + _SET(lock_user_fullscreen); + _SET(lock_client_fullscreen); +#undef _SET + + if (changed) + EC_CHANGED(pc->ec); +} + +E_Config_Policy_Desk * +_e_policy_desk_get_by_num(unsigned int zone_num, int x, int y) +{ + Eina_List *l; + E_Config_Policy_Desk *d2; + + EINA_LIST_FOREACH(e_config->policy_desks, l, d2) + { + if ((d2->zone_num == zone_num) && + (d2->x == x) && (d2->y == y)) + { + return d2; + } + } + + return NULL; +} + + +static void +_e_policy_cb_hook_client_new(void *d EINA_UNUSED, E_Client *ec) +{ + if (EINA_UNLIKELY(!ec)) + return; + + _e_policy_client_add(ec); +} + +static void +_e_policy_cb_hook_client_del(void *d EINA_UNUSED, E_Client *ec) +{ + E_Policy_Client *pc; + + if (EINA_UNLIKELY(!ec)) + return; + + e_policy_wl_win_brightness_apply(ec); + e_policy_wl_client_del(ec); + + if (e_policy_client_is_lockscreen(ec)) + e_policy_stack_clients_restack_above_lockscreen(ec, EINA_FALSE); + + e_policy_stack_cb_client_remove(ec); + e_client_visibility_calculate(); + + pc = eina_hash_find(hash_policy_clients, &ec); + _e_policy_client_del(pc); +} + +static void +_e_policy_cb_hook_client_eval_pre_new_client(void *d EINA_UNUSED, E_Client *ec) +{ + short ly; + + if (e_object_is_del(E_OBJECT(ec))) return; + + if (e_policy_client_is_keyboard_sub(ec)) + { + ec->placed = 1; + ec->exp_iconify.skip_iconify = EINA_TRUE; + + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + if (ec->layer != E_LAYER_CLIENT_ABOVE) + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_ABOVE); + } + if (e_policy_client_is_noti(ec)) + { + if (ec->frame) + { + ly = evas_object_layer_get(ec->frame); + ELOGF("NOTI", " |ec->layer:%d object->layer:%d", ec->pixmap, ec, ec->layer, ly); + if (ly != ec->layer) + evas_object_layer_set(ec->frame, ec->layer); + } + } + if (e_policy_client_is_floating(ec)) + { + if (ec->frame) + { + if (ec->layer != E_LAYER_CLIENT_ABOVE) + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_ABOVE); + } + } +} + +static void +_e_policy_cb_hook_client_eval_pre_fetch(void *d EINA_UNUSED, E_Client *ec) +{ + if (e_object_is_del(E_OBJECT(ec))) return; + + e_policy_stack_hook_pre_fetch(ec); +} + +static void +_e_policy_cb_hook_client_eval_pre_post_fetch(void *d EINA_UNUSED, E_Client *ec) +{ + if (e_object_is_del(E_OBJECT(ec))) return; + + e_policy_stack_hook_pre_post_fetch(ec); + e_policy_wl_notification_level_fetch(ec); + e_policy_wl_eval_pre_post_fetch(ec); +} + +static void +_e_policy_cb_hook_client_eval_post_fetch(void *d EINA_UNUSED, E_Client *ec) +{ + E_Policy_Client *pc; + E_Policy_Desk *pd; + + if (e_object_is_del(E_OBJECT(ec))) return; + /* Following E_Clients will be added to module hash and will be managed. + * + * - Not new client: Updating internal info of E_Client has been finished + * by e main evaluation, thus module can classify E_Client and manage it. + * + * - New client that has valid buffer: This E_Client has been passed e main + * evaluation, and it has handled first wl_surface::commit request. + */ + if ((ec->new_client) && (!e_pixmap_usable_get(ec->pixmap))) return; + + if (e_policy_client_is_keyboard(ec) || + e_policy_client_is_keyboard_sub(ec)) + { + E_Policy_Client *pc; + pc = eina_hash_find(hash_policy_clients, &ec); + _e_policy_client_maximize_policy_cancel(pc); + + e_policy_keyboard_layout_apply(ec); + } + + if (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role)) + { + E_Policy_Client *pc; + pc = eina_hash_find(hash_policy_clients, &ec); + _e_policy_client_maximize_policy_cancel(pc); + return; + } + + if (e_policy_client_is_floating(ec)) + { + E_Policy_Client *pc; + pc = eina_hash_find(hash_policy_clients, &ec); + _e_policy_client_maximize_policy_cancel(pc); + _e_policy_client_floating_policy_apply(pc); + return; + } + + if (!_e_policy_client_normal_check(ec)) return; + + pd = eina_hash_find(hash_policy_desks, &ec->desk); + if (!pd) return; + + pc = eina_hash_find(hash_policy_clients, &ec); + if (!pc) return; + + if (pc->flt_policy_state) + _e_policy_client_floating_policy_cancel(pc); + + _e_policy_client_maximize_policy_apply(pc); +} + +static void +_e_policy_cb_hook_client_eval_post_new_client(void *d EINA_UNUSED, E_Client *ec) +{ + if (e_object_is_del(E_OBJECT(ec))) return; + if ((ec->new_client) && (!e_pixmap_usable_get(ec->pixmap))) return; + + if (e_policy_client_is_lockscreen(ec)) + e_policy_stack_clients_restack_above_lockscreen(ec, EINA_TRUE); +} + +static void +_e_policy_cb_hook_client_desk_set(void *d EINA_UNUSED, E_Client *ec) +{ + E_Policy_Client *pc; + E_Policy_Desk *pd; + + if (e_object_is_del(E_OBJECT(ec))) return; + if (!_e_policy_client_normal_check(ec)) return; + if (ec->internal) return; + if (ec->new_client) return; + + pc = eina_hash_find(hash_policy_clients, &ec); + if (EINA_UNLIKELY(!pc)) + return; + + pd = eina_hash_find(hash_policy_desks, &ec->desk); + + if (pd) + _e_policy_client_maximize_policy_apply(pc); + else + _e_policy_client_maximize_policy_cancel(pc); +} + +static void +_e_policy_cb_hook_client_fullscreen_pre(void* data EINA_UNUSED, E_Client *ec) +{ + if (e_object_is_del(E_OBJECT(ec))) return; + if (!_e_policy_client_normal_check(ec)) return; + if (ec->internal) return; + + ec->skip_fullscreen = 1; +} + +static void +_e_policy_cb_hook_client_visibility(void *d EINA_UNUSED, E_Client *ec) +{ + if (ec->visibility.changed) + { + e_policy_client_visibility_send(ec); + + if (ec->visibility.obscured == E_VISIBILITY_UNOBSCURED) + { + e_policy_client_uniconify_by_visibility(ec); + } + else + { + e_policy_client_iconify_by_visibility(ec); + } + + e_policy_wl_win_brightness_apply(ec); + } + else + { + if (ec->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED) + { + Eina_Bool obscured_by_alpha_opaque = EINA_FALSE; + Eina_Bool find_above = EINA_FALSE; + E_Client *above_ec; + Evas_Object *o; + + if (ec->zone->display_state == E_ZONE_DISPLAY_STATE_ON) + { + for (o = evas_object_above_get(ec->frame); o; o = evas_object_above_get(o)) + { + above_ec = evas_object_data_get(o, "E_Client"); + if (!above_ec) continue; + if (e_client_util_ignored_get(above_ec)) continue; + + if (above_ec->exp_iconify.by_client) continue; + if (above_ec->exp_iconify.skip_iconify) continue; + + if (!above_ec->iconic) + { + if (above_ec->argb && (above_ec->visibility.opaque > 0)) + obscured_by_alpha_opaque = EINA_TRUE; + } + find_above = EINA_TRUE; + break; + } + + if (!find_above) return; + if (obscured_by_alpha_opaque) + { + e_policy_client_uniconify_by_visibility(ec); + } + else + { + e_policy_client_iconify_by_visibility(ec); + } + } + else if (ec->zone->display_state == E_ZONE_DISPLAY_STATE_OFF) + { + if (e_client_util_ignored_get(ec)) return; + if (ec->exp_iconify.by_client) return; + if (ec->exp_iconify.skip_iconify) return; + if (!ec->iconic) + { + e_policy_client_iconify_by_visibility(ec); + } + } + } + } +} + +static void +_e_policy_cb_hook_pixmap_del(void *data EINA_UNUSED, E_Pixmap *cp) +{ + e_policy_wl_pixmap_del(cp); +} + +static void +_e_policy_cb_hook_pixmap_unusable(void *data EINA_UNUSED, E_Pixmap *cp) +{ + E_Client *ec = (E_Client *)e_pixmap_client_get(cp); + + if (!ec) return; + if (!ec->iconic) return; + if (ec->exp_iconify.by_client) return; + if (ec->exp_iconify.skip_iconify) return; + + ec->exp_iconify.not_raise = 1; + e_client_uniconify(ec); + e_policy_wl_iconify_state_change_send(ec, 0); +} + +static void +_e_policy_cb_desk_data_free(void *data) +{ + free(data); +} + +static void +_e_policy_cb_client_data_free(void *data) +{ + free(data); +} + +static Eina_Bool +_e_policy_cb_zone_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Zone_Add *ev; + E_Zone *zone; + E_Config_Policy_Desk *d; + int i, n; + + ev = event; + zone = ev->zone; + n = zone->desk_y_count * zone->desk_x_count; + for (i = 0; i < n; i++) + { + d = _e_policy_desk_get_by_num(zone->num, + zone->desks[i]->x, + zone->desks[i]->y); + if (d) + e_policy_desk_add(zone->desks[i]); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_zone_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Zone_Del *ev; + E_Zone *zone; + E_Policy_Desk *pd; + int i, n; + + ev = event; + zone = ev->zone; + n = zone->desk_y_count * zone->desk_x_count; + for (i = 0; i < n; i++) + { + pd = eina_hash_find(hash_policy_desks, &zone->desks[i]); + if (pd) e_policy_desk_del(pd); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_zone_move_resize(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Zone_Move_Resize *ev; + E_Policy_Softkey *softkey; + + ev = event; + + if (e_config->use_softkey) + { + softkey = e_policy_softkey_get(ev->zone); + e_policy_softkey_update(softkey); + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_zone_desk_count_set(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Zone_Desk_Count_Set *ev; + E_Zone *zone; + E_Desk *desk; + Eina_Iterator *it; + E_Policy_Desk *pd; + E_Config_Policy_Desk *d; + int i, n; + Eina_Bool found; + Eina_List *desks_del = NULL; + + ev = event; + zone = ev->zone; + + /* remove deleted desk from hash */ + it = eina_hash_iterator_data_new(hash_policy_desks); + while (eina_iterator_next(it, (void **)&pd)) + { + if (pd->zone != zone) continue; + + found = EINA_FALSE; + n = zone->desk_y_count * zone->desk_x_count; + for (i = 0; i < n; i++) + { + if (pd->desk == zone->desks[i]) + { + found = EINA_TRUE; + break; + } + } + if (!found) + desks_del = eina_list_append(desks_del, pd->desk); + } + eina_iterator_free(it); + + EINA_LIST_FREE(desks_del, desk) + { + pd = eina_hash_find(hash_policy_desks, &desk); + if (pd) e_policy_desk_del(pd); + } + + /* add newly added desk to hash */ + n = zone->desk_y_count * zone->desk_x_count; + for (i = 0; i < n; i++) + { + d = _e_policy_desk_get_by_num(zone->num, + zone->desks[i]->x, + zone->desks[i]->y); + if (d) + e_policy_desk_add(zone->desks[i]); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_zone_display_state_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Zone_Display_State_Change *ev; + + ev = event; + if (!ev) return ECORE_CALLBACK_PASS_ON; + + e_client_visibility_calculate(); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_desk_show(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Desk_Show *ev; + E_Policy_Softkey *softkey; + + ev = event; + + if (e_config->use_softkey) + { + softkey = e_policy_softkey_get(ev->desk->zone); + if (eina_hash_find(hash_policy_desks, &ev->desk)) + e_policy_softkey_show(softkey); + else + e_policy_softkey_hide(softkey); + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_client_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + + ev = event; + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON); + + e_policy_wl_client_add(ev->ec); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_client_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + + ev = event; + if (!ev) goto end; + + e_policy_wl_position_send(ev->ec); + e_client_visibility_calculate(); + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_client_resize(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + E_Client *ec; + int zh = 0; + + ev = (E_Event_Client *)event; + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON); + + ec = ev->ec; + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, ECORE_CALLBACK_PASS_ON); + + /* re-calculate window's position with changed size */ + if (e_policy_client_is_volume_tv(ec)) + { + e_zone_useful_geometry_get(ec->zone, NULL, NULL, NULL, &zh); + evas_object_move(ec->frame, 0, (zh / 2) - (ec->h / 2)); + + evas_object_pass_events_set(ec->frame, 1); + } + + /* calculate e_client visibility */ + e_client_visibility_calculate(); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_client_stack(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + + ev = event; + if (!ev) return ECORE_CALLBACK_PASS_ON; + /* calculate e_client visibility */ + e_client_visibility_calculate(); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_client_property(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client_Property *ev; + + ev = event; + if (!ev || (!ev->ec)) return ECORE_CALLBACK_PASS_ON; + if (ev->property & E_CLIENT_PROPERTY_CLIENT_TYPE) + { + if (e_policy_client_is_home_screen(ev->ec)) + { + ev->ec->lock_client_stacking = 0; + return ECORE_CALLBACK_PASS_ON; + } + else if (e_policy_client_is_lockscreen(ev->ec)) + return ECORE_CALLBACK_PASS_ON; + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_cb_client_vis_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + e_policy_wl_win_scrmode_apply(); + return ECORE_CALLBACK_PASS_ON; +} + +void +e_policy_allow_user_geometry_set(E_Client *ec, Eina_Bool set) +{ + E_Policy_Client *pc; + + if (EINA_UNLIKELY(!ec)) + return; + + pc = eina_hash_find(hash_policy_clients, &ec); + if (EINA_UNLIKELY(!pc)) + return; + + if (set) pc->user_geom_ref++; + else pc->user_geom_ref--; + + if (pc->user_geom_ref == 1 && !pc->allow_user_geom) + { + pc->allow_user_geom = EINA_TRUE; + + if (!e_policy_client_is_noti(ec)) + { + ec->netwm.type = E_WINDOW_TYPE_UTILITY; + ec->lock_client_location = EINA_FALSE; + } + + ec->lock_client_size = EINA_FALSE; + ec->placed = 1; + EC_CHANGED(ec); + } + else if (pc->user_geom_ref == 0 && pc->allow_user_geom) + { + pc->allow_user_geom = EINA_FALSE; + + ec->lock_client_location = EINA_TRUE; + ec->lock_client_size = EINA_TRUE; + ec->placed = 0; + ec->netwm.type = E_WINDOW_TYPE_NORMAL; + EC_CHANGED(ec); + } +} + +void +e_policy_desk_add(E_Desk *desk) +{ + E_Policy_Desk *pd; + E_Client *ec; + E_Policy_Softkey *softkey; + E_Policy_Client *pc; + + pd = eina_hash_find(hash_policy_desks, &desk); + if (pd) return; + + pd = E_NEW(E_Policy_Desk, 1); + pd->desk = desk; + pd->zone = desk->zone; + + eina_hash_add(hash_policy_desks, &desk, pd); + + /* add clients */ + E_CLIENT_FOREACH(ec) + { + if (pd->desk == ec->desk) + { + pc = eina_hash_find(hash_policy_clients, &ec); + _e_policy_client_maximize_policy_apply(pc); + } + } + + /* add and show softkey */ + if (e_config->use_softkey) + { + softkey = e_policy_softkey_get(desk->zone); + if (!softkey) + softkey = e_policy_softkey_add(desk->zone); + if (e_desk_current_get(desk->zone) == desk) + e_policy_softkey_show(softkey); + } +} + +void +e_policy_desk_del(E_Policy_Desk *pd) +{ + Eina_Iterator *it; + E_Policy_Client *pc; + E_Client *ec; + Eina_List *clients_del = NULL; + E_Policy_Softkey *softkey; + Eina_Bool keep = EINA_FALSE; + int i, n; + + /* hide and delete softkey */ + if (e_config->use_softkey) + { + softkey = e_policy_softkey_get(pd->zone); + if (e_desk_current_get(pd->zone) == pd->desk) + e_policy_softkey_hide(softkey); + + n = pd->zone->desk_y_count * pd->zone->desk_x_count; + for (i = 0; i < n; i++) + { + if (eina_hash_find(hash_policy_desks, &pd->zone->desks[i])) + { + keep = EINA_TRUE; + break; + } + } + + if (!keep) + e_policy_softkey_del(softkey); + } + + /* remove clients */ + it = eina_hash_iterator_data_new(hash_policy_clients); + while (eina_iterator_next(it, (void **)&pc)) + { + if (pc->ec->desk == pd->desk) + clients_del = eina_list_append(clients_del, pc->ec); + } + eina_iterator_free(it); + + EINA_LIST_FREE(clients_del, ec) + { + pc = eina_hash_find(hash_policy_clients, &ec); + _e_policy_client_maximize_policy_cancel(pc); + } + + eina_hash_del_by_key(hash_policy_desks, &pd->desk); +} + +E_Policy_Client * +e_policy_client_launcher_get(E_Zone *zone) +{ + E_Policy_Client *pc; + Eina_List *l; + + EINA_LIST_FOREACH(e_policy->launchers, l, pc) + { + if (pc->ec->zone == zone) + return pc; + } + return NULL; +} + +Eina_Bool +e_policy_client_maximize(E_Client *ec) +{ + E_Policy_Desk *pd; + E_Policy_Client *pc; + + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (EINA_UNLIKELY(!ec)) return EINA_FALSE; + if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE; + + if ((e_policy_client_is_keyboard(ec)) || + (e_policy_client_is_keyboard_sub(ec)) || + (e_policy_client_is_floating(ec)) || + (e_policy_client_is_quickpanel(ec)) || + (e_policy_client_is_volume(ec)) || + (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role)) || + (!e_util_strcmp("e_demo", ec->icccm.window_role))) + return EINA_FALSE; + + if (e_policy_client_is_subsurface(ec)) return EINA_FALSE; + + if ((ec->netwm.type != E_WINDOW_TYPE_NORMAL) && + (ec->netwm.type != E_WINDOW_TYPE_UNKNOWN) && + (ec->netwm.type != E_WINDOW_TYPE_NOTIFICATION)) + return EINA_FALSE; + + pd = eina_hash_find(hash_policy_desks, &ec->desk); + if (!pd) return EINA_FALSE; + + pc = eina_hash_find(hash_policy_clients, &ec); + EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE); + + if (pc->flt_policy_state) + _e_policy_client_floating_policy_cancel(pc); + + return _e_policy_client_maximize_policy_apply(pc); +} + +Eina_Bool +e_policy_client_is_lockscreen(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (ec->client_type == 2) + return EINA_TRUE; + + if (!e_util_strcmp(ec->icccm.title, "LOCKSCREEN")) + return EINA_TRUE; + + if (!e_util_strcmp(ec->icccm.window_role, "lockscreen")) + return EINA_TRUE; + + return EINA_FALSE; +} + +Eina_Bool +e_policy_client_is_home_screen(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (ec->client_type == 1) + return EINA_TRUE; + + + return EINA_FALSE; +} + +Eina_Bool +e_policy_client_is_quickpanel(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (!e_util_strcmp(ec->icccm.window_role, "quickpanel")) + return EINA_TRUE; + + return EINA_FALSE; +} + +Eina_Bool +e_policy_client_is_conformant(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(ec->comp_data, EINA_FALSE); + + E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data *)ec->comp_data; + if (cdata->conformant == 1) + { + return EINA_TRUE; + } + + return EINA_FALSE; +} + +Eina_Bool +e_policy_client_is_volume(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (!e_util_strcmp(ec->netwm.name, "volume")) + return EINA_TRUE; + + if (!e_util_strcmp(ec->icccm.title, "volume")) + return EINA_TRUE; + + return EINA_FALSE; +} + +Eina_Bool +e_policy_client_is_volume_tv(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (!e_util_strcmp(ec->icccm.window_role, "tv-volume-popup")) + return EINA_TRUE; + + return EINA_FALSE; +} + +Eina_Bool +e_policy_client_is_noti(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (!e_util_strcmp(ec->icccm.title, "noti_win")) + return EINA_TRUE; + + if (ec->netwm.type == E_WINDOW_TYPE_NOTIFICATION) + return EINA_TRUE; + + return EINA_FALSE; +} + +Eina_Bool +e_policy_client_is_subsurface(E_Client *ec) +{ + E_Comp_Wl_Client_Data *cd; + + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + cd = (E_Comp_Wl_Client_Data *)ec->comp_data; + if (cd && cd->sub.data) + return EINA_TRUE; + + return EINA_FALSE; +} + +Eina_Bool +e_policy_client_is_floating(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (EINA_UNLIKELY(!ec)) + return EINA_FALSE; + + return ec->floating; +} + +Eina_Bool +e_policy_client_is_cursor(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role)) + return EINA_TRUE; + + return EINA_FALSE; +} + +E_API void +e_policy_deferred_job(void) +{ + if (!e_policy) return; + + e_policy_wl_defer_job(); +} + + +#undef E_CLIENT_HOOK_APPEND +#define E_CLIENT_HOOK_APPEND(l, t, cb, d) \ + do \ + { \ + E_Client_Hook *_h; \ + _h = e_client_hook_add(t, cb, d); \ + assert(_h); \ + l = eina_list_append(l, _h); \ + } \ + while (0) + +#undef E_PIXMAP_HOOK_APPEND +#define E_PIXMAP_HOOK_APPEND(l, t, cb, d) \ + do \ + { \ + E_Pixmap_Hook *_h; \ + _h = e_pixmap_hook_add(t, cb, d); \ + assert(_h); \ + l = eina_list_append(l, _h); \ + } \ + while (0) + +E_API int +e_policy_init(void) +{ + E_Policy *pol; + E_Zone *zone; + E_Config_Policy_Desk *d; + const Eina_List *l; + int i, n; + + pol = E_NEW(E_Policy, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(pol, EINA_FALSE); + + e_policy = pol; + + hash_policy_clients = eina_hash_pointer_new(_e_policy_cb_client_data_free); + hash_policy_desks = eina_hash_pointer_new(_e_policy_cb_desk_data_free); + + e_policy_stack_init(); + e_policy_wl_init(); + e_policy_wl_aux_hint_init(); + + EINA_LIST_FOREACH(e_comp->zones, l, zone) + { + n = zone->desk_y_count * zone->desk_x_count; + for (i = 0; i < n; i++) + { + d = _e_policy_desk_get_by_num(zone->num, + zone->desks[i]->x, + zone->desks[i]->y); + if (d) + e_policy_desk_add(zone->desks[i]); + } + } + + E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_ADD, _e_policy_cb_zone_add, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_DEL, _e_policy_cb_zone_del, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_MOVE_RESIZE, _e_policy_cb_zone_move_resize, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_DESK_COUNT_SET, _e_policy_cb_zone_desk_count_set, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_DISPLAY_STATE_CHANGE, _e_policy_cb_zone_display_state_change, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_DESK_SHOW, _e_policy_cb_desk_show, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_ADD, _e_policy_cb_client_add, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_MOVE, _e_policy_cb_client_move, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_RESIZE, _e_policy_cb_client_resize, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_STACK, _e_policy_cb_client_stack, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_PROPERTY, _e_policy_cb_client_property, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_VISIBILITY_CHANGE, _e_policy_cb_client_vis_change, NULL); + + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_NEW_CLIENT, _e_policy_cb_hook_client_new, NULL); + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_DEL, _e_policy_cb_hook_client_del, NULL); + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_EVAL_PRE_NEW_CLIENT, _e_policy_cb_hook_client_eval_pre_new_client, NULL); + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_EVAL_PRE_FETCH, _e_policy_cb_hook_client_eval_pre_fetch, NULL); + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_EVAL_PRE_POST_FETCH, _e_policy_cb_hook_client_eval_pre_post_fetch, NULL); + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_EVAL_POST_FETCH, _e_policy_cb_hook_client_eval_post_fetch, NULL); + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT,_e_policy_cb_hook_client_eval_post_new_client,NULL); + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_DESK_SET, _e_policy_cb_hook_client_desk_set, NULL); + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_FULLSCREEN_PRE, _e_policy_cb_hook_client_fullscreen_pre, NULL); + E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_EVAL_VISIBILITY, _e_policy_cb_hook_client_visibility, NULL); + + E_PIXMAP_HOOK_APPEND(hooks_cp, E_PIXMAP_HOOK_DEL, _e_policy_cb_hook_pixmap_del, NULL); + E_PIXMAP_HOOK_APPEND(hooks_cp, E_PIXMAP_HOOK_UNUSABLE, _e_policy_cb_hook_pixmap_unusable, NULL); + + e_policy_transform_mode_init(); + e_policy_conformant_init(); + + return EINA_TRUE; +} + +E_API int +e_policy_shutdown(void) +{ + E_Policy *pol = e_policy; + Eina_Inlist *l; + E_Policy_Softkey *softkey; + + eina_list_free(pol->launchers); + EINA_INLIST_FOREACH_SAFE(pol->softkeys, l, softkey) + e_policy_softkey_del(softkey); + E_FREE_LIST(hooks_cp, e_pixmap_hook_del); + E_FREE_LIST(hooks_ec, e_client_hook_del); + E_FREE_LIST(handlers, ecore_event_handler_del); + + E_FREE_FUNC(hash_policy_desks, eina_hash_free); + E_FREE_FUNC(hash_policy_clients, eina_hash_free); + + e_policy_stack_shutdonw(); + e_policy_wl_shutdown(); + + e_policy_transform_mode_shutdown(); + e_policy_conformant_shutdown(); + + E_FREE(pol); + + e_policy = NULL; + + return 1; +} diff --git a/src/bin/e_policy.h b/src/bin/e_policy.h new file mode 100644 index 0000000000..e1f202fae0 --- /dev/null +++ b/src/bin/e_policy.h @@ -0,0 +1,148 @@ +# ifdef E_TYPEDEFS +typedef struct _E_Policy_Desk E_Policy_Desk; +typedef struct _E_Policy_Client E_Policy_Client; +typedef struct _E_Policy_Softkey E_Policy_Softkey; +typedef struct _E_Policy_Config_Match E_Policy_Config_Match; +typedef struct _E_Policy_Config_Desk E_Policy_Config_Desk; +typedef struct _E_Policy_Config_Rot E_Policy_Config_Rot; +typedef struct _E_Policy_Config E_Policy_Config; +typedef struct _E_Policy E_Policy; +typedef struct _E_Policy_System_Info E_Policy_System_Info; + +# else +# ifndef E_POLICY_H +# define E_POLICY_H +# ifndef _ +# ifdef HAVE_GETTEXT +# define _(str) gettext(str) +# else +# define _(str) (str) +# endif +# endif + +struct _E_Policy_Desk +{ + E_Desk *desk; + E_Zone *zone; +}; + +struct _E_Policy_Client +{ + E_Client *ec; + struct + { + E_Maximize maximized; + unsigned int fullscreen : 1; + unsigned char borderless : 1; + unsigned int lock_user_location : 1; + unsigned int lock_client_location : 1; + unsigned int lock_user_size : 1; + unsigned int lock_client_size : 1; + unsigned int lock_client_stacking : 1; + unsigned int lock_user_shade : 1; + unsigned int lock_client_shade : 1; + unsigned int lock_user_maximize : 1; + unsigned int lock_client_maximize : 1; + unsigned int lock_user_fullscreen : 1; + unsigned int lock_client_fullscreen : 1; + } orig; + + struct + { + unsigned int vkbd_state; + unsigned int already_hide; + } changes; + + Eina_Bool max_policy_state; + Eina_Bool flt_policy_state; + Eina_Bool allow_user_geom; + int user_geom_ref; +}; + +struct _E_Policy_Softkey +{ + EINA_INLIST; + + E_Zone *zone; + Evas_Object *home; + Evas_Object *back; +}; + +struct _E_Policy +{ + E_Module *module; + Eina_List *launchers; /* launcher window per zone */ + Eina_Inlist *softkeys; /* softkey ui object per zone */ +}; + +struct _E_Policy_System_Info +{ + struct + { + E_Client *ec; + Eina_Bool show; + } lockscreen; + + struct + { + int system; + int client; + Eina_Bool use_client; + } brightness; +}; + +extern E_Policy *e_policy; +extern E_Policy_System_Info e_policy_system_info; + +EINTERN E_Policy_Config_Desk *e_policy_conf_desk_get_by_nums(E_Policy_Config *conf, unsigned int zone_num, int x, int y); +EINTERN E_Policy_Client *e_policy_client_get(E_Client *ec); +EINTERN void e_policy_allow_user_geometry_set(E_Client *ec, Eina_Bool set); +EINTERN void e_policy_desk_add(E_Desk *desk); +EINTERN void e_policy_desk_del(E_Policy_Desk *pd); +EINTERN E_Policy_Client *e_policy_client_launcher_get(E_Zone *zone); + +EINTERN Eina_Bool e_policy_client_is_lockscreen(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_home_screen(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_quickpanel(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_conformant(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_volume(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_volume_tv(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_noti(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_floating(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_cursor(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_subsurface(E_Client *ec); + +EINTERN E_Policy_Softkey *e_policy_softkey_add(E_Zone *zone); +EINTERN void e_policy_softkey_del(E_Policy_Softkey *softkey); +EINTERN void e_policy_softkey_show(E_Policy_Softkey *softkey); +EINTERN void e_policy_softkey_hide(E_Policy_Softkey *softkey); +EINTERN void e_policy_softkey_update(E_Policy_Softkey *softkey); +EINTERN E_Policy_Softkey *e_policy_softkey_get(E_Zone *zone); + +EINTERN void e_policy_client_visibility_send(E_Client *ec); +EINTERN void e_policy_client_iconify_by_visibility(E_Client *ec); +EINTERN void e_policy_client_uniconify_by_visibility(E_Client *ec); + +EINTERN Eina_Bool e_policy_client_maximize(E_Client *ec); + +EINTERN void e_policy_client_window_opaque_set(E_Client *ec); + +EINTERN void e_policy_stack_init(void); +EINTERN void e_policy_stack_shutdonw(void); +EINTERN void e_policy_stack_transient_for_set(E_Client *child, E_Client *parent); +EINTERN void e_policy_stack_cb_client_remove(E_Client *ec); +EINTERN void e_policy_stack_hook_pre_fetch(E_Client *ec); +EINTERN void e_policy_stack_hook_pre_post_fetch(E_Client *ec); + +EINTERN void e_policy_stack_below(E_Client *ec, E_Client *below_ec); + +EINTERN void e_policy_stack_clients_restack_above_lockscreen(E_Client *ec_lock, Eina_Bool show); +EINTERN Eina_Bool e_policy_stack_check_above_lockscreen(E_Client *ec, E_Layer layer, E_Layer *new_layer, Eina_Bool set_layer); + +EINTERN Eina_Bool e_policy_conf_rot_enable_get(int angle); + +E_API void e_policy_deferred_job(void); +E_API int e_policy_init(void); +E_API int e_policy_shutdown(void); +#endif +#endif diff --git a/src/bin/e_policy_conformant.c b/src/bin/e_policy_conformant.c new file mode 100644 index 0000000000..6ab79dc340 --- /dev/null +++ b/src/bin/e_policy_conformant.c @@ -0,0 +1,511 @@ +#include "e.h" + +#include +#include + +#define CFDBG(f, x...) DBG("Conformant|"f, ##x) +#define CFINF(f, x...) INF("Conformant|"f, ##x) +#define CFERR(f, x...) ERR("Conformant|"f, ##x) + +#define CONF_DATA_GET(ptr) \ + Conformant *ptr = _conf_data_get() +#define CONF_DATA_GET_OR_RETURN(ptr) \ + CONF_DATA_GET(ptr); \ + if (!ptr) \ + { \ + CFERR("no conformant data"); \ + return; \ + } +#define CONF_DATA_GET_OR_RETURN_VAL(ptr, val) \ + CONF_DATA_GET(ptr); \ + if (!ptr) \ + { \ + CFERR("no conformant data"); \ + return val; \ + } + +typedef struct +{ + E_Client *vkbd; + E_Client *owner; + Eina_Hash *client_hash; + Eina_List *handlers; + E_Client_Hook *client_del_hook; + Ecore_Idle_Enterer *idle_enterer; + + struct + { + Eina_Bool restore; + Eina_Bool visible; + int x, y, w, h; + } state; + + Eina_Bool changed : 1; +} Conformant; + +typedef struct +{ + E_Client *ec; + Eina_List *res_list; +} Conformant_Client; + +typedef struct +{ + Conformant_Client *cfc; + struct wl_resource *res; + struct wl_listener destroy_listener; +} Conformant_Wl_Res; + +Conformant *_conf = NULL; + +static Conformant * +_conf_data_get() +{ + return _conf; +} + +static void +_conf_state_update(Conformant *conf, Eina_Bool visible, int x, int y, int w, int h) +{ + Conformant_Client *cfc; + Conformant_Wl_Res *cres; + Eina_List *l; + + if ((conf->state.visible == visible) && + (conf->state.x == x) && (conf->state.x == y) && + (conf->state.x == w) && (conf->state.x == h)) + return; + + CFDBG("Update Conformant State\n"); + CFDBG("\tprev: v %d geom %d %d %d %d\n", + conf->state.visible, conf->state.x, conf->state.y, conf->state.w, conf->state.h); + CFDBG("\tnew : v %d geom %d %d %d %d\n", visible, x, y, w, h); + + conf->state.visible = visible; + conf->state.x = x; + conf->state.y = y; + conf->state.w = w; + conf->state.h = h; + + if (!conf->owner) + return; + + cfc = eina_hash_find(conf->client_hash, &conf->owner); + if (!cfc) + return; + + CFDBG("\t=> '%s'(%p)", cfc->ec ? (cfc->ec->icccm.name ?:"") : "", cfc->ec); + EINA_LIST_FOREACH(cfc->res_list, l, cres) + { + tizen_policy_send_conformant_area + (cres->res, + cfc->ec->comp_data->surface, + TIZEN_POLICY_CONFORMANT_PART_KEYBOARD, + (unsigned int)visible, x, y, w, h); + } +} + +static void +_conf_cb_vkbd_obj_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Conformant *conf; + + CFDBG("VKBD Deleted"); + conf = data; + conf->vkbd = NULL; +} + +static void +_conf_cb_vkbd_obj_show(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Conformant *conf; + + CFDBG("VKBD Show"); + conf = data; + conf->owner = conf->vkbd->parent; + if (!conf->owner) + WRN("Not exist vkbd's parent even if it becomes visible"); + conf->changed = 1; +} + +static void +_conf_cb_vkbd_obj_hide(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Conformant *conf; + + CFDBG("VKBD Hide"); + conf = data; + _conf_state_update(conf, EINA_FALSE, conf->state.x, conf->state.y, conf->state.w, conf->state.h); + conf->owner = NULL; +} + +static void +_conf_cb_vkbd_obj_move(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Conformant *conf; + + CFDBG("VKBD Move"); + conf = data; + conf->changed = 1; +} + +static void +_conf_cb_vkbd_obj_resize(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Conformant *conf; + + CFDBG("VKBD Resize"); + conf = data; + conf->changed = 1; +} + +static void +_conf_client_del(Conformant_Client *cfc) +{ + Conformant_Wl_Res *cres; + + EINA_LIST_FREE(cfc->res_list, cres) + { + wl_list_remove(&cres->destroy_listener.link); + free(cres); + } + + free(cfc); +} + +static void +_conf_client_resource_destroy(struct wl_listener *listener, void *data) +{ + Conformant_Wl_Res *cres; + + cres = container_of(listener, Conformant_Wl_Res, destroy_listener); + if (!cres) + return; + + CFDBG("Destroy Wl Resource res %p owner %s(%p)", + cres->res, cres->cfc->ec->icccm.name ? cres->cfc->ec->icccm.name : "", cres->cfc->ec); + + cres->cfc->res_list = eina_list_remove(cres->cfc->res_list, cres); + + free(cres); +} + +static void +_conf_client_resource_add(Conformant_Client *cfc, struct wl_resource *res) +{ + Conformant_Wl_Res *cres; + Eina_List *l; + + if (cfc->res_list) + { + EINA_LIST_FOREACH(cfc->res_list, l, cres) + { + if (cres->res == res) + { + CFERR("Already Added Resource, Nothing to do. res: %p", res); + return; + } + } + } + + cres = E_NEW(Conformant_Wl_Res, 1); + if (!cres) + return; + + cres->cfc = cfc; + cres->res = res; + cres->destroy_listener.notify = _conf_client_resource_destroy; + wl_resource_add_destroy_listener(res, &cres->destroy_listener); + + cfc->res_list = eina_list_append(cfc->res_list, cres); +} + +static Conformant_Client * +_conf_client_add(Conformant *conf, E_Client *ec, struct wl_resource *res) +{ + Conformant_Client *cfc; + + cfc = E_NEW(Conformant_Client, 1); + if (!cfc) + return NULL; + + cfc->ec = ec; + + _conf_client_resource_add(cfc, res); + + return cfc; +} + +static void +_conf_vkbd_register(Conformant *conf, E_Client *ec) +{ + CFINF("VKBD Registered"); + if (conf->vkbd) + { + CFERR("Something strange error, VKBD Already Registered."); + return; + } + conf->vkbd = ec; + + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_DEL, _conf_cb_vkbd_obj_del, conf); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW, _conf_cb_vkbd_obj_show, conf); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE, _conf_cb_vkbd_obj_hide, conf); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE, _conf_cb_vkbd_obj_move, conf); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESIZE, _conf_cb_vkbd_obj_resize, conf); +} + +static Eina_Bool +_conf_cb_client_add(void *data, int type EINA_UNUSED, void *event) +{ + Conformant *conf; + E_Event_Client *ev; + + conf = data; + ev = event; + + if (ev->ec->vkbd.vkbd) + _conf_vkbd_register(conf, ev->ec); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_conf_cb_client_rot_change_begin(void *data, int type EINA_UNUSED, void *event) +{ + Conformant *conf; + E_Event_Client *ev; + + ev = event; + conf = data; + + if (ev->ec != conf->vkbd) + goto end; + + /* set conformant area to non-visible state before starting rotation. + * this is to prevent to apply wrong area of conformant area after rotation. + * Suppose conformant area will be set later according to changes of vkbd such as resize or move. + * if there is no being called rot_change_cancel and nothing changes vkbd, + * that is unexpected case. + */ + if (conf->state.visible) + { + CFDBG("Rotation Begin"); + _conf_state_update(conf, EINA_FALSE, conf->state.x, conf->state.y, conf->state.w, conf->state.h); + conf->state.restore = EINA_TRUE; + } + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_conf_cb_client_rot_change_cancel(void *data, int type EINA_UNUSED, void *event) +{ + Conformant *conf; + E_Event_Client *ev; + + ev = event; + conf = data; + + if (ev->ec != conf->vkbd) + goto end; + + if (conf->state.restore) + { + CFDBG("Rotation Cancel"); + _conf_state_update(conf, EINA_FALSE, conf->state.x, conf->state.y, conf->state.w, conf->state.h); + conf->state.restore = EINA_TRUE; + } + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_conf_cb_client_rot_change_end(void *data, int type EINA_UNUSED, void *event) +{ + Conformant *conf; + E_Event_Client *ev; + + ev = event; + conf = data; + + if (ev->ec != conf->vkbd) + goto end; + + conf->state.restore = EINA_FALSE; + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static void +_conf_cb_client_del(void *data, E_Client *ec) +{ + Conformant *conf; + Conformant_Client *cfc; + + conf = data; + if (!conf->client_hash) + return; + + cfc = eina_hash_find(conf->client_hash, &ec); + if (!cfc) + return; + + eina_hash_del(conf->client_hash, &ec, cfc); + _conf_client_del(cfc); +} + +static Eina_Bool +_conf_idle_enter(void *data) +{ + Conformant *conf; + Eina_Bool visible; + int x, y, w, h; + + conf = data; + if (!conf->vkbd) + goto end; + + if (conf->changed) + { + visible = evas_object_visible_get(conf->vkbd->frame); + evas_object_geometry_get(conf->vkbd->frame, &x, &y, &w, &h); + + _conf_state_update(conf, visible, x, y, w, h); + + conf->changed = EINA_FALSE; + } + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static void +_conf_event_init(Conformant *conf) +{ + E_LIST_HANDLER_APPEND(conf->handlers, E_EVENT_CLIENT_ADD, _conf_cb_client_add, conf); + E_LIST_HANDLER_APPEND(conf->handlers, E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN, _conf_cb_client_rot_change_begin, conf); + E_LIST_HANDLER_APPEND(conf->handlers, E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL, _conf_cb_client_rot_change_cancel, conf); + E_LIST_HANDLER_APPEND(conf->handlers, E_EVENT_CLIENT_ROTATION_CHANGE_END, _conf_cb_client_rot_change_end, conf); + + conf->client_del_hook = e_client_hook_add(E_CLIENT_HOOK_DEL, _conf_cb_client_del, conf); + conf->idle_enterer = ecore_idle_enterer_add(_conf_idle_enter, conf); +} + +static void +_conf_event_shutdown(Conformant *conf) +{ + E_FREE_LIST(conf->handlers, ecore_event_handler_del); + E_FREE_FUNC(conf->client_del_hook, e_client_hook_del); + E_FREE_FUNC(conf->idle_enterer, ecore_idle_enterer_del); +} + +EINTERN void +e_policy_conformant_client_add(E_Client *ec, struct wl_resource *res) +{ + Conformant_Client *cfc; + + CONF_DATA_GET_OR_RETURN(conf); + + EINA_SAFETY_ON_NULL_RETURN(ec); + + CFDBG("Client Add '%s'(%p)", ec->icccm.name ? ec->icccm.name : "", ec); + + if (conf->client_hash) + { + cfc = eina_hash_find(conf->client_hash, &ec); + if (cfc) + { + CFDBG("Already Added Client, Just Add Resource"); + _conf_client_resource_add(cfc, res); + return; + } + } + + cfc = _conf_client_add(conf, ec, res); + + /* do we need to send conformant state if vkbd is visible ? */ + + if (!conf->client_hash) + conf->client_hash = eina_hash_pointer_new(NULL); + + eina_hash_add(conf->client_hash, &ec, cfc); +} + +EINTERN void +e_policy_conformant_client_del(E_Client *ec) +{ + Conformant_Client *cfc; + + CONF_DATA_GET_OR_RETURN(conf); + + EINA_SAFETY_ON_NULL_RETURN(ec); + + CFDBG("Client Del '%s'(%p)", ec->icccm.name ? ec->icccm.name : "", ec); + + cfc = eina_hash_find(conf->client_hash, &ec); + if (cfc) + { + eina_hash_del(conf->client_hash, &ec, cfc); + _conf_client_del(cfc); + } +} + +EINTERN Eina_Bool +e_policy_conformant_client_check(E_Client *ec) +{ + CONF_DATA_GET_OR_RETURN_VAL(conf, EINA_FALSE); + + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); + + if (!conf->client_hash) + return EINA_FALSE; + + return !!eina_hash_find(conf->client_hash, &ec); +} + +EINTERN Eina_Bool +e_policy_conformant_init(void) +{ + Conformant *conf; + + if (_conf) + return EINA_TRUE; + + CFINF("Conformant Module Init"); + + conf = E_NEW(Conformant, 1); + if (!conf) + return EINA_FALSE; + + _conf_event_init(conf); + + _conf = conf; + + return EINA_TRUE; +} + +EINTERN void +e_policy_conformant_shutdown(void) +{ + Conformant_Client *cfc; + Eina_Iterator *itr; + + if (!_conf) + return; + + CFINF("Conformant Module Shutdown"); + + _conf_event_shutdown(_conf); + + itr = eina_hash_iterator_data_new(_conf->client_hash); + EINA_ITERATOR_FOREACH(itr, cfc) + _conf_client_del(cfc); + eina_iterator_free(itr); + + E_FREE_FUNC(_conf->client_hash, eina_hash_free); + + E_FREE(_conf); +} diff --git a/src/bin/e_policy_conformant.h b/src/bin/e_policy_conformant.h new file mode 100644 index 0000000000..d94a4e279c --- /dev/null +++ b/src/bin/e_policy_conformant.h @@ -0,0 +1,10 @@ +#ifndef E_POLICY_CONFORMANT_H +#define E_POLICY_CONFORMANT_H + +EINTERN Eina_Bool e_policy_conformant_init(void); +EINTERN void e_policy_conformant_shutdown(void); +EINTERN void e_policy_conformant_client_add(E_Client *ec, struct wl_resource *res); +EINTERN void e_policy_conformant_client_del(E_Client *ec); +EINTERN Eina_Bool e_policy_conformant_client_check(E_Client *ec); + +#endif diff --git a/src/bin/e_policy_keyboard.c b/src/bin/e_policy_keyboard.c new file mode 100644 index 0000000000..e7e91992e9 --- /dev/null +++ b/src/bin/e_policy_keyboard.c @@ -0,0 +1,98 @@ +#include "e_policy_keyboard.h" + +EINTERN Eina_Bool +e_policy_client_is_keyboard(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (ec->vkbd.vkbd) return EINA_TRUE; + + return EINA_FALSE; +} + +EINTERN Eina_Bool +e_policy_client_is_keyboard_sub(E_Client *ec) +{ + E_OBJECT_CHECK_RETURN(ec, EINA_FALSE); + E_OBJECT_TYPE_CHECK_RETURN(ec, E_CLIENT_TYPE, EINA_FALSE); + + if (ec->vkbd.vkbd) return EINA_FALSE; + + if ((ec->icccm.class) && + (!strcmp(ec->icccm.class, "ISF"))) + return EINA_TRUE; + if ((ec->icccm.title) && + (!strcmp(ec->icccm.title, "ISF Popup"))) + return EINA_TRUE; + + return EINA_FALSE; +} + +EINTERN void +e_policy_keyboard_layout_apply(E_Client *ec EINA_UNUSED) +{ +/* FIXME: do not resize and move client. + * ec->e.state.rot.geom[].w/h is always 0, + * then the geometry calculated here is not valid. */ +#if 0 + int angle; + int angle_id = 0; + int kbd_x, kbd_y, kbd_w, kbd_h; + + if (!e_policy_client_is_keyboard(ec) && + !e_policy_client_is_keyboard_sub(ec)) + return; + + angle = e_client_rotation_curr_angle_get(ec); + + switch (angle) + { + case 0: angle_id = 0; break; + case 90: angle_id = 1; break; + case 180: angle_id = 2; break; + case 270: angle_id = 3; break; + default: angle_id = 0; break; + } + + kbd_w = ec->e.state.rot.geom[angle_id].w; + kbd_h = ec->e.state.rot.geom[angle_id].h; + + switch (angle) + { + case 0: + kbd_x = ec->zone->w - kbd_w; + kbd_y = ec->zone->h - kbd_h; + break; + + case 90: + kbd_x = ec->zone->w - kbd_w; + kbd_y = ec->zone->h - kbd_h; + break; + + case 180: + kbd_x = 0; + kbd_y = 0; + break; + + case 270: + kbd_x = 0; + kbd_y = 0; + break; + + default: + kbd_x = ec->zone->w - kbd_w; + kbd_y = ec->zone->h - kbd_h; + break; + } + + if ((ec->frame) && + ((ec->w != kbd_w) || (ec->h != kbd_h))) + e_client_util_resize_without_frame(ec, kbd_w, kbd_h); + + if ((e_policy_client_is_keyboard(ec)) && + (ec->frame) && + ((ec->x != kbd_x) || (ec->y != kbd_y))) + e_client_util_move_without_frame(ec, kbd_x, kbd_y); +#endif +} diff --git a/src/bin/e_policy_keyboard.h b/src/bin/e_policy_keyboard.h new file mode 100644 index 0000000000..a17c441589 --- /dev/null +++ b/src/bin/e_policy_keyboard.h @@ -0,0 +1,9 @@ +#ifndef E_POLICY_KEYBOARD_H +#define E_POLICY_KEYBOARD_H +#include + +EINTERN Eina_Bool e_policy_client_is_keyboard(E_Client *ec); +EINTERN Eina_Bool e_policy_client_is_keyboard_sub(E_Client *ec); +EINTERN void e_policy_keyboard_layout_apply(E_Client *ec); + +#endif diff --git a/src/bin/e_policy_private_data.h b/src/bin/e_policy_private_data.h new file mode 100644 index 0000000000..83327d0249 --- /dev/null +++ b/src/bin/e_policy_private_data.h @@ -0,0 +1,56 @@ +#ifndef E_POLICY_PRIVATE_DATA_H +#define E_POLICY_PRIVATE_DATA_H + +/* define layer values here */ +typedef enum { + E_POLICY_ANGLE_MAP_0 = 0, + E_POLICY_ANGLE_MAP_90, + E_POLICY_ANGLE_MAP_180, + E_POLICY_ANGLE_MAP_270, + E_POLICY_ANGLE_MAP_NUM, +} E_Policy_Angle_Map; + +static inline Eina_Bool +e_policy_angle_valid_check(int angle) +{ + return ((angle >= 0) && (angle <= 270) && !(angle % 90)); +} + +static inline E_Policy_Angle_Map +e_policy_angle_map(int angle) +{ + if (!e_policy_angle_valid_check(angle)) + return -1; + + return angle / 90; +} + +static inline int +e_policy_angle_get(E_Policy_Angle_Map map) +{ + if ((map < E_POLICY_ANGLE_MAP_0 ) || (map > E_POLICY_ANGLE_MAP_NUM)) + return -1; + + return map * 90; +} + +/* layer level - 999 */ +# define E_POLICY_QUICKPANEL_LAYER E_LAYER_CLIENT_ALERT +# define E_POLICY_TOAST_POPUP_LAYER E_LAYER_CLIENT_ALERT + +/* layer level - E_LAYER_CLIENT_NOTIFICATION_TOP (800) */ +# define E_POLICY_VOLUME_LAYER E_LAYER_CLIENT_NOTIFICATION_TOP + +/* layer level - E_LAYER_CLIENT_NOTIFICATION_HIGH (750) */ +/* layer level - E_LAYER_CLIENT_NOTIFICATION_NORMAL (700) */ +/* layer level - E_LAYER_CLIENT_NOTIFICATION_LOW (650) */ + +/* layer level - E_LAYER_CLIENT_PRIO (600) */ +# define E_POLICY_FLOATING_LAYER E_LAYER_CLIENT_PRIO + +/* layer level - E_LAYER_CLIENT_FULLSCREEN (350) */ +/* layer level - E_LAYER_CLIENT_ABOVE (250) */ +/* layer level - E_LAYER_CLIENT_NORMAL (200) */ +/* layer level - E_LAYER_CLIENT_BELOW (150) */ + +#endif diff --git a/src/bin/e_policy_softkey.c b/src/bin/e_policy_softkey.c new file mode 100644 index 0000000000..b33b5c1805 --- /dev/null +++ b/src/bin/e_policy_softkey.c @@ -0,0 +1,177 @@ +#include "e.h" + +static void _e_policy_cb_softkey(void *data, Evas_Object *obj EINA_UNUSED, const char *emission, const char *source EINA_UNUSED); +static void _e_policy_softkey_iconify(E_Zone *zone, Eina_Bool all); +static Evas_Object *_e_policy_softkey_icon_add(E_Zone *zone, const char *name); +static void _e_policy_softkey_icon_del(Evas_Object *comp_obj); + +static void +_e_policy_cb_softkey(void *data, Evas_Object *obj EINA_UNUSED, const char *emission, const char *source EINA_UNUSED) +{ + E_Zone *zone; + Eina_Bool all; + + zone = data; + + if (!e_util_strcmp(emission, "e,action,softkey,home")) + all = EINA_TRUE; + else if (!e_util_strcmp(emission, "e,action,softkey,back")) + all = EINA_FALSE; + else + return; + + _e_policy_softkey_iconify(zone, all); +} + +static void +_e_policy_softkey_iconify(E_Zone *zone, Eina_Bool all) +{ + E_Desk *desk; + E_Client *ec; + E_Policy_Client *launcher; + + desk = e_desk_current_get(zone); + launcher = e_policy_client_launcher_get(zone); + + E_CLIENT_REVERSE_FOREACH(ec) + { + if (e_client_util_ignored_get(ec)) continue; + if (!e_client_util_desk_visible(ec, desk)) continue; + if (!evas_object_visible_get(ec->frame)) continue; + + if ((launcher) && (launcher->ec == ec)) + return; + + if (e_policy_client_is_home_screen(ec)) + { + evas_object_raise(ec->frame); + return; + } + if (!all) + { + evas_object_lower(ec->frame); + return; + } + } +} + +static Evas_Object * +_e_policy_softkey_icon_add(E_Zone *zone, const char *name) +{ + Evas_Object *obj, *comp_obj; + char path[PATH_MAX], group[PATH_MAX]; + + obj = edje_object_add(e_comp->evas); + + snprintf(group, sizeof(group), "e/modules/policy-mobile/softkey/%s", name); + e_prefix_data_snprintf(path, sizeof(path), "data/themes/%s", "e-policy.edj"); + + if (!e_theme_edje_object_set(obj, NULL, group)) + edje_object_file_set(obj, path, group); + + edje_object_signal_callback_add(obj, "e,action,softkey,*", "e", + _e_policy_cb_softkey, zone); + + /* use TYPE_NONE to disable shadow for softkey object */ + comp_obj = e_comp_object_util_add(obj, E_COMP_OBJECT_TYPE_NONE); + evas_object_layer_set(comp_obj, E_LAYER_POPUP); + + evas_object_data_set(comp_obj, "policy_mobile_obj", obj); + + return comp_obj; +} + +static void +_e_policy_softkey_icon_del(Evas_Object *comp_obj) +{ + Evas_Object *obj; + + obj = evas_object_data_get(comp_obj, "policy_mobile_obj"); + + edje_object_signal_callback_del(obj, "e,action,softkey,*", + "e", _e_policy_cb_softkey); + evas_object_hide(comp_obj); + evas_object_del(comp_obj); +} + +E_Policy_Softkey * +e_policy_softkey_add(E_Zone *zone) +{ + E_Policy_Softkey *softkey; + + softkey = E_NEW(E_Policy_Softkey, 1); + + softkey->zone = zone; + softkey->home = _e_policy_softkey_icon_add(zone, "home"); + softkey->back = _e_policy_softkey_icon_add(zone, "back"); + + e_policy->softkeys = eina_inlist_append(e_policy->softkeys, EINA_INLIST_GET(softkey)); + + return softkey; +} + +void +e_policy_softkey_del(E_Policy_Softkey *softkey) +{ + if (!softkey) return; + + _e_policy_softkey_icon_del(softkey->home); + _e_policy_softkey_icon_del(softkey->back); + + e_policy->softkeys = eina_inlist_remove(e_policy->softkeys, EINA_INLIST_GET(softkey)); + + free(softkey); +} + +void +e_policy_softkey_show(E_Policy_Softkey *softkey) +{ + if (!softkey) return; + + e_policy_softkey_update(softkey); + + evas_object_show(softkey->home); + evas_object_show(softkey->back); +} + +void +e_policy_softkey_hide(E_Policy_Softkey *softkey) +{ + if (!softkey) return; + + evas_object_hide(softkey->home); + evas_object_hide(softkey->back); +} + +void +e_policy_softkey_update(E_Policy_Softkey *softkey) +{ + int x, y, w, h, ow, oh, space; + + if (!softkey) return; + + e_zone_useful_geometry_get(softkey->zone, &x, &y, &w, &h); + + ow = oh = e_config->softkey_size; + + x = x + (w - ow) / 2; + y = h - oh; + space = ow * 4; + + evas_object_geometry_set(softkey->home, x - space, y, ow, oh); + evas_object_geometry_set(softkey->back, x + space, y, ow, oh); +} + +E_Policy_Softkey * +e_policy_softkey_get(E_Zone *zone) +{ + E_Policy_Softkey *softkey; + + EINA_INLIST_FOREACH(e_policy->softkeys, softkey) + { + if (softkey->zone == zone) + return softkey; + } + + return NULL; +} diff --git a/src/bin/e_policy_stack.c b/src/bin/e_policy_stack.c new file mode 100644 index 0000000000..6d2f56c335 --- /dev/null +++ b/src/bin/e_policy_stack.c @@ -0,0 +1,485 @@ +#include "e.h" + +typedef struct _E_Policy_Stack E_Policy_Stack; + +struct _E_Policy_Stack +{ + E_Client *ec; + + struct + { + Ecore_Window win; + Eina_Bool fetched; + } transient; +}; + +static Eina_Hash *hash_pol_stack = NULL; + +static void +_e_policy_stack_cb_data_free(void *data) +{ + E_FREE(data); +} + +E_Policy_Stack* +_e_policy_stack_data_add(E_Client *ec) +{ + E_Policy_Stack *ps; + + if ((ps = eina_hash_find(hash_pol_stack, &ec))) + return ps; + + ps = E_NEW(E_Policy_Stack, 1); + if (!ps) return NULL; + + ps->ec = ec; + eina_hash_add(hash_pol_stack, &ec, ps); + + return ps; +} + +void +_e_policy_stack_data_del(E_Client *ec) +{ + E_Policy_Stack *ps; + + if ((ps = eina_hash_find(hash_pol_stack, &ec))) + { + eina_hash_del_by_key(hash_pol_stack, &ec); + } +} + +void +_e_policy_stack_transient_for_apply(E_Client *ec) +{ + int raise; + E_Client *child, *top; + Eina_List *l; + + if (ec->parent->layer != ec->layer) + { + raise = e_config->transient.raise; + + ec->saved.layer = ec->layer; + ec->layer = ec->parent->layer; + if (e_config->transient.layer) + { + e_config->transient.raise = 1; + EINA_LIST_FOREACH(ec->transients, l, child) + { + if (!child) continue; + child->saved.layer = child->layer; + child->layer = ec->parent->layer; + } + } + + e_config->transient.raise = raise; + } + + if (ec->transient_policy == E_TRANSIENT_ABOVE) + { + top = e_client_top_get(); + while (top) + { + if ((!ec->parent->transients) || (top == ec->parent)) + { + top = NULL; + break; + } + if ((top != ec) && (eina_list_data_find(ec->parent->transients, top))) + break; + + top = e_client_below_get(top); + } + + if (top) + evas_object_stack_above(ec->frame, top->frame); + else + evas_object_stack_above(ec->frame, ec->parent->frame); + } + else if (ec->transient_policy == E_TRANSIENT_BELOW) + { + evas_object_stack_below(ec->frame, ec->parent->frame); + } +} + +Eina_Bool +_e_policy_stack_transient_for_tree_check(E_Client *child, E_Client *parent) +{ + E_Client *p; + + p = parent->parent; + while (p) + { + if (e_object_is_del(E_OBJECT(p))) return EINA_FALSE; + if (p == child) return EINA_TRUE; + + p = p->parent; + } + + return EINA_FALSE; +} + +void +e_policy_stack_hook_pre_post_fetch(E_Client *ec) +{ + E_Policy_Stack *ps; + ps = eina_hash_find(hash_pol_stack, &ec); + + if (ps) + { + if ((ps->transient.win) && (ps->transient.fetched)) + { + if ((ec->icccm.transient_for == ps->transient.win) && + (ec->parent)) + _e_policy_stack_transient_for_apply(ec); + else + ps->transient.win = ec->icccm.transient_for; + + ps->transient.fetched = 0; + } + } +} + +void +e_policy_stack_hook_pre_fetch(E_Client *ec) +{ + E_Policy_Stack *ps; + ps = eina_hash_find(hash_pol_stack, &ec); + + if (ec->icccm.fetch.transient_for) + { + Ecore_Window transient_for_win = 0; + E_Client *parent = NULL; + Eina_Bool transient_each_other = EINA_FALSE; + + parent = e_pixmap_find_client(E_PIXMAP_TYPE_WL, ec->icccm.transient_for); + + if (parent) + { + if (!ps) ps = _e_policy_stack_data_add(ec); + + ps->transient.win = e_client_util_win_get(parent); + ps->transient.fetched = 1; + + /* clients transient for each other */ + transient_each_other = _e_policy_stack_transient_for_tree_check(ec, parent); + if (transient_each_other) + { + ec->icccm.transient_for = transient_for_win; + ec->icccm.fetch.transient_for = 0; + ps->transient.fetched = 0; + parent = NULL; + } + } + } +} + +void +e_policy_stack_transient_for_set(E_Client *child, E_Client *parent) +{ + Ecore_Window pwin = 0; + + EINA_SAFETY_ON_NULL_RETURN(child); + + if (!parent) + { + child->icccm.fetch.transient_for = EINA_FALSE; + child->icccm.transient_for = 0; + if (child->parent) + { + child->parent->transients = + eina_list_remove(child->parent->transients, child); + if (child->parent->modal == child) child->parent->modal = NULL; + child->parent = NULL; + } + return; + } + + pwin = e_client_util_win_get(parent); + + /* If we already have a parent, remove it */ + if (child->parent) + { + if (parent != child->parent) + { + child->parent->transients = + eina_list_remove(child->parent->transients, child); + if (child->parent->modal == child) child->parent->modal = NULL; + child->parent = NULL; + } + else + parent = NULL; + } + + if ((parent) && (parent != child) && + (eina_list_data_find(parent->transients, child) != child)) + { + parent->transients = eina_list_append(parent->transients, child); + child->parent = parent; + } + + child->icccm.fetch.transient_for = EINA_TRUE; + child->icccm.transient_for = pwin; +} + +void +e_policy_stack_cb_client_remove(E_Client *ec) +{ + _e_policy_stack_data_del(ec); +} + +void +e_policy_stack_shutdonw(void) +{ + eina_hash_free(hash_pol_stack); + hash_pol_stack = NULL; +} + +void +e_policy_stack_init(void) +{ + hash_pol_stack = eina_hash_pointer_new(_e_policy_stack_cb_data_free); +} + +void +e_policy_stack_below(E_Client *ec, E_Client *below_ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + EINA_SAFETY_ON_NULL_RETURN(below_ec); + EINA_SAFETY_ON_NULL_RETURN(below_ec->frame); + + evas_object_stack_below(ec->frame, below_ec->frame); + if (e_config->transient.iconify) + { + E_Client *child; + Eina_List *list = eina_list_clone(ec->transients); + + EINA_LIST_FREE(list, child) + { + e_policy_stack_below(child, below_ec); + } + } +} + +static E_Client * +_e_policy_stack_find_top_lockscreen(E_Client *ec_lock, E_Client *ec_except) +{ + E_Client *ec = NULL; + E_Client *ec_top_lock = NULL; + int x, y, w, h; + + if (!ec_lock) return NULL; + + E_CLIENT_REVERSE_FOREACH(ec) + { + if (e_object_is_del(E_OBJECT(ec))) continue; + if ((ec != ec_except) && + (e_policy_client_is_lockscreen(ec))) + { + e_client_geometry_get(ec, &x, &y, &w, &h); + if (E_CONTAINS(ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h, + x, y, w, h)) + { + ec_top_lock = ec; + break; + } + } + } + + return ec_top_lock; +} + +void +e_policy_stack_clients_restack_above_lockscreen(E_Client *ec_lock, Eina_Bool show) +{ + E_Client *ec = NULL; + E_Client *new_lock = NULL; + Eina_Bool restack_above = EINA_FALSE; + + if (!ec_lock) return; + + if (show) + { + new_lock = _e_policy_stack_find_top_lockscreen(ec_lock, NULL); + if (!new_lock) + new_lock = ec_lock; + + e_policy_system_info.lockscreen.show = show; + e_policy_system_info.lockscreen.ec = new_lock; + + restack_above = EINA_TRUE; + } + else + { + if (ec_lock != e_policy_system_info.lockscreen.ec) + return; + + new_lock = _e_policy_stack_find_top_lockscreen(ec_lock, e_policy_system_info.lockscreen.ec); + if (new_lock) + { + e_policy_system_info.lockscreen.show = EINA_TRUE; + e_policy_system_info.lockscreen.ec = new_lock; + restack_above = EINA_TRUE; + } + else + { + E_Layer org_layer; + Eina_List *restore_list = NULL; + Eina_List *l = NULL; + + e_policy_system_info.lockscreen.show = show; + e_policy_system_info.lockscreen.ec = NULL; + + E_CLIENT_FOREACH(ec) + { + if (e_object_is_del(E_OBJECT(ec))) continue; + if (ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].set && + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved) + { + restore_list = eina_list_append(restore_list, ec); + } + } + + if (restore_list) + { + EINA_LIST_FOREACH(restore_list, l, ec) + { + org_layer = ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved_layer; + ELOGF("CHANGE to Original layer", "AboveLock|layer: %d -> %d", ec->pixmap, ec, ec->layer, org_layer); + evas_object_layer_set(ec->frame, org_layer); + ec->layer = org_layer; + + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved = EINA_FALSE; + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved_layer = 0; + } + eina_list_free(restore_list); + restore_list = NULL; + } + } + } + + if (restack_above) + { + Eina_List *restack_list = NULL; + Eina_List *l = NULL; + E_Layer lock_layer = e_policy_system_info.lockscreen.ec->layer; + Eina_Bool passed_new_lock = EINA_FALSE; + int x, y, w, h; + + E_CLIENT_REVERSE_FOREACH(ec) + { + if (e_object_is_del(E_OBJECT(ec))) continue; + if (ec == new_lock) + { + passed_new_lock = EINA_TRUE; + continue; + } + if (!passed_new_lock) continue; + if (e_policy_client_is_lockscreen(ec)) continue; + if (ec->exp_iconify.by_client) continue; + + if (ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].set) + { + if (ec->layer <= lock_layer) + { + restack_list = eina_list_append(restack_list, ec); + } + } + + if ((!ec->argb) || + ((ec->argb) && + (ec->visibility.opaque == 1))) + { + e_client_geometry_get(ec, &x, &y, &w, &h); + if (E_CONTAINS(x, y, w, h, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h)) + { + break; + } + } + } + + if (restack_list) + { + EINA_LIST_REVERSE_FOREACH(restack_list, l, ec) + { + if (ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved == EINA_FALSE) + { + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved = EINA_TRUE; + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved_layer = ec->layer; + } + + ELOGF("CHANGE to Lockscreen layer", "AboveLock|layer: %d -> %d", ec->pixmap, ec, ec->layer, lock_layer); + if (ec->layer == lock_layer) + evas_object_raise(ec->frame); + else + evas_object_layer_set(ec->frame, lock_layer); + + ec->layer = lock_layer; + } + eina_list_free(restack_list); + restack_list = NULL; + } + } + +} + +Eina_Bool +e_policy_stack_check_above_lockscreen(E_Client *ec, E_Layer layer, E_Layer *new_layer, Eina_Bool set_layer) +{ + E_Layer lock_layer; + + if (!ec) return EINA_FALSE; + if (!ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].set) + return EINA_FALSE; + + if (e_policy_system_info.lockscreen.show && + e_policy_system_info.lockscreen.ec) + { + lock_layer = e_policy_system_info.lockscreen.ec->layer; + if (layer <= lock_layer) + { + if (ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved == EINA_FALSE) + { + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved = EINA_TRUE; + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved_layer = ec->layer; + } + + if (set_layer) + { + ELOGF("CHANGE to Lockscreen layer", "AboveLock|layer: %d -> %d", ec->pixmap, ec, ec->layer, lock_layer); + if (ec->layer == lock_layer) + evas_object_raise(ec->frame); + else + evas_object_layer_set(ec->frame, lock_layer); + ec->layer = lock_layer; + } + + if (new_layer) + *new_layer = lock_layer; + } + else + { + if (set_layer) + { + if (ec->layer != layer) + { + ELOGF("CHANGE to Lockscreen layer", "AboveLock|layer: %d -> %d", ec->pixmap, ec, ec->layer, lock_layer); + evas_object_layer_set(ec->frame, lock_layer); + ec->layer = lock_layer; + } + } + + if (new_layer) + *new_layer = layer; + } + + return EINA_TRUE; + } + + return EINA_FALSE; + +} + diff --git a/src/bin/e_policy_transform_mode.c b/src/bin/e_policy_transform_mode.c new file mode 100644 index 0000000000..daaad5822b --- /dev/null +++ b/src/bin/e_policy_transform_mode.c @@ -0,0 +1,395 @@ +#include "e.h" +#include "e_policy_transform_mode.h" + +#define E_TRANSFORM_MODE_NAME "wm.policy.win.transform.mode" +#define E_TRANSFORM_MODE_AUTOFIT "autofit" +#define E_TRANSFORM_MODE_RATIOFIT "ratiofit" + +typedef struct _E_Mod_Transform_Client E_Mod_Transform_Client; +typedef struct _E_Mod_Transform_Manager E_Mod_Transform_Manager; + +typedef enum +{ + E_Mod_Transform_Type_None = 0, + E_Mod_Transform_Type_AutoFit, + E_Mod_Transform_Type_RatioFit + +}E_Mod_Transform_Type; + +struct _E_Mod_Transform_Client +{ + E_Client *ec; + E_Util_Transform *transform; + Eina_Bool user_geometry_by_me; + E_Mod_Transform_Type transform_type; + int x, y, w, h; +}; + +struct _E_Mod_Transform_Manager +{ + Eina_List *transform_client_list; + Eina_List *hook_list; + Eina_List *event_list; +}; + +static E_Mod_Transform_Manager *_transform_mode = NULL; + +static E_Mod_Transform_Client *_e_policy_transform_client_new(E_Client *ec, E_Mod_Transform_Manager *mng); +static void _e_policy_transform_client_del(E_Mod_Transform_Client *transform_ec, E_Mod_Transform_Manager *mng); +static E_Mod_Transform_Client *_e_policy_transform_client_find(E_Client *ec, E_Mod_Transform_Manager *mng); +static void _e_policy_transform_client_mode_change(E_Mod_Transform_Client *transform_ec, E_Mod_Transform_Type mode); +static void _e_policy_transform_client_mode_cancel(E_Mod_Transform_Client *transform_ec); +static void _e_policy_transform_client_mode_autofit_ratiofit_set(E_Mod_Transform_Client *transform_ec, E_Mod_Transform_Type mode); +static void _e_policy_transform_client_mode_autofit_ratiofit_cancel(E_Mod_Transform_Client *transform_ec); + +static void _e_policy_transform_cb_aux_change(void *data, E_Client *ec); +static void _e_policy_transform_cb_client_del(void *data, E_Client *ec); +static void _e_policy_transform_cb_client_move_resize(void *data, Evas *e, Evas_Object *obj, void *event_info); + + +static E_Mod_Transform_Type _e_policy_transform_mode_string_to_enum(const char *str_mode); +static void _e_policy_transform_screen_size_get(E_Mod_Transform_Client *transform_ec, int *w, int *h); +static void _e_policy_transform_client_size_get(E_Mod_Transform_Client *transform_ec, int *w, int *h); +static void _e_policy_transform_client_pos_get(E_Mod_Transform_Client *transform_ec, int *x, int *y); +static Eina_Bool _e_policy_transform_client_geometry_change_check(E_Mod_Transform_Client *transform_ec); + +Eina_Bool +e_policy_transform_mode_init(void) +{ + if (_transform_mode) return EINA_FALSE; + + _transform_mode = (E_Mod_Transform_Manager*)malloc(sizeof(E_Mod_Transform_Manager)); + memset(_transform_mode, 0, sizeof(E_Mod_Transform_Manager)); + + _transform_mode->hook_list = eina_list_append(_transform_mode->hook_list, + e_client_hook_add(E_CLIENT_HOOK_AUX_HINT_CHANGE , + _e_policy_transform_cb_aux_change, + _transform_mode)); + + _transform_mode->hook_list = eina_list_append(_transform_mode->hook_list, + e_client_hook_add(E_CLIENT_HOOK_DEL , + _e_policy_transform_cb_client_del, + _transform_mode)); + + e_hints_aux_hint_supported_add(E_TRANSFORM_MODE_NAME); + return EINA_TRUE; +} + +void +e_policy_transform_mode_shutdown(void) +{ + if (!_transform_mode) return; + + while(_transform_mode->transform_client_list) + { + _e_policy_transform_client_del(eina_list_nth(_transform_mode->transform_client_list, 0), _transform_mode); + } + + if (_transform_mode->hook_list) + { + E_Client_Hook *hook; + + EINA_LIST_FREE(_transform_mode->hook_list, hook) + { + e_client_hook_del(hook); + } + } + + free(_transform_mode); + _transform_mode = NULL; + + e_hints_aux_hint_supported_del(E_TRANSFORM_MODE_NAME); +} + +static E_Mod_Transform_Client* +_e_policy_transform_client_new(E_Client *ec, E_Mod_Transform_Manager *mng) +{ + E_Mod_Transform_Client *result = NULL; + + if (!mng) return NULL; + if (!ec) return NULL; + if (_e_policy_transform_client_find(ec, mng)) return NULL; + + result = (E_Mod_Transform_Client*)malloc(sizeof(E_Mod_Transform_Client)); + memset(result, 0, sizeof(E_Mod_Transform_Client)); + result->ec = ec; + result->transform = e_util_transform_new(); + + mng->transform_client_list = eina_list_append(mng->transform_client_list, result); + return result; +} + +static void +_e_policy_transform_client_del(E_Mod_Transform_Client *transform_ec, E_Mod_Transform_Manager *mng) +{ + if (!mng) return; + if (!transform_ec) return; + + if (transform_ec->transform) + { + _e_policy_transform_client_mode_cancel(transform_ec); + e_util_transform_del(transform_ec->transform); + transform_ec->transform = NULL; + } + + mng->transform_client_list = eina_list_remove(mng->transform_client_list, transform_ec); + free(transform_ec); +} + +static E_Mod_Transform_Client* +_e_policy_transform_client_find(E_Client *ec, E_Mod_Transform_Manager *mng) +{ + E_Mod_Transform_Client *temp = NULL; + E_Mod_Transform_Client *result = NULL; + Eina_List *l = NULL; + + if (!mng) return NULL; + if (!ec) return NULL; + + EINA_LIST_FOREACH(mng->transform_client_list, l, temp) + { + if (temp->ec == ec) + { + result = temp; + break; + } + } + return result; +} + +static void +_e_policy_transform_client_mode_change(E_Mod_Transform_Client *transform_ec, E_Mod_Transform_Type mode) +{ + if (!transform_ec) return; + if (mode == E_Mod_Transform_Type_None) return; + + if (transform_ec->transform_type != mode) + { + _e_policy_transform_client_mode_cancel(transform_ec); + + if (mode == E_Mod_Transform_Type_AutoFit || + mode == E_Mod_Transform_Type_RatioFit) + { + _e_policy_transform_client_mode_autofit_ratiofit_set(transform_ec, mode); + } + } +} + +static void +_e_policy_transform_client_mode_cancel(E_Mod_Transform_Client *transform_ec) +{ + if (!transform_ec) return; + if (transform_ec->transform_type == E_Mod_Transform_Type_None) return; + + if (transform_ec->transform_type == E_Mod_Transform_Type_AutoFit || + transform_ec->transform_type == E_Mod_Transform_Type_RatioFit) + { + _e_policy_transform_client_mode_autofit_ratiofit_cancel(transform_ec); + } + + transform_ec->transform_type = E_Mod_Transform_Type_None; +} + +static void +_e_policy_transform_client_mode_autofit_ratiofit_set(E_Mod_Transform_Client *transform_ec, E_Mod_Transform_Type mode) +{ + if (!transform_ec) return; + if (transform_ec->transform_type != E_Mod_Transform_Type_None) return; + + if (transform_ec->transform) + { + if (mode == E_Mod_Transform_Type_RatioFit) + e_util_transform_keep_ratio_set(transform_ec->transform, EINA_TRUE); + e_client_transform_core_add(transform_ec->ec, transform_ec->transform); + } + _e_policy_transform_cb_client_move_resize(transform_ec, 0, 0, 0); + + if (transform_ec->ec->frame) + { + evas_object_event_callback_add(transform_ec->ec->frame, EVAS_CALLBACK_RESIZE, _e_policy_transform_cb_client_move_resize, transform_ec); + evas_object_event_callback_add(transform_ec->ec->frame, EVAS_CALLBACK_MOVE, _e_policy_transform_cb_client_move_resize, transform_ec); + } + + e_policy_allow_user_geometry_set(transform_ec->ec, EINA_TRUE); + transform_ec->transform_type = mode; +} + +static void +_e_policy_transform_client_mode_autofit_ratiofit_cancel(E_Mod_Transform_Client *transform_ec) +{ + if (!transform_ec) return; + if (transform_ec->transform_type != E_Mod_Transform_Type_AutoFit && + transform_ec->transform_type != E_Mod_Transform_Type_RatioFit) return; + + if (transform_ec->transform) + { + e_util_transform_keep_ratio_set(transform_ec->transform, EINA_FALSE); + e_client_transform_core_remove(transform_ec->ec, transform_ec->transform); + } + + if (transform_ec->ec->frame) + { + evas_object_event_callback_del(transform_ec->ec->frame, EVAS_CALLBACK_RESIZE, _e_policy_transform_cb_client_move_resize); + evas_object_event_callback_del(transform_ec->ec->frame, EVAS_CALLBACK_MOVE, _e_policy_transform_cb_client_move_resize); + } + + e_policy_allow_user_geometry_set(transform_ec->ec, EINA_FALSE); + transform_ec->transform_type = E_Mod_Transform_Type_None; +} + +static void +_e_policy_transform_cb_aux_change(void *data, E_Client *ec) +{ + E_Mod_Transform_Manager *mng = (E_Mod_Transform_Manager*)data; + E_Mod_Transform_Client *t_ec = NULL; + E_Mod_Transform_Type t_mode = E_Mod_Transform_Type_None; + const char *t_str = NULL; + + if (!ec) return; + if (!mng) return; + + t_ec = _e_policy_transform_client_find(ec, mng); + t_str = e_hints_aux_hint_value_get(ec, E_TRANSFORM_MODE_NAME); + t_mode = _e_policy_transform_mode_string_to_enum(t_str); + + if (t_ec) + { + if (t_mode == E_Mod_Transform_Type_None) + _e_policy_transform_client_del(t_ec, mng); + else + _e_policy_transform_client_mode_change(t_ec, t_mode); + } + else + { + if (t_mode != E_Mod_Transform_Type_None) + { + t_ec = _e_policy_transform_client_new(ec, mng); + _e_policy_transform_client_mode_change(t_ec, t_mode); + } + } +} + +static void +_e_policy_transform_cb_client_del(void *data, E_Client *ec) +{ + E_Mod_Transform_Manager *mng = (E_Mod_Transform_Manager*)data; + E_Mod_Transform_Client *transform_ec = NULL; + + if (!mng) return; + if (!ec) return; + + transform_ec = _e_policy_transform_client_find(ec, mng); + + if (transform_ec) + _e_policy_transform_client_del(transform_ec, mng); +} + +static void +_e_policy_transform_cb_client_move_resize(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + E_Mod_Transform_Client *transform_ec = (E_Mod_Transform_Client*)data; + int zone_w = 1, zone_h = 1; + double sx = 1.0, sy = 1.0; + int w = 1, h = 1; + int x, y; + + if (!transform_ec) return; + if (!_e_policy_transform_client_geometry_change_check(transform_ec)) return; + + _e_policy_transform_screen_size_get(transform_ec, &zone_w, &zone_h); + _e_policy_transform_client_size_get(transform_ec, &w, &h); + _e_policy_transform_client_pos_get(transform_ec, &x, &y); + + sx = (double) zone_w / (double) w; + sy = (double) zone_h / (double) h; + + e_util_transform_init(transform_ec->transform); + if (transform_ec->transform_type == E_Mod_Transform_Type_RatioFit) + e_util_transform_keep_ratio_set(transform_ec->transform, EINA_TRUE); + e_util_transform_move(transform_ec->transform, -x, -y, 0.0); + e_util_transform_scale(transform_ec->transform, sx, sy, 1.0); +} + +static E_Mod_Transform_Type +_e_policy_transform_mode_string_to_enum(const char *str_mode) +{ + if (!str_mode) return E_Mod_Transform_Type_None; + else if (!e_util_strcmp(str_mode, E_TRANSFORM_MODE_AUTOFIT)) return E_Mod_Transform_Type_AutoFit; + else if (!e_util_strcmp(str_mode, E_TRANSFORM_MODE_RATIOFIT)) return E_Mod_Transform_Type_RatioFit; + + return E_Mod_Transform_Type_None; +} + +static void +_e_policy_transform_screen_size_get(E_Mod_Transform_Client *transform_ec, int *w, int *h) +{ + int zone_w = 1; + int zone_h = 1; + + if (!transform_ec) return; + + if (transform_ec->ec->zone) + { + zone_w = transform_ec->ec->zone->w; + zone_h = transform_ec->ec->zone->h; + } + else + { + zone_w = 1920; + zone_h = 1080; + } + + if (zone_w < 1) zone_w = 1; + if (zone_h < 1) zone_h = 1; + + if (w) *w = zone_w; + if (h) *h = zone_h; +} + +static void +_e_policy_transform_client_size_get(E_Mod_Transform_Client *transform_ec, int *w, int *h) +{ + int ec_w = 1; + int ec_h = 1; + + if (!transform_ec) return; + + ec_w = transform_ec->ec->w; + ec_h = transform_ec->ec->h; + + if (ec_w < 1) ec_w = 1; + if (ec_h < 1) ec_h = 1; + + if (w) *w = ec_w; + if (h) *h = ec_h; +} + +static void +_e_policy_transform_client_pos_get(E_Mod_Transform_Client *transform_ec, int *x, int *y) +{ + if (!transform_ec) return; + + if (x) *x = transform_ec->ec->x; + if (y) *y = transform_ec->ec->y; + +} + +static Eina_Bool +_e_policy_transform_client_geometry_change_check(E_Mod_Transform_Client *transform_ec) +{ + if (!transform_ec) return EINA_FALSE; + if (transform_ec->ec->x != transform_ec->x || + transform_ec->ec->y != transform_ec->y || + transform_ec->ec->w != transform_ec->w || + transform_ec->ec->h != transform_ec->h) + { + transform_ec->x = transform_ec->ec->x; + transform_ec->y = transform_ec->ec->y; + transform_ec->w = transform_ec->ec->w; + transform_ec->h = transform_ec->ec->h; + + return EINA_TRUE; + } + + return EINA_FALSE; +} diff --git a/src/bin/e_policy_transform_mode.h b/src/bin/e_policy_transform_mode.h new file mode 100644 index 0000000000..45e82a5d84 --- /dev/null +++ b/src/bin/e_policy_transform_mode.h @@ -0,0 +1,9 @@ +#ifndef E_POLICY_TRANSFORM_MODE_H +#define E_POLICY_TRANSFORM_MODE_H + +#include "e.h" + +Eina_Bool e_policy_transform_mode_init(void); +void e_policy_transform_mode_shutdown(void); + +#endif /* end of E_POLICY_TRANSFORM_MODE_H */ diff --git a/src/bin/e_policy_visibility.c b/src/bin/e_policy_visibility.c new file mode 100644 index 0000000000..25ec0d4504 --- /dev/null +++ b/src/bin/e_policy_visibility.c @@ -0,0 +1,284 @@ +#include "e.h" +#include "e_comp_wl.h" +#include "e_policy_wl.h" + +#ifdef ENABLE_TTRACE +# include +# undef TRACE_DS_BEGIN +# undef TRACE_DS_END + +# define TRACE_DS_BEGIN(NAME) traceBegin(TTRACE_TAG_WINDOW_MANAGER, "DS:POL:"#NAME) +# define TRACE_DS_END() traceEnd(TTRACE_TAG_WINDOW_MANAGER) +#else +# define TRACE_DS_BEGIN(NAME) +# define TRACE_DS_END() +#endif + +static Eina_Bool _e_policy_check_transient_child_visible(E_Client *ancestor_ec, E_Client *ec); +static Eina_Bool _e_policy_check_above_alpha_opaque(E_Client *ec); +static void _e_policy_client_iconify_by_visibility(E_Client *ec); +static void _e_policy_client_ancestor_uniconify(E_Client *ec); +static void _e_policy_client_below_uniconify(E_Client *ec); +static void _e_policy_client_uniconify_by_visibility(E_Client *ec); + +static Eina_Bool +_e_policy_check_transient_child_visible(E_Client *ancestor_ec, E_Client *ec) +{ + Eina_Bool visible = EINA_FALSE; + Eina_List *list = NULL; + E_Client *child_ec = NULL; + int anc_x, anc_y, anc_w, anc_h; + int child_x, child_y, child_w, child_h; + + if (!ancestor_ec) return EINA_FALSE; + + e_client_geometry_get(ancestor_ec, &anc_x, &anc_y, &anc_w, &anc_h); + + list = eina_list_clone(ec->transients); + EINA_LIST_FREE(list, child_ec) + { + if (visible == EINA_TRUE) continue; + + if (child_ec->exp_iconify.skip_iconify == EINA_TRUE) + { + if (child_ec->visibility.obscured == E_VISIBILITY_UNOBSCURED) + { + return EINA_TRUE; + } + else + { + if (!child_ec->iconic) + { + e_client_geometry_get(child_ec, &child_x, &child_y, &child_w, &child_h); + if (E_CONTAINS(child_x, child_y, child_w, child_h, anc_x, anc_y, anc_w, anc_h)) + { + return EINA_TRUE; + } + } + } + } + else + { + if ((!child_ec->iconic) || + (child_ec->visibility.obscured == E_VISIBILITY_UNOBSCURED)) + { + return EINA_TRUE; + } + } + + visible = _e_policy_check_transient_child_visible(ancestor_ec, child_ec); + } + + return visible; +} + +static Eina_Bool +_e_policy_check_above_alpha_opaque(E_Client *ec) +{ + E_Client *above_ec; + Evas_Object *o; + Eina_Bool alpha_opaque = EINA_FALSE; + + for (o = evas_object_above_get(ec->frame); o; o = evas_object_above_get(o)) + { + above_ec = evas_object_data_get(o, "E_Client"); + if (!above_ec) continue; + if (e_client_util_ignored_get(above_ec)) continue; + if (!E_CONTAINS(above_ec->x, above_ec->y, above_ec->w, above_ec->h, ec->x, ec->y, ec->w, ec->h)) continue; + + if ((above_ec->visibility.opaque > 0) && (above_ec->argb)) + { + if (above_ec->visibility.obscured == E_VISIBILITY_UNOBSCURED) + { + alpha_opaque = EINA_TRUE; + } + else + { + if (!above_ec->iconic) + { + alpha_opaque = EINA_TRUE; + } + } + } + break; + } + + return alpha_opaque; +} + +static void +_e_policy_client_iconify_by_visibility(E_Client *ec) +{ + Eina_Bool do_iconify = EINA_TRUE; + + if (!ec) return; + if (ec->iconic) return; + if (ec->exp_iconify.by_client) return; + if (ec->exp_iconify.skip_iconify) return; + + E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data *)ec->comp_data; + if (cdata && !cdata->mapped) return; + + if (e_config->transient.iconify) + { + if (_e_policy_check_transient_child_visible(ec, ec)) + { + do_iconify = EINA_FALSE; + } + } + + if (ec->zone->display_state != E_ZONE_DISPLAY_STATE_OFF) + { + // check above window is alpha opaque or not + if (_e_policy_check_above_alpha_opaque(ec)) + { + do_iconify = EINA_FALSE; + } + } + + if (!do_iconify) + { + ELOGF("SKIP.. ICONIFY_BY_WM", "win:0x%08x", ec->pixmap, ec, e_client_util_win_get(ec)); + return; + } + + ELOGF("ICONIFY_BY_WM", "win:0x%08x", ec->pixmap, ec, e_client_util_win_get(ec)); + e_policy_wl_iconify_state_change_send(ec, 1); + e_client_iconify(ec); + + /* if client has obscured parent, try to iconify the parent also */ + if (ec->parent) + { + if (ec->parent->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED) + _e_policy_client_iconify_by_visibility(ec->parent); + } +} + +static void +_e_policy_client_ancestor_uniconify(E_Client *ec) +{ + Eina_List *list = NULL; + Eina_List *l = NULL; + E_Client *parent = NULL; + int transient_iconify = 0; + int count = 0; + + if (!ec) return; + if (e_object_is_del(E_OBJECT(ec))) return; + if (!ec->iconic) return; + if (ec->exp_iconify.by_client) return; + if (ec->exp_iconify.skip_iconify) return; + + parent = ec->parent; + while (parent) + { + if (count > 10) + { + // something strange state. + ELOGF("CHECK transient_for tree", "win:0x%08x, parent:0x%08x", NULL, NULL, e_client_util_win_get(ec), e_client_util_win_get(parent)); + break; + } + + if (e_object_is_del(E_OBJECT(parent))) break; + if (!parent->iconic) break; + if (parent->exp_iconify.by_client) break; + if (parent->exp_iconify.skip_iconify) break; + + if (eina_list_data_find(list, parent)) + { + // very bad. there are loop for parenting + ELOGF("Very BAD. Circling transient_for window", "win:0x%08x, parent:0x%08x", NULL, NULL, e_client_util_win_get(ec), e_client_util_win_get(parent)); + break; + } + + list = eina_list_prepend(list, parent); + parent = parent->parent; + + // for preventing infiniting loop + count++; + } + + transient_iconify = e_config->transient.iconify; + e_config->transient.iconify = 0; + + parent = NULL; + EINA_LIST_FOREACH(list, l, parent) + { + ELOGF("UNICONIFY_BY_WM", "parent_win:0x%08x", parent->pixmap, parent, e_client_util_win_get(parent)); + parent->exp_iconify.not_raise = 1; + e_client_uniconify(parent); + e_policy_wl_iconify_state_change_send(parent, 0); + } + eina_list_free(list); + + e_config->transient.iconify = transient_iconify; +} + +static void +_e_policy_client_below_uniconify(E_Client *ec) +{ + E_Client *below_ec; + Evas_Object *o; + + for (o = evas_object_below_get(ec->frame); o; o = evas_object_below_get(o)) + { + below_ec = evas_object_data_get(o, "E_Client"); + if (!below_ec) continue; + if (e_client_util_ignored_get(below_ec)) continue; + + if (ec->parent == below_ec) break; + if (!below_ec->iconic) break; + + if (below_ec->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED) + { + _e_policy_client_uniconify_by_visibility(below_ec); + } + + break; + } +} + +static void +_e_policy_client_uniconify_by_visibility(E_Client *ec) +{ + if (!ec) return; + if (e_object_is_del(E_OBJECT(ec))) return; + if (!ec->iconic) return; + if (ec->exp_iconify.by_client) return; + if (ec->exp_iconify.skip_iconify) return; + + E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data *)ec->comp_data; + if (cdata && !cdata->mapped) return; + + _e_policy_client_ancestor_uniconify(ec); + + ELOGF("UNICONIFY_BY_WM", "win:0x%08x", ec->pixmap, ec, e_client_util_win_get(ec)); + ec->exp_iconify.not_raise = 1; + e_client_uniconify(ec); + e_policy_wl_iconify_state_change_send(ec, 0); + + if ((ec->visibility.opaque > 0) && (ec->argb)) + { + _e_policy_client_below_uniconify(ec); + } +} + +void +e_policy_client_visibility_send(E_Client *ec) +{ + e_policy_wl_visibility_send(ec, ec->visibility.obscured); +} + +void +e_policy_client_iconify_by_visibility(E_Client *ec) +{ + if (!ec) return; + _e_policy_client_iconify_by_visibility(ec); +} + +void +e_policy_client_uniconify_by_visibility(E_Client *ec) +{ + if (!ec) return; + _e_policy_client_uniconify_by_visibility(ec); +} diff --git a/src/bin/e_policy_wl.c b/src/bin/e_policy_wl.c new file mode 100644 index 0000000000..1bfa0e7d5b --- /dev/null +++ b/src/bin/e_policy_wl.c @@ -0,0 +1,4448 @@ +#include "e_policy_wl.h" +#include "e.h" +#include "services/e_service_quickpanel.h" +#include "services/e_service_volume.h" +#include "services/e_service_lockscreen.h" +#include "e_policy_wl_display.h" +#include "e_policy_conformant.h" + +#include +#include +#include +#include + +#ifdef HAVE_CYNARA +# include +# include +# include +#endif + +#define PRIVILEGE_NOTIFICATION_LEVEL_SET "http://tizen.org/privilege/window.priority.set" +#define PRIVILEGE_SCREEN_MODE_SET "http://tizen.org/privilege/display" +#define PRIVILEGE_BRIGHTNESS_SET "http://tizen.org/privilege/display" + +#define APP_DEFINE_GROUP_NAME "effect" + +typedef enum _Tzsh_Srv_Role +{ + TZSH_SRV_ROLE_UNKNOWN = -1, + TZSH_SRV_ROLE_CALL, + TZSH_SRV_ROLE_VOLUME, + TZSH_SRV_ROLE_QUICKPANEL, + TZSH_SRV_ROLE_LOCKSCREEN, + TZSH_SRV_ROLE_INDICATOR, + TZSH_SRV_ROLE_TVSERVICE, + TZSH_SRV_ROLE_SCREENSAVER_MNG, + TZSH_SRV_ROLE_SCREENSAVER, + TZSH_SRV_ROLE_MAX +} Tzsh_Srv_Role; + +typedef enum _Tzsh_Type +{ + TZSH_TYPE_UNKNOWN = 0, + TZSH_TYPE_SRV, + TZSH_TYPE_CLIENT +} Tzsh_Type; + +typedef struct _E_Policy_Wl_Tzpol +{ + struct wl_resource *res_tzpol; /* tizen_policy_interface */ + Eina_List *psurfs; /* list of E_Policy_Wl_Surface */ + Eina_List *pending_bg; +} E_Policy_Wl_Tzpol; + +typedef struct _E_Policy_Wl_Tz_Dpy_Pol +{ + struct wl_resource *res_tz_dpy_pol; + Eina_List *dpy_surfs; // list of E_Policy_Wl_Dpy_Surface +} E_Policy_Wl_Tz_Dpy_Pol; + +typedef struct _E_Policy_Wl_Tzsh +{ + struct wl_resource *res_tzsh; /* tizen_ws_shell_interface */ + Tzsh_Type type; + E_Pixmap *cp; + E_Client *ec; +} E_Policy_Wl_Tzsh; + +typedef struct _E_Policy_Wl_Tzsh_Srv +{ + E_Policy_Wl_Tzsh *tzsh; + struct wl_resource *res_tzsh_srv; + Tzsh_Srv_Role role; + const char *name; +} E_Policy_Wl_Tzsh_Srv; + +typedef struct _E_Policy_Wl_Tzsh_Client +{ + E_Policy_Wl_Tzsh *tzsh; + struct wl_resource *res_tzsh_client; + Eina_Bool qp_client; +} E_Policy_Wl_Tzsh_Client; + +typedef struct _E_Policy_Wl_Tzsh_Region +{ + E_Policy_Wl_Tzsh *tzsh; + struct wl_resource *res_tzsh_reg; + Eina_Tiler *tiler; + struct wl_listener destroy_listener; +} E_Policy_Wl_Tzsh_Region; + +typedef struct _E_Policy_Wl_Surface +{ + struct wl_resource *surf; + E_Policy_Wl_Tzpol *tzpol; + E_Pixmap *cp; + E_Client *ec; + pid_t pid; + Eina_Bool pending_notilv; + int32_t notilv; + Eina_List *vislist; /* list of tizen_visibility_interface resources */ + Eina_List *poslist; /* list of tizen_position_inteface resources */ + Eina_Bool is_background; +} E_Policy_Wl_Surface; + +typedef struct _E_Policy_Wl_Dpy_Surface +{ + E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol; + struct wl_resource *surf; + E_Client *ec; + Eina_Bool set; + int32_t brightness; +} E_Policy_Wl_Dpy_Surface; + +typedef struct _E_Policy_Wl_Tzlaunch +{ + struct wl_resource *res_tzlaunch; /* tizen_launchscreen */ + Eina_List *imglist; /* list of E_Policy_Wl_Tzlaunch_Img */ +} E_Policy_Wl_Tzlaunch; + +typedef struct _E_Policy_Wl_Tzlaunch_Img +{ + struct wl_resource *res_tzlaunch_img; /* tizen_launch_image */ + E_Policy_Wl_Tzlaunch *tzlaunch; /* launcher */ + + const char *path; /* image resource path */ + uint32_t type; /* 0: image, 1: edc */ + uint32_t indicator; /* 0: off, 1: on */ + uint32_t angle; /* 0, 90, 180, 270 : rotation angle */ + uint32_t pid; + + Evas_Object *obj; /* launch screen image */ + E_Pixmap *ep; /* pixmap for launch screen client */ + E_Client *ec; /* client for launch screen image */ + Ecore_Timer *timeout; /* launch screen image hide timer */ + + Eina_Bool valid; +} E_Policy_Wl_Tzlaunch_Img; + +typedef enum _E_Launch_Img_File_type +{ + E_LAUNCH_FILE_TYPE_ERROR = -1, + E_LAUNCH_FILE_TYPE_IMAGE = 0, + E_LAUNCH_FILE_TYPE_EDJ +} E_Launch_Img_File_type; + +typedef struct _E_Policy_Wl +{ + Eina_List *globals; /* list of wl_global */ + Eina_Hash *tzpols; /* list of E_Policy_Wl_Tzpol */ + + Eina_List *tz_dpy_pols; /* list of E_Policy_Wl_Tz_Dpy_Pol */ + Eina_List *pending_vis; /* list of clients that have pending visibility change*/ + + /* tizen_ws_shell_interface */ + Eina_List *tzshs; /* list of E_Policy_Wl_Tzsh */ + Eina_List *tzsh_srvs; /* list of E_Policy_Wl_Tzsh_Srv */ + Eina_List *tzsh_clients; /* list of E_Policy_Wl_Tzsh_Client */ + E_Policy_Wl_Tzsh_Srv *srvs[TZSH_SRV_ROLE_MAX]; /* list of registered E_Policy_Wl_Tzsh_Srv */ + Eina_List *tvsrv_bind_list; /* list of activated E_Policy_Wl_Tzsh_Client */ + + /* tizen_launchscreen_interface */ + Eina_List *tzlaunchs; /* list of E_Policy_Wl_Tzlaunch */ +#ifdef HAVE_CYNARA + cynara *p_cynara; +#endif +} E_Policy_Wl; + +typedef struct _E_Tzsh_QP_Event +{ + int type; + int val; +} E_Tzsh_QP_Event; + +static E_Policy_Wl *polwl = NULL; + +static Eina_List *handlers = NULL; +static Eina_List *hooks_cw = NULL; +static struct wl_resource *_scrsaver_mng_res = NULL; // TODO + +enum _E_Policy_Hint_Type +{ + E_POLICY_HINT_USER_GEOMETRY = 0, + E_POLICY_HINT_FIXED_RESIZE = 1, + E_POLICY_HINT_DEICONIFY_APPROVE_DISABLE = 2, + E_POLICY_HINT_ICONIFY = 3, + E_POLICY_HINT_ABOVE_LOCKSCREEN = 4, + E_POLICY_HINT_GESTURE_DISABLE = 5, + E_POLICY_HINT_EFFECT_DISABLE = 6, +}; + +static const char *hint_names[] = +{ + "wm.policy.win.user.geometry", + "wm.policy.win.fixed.resize", + "wm.policy.win.deiconify.approve.disable", + "wm.policy.win.iconify", + "wm.policy.win.above.lock", + "wm.policy.win.gesture.disable", + "wm.policy.win.effect.disable", +}; + +static void _e_policy_wl_surf_del(E_Policy_Wl_Surface *psurf); +static void _e_policy_wl_tzsh_srv_register_handle(E_Policy_Wl_Tzsh_Srv *tzsh_srv); +static void _e_policy_wl_tzsh_srv_unregister_handle(E_Policy_Wl_Tzsh_Srv *tzsh_srv); +static void _e_policy_wl_tzsh_srv_state_broadcast(E_Policy_Wl_Tzsh_Srv *tzsh_srv, Eina_Bool reg); +static void _e_policy_wl_tzsh_srv_tvsrv_bind_update(void); +static Eina_Bool _e_policy_wl_e_client_is_valid(E_Client *ec); +static E_Policy_Wl_Tzsh_Srv *_e_policy_wl_tzsh_srv_add(E_Policy_Wl_Tzsh *tzsh, Tzsh_Srv_Role role, struct wl_resource *res_tzsh_srv, const char *name); +static void _e_policy_wl_tzsh_srv_del(E_Policy_Wl_Tzsh_Srv *tzsh_srv); +static E_Policy_Wl_Tzsh_Client *_e_policy_wl_tzsh_client_add(E_Policy_Wl_Tzsh *tzsh, struct wl_resource *res_tzsh_client); +static void _e_policy_wl_tzsh_client_del(E_Policy_Wl_Tzsh_Client *tzsh_client); +static void _launchscreen_hide(uint32_t pid); +static void _launch_img_off(E_Policy_Wl_Tzlaunch_Img *tzlaunchimg); +static void _e_policy_wl_background_state_set(E_Policy_Wl_Surface *psurf, Eina_Bool state); + +// -------------------------------------------------------- +// E_Policy_Wl_Tzpol +// -------------------------------------------------------- +static E_Policy_Wl_Tzpol * +_e_policy_wl_tzpol_add(struct wl_resource *res_tzpol) +{ + E_Policy_Wl_Tzpol *tzpol; + + tzpol = E_NEW(E_Policy_Wl_Tzpol, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(tzpol, NULL); + + eina_hash_add(polwl->tzpols, &res_tzpol, tzpol); + + tzpol->res_tzpol = res_tzpol; + + return tzpol; +} + +static void +_e_policy_wl_tzpol_del(void *data) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf; + + tzpol = (E_Policy_Wl_Tzpol *)data; + + EINA_LIST_FREE(tzpol->psurfs, psurf) + { + _e_policy_wl_surf_del(psurf); + } + + tzpol->pending_bg = eina_list_free(tzpol->pending_bg); + + memset(tzpol, 0x0, sizeof(E_Policy_Wl_Tzpol)); + E_FREE(tzpol); +} + +static E_Policy_Wl_Tzpol * +_e_policy_wl_tzpol_get(struct wl_resource *res_tzpol) +{ + return (E_Policy_Wl_Tzpol *)eina_hash_find(polwl->tzpols, &res_tzpol); +} + +static E_Policy_Wl_Surface * +_e_policy_wl_tzpol_surf_find(E_Policy_Wl_Tzpol *tzpol, E_Client *ec) +{ + Eina_List *l; + E_Policy_Wl_Surface *psurf; + + EINA_LIST_FOREACH(tzpol->psurfs, l, psurf) + { + if (psurf->ec == ec) + return psurf; + } + + return NULL; +} + +static Eina_List * +_e_policy_wl_tzpol_surf_find_by_pid(E_Policy_Wl_Tzpol *tzpol, pid_t pid) +{ + Eina_List *surfs = NULL, *l; + E_Policy_Wl_Surface *psurf; + + EINA_LIST_FOREACH(tzpol->psurfs, l, psurf) + { + if (psurf->pid == pid) + { + surfs = eina_list_append(surfs, psurf); + } + } + + return surfs; +} + +static Eina_Bool +_e_policy_wl_surf_is_valid(E_Policy_Wl_Surface *psurf) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf2; + Eina_Iterator *it; + Eina_List *l; + + it = eina_hash_iterator_data_new(polwl->tzpols); + EINA_ITERATOR_FOREACH(it, tzpol) + EINA_LIST_FOREACH(tzpol->psurfs, l, psurf2) + { + if (psurf2 == psurf) + { + eina_iterator_free(it); + return EINA_TRUE; + } + } + eina_iterator_free(it); + + return EINA_FALSE; +} + +// -------------------------------------------------------- +// E_Policy_Wl_Tzsh +// -------------------------------------------------------- +static E_Policy_Wl_Tzsh * +_e_policy_wl_tzsh_add(struct wl_resource *res_tzsh) +{ + E_Policy_Wl_Tzsh *tzsh; + + tzsh = E_NEW(E_Policy_Wl_Tzsh, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(tzsh, NULL); + + tzsh->res_tzsh = res_tzsh; + tzsh->type = TZSH_TYPE_UNKNOWN; + + polwl->tzshs = eina_list_append(polwl->tzshs, tzsh); + + return tzsh; +} + +static void +_e_policy_wl_tzsh_del(E_Policy_Wl_Tzsh *tzsh) +{ + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + E_Policy_Wl_Tzsh_Client *tzsh_client; + Eina_List *l, *ll; + + polwl->tzshs = eina_list_remove(polwl->tzshs, tzsh); + + if (tzsh->type == TZSH_TYPE_SRV) + { + EINA_LIST_FOREACH_SAFE(polwl->tzsh_srvs, l, ll, tzsh_srv) + { + if (tzsh_srv->tzsh != tzsh) continue; + _e_policy_wl_tzsh_srv_del(tzsh_srv); + break; + } + } + else + { + EINA_LIST_FOREACH_SAFE(polwl->tzsh_clients, l, ll, tzsh_client) + { + if (tzsh_client->tzsh != tzsh) continue; + _e_policy_wl_tzsh_client_del(tzsh_client); + break; + } + } + + memset(tzsh, 0x0, sizeof(E_Policy_Wl_Tzsh)); + E_FREE(tzsh); +} + +static void +_e_policy_wl_tzsh_data_set(E_Policy_Wl_Tzsh *tzsh, Tzsh_Type type, E_Pixmap *cp, E_Client *ec) +{ + tzsh->type = type; + tzsh->cp = cp; + tzsh->ec = ec; +} + +/* notify current registered services to the client */ +static void +_e_policy_wl_tzsh_registered_srv_send(E_Policy_Wl_Tzsh *tzsh) +{ + int i; + + for (i = 0; i < TZSH_SRV_ROLE_MAX; i++) + { + if (!polwl->srvs[i]) continue; + + tizen_ws_shell_send_service_register + (tzsh->res_tzsh, polwl->srvs[i]->name); + } +} + +static E_Policy_Wl_Tzsh * +_e_policy_wl_tzsh_get_from_client(E_Client *ec) +{ + E_Policy_Wl_Tzsh *tzsh = NULL; + Eina_List *l; + + EINA_LIST_FOREACH(polwl->tzshs, l, tzsh) + { + if (tzsh->cp == ec->pixmap) + { + if ((tzsh->ec) && + (tzsh->ec != ec)) + { + ELOGF("TZSH", + "CRI ERR!!|tzsh_cp:0x%08x|tzsh_ec:0x%08x|tzsh:0x%08x", + ec->pixmap, ec, + (unsigned int)tzsh->cp, + (unsigned int)tzsh->ec, + (unsigned int)tzsh); + } + + return tzsh; + } + } + + return NULL; +} + +static E_Policy_Wl_Tzsh_Client * +_e_policy_wl_tzsh_client_get_from_client(E_Client *ec) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client = NULL; + Eina_List *l; + + if (!ec) return NULL; + if (e_object_is_del(E_OBJECT(ec))) return NULL; + + EINA_LIST_FOREACH(polwl->tzsh_clients, l, tzsh_client) + { + if (!tzsh_client->tzsh) continue; + if (!tzsh_client->tzsh->ec) continue; + + if (tzsh_client->tzsh->cp == ec->pixmap) + { + if (tzsh_client->tzsh->ec != ec) + { + ELOGF("TZSH", + "CRI ERR!!|tzsh_cp:0x%08x|tzsh_ec:0x%08x|tzsh:0x%08x", + ec->pixmap, ec, + (unsigned int)tzsh_client->tzsh->cp, + (unsigned int)tzsh_client->tzsh->ec, + (unsigned int)tzsh_client->tzsh); + } + return tzsh_client; + } + } + + return NULL; +} + +static E_Policy_Wl_Tzsh_Client * +_e_policy_wl_tzsh_client_get_from_tzsh(E_Policy_Wl_Tzsh *tzsh) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + Eina_List *l; + + EINA_LIST_FOREACH(polwl->tvsrv_bind_list, l, tzsh_client) + { + if (tzsh_client->tzsh == tzsh) + return tzsh_client; + } + + return NULL; +} + +static void +_e_policy_wl_tzsh_client_set(E_Client *ec) +{ + E_Policy_Wl_Tzsh *tzsh, *tzsh2; + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + + tzsh = _e_policy_wl_tzsh_get_from_client(ec); + if (!tzsh) return; + + tzsh->ec = ec; + + if (tzsh->type == TZSH_TYPE_SRV) + { + tzsh_srv = polwl->srvs[TZSH_SRV_ROLE_TVSERVICE]; + if (tzsh_srv) + { + tzsh2 = tzsh_srv->tzsh; + if (tzsh2 == tzsh) + _e_policy_wl_tzsh_srv_register_handle(tzsh_srv); + } + } + else + { + if (_e_policy_wl_tzsh_client_get_from_tzsh(tzsh)) + _e_policy_wl_tzsh_srv_tvsrv_bind_update(); + } +} + +static void +_e_policy_wl_tzsh_client_unset(E_Client *ec) +{ + E_Policy_Wl_Tzsh *tzsh, *tzsh2; + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + + tzsh = _e_policy_wl_tzsh_get_from_client(ec); + if (!tzsh) return; + + tzsh->ec = NULL; + + if (tzsh->type == TZSH_TYPE_SRV) + { + tzsh_srv = polwl->srvs[TZSH_SRV_ROLE_TVSERVICE]; + if (tzsh_srv) + { + tzsh2 = tzsh_srv->tzsh; + if (tzsh2 == tzsh) + _e_policy_wl_tzsh_srv_unregister_handle(tzsh_srv); + } + } + else + { + if (_e_policy_wl_tzsh_client_get_from_tzsh(tzsh)) + _e_policy_wl_tzsh_srv_tvsrv_bind_update(); + } +} + +// -------------------------------------------------------- +// E_Policy_Wl_Tzsh_Srv +// -------------------------------------------------------- +static E_Policy_Wl_Tzsh_Srv * +_e_policy_wl_tzsh_srv_add(E_Policy_Wl_Tzsh *tzsh, Tzsh_Srv_Role role, struct wl_resource *res_tzsh_srv, const char *name) +{ + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + + tzsh_srv = E_NEW(E_Policy_Wl_Tzsh_Srv, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(tzsh_srv, NULL); + + tzsh_srv->tzsh = tzsh; + tzsh_srv->res_tzsh_srv = res_tzsh_srv; + tzsh_srv->role = role; + tzsh_srv->name = eina_stringshare_add(name); + + polwl->srvs[role] = tzsh_srv; + polwl->tzsh_srvs = eina_list_append(polwl->tzsh_srvs, tzsh_srv); + + _e_policy_wl_tzsh_srv_register_handle(tzsh_srv); + _e_policy_wl_tzsh_srv_state_broadcast(tzsh_srv, EINA_TRUE); + + return tzsh_srv; +} + +static void +_e_policy_wl_tzsh_srv_del(E_Policy_Wl_Tzsh_Srv *tzsh_srv) +{ + polwl->tzsh_srvs = eina_list_remove(polwl->tzsh_srvs, tzsh_srv); + + if (polwl->srvs[tzsh_srv->role] == tzsh_srv) + polwl->srvs[tzsh_srv->role] = NULL; + + _e_policy_wl_tzsh_srv_state_broadcast(tzsh_srv, EINA_TRUE); + _e_policy_wl_tzsh_srv_unregister_handle(tzsh_srv); + + if (tzsh_srv->name) + eina_stringshare_del(tzsh_srv->name); + + memset(tzsh_srv, 0x0, sizeof(E_Policy_Wl_Tzsh_Srv)); + E_FREE(tzsh_srv); +} + +static int +_e_policy_wl_tzsh_srv_role_get(const char *name) +{ + Tzsh_Srv_Role role = TZSH_SRV_ROLE_UNKNOWN; + + if (!e_util_strcmp(name, "call" )) role = TZSH_SRV_ROLE_CALL; + else if (!e_util_strcmp(name, "volume" )) role = TZSH_SRV_ROLE_VOLUME; + else if (!e_util_strcmp(name, "quickpanel" )) role = TZSH_SRV_ROLE_QUICKPANEL; + else if (!e_util_strcmp(name, "lockscreen" )) role = TZSH_SRV_ROLE_LOCKSCREEN; + else if (!e_util_strcmp(name, "indicator" )) role = TZSH_SRV_ROLE_INDICATOR; + else if (!e_util_strcmp(name, "tvsrv" )) role = TZSH_SRV_ROLE_TVSERVICE; + else if (!e_util_strcmp(name, "screensaver_manager")) role = TZSH_SRV_ROLE_SCREENSAVER_MNG; + else if (!e_util_strcmp(name, "screensaver" )) role = TZSH_SRV_ROLE_SCREENSAVER; + + return role; +} + +static E_Client * +_e_policy_wl_tzsh_srv_parent_client_pick(void) +{ + E_Policy_Wl_Tzsh *tzsh = NULL; + E_Policy_Wl_Tzsh_Client *tzsh_client; + E_Client *ec = NULL, *ec2; + Eina_List *l; + + EINA_LIST_REVERSE_FOREACH(polwl->tvsrv_bind_list, l, tzsh_client) + { + tzsh = tzsh_client->tzsh; + if (!tzsh) continue; + + ec2 = tzsh->ec; + if (!ec2) continue; + if (!_e_policy_wl_e_client_is_valid(ec2)) continue; + + ec = ec2; + break; + } + + return ec; +} + +static void +_e_policy_wl_tzsh_srv_tvsrv_bind_update(void) +{ + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + E_Client *tzsh_client_ec = NULL; + E_Client *tzsh_srv_ec = NULL; + + tzsh_srv = polwl->srvs[TZSH_SRV_ROLE_TVSERVICE]; + if ((tzsh_srv) && (tzsh_srv->tzsh)) + tzsh_srv_ec = tzsh_srv->tzsh->ec; + + tzsh_client_ec = _e_policy_wl_tzsh_srv_parent_client_pick(); + + if ((tzsh_srv_ec) && + (tzsh_srv_ec->parent == tzsh_client_ec)) + return; + + if ((tzsh_client_ec) && (tzsh_srv_ec)) + { + ELOGF("TZSH", + "TR_SET |parent_ec:0x%08x|child_ec:0x%08x", + NULL, NULL, + (unsigned int)e_client_util_win_get(tzsh_client_ec), + (unsigned int)e_client_util_win_get(tzsh_srv_ec)); + + e_policy_stack_transient_for_set(tzsh_srv_ec, tzsh_client_ec); + evas_object_stack_below(tzsh_srv_ec->frame, tzsh_client_ec->frame); + } + else + { + if (tzsh_srv_ec) + { + ELOGF("TZSH", + "TR_UNSET | |child_ec:0x%08x", + NULL, NULL, + (unsigned int)e_client_util_win_get(tzsh_srv_ec)); + + e_policy_stack_transient_for_set(tzsh_srv_ec, NULL); + } + } +} + +static void +_e_policy_wl_tzsh_srv_register_handle(E_Policy_Wl_Tzsh_Srv *tzsh_srv) +{ + E_Policy_Wl_Tzsh *tzsh; + + EINA_SAFETY_ON_NULL_RETURN(tzsh_srv); + + tzsh = tzsh_srv->tzsh; + EINA_SAFETY_ON_NULL_RETURN(tzsh); + + switch (tzsh_srv->role) + { + case TZSH_SRV_ROLE_TVSERVICE: + if (tzsh->ec) tzsh->ec->transient_policy = E_TRANSIENT_BELOW; + _e_policy_wl_tzsh_srv_tvsrv_bind_update(); + break; + + default: + break; + } +} + +static void +_e_policy_wl_tzsh_srv_unregister_handle(E_Policy_Wl_Tzsh_Srv *tzsh_srv) +{ + E_Policy_Wl_Tzsh *tzsh; + + EINA_SAFETY_ON_NULL_RETURN(tzsh_srv); + + tzsh = tzsh_srv->tzsh; + EINA_SAFETY_ON_NULL_RETURN(tzsh); + + switch (tzsh_srv->role) + { + case TZSH_SRV_ROLE_TVSERVICE: + _e_policy_wl_tzsh_srv_tvsrv_bind_update(); + break; + + default: + break; + } +} + +/* broadcast state of registered service to all subscribers */ +static void +_e_policy_wl_tzsh_srv_state_broadcast(E_Policy_Wl_Tzsh_Srv *tzsh_srv, Eina_Bool reg) +{ + E_Policy_Wl_Tzsh *tzsh; + Eina_List *l; + + EINA_LIST_FOREACH(polwl->tzshs, l, tzsh) + { + if (tzsh->type == TZSH_TYPE_SRV) continue; + + if (reg) + tizen_ws_shell_send_service_register + (tzsh->res_tzsh, tzsh_srv->name); + else + tizen_ws_shell_send_service_unregister + (tzsh->res_tzsh, tzsh_srv->name); + } +} + +// -------------------------------------------------------- +// E_Policy_Wl_Tzsh_Client +// -------------------------------------------------------- +static E_Policy_Wl_Tzsh_Client * +_e_policy_wl_tzsh_client_add(E_Policy_Wl_Tzsh *tzsh, struct wl_resource *res_tzsh_client) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + + tzsh_client = E_NEW(E_Policy_Wl_Tzsh_Client, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(tzsh_client, NULL); + + tzsh_client->tzsh = tzsh; + tzsh_client->res_tzsh_client = res_tzsh_client; + + /* TODO: add tzsh_client to list or hash */ + + polwl->tzsh_clients = eina_list_append(polwl->tzsh_clients, tzsh_client); + + return tzsh_client; +} + +static void +_e_policy_wl_tzsh_client_del(E_Policy_Wl_Tzsh_Client *tzsh_client) +{ + if (!tzsh_client) return; + + if (!eina_list_data_find(polwl->tzsh_clients, tzsh_client)) + return; + + polwl->tzsh_clients = eina_list_remove(polwl->tzsh_clients, tzsh_client); + polwl->tvsrv_bind_list = eina_list_remove(polwl->tvsrv_bind_list, tzsh_client); + + if ((tzsh_client->qp_client) && + (tzsh_client->tzsh) && + (tzsh_client->tzsh->ec)) + e_qp_client_del(tzsh_client->tzsh->ec); + + memset(tzsh_client, 0x0, sizeof(E_Policy_Wl_Tzsh_Client)); + E_FREE(tzsh_client); +} + +// -------------------------------------------------------- +// E_Policy_Wl_Surface +// -------------------------------------------------------- +static E_Policy_Wl_Surface * +_e_policy_wl_surf_add(E_Client *ec, struct wl_resource *res_tzpol) +{ + E_Policy_Wl_Surface *psurf = NULL; + + E_Policy_Wl_Tzpol *tzpol; + + tzpol = _e_policy_wl_tzpol_get(res_tzpol); + EINA_SAFETY_ON_NULL_RETURN_VAL(tzpol, NULL); + + psurf = _e_policy_wl_tzpol_surf_find(tzpol, ec); + if (psurf) return psurf; + + psurf = E_NEW(E_Policy_Wl_Surface, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(psurf, NULL); + + psurf->surf = ec->comp_data->surface; + psurf->tzpol = tzpol; + psurf->cp = ec->pixmap; + psurf->ec = ec; + psurf->pid = ec->netwm.pid; + + tzpol->psurfs = eina_list_append(tzpol->psurfs, psurf); + + return psurf; +} + +static void +_e_policy_wl_surf_del(E_Policy_Wl_Surface *psurf) +{ + eina_list_free(psurf->vislist); + eina_list_free(psurf->poslist); + + memset(psurf, 0x0, sizeof(E_Policy_Wl_Surface)); + E_FREE(psurf); +} + +static void +_e_policy_wl_surf_client_set(E_Client *ec) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf; + Eina_Iterator *it; + + it = eina_hash_iterator_data_new(polwl->tzpols); + EINA_ITERATOR_FOREACH(it, tzpol) + { + psurf = _e_policy_wl_tzpol_surf_find(tzpol, ec); + if (psurf) + { + if ((psurf->ec) && (psurf->ec != ec)) + { + ELOGF("POLSURF", + "CRI ERR!!|s:0x%08x|tzpol:0x%08x|ps:0x%08x|new_ec:0x%08x|new_cp:0x%08x", + psurf->cp, + psurf->ec, + (unsigned int)psurf->surf, + (unsigned int)psurf->tzpol, + (unsigned int)psurf, + (unsigned int)ec, + (unsigned int)ec->pixmap); + } + + psurf->ec = ec; + } + } + eina_iterator_free(it); + + return; +} + +static void +_e_policy_wl_pending_bg_client_set(E_Client *ec) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf; + Eina_Iterator *it; + + if (ec->netwm.pid == 0) return; + + it = eina_hash_iterator_data_new(polwl->tzpols); + EINA_ITERATOR_FOREACH(it, tzpol) + { + Eina_List *psurfs; + + if (!tzpol->pending_bg) continue; + + if ((psurfs = _e_policy_wl_tzpol_surf_find_by_pid(tzpol, ec->netwm.pid))) + { + EINA_LIST_FREE(psurfs, psurf) + { + psurf->ec = ec; + + if (eina_list_data_find(tzpol->pending_bg, psurf)) + { + _e_policy_wl_background_state_set(psurf, EINA_TRUE); + tzpol->pending_bg = eina_list_remove(tzpol->pending_bg, psurf); + } + } + } + } + eina_iterator_free(it); +} + +static E_Pixmap * +_e_policy_wl_e_pixmap_get_from_id(struct wl_client *client, uint32_t id) +{ + E_Pixmap *cp; + E_Client *ec; + struct wl_resource *res_surf; + + res_surf = wl_client_get_object(client, id); + if (!res_surf) + { + ERR("Could not get surface resource"); + return NULL; + } + + ec = wl_resource_get_user_data(res_surf); + if (!ec) + { + ERR("Could not get surface's user data"); + return NULL; + } + + /* check E_Pixmap */ + cp = e_pixmap_find(E_PIXMAP_TYPE_WL, (uintptr_t)res_surf); + if (cp != ec->pixmap) + { + ELOGF("POLWL", + "CRI ERR!!|cp2:0x%08x|ec2:0x%08x|res_surf:0x%08x", + ec->pixmap, ec, + (unsigned int)cp, + (unsigned int)e_pixmap_client_get(cp), + (unsigned int)res_surf); + return NULL; + } + + return cp; +} + +static Eina_Bool +_e_policy_wl_e_client_is_valid(E_Client *ec) +{ + E_Client *ec2; + Eina_List *l; + Eina_Bool del = EINA_FALSE; + Eina_Bool found = EINA_FALSE; + + EINA_LIST_FOREACH(e_comp->clients, l, ec2) + { + if (ec2 == ec) + { + if (e_object_is_del(E_OBJECT(ec2))) + del = EINA_TRUE; + found = EINA_TRUE; + break; + } + } + + return ((!del) && (found)); +} + +static Eina_List * +_e_policy_wl_e_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; +} + +// -------------------------------------------------------- +// visibility +// -------------------------------------------------------- +static void +_tzvis_iface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzvis) +{ + wl_resource_destroy(res_tzvis); +} + +static const struct tizen_visibility_interface _tzvis_iface = +{ + _tzvis_iface_cb_destroy +}; + +static void +_tzvis_iface_cb_vis_destroy(struct wl_resource *res_tzvis) +{ + E_Policy_Wl_Surface *psurf; + Eina_Bool r; + + psurf = wl_resource_get_user_data(res_tzvis); + EINA_SAFETY_ON_NULL_RETURN(psurf); + + r = _e_policy_wl_surf_is_valid(psurf); + if (!r) return; + + psurf->vislist = eina_list_remove(psurf->vislist, res_tzvis); +} + +static void +_tzpol_iface_cb_vis_get(struct wl_client *client, struct wl_resource *res_tzpol, uint32_t id, struct wl_resource *surf) +{ + E_Client *ec; + E_Policy_Wl_Surface *psurf; + struct wl_resource *res_tzvis; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + psurf = _e_policy_wl_surf_add(ec, res_tzpol); + EINA_SAFETY_ON_NULL_RETURN(psurf); + + res_tzvis = wl_resource_create(client, + &tizen_visibility_interface, + wl_resource_get_version(res_tzpol), + id); + if (!res_tzvis) + { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(res_tzvis, + &_tzvis_iface, + psurf, + _tzvis_iface_cb_vis_destroy); + + psurf->vislist = eina_list_append(psurf->vislist, res_tzvis); + + if (eina_list_data_find(polwl->pending_vis, ec)) + { + e_policy_wl_visibility_send(ec, ec->visibility.obscured); + } +} + +void +e_policy_wl_visibility_send(E_Client *ec, int vis) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf; + struct wl_resource *res_tzvis; + Eina_List *l, *ll; + Eina_Iterator *it; + E_Client *ec2; + Ecore_Window win; + Eina_Bool sent = EINA_FALSE; + + win = e_client_util_win_get(ec); + + it = eina_hash_iterator_data_new(polwl->tzpols); + EINA_ITERATOR_FOREACH(it, tzpol) + EINA_LIST_FOREACH(tzpol->psurfs, l, psurf) + { + ec2 = e_pixmap_client_get(psurf->cp); + if (ec2 != ec) continue; + + EINA_LIST_FOREACH(psurf->vislist, ll, res_tzvis) + { + tizen_visibility_send_notify(res_tzvis, vis); + ELOGF("TZVIS", + "SEND |win:0x%08x|res_tzvis:0x%08x|v:%d", + ec->pixmap, ec, + (unsigned int)win, + (unsigned int)res_tzvis, + vis); + sent = EINA_TRUE; + _launchscreen_hide(ec->netwm.pid); + } + } + eina_iterator_free(it); + + polwl->pending_vis = eina_list_remove(polwl->pending_vis, ec); + if (!sent) + polwl->pending_vis = eina_list_append(polwl->pending_vis, ec); +} + +void +e_policy_wl_iconify_state_change_send(E_Client *ec, int iconic) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf; + E_Client *ec2; + Eina_List *l; + Eina_Iterator *it; + Ecore_Window win; + + if (ec->exp_iconify.skip_iconify) return; + + if (e_config->transient.iconify) + { + E_Client *child; + Eina_List *list = eina_list_clone(ec->transients); + + EINA_LIST_FREE(list, child) + { + if ((child->iconic == ec->iconic) && + (child->exp_iconify.by_client == ec->exp_iconify.by_client)) + e_policy_wl_iconify_state_change_send(child, iconic); + + } + } + + win = e_client_util_win_get(ec); + + it = eina_hash_iterator_data_new(polwl->tzpols); + EINA_ITERATOR_FOREACH(it, tzpol) + EINA_LIST_FOREACH(tzpol->psurfs, l, psurf) + { + ec2 = e_pixmap_client_get(psurf->cp); + if (ec2 != ec) continue; + + tizen_policy_send_iconify_state_changed(tzpol->res_tzpol, psurf->surf, iconic, 1); + ELOGF("ICONIFY", + "SEND |win:0x%08x|iconic:%d |sur:%p", + ec->pixmap, ec, + (unsigned int)win, + iconic, psurf->surf); + break; + } + eina_iterator_free(it); +} + +// -------------------------------------------------------- +// position +// -------------------------------------------------------- +static void +_tzpos_iface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpos) +{ + wl_resource_destroy(res_tzpos); +} + +static void +_tzpos_iface_cb_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpos, int32_t x, int32_t y) +{ + E_Client *ec; + E_Policy_Wl_Surface *psurf; + + psurf = wl_resource_get_user_data(res_tzpos); + EINA_SAFETY_ON_NULL_RETURN(psurf); + + ec = e_pixmap_client_get(psurf->cp); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + if(!E_INTERSECTS(ec->zone->x, ec->zone->y, + ec->zone->w, ec->zone->h, + x, y, + ec->w, ec->h)) + { + e_policy_wl_position_send(ec); + return; + } + + if (!ec->lock_client_location) + { + ec->x = ec->client.x = x; + ec->y = ec->client.y = y; + ec->placed = 1; + } +} + +static const struct tizen_position_interface _tzpos_iface = +{ + _tzpos_iface_cb_destroy, + _tzpos_iface_cb_set, +}; + +static void +_tzpol_iface_cb_pos_destroy(struct wl_resource *res_tzpos) +{ + E_Policy_Wl_Surface *psurf; + Eina_Bool r; + + psurf = wl_resource_get_user_data(res_tzpos); + EINA_SAFETY_ON_NULL_RETURN(psurf); + + r = _e_policy_wl_surf_is_valid(psurf); + if (!r) return; + + psurf->poslist = eina_list_remove(psurf->poslist, res_tzpos); +} + +static void +_tzpol_iface_cb_pos_get(struct wl_client *client, struct wl_resource *res_tzpol, uint32_t id, struct wl_resource *surf) +{ + E_Client *ec; + E_Policy_Wl_Surface *psurf; + struct wl_resource *res_tzpos; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + psurf = _e_policy_wl_surf_add(ec, res_tzpol); + EINA_SAFETY_ON_NULL_RETURN(psurf); + + res_tzpos = wl_resource_create(client, + &tizen_position_interface, + wl_resource_get_version(res_tzpol), + id); + if (!res_tzpos) + { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(res_tzpos, + &_tzpos_iface, + psurf, + _tzpol_iface_cb_pos_destroy); + + psurf->poslist = eina_list_append(psurf->poslist, res_tzpos); +} + +void +e_policy_wl_position_send(E_Client *ec) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf; + struct wl_resource *res_tzpos; + Eina_List *l, *ll; + Eina_Iterator *it; + Ecore_Window win; + + win = e_client_util_win_get(ec); + + it = eina_hash_iterator_data_new(polwl->tzpols); + EINA_ITERATOR_FOREACH(it, tzpol) + EINA_LIST_FOREACH(tzpol->psurfs, l, psurf) + { + if (e_pixmap_client_get(psurf->cp) != ec) continue; + + EINA_LIST_FOREACH(psurf->poslist, ll, res_tzpos) + { + tizen_position_send_changed(res_tzpos, ec->client.x, ec->client.y); + ELOGF("TZPOS", + "SEND |win:0x%08x|res_tzpos:0x%08x|ec->x:%d, ec->y:%d, ec->client.x:%d, ec->client.y:%d", + ec->pixmap, ec, + (unsigned int)win, + (unsigned int)res_tzpos, + ec->x, ec->y, + ec->client.x, ec->client.y); + } + } + eina_iterator_free(it); +} + +// -------------------------------------------------------- +// stack: activate, raise, lower +// -------------------------------------------------------- +static void +_tzpol_iface_cb_activate(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + ELOGF("TZPOL", "ACTIVATE", ec->pixmap, ec); + + if ((!starting) && (!ec->focused)) + { + if ((ec->iconic) && (!ec->exp_iconify.by_client)) + e_policy_wl_iconify_state_change_send(ec, 0); + e_client_activate(ec, EINA_TRUE); + } + else + evas_object_raise(ec->frame); + + if (e_policy_client_is_lockscreen(ec)) + e_policy_stack_clients_restack_above_lockscreen(ec, EINA_TRUE); + else + e_policy_stack_check_above_lockscreen(ec, ec->layer, NULL, EINA_TRUE); +} + +static void +_tzpol_iface_cb_activate_below_by_res_id(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, uint32_t res_id, uint32_t below_res_id) +{ + E_Client *ec = NULL; + E_Client *below_ec = NULL; + E_Client *parent_ec = NULL; + Eina_Bool check_ancestor = EINA_FALSE; + + ec = e_pixmap_find_client_by_res_id(res_id); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + below_ec = e_pixmap_find_client_by_res_id(below_res_id); + EINA_SAFETY_ON_NULL_RETURN(below_ec); + EINA_SAFETY_ON_NULL_RETURN(below_ec->frame); + + if (ec->layer > below_ec->layer) return; + + parent_ec = ec->parent; + while (parent_ec) + { + if (parent_ec == below_ec) + { + check_ancestor = EINA_TRUE; + break; + } + parent_ec = parent_ec->parent; + } + if (check_ancestor) return; + + if ((!starting) && (!ec->focused)) + { + if ((ec->iconic) && (!ec->exp_iconify.by_client)) + e_policy_wl_iconify_state_change_send(ec, 0); + + e_client_activate(ec, EINA_TRUE); + } + + e_policy_stack_below(ec, below_ec); + + if (!e_client_first_mapped_get(ec)) + e_client_post_raise_lower_set(ec, EINA_FALSE, EINA_FALSE); +} + +static void +_tzpol_iface_cb_raise(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + ELOGF("TZPOL", "RAISE", ec->pixmap, ec); + + evas_object_raise(ec->frame); + + if (!e_client_first_mapped_get(ec)) + e_client_post_raise_lower_set(ec, EINA_TRUE, EINA_FALSE); +} + +static void +_tzpol_iface_cb_lower(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf) +{ + E_Client *ec, *below = NULL; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + ELOGF("TZPOL", "LOWER", ec->pixmap, ec); + + below = ec; + while ((below = e_client_below_get(below))) + { + if ((e_client_util_ignored_get(below)) || + (below->iconic)) + continue; + + break; + } + + evas_object_lower(ec->frame); + + if (!e_client_first_mapped_get(ec)) + e_client_post_raise_lower_set(ec, EINA_FALSE, EINA_TRUE); + + if ((!below) || (!ec->focused)) return; + + evas_object_focus_set(below->frame, 1); +} + +static void +_tzpol_iface_cb_lower_by_res_id(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, uint32_t res_id) +{ + E_Client *ec, *below = NULL; + + ELOGF("TZPOL", + "LOWER_RES|res_tzpol:0x%08x|res_id:%d", + NULL, NULL, (unsigned int)res_tzpol, res_id); + + ec = e_pixmap_find_client_by_res_id(res_id); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + below = ec; + while ((below = e_client_below_get(below))) + { + if ((e_client_util_ignored_get(below)) || + (below->iconic)) + continue; + + break; + } + + evas_object_lower(ec->frame); + + if (!e_client_first_mapped_get(ec)) + e_client_post_raise_lower_set(ec, EINA_FALSE, EINA_TRUE); + + if ((!below) || (!ec->focused)) return; + + if ((below->icccm.accepts_focus) ||(below->icccm.take_focus)) + evas_object_focus_set(below->frame, 1); +} + +// -------------------------------------------------------- +// focus +// -------------------------------------------------------- +static void +_tzpol_iface_cb_focus_skip_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + if (ec->icccm.accepts_focus) + { + ec->icccm.accepts_focus = ec->icccm.take_focus = 0; + EC_CHANGED(ec); + } +} + +static void +_tzpol_iface_cb_focus_skip_unset(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + if (!ec->icccm.accepts_focus) + { + ec->icccm.accepts_focus = ec->icccm.take_focus = 1; + EC_CHANGED(ec); + } +} + +// -------------------------------------------------------- +// role +// -------------------------------------------------------- +static void +_tzpol_iface_cb_role_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf, const char *role) +{ + E_Client *ec; + + EINA_SAFETY_ON_NULL_RETURN(role); + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + eina_stringshare_replace(&ec->icccm.window_role, role); + + /* TODO: support multiple roles */ + if (!e_util_strcmp("notification-low", role)) + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NOTIFICATION_LOW); + } + else if (!e_util_strcmp("notification-normal", role)) + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NOTIFICATION_NORMAL); + } + else if (!e_util_strcmp("notification-high", role)) + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NOTIFICATION_HIGH); + } + else if (!e_util_strcmp("alert", role)) + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_ALERT); + } + else if (!e_util_strcmp("tv-volume-popup", role)) + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NOTIFICATION_LOW); + ec->lock_client_location = 1; + } + else if (!e_util_strcmp("e_demo", role)) + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NOTIFICATION_HIGH); + ec->lock_client_location = 1; + } + else if (!e_util_strcmp("cbhm", role)) + { + if (!ec->comp_data) return; + e_comp_wl->selection.cbhm = ec->comp_data->surface; + } +} + +static void +_tzpol_iface_cb_type_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf, uint32_t type) +{ + E_Client *ec; + E_Window_Type win_type; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + switch (type) + { + /* TODO: support other types */ + case TIZEN_POLICY_WIN_TYPE_NOTIFICATION: + win_type = E_WINDOW_TYPE_NOTIFICATION; + break; + + case TIZEN_POLICY_WIN_TYPE_UTILITY: + win_type = E_WINDOW_TYPE_UTILITY; + break; + + default: return; + } + + ELOGF("TZPOL", + "TYPE_SET |win:0x%08x|s:0x%08x|res_tzpol:0x%08x|tizen_win_type:%d, e_win_type:%d", + ec->pixmap, ec, + (unsigned int)e_client_util_win_get(ec), + (unsigned int)surf, + (unsigned int)res_tzpol, + type, win_type); + + ec->netwm.type = win_type; + + EC_CHANGED(ec); +} +// -------------------------------------------------------- +// conformant +// -------------------------------------------------------- +static void +_tzpol_iface_cb_conformant_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + e_policy_conformant_client_add(ec, res_tzpol); +} + +static void +_tzpol_iface_cb_conformant_unset(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + e_policy_conformant_client_del(ec); +} + +static void +_tzpol_iface_cb_conformant_get(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + tizen_policy_send_conformant(res_tzpol, surf, e_policy_conformant_client_check(ec)); +} + +// -------------------------------------------------------- +// notification level +// -------------------------------------------------------- +#define SMACK_LABEL_LEN 255 +#define PATH_MAX_LEN 64 + +#ifdef HAVE_CYNARA +static void +_e_policy_wl_smack_label_direct_read(int pid, char **client) +{ + int ret; + int fd = -1; + char smack_label[SMACK_LABEL_LEN +1]; + char path[PATH_MAX_LEN + 1]; + + bzero(smack_label, SMACK_LABEL_LEN + 1); + bzero(path, PATH_MAX_LEN + 1); + snprintf(path, PATH_MAX_LEN, "/proc/%d/attr/current", pid); + fd = open(path, O_RDONLY); + if (fd == -1) return; + + ret = read(fd, smack_label, SMACK_LABEL_LEN); + close(fd); + if (ret < 0) return; + + *client = calloc(SMACK_LABEL_LEN + 1, sizeof(char)); + strncpy(*client, smack_label, SMACK_LABEL_LEN + 1); +} +#endif + +static Eina_Bool +_e_policy_wl_privilege_check(int fd, const char *privilege) +{ +#ifdef HAVE_CYNARA + char *client = NULL, *user = NULL, *client_session = NULL; + pid_t pid = 0; + int ret = -1; + Eina_Bool res = EINA_FALSE; + + if ((!polwl->p_cynara)) + { + ELOGF("TZPOL", + "Cynara is not initialized. DENY all requests", NULL, NULL); + return EINA_FALSE; + } + + ret = cynara_creds_socket_get_user(fd, USER_METHOD_DEFAULT, &user); + if (ret != CYNARA_API_SUCCESS) goto cynara_finished; + + ret = cynara_creds_socket_get_pid(fd, &pid); + if (ret != CYNARA_API_SUCCESS) goto cynara_finished; + + client_session = cynara_session_from_pid(pid); + if (!client_session) goto cynara_finished; + + /* Temporary fix for mis matching socket smack label + * ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_DEFAULT, &client); + * if (ret != CYNARA_API_SUCCESS) goto cynara_finished; + */ + _e_policy_wl_smack_label_direct_read(pid, &client); + if (!client) goto cynara_finished; + + ret = cynara_check(polwl->p_cynara, + client, + client_session, + user, + privilege); + + if (ret == CYNARA_API_ACCESS_ALLOWED) + res = EINA_TRUE; + +cynara_finished: + ELOGF("TZPOL", + "Privilege Check For %s %s fd:%d client:%s user:%s pid:%u client_session:%s ret:%d", + NULL, NULL, + privilege, res?"SUCCESS":"FAIL", + fd, client?:"N/A", user?:"N/A", pid, client_session?:"N/A", ret); + + if (client_session) free(client_session); + if (user) free(user); + if (client) free(client); + + return res; +#else + return EINA_TRUE; +#endif +} + +static void +_tzpol_notilv_set(E_Client *ec, int lv) +{ + short ly; + + switch (lv) + { + case 0: ly = E_LAYER_CLIENT_NOTIFICATION_LOW; break; + case 1: ly = E_LAYER_CLIENT_NOTIFICATION_NORMAL; break; + case 2: ly = E_LAYER_CLIENT_NOTIFICATION_TOP; break; + case -1: ly = E_LAYER_CLIENT_NORMAL; break; + case 10: ly = E_LAYER_CLIENT_NOTIFICATION_LOW; break; + case 20: ly = E_LAYER_CLIENT_NOTIFICATION_NORMAL; break; + case 30: ly = E_LAYER_CLIENT_NOTIFICATION_HIGH; break; + case 40: ly = E_LAYER_CLIENT_NOTIFICATION_TOP; break; + default: ly = E_LAYER_CLIENT_NOTIFICATION_LOW; break; + } + + if (ly != evas_object_layer_get(ec->frame)) + { + evas_object_layer_set(ec->frame, ly); + } + + ec->layer = ly; +} + +static void +_tzpol_iface_cb_notilv_set(struct wl_client *client, struct wl_resource *res_tzpol, struct wl_resource *surf, int32_t lv) +{ + E_Client *ec; + E_Policy_Wl_Surface *psurf; + int fd; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + psurf = _e_policy_wl_surf_add(ec, res_tzpol); + EINA_SAFETY_ON_NULL_RETURN(psurf); + + fd = wl_client_get_fd(client); + if (!_e_policy_wl_privilege_check(fd, PRIVILEGE_NOTIFICATION_LEVEL_SET)) + { + ELOGF("TZPOL", + "Privilege Check Failed! DENY set_notification_level", + ec->pixmap, ec); + + tizen_policy_send_notification_done + (res_tzpol, + surf, + -1, + TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED); + return; + } + + ELOGF("TZPOL", "NOTI_LEVEL|level:%d", ec->pixmap, ec, lv); + _tzpol_notilv_set(ec, lv); + + psurf->notilv = lv; + + tizen_policy_send_notification_done + (res_tzpol, surf, lv, TIZEN_POLICY_ERROR_STATE_NONE); + + if (e_policy_client_is_lockscreen(ec)) + e_policy_stack_clients_restack_above_lockscreen(ec, EINA_TRUE); +} + +void +e_policy_wl_notification_level_fetch(E_Client *ec) +{ + E_Pixmap *cp; + E_Policy_Wl_Surface *psurf; + E_Policy_Wl_Tzpol *tzpol; + Eina_Iterator *it; + Eina_List *l; + Eina_Bool changed_stack = EINA_FALSE; + + EINA_SAFETY_ON_NULL_RETURN(ec); + + cp = ec->pixmap; + EINA_SAFETY_ON_NULL_RETURN(cp); + + // TODO: use pending_notilv_list instead of loop + it = eina_hash_iterator_data_new(polwl->tzpols); + EINA_ITERATOR_FOREACH(it, tzpol) + EINA_LIST_FOREACH(tzpol->psurfs, l, psurf) + { + if (psurf->cp != cp) continue; + if (!psurf->pending_notilv) continue; + + psurf->pending_notilv = EINA_FALSE; + _tzpol_notilv_set(ec, psurf->notilv); + changed_stack = EINA_TRUE; + } + eina_iterator_free(it); + + if (changed_stack && + e_policy_client_is_lockscreen(ec)) + { + e_policy_stack_clients_restack_above_lockscreen(ec, EINA_TRUE); + } +} + +// -------------------------------------------------------- +// transient for +// -------------------------------------------------------- +static void +_e_policy_wl_parent_surf_set(E_Client *ec, struct wl_resource *parent_surf) +{ + E_Client *pc = NULL; + + if (parent_surf) + { + if (!(pc = wl_resource_get_user_data(parent_surf))) + { + ERR("Could not get parent res e_client"); + return; + } + } + + e_policy_stack_transient_for_set(ec, pc); +} + +static void +_tzpol_iface_cb_transient_for_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, uint32_t child_id, uint32_t parent_id) +{ + E_Client *ec, *pc; + struct wl_resource *parent_surf; + + ELOGF("TZPOL", + "TF_SET |res_tzpol:0x%08x|parent:%d|child:%d", + NULL, NULL, (unsigned int)res_tzpol, parent_id, child_id); + + ec = e_pixmap_find_client_by_res_id(child_id); + EINA_SAFETY_ON_NULL_RETURN(ec); + + pc = e_pixmap_find_client_by_res_id(parent_id); + EINA_SAFETY_ON_NULL_RETURN(pc); + EINA_SAFETY_ON_NULL_RETURN(pc->comp_data); + + parent_surf = pc->comp_data->surface; + + _e_policy_wl_parent_surf_set(ec, parent_surf); + + ELOGF("TZPOL", + " |win:0x%08x|parent|s:0x%08x", + pc->pixmap, pc, + (unsigned int)e_client_util_win_get(pc), + (unsigned int)parent_surf); + + ELOGF("TZPOL", + " |win:0x%08x|child |s:0x%08x", + ec->pixmap, ec, + (unsigned int)e_client_util_win_get(ec), + (unsigned int)(ec->comp_data ? ec->comp_data->surface : NULL)); + + tizen_policy_send_transient_for_done(res_tzpol, child_id); + + EC_CHANGED(ec); +} + +static void +_tzpol_iface_cb_transient_for_unset(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, uint32_t child_id) +{ + E_Client *ec; + + ELOGF("TZPOL", + "TF_UNSET |res_tzpol:0x%08x|child:%d", + NULL, NULL, (unsigned int)res_tzpol, child_id); + + ec = e_pixmap_find_client_by_res_id(child_id); + EINA_SAFETY_ON_NULL_RETURN(ec); + + _e_policy_wl_parent_surf_set(ec, NULL); + + tizen_policy_send_transient_for_done(res_tzpol, child_id); + + EC_CHANGED(ec); +} + +// -------------------------------------------------------- +// window screen mode +// -------------------------------------------------------- +static void +_tzpol_iface_cb_win_scrmode_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf, uint32_t mode) +{ + E_Client *ec; + int fd; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + fd = wl_client_get_fd(client); + if (!_e_policy_wl_privilege_check(fd, PRIVILEGE_SCREEN_MODE_SET)) + { + ELOGF("TZPOL", + "Privilege Check Failed! DENY set_screen_mode", + ec->pixmap, ec); + + tizen_policy_send_window_screen_mode_done + (res_tzpol, + surf, + -1, + TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED); + return; + } + + ELOGF("TZPOL", "SCR_MODE |mode:%d", ec->pixmap, ec, mode); + + e_policy_display_screen_mode_set(ec, mode); + e_policy_wl_win_scrmode_apply(); + + tizen_policy_send_window_screen_mode_done + (res_tzpol, surf, mode, TIZEN_POLICY_ERROR_STATE_NONE); +} + +void +e_policy_wl_win_scrmode_apply(void) +{ + e_policy_display_screen_mode_apply(); +} + +// -------------------------------------------------------- +// subsurface +// -------------------------------------------------------- +static void +_tzpol_iface_cb_subsurf_place_below_parent(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *subsurf) +{ + E_Client *ec; + E_Client *epc; + E_Comp_Wl_Subsurf_Data *sdata; + + ec = wl_resource_get_user_data(subsurf); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->comp_data); + + sdata = ec->comp_data->sub.data; + EINA_SAFETY_ON_NULL_RETURN(sdata); + + epc = sdata->parent; + EINA_SAFETY_ON_NULL_RETURN(epc); + + /* check if a subsurface has already placed below a parent */ + if (eina_list_data_find(epc->comp_data->sub.below_list, ec)) return; + + epc->comp_data->sub.list = eina_list_remove(epc->comp_data->sub.list, ec); + epc->comp_data->sub.list_pending = eina_list_remove(epc->comp_data->sub.list_pending, ec); + epc->comp_data->sub.below_list = eina_list_append(epc->comp_data->sub.below_list, ec); + epc->comp_data->sub.list_changed = EINA_TRUE; +} + +static void +_tzpol_iface_cb_subsurf_stand_alone_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *subsurf) +{ + E_Client *ec; + E_Comp_Wl_Subsurf_Data *sdata; + + ec = wl_resource_get_user_data(subsurf); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->comp_data); + + sdata = ec->comp_data->sub.data; + EINA_SAFETY_ON_NULL_RETURN(sdata); + + sdata->stand_alone = EINA_TRUE; +} + +static void +_tzpol_iface_cb_subsurface_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface, uint32_t parent_id) +{ + E_Client *ec, *epc; + + ELOGF("TZPOL", + "SUBSURF |wl_surface@%d|parent_id:%d", + NULL, NULL, wl_resource_get_id(surface), parent_id); + + ec = wl_resource_get_user_data(surface); + if (!ec) + { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "tizen_policy failed: wrong wl_surface@%d resource", + wl_resource_get_id(surface)); + return; + } + + if (e_object_is_del(E_OBJECT(ec))) return; + + epc = e_pixmap_find_client_by_res_id(parent_id); + if (!epc) + { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "tizen_policy failed: wrong parent_id(%d)", parent_id); + return; + } + + if (e_object_is_del(E_OBJECT(epc))) return; + + /* check if this surface is already a sub-surface */ + if ((ec->comp_data) && (ec->comp_data->sub.data)) + { + wl_resource_post_error(resource, + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, + "wl_surface@%d is already a sub-surface", + wl_resource_get_id(surface)); + return; + } + + /* try to create a new subsurface */ + if (!e_comp_wl_subsurface_create(ec, epc, id, surface)) + ERR("Failed to create subsurface for surface@%d", + wl_resource_get_id(surface)); + + /* ec's parent comes from another process */ + if (ec->comp_data) + ec->comp_data->has_extern_parent = EINA_TRUE; +} + +static void +_tzpol_iface_cb_opaque_state_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, int32_t state) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surface); + EINA_SAFETY_ON_NULL_RETURN(ec); + + ELOGF("TZPOL", "OPAQUE |opaque_state:%d", ec->pixmap, ec, state); + ec->visibility.opaque = state; +} + +// -------------------------------------------------------- +// iconify +// -------------------------------------------------------- +static void +_tzpol_iface_cb_iconify(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + ELOG("Set ICONIFY BY CLIENT", ec->pixmap, ec); + ec->exp_iconify.by_client = 1; + e_client_iconify(ec); + + EC_CHANGED(ec); +} + +static void +_tzpol_iface_cb_uniconify(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol EINA_UNUSED, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(ec->frame); + + if ((ec->iconic) && (!ec->exp_iconify.by_client)) + e_policy_wl_iconify_state_change_send(ec, 0); + + ELOG("Un-Set ICONIFY BY CLIENT", ec->pixmap, ec); + ec->exp_iconify.by_client = 0; + e_client_uniconify(ec); + + EC_CHANGED(ec); +} + +static void +_e_policy_wl_allowed_aux_hint_send(E_Client *ec, int id) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf; + Eina_List *l; + Eina_Iterator *it; + + it = eina_hash_iterator_data_new(polwl->tzpols); + EINA_ITERATOR_FOREACH(it, tzpol) + EINA_LIST_FOREACH(tzpol->psurfs, l, psurf) + { + if (e_pixmap_client_get(psurf->cp) != ec) continue; + tizen_policy_send_allowed_aux_hint + (tzpol->res_tzpol, + psurf->surf, + id); + ELOGF("TZPOL", + "SEND |res_tzpol:0x%08x|allowed hint->id:%d", + ec->pixmap, ec, + (unsigned int)tzpol->res_tzpol, + id); + } + eina_iterator_free(it); +} + +static void +_e_policy_wl_aux_hint_apply(E_Client *ec) +{ + E_Comp_Wl_Aux_Hint *hint; + Eina_List *l; + Eina_Bool send; + + if (!ec->comp_data) return; + if (!ec->comp_data->aux_hint.changed) return; + + EINA_LIST_FOREACH(ec->comp_data->aux_hint.hints, l, hint) + { + if (!hint->changed) continue; + + send = EINA_FALSE; + if (!strcmp(hint->hint, hint_names[E_POLICY_HINT_USER_GEOMETRY])) + { + if (hint->deleted) + { + e_policy_allow_user_geometry_set(ec, EINA_FALSE); + continue; + } + + if (!strcmp(hint->val, "1")) + { + send = EINA_TRUE; + e_policy_allow_user_geometry_set(ec, EINA_TRUE); + } + else if (strcmp(hint->val, "1")) + { + send = EINA_TRUE; + e_policy_allow_user_geometry_set(ec, EINA_FALSE); + } + } + else if (!strcmp(hint->hint, hint_names[E_POLICY_HINT_FIXED_RESIZE])) + { + /* TODO: support other aux_hints */ + } + else if (!strcmp(hint->hint, hint_names[E_POLICY_HINT_DEICONIFY_APPROVE_DISABLE])) + { + /* TODO: would implement after deiconify approve protocol provided */ + } + else if (!strcmp(hint->hint, hint_names[E_POLICY_HINT_GESTURE_DISABLE])) + { + if (hint->deleted) + { + ec->gesture_disable = EINA_FALSE; + continue; + } + + if (atoi(hint->val) == 1) + { + ec->gesture_disable = EINA_TRUE; + } + else + { + ec->gesture_disable = EINA_FALSE; + } + } + else if (!strcmp(hint->hint, hint_names[E_POLICY_HINT_ICONIFY])) + { + if (hint->deleted) + { + ec->exp_iconify.skip_iconify = 0; + EC_CHANGED(ec); + continue; + } + + if (!strcmp(hint->val, "disable")) + { + ec->exp_iconify.skip_iconify = 1; + EC_CHANGED(ec); + } + else if (!strcmp(hint->val, "enable")) + { + ec->exp_iconify.skip_iconify = 0; + EC_CHANGED(ec); + } + } + else if (!strcmp(hint->hint, hint_names[E_POLICY_HINT_ABOVE_LOCKSCREEN])) + { + if ((hint->deleted) || + (!strcmp(hint->val, "0"))) + { + E_Layer original_layer = ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved_layer; + if (ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].set && + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved) + { + // restore original layer + if (original_layer != evas_object_layer_get(ec->frame)) + { + evas_object_layer_set(ec->frame, original_layer); + ec->layer = original_layer; + } + } + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].set = 0; + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved = 0; + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved_layer = 0; + EC_CHANGED(ec); + } + else if (!strcmp(hint->val, "1")) + { + if (!ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved) + { + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].set = 1; + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved = 0; + ec->changable_layer[E_CHANGABLE_LAYER_TYPE_ABOVE_NOTIFICATION].saved_layer = ec->layer; + EC_CHANGED(ec); + } + } + } + else if (!strcmp(hint->hint, hint_names[E_POLICY_HINT_EFFECT_DISABLE])) + { + if ((hint->deleted) || + (!strcmp(hint->val, "0"))) + { + ec->animatable = 1; + } + else if (!strcmp(hint->val, "1")) + { + ec->animatable = 0; + } + } + + if (send) + _e_policy_wl_allowed_aux_hint_send(ec, hint->id); + } +} + +void +e_policy_wl_eval_pre_post_fetch(E_Client *ec) +{ + if (!ec) return; + + _e_policy_wl_aux_hint_apply(ec); +} + +static void +_tzpol_iface_cb_aux_hint_add(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf, int32_t id, const char *name, const char *value) +{ + E_Client *ec; + Eina_Bool res = EINA_FALSE; + + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + res = e_hints_aux_hint_add(ec, id, name, value); + + ELOGF("TZPOL", "HINT_ADD |res_tzpol:0x%08x|id:%d, name:%s, val:%s, res:%d", ec->pixmap, ec, (unsigned int)res_tzpol, id, name, value, res); + + if (res) + { + _e_policy_wl_aux_hint_apply(ec); + tizen_policy_send_allowed_aux_hint(res_tzpol, surf, id); + EC_CHANGED(ec); + } +} + +static void +_tzpol_iface_cb_aux_hint_change(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf, int32_t id, const char *value) +{ + E_Client *ec; + Eina_Bool res = EINA_FALSE; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + res = e_hints_aux_hint_change(ec, id, value); + + ELOGF("TZPOL", "HINT_CHD |res_tzpol:0x%08x|id:%d, val:%s, result:%d", ec->pixmap, ec, (unsigned int)res_tzpol, id, value, res); + + if (res) + { + _e_policy_wl_aux_hint_apply(ec); + tizen_policy_send_allowed_aux_hint(res_tzpol, surf, id); + EC_CHANGED(ec); + } +} + +static void +_tzpol_iface_cb_aux_hint_del(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf, int32_t id) +{ + E_Client *ec; + unsigned int res = -1; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + res = e_hints_aux_hint_del(ec, id); + ELOGF("TZPOL", "HINT_DEL |res_tzpol:0x%08x|id:%d, result:%d", ec->pixmap, ec, (unsigned int)res_tzpol, id, res); + + if (res) + { + _e_policy_wl_aux_hint_apply(ec); + EC_CHANGED(ec); + } +} + +static void +_tzpol_iface_cb_supported_aux_hints_get(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf) +{ + E_Client *ec; + const Eina_List *hints_list; + const Eina_List *l; + struct wl_array hints; + const char *hint_name; + int len; + char *p; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + hints_list = e_hints_aux_hint_supported_get(); + + wl_array_init(&hints); + EINA_LIST_FOREACH(hints_list, l, hint_name) + { + len = strlen(hint_name) + 1; + p = wl_array_add(&hints, len); + + if (p == NULL) + break; + strncpy(p, hint_name, len); + } + + tizen_policy_send_supported_aux_hints(res_tzpol, surf, &hints, eina_list_count(hints_list)); + ELOGF("TZPOL", + "SEND |res_tzpol:0x%08x|supported_hints size:%d", + ec->pixmap, ec, + (unsigned int)res_tzpol, + eina_list_count(hints_list)); + wl_array_release(&hints); +} + +static void +e_client_background_state_set(E_Client *ec, Eina_Bool state) +{ + if (!ec) return; + + ELOGF("TZPOL", + "BACKGROUND STATE %s for PID(%u)", + ec->pixmap, ec, + state?"SET":"UNSET", ec->netwm.pid); + + if (state) + { + ec->comp_data->mapped = EINA_TRUE; + evas_object_hide(ec->frame); + EC_CHANGED(ec); + } + else + { + ec->comp_data->mapped = EINA_FALSE; + if ((ec->comp_data->shell.surface) && (ec->comp_data->shell.map)) + ec->comp_data->shell.map(ec->comp_data->shell.surface); + evas_object_show(ec->frame); + e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h); + } +} + +static void +_e_policy_wl_background_state_set(E_Policy_Wl_Surface *psurf, Eina_Bool state) +{ + if (state) + { + if (psurf->ec) + e_client_background_state_set(psurf->ec, EINA_TRUE); + else + { + ELOGF("TZPOL", + "PENDING BACKGROUND STATE SET for PID(%u) psurf:%p tzpol:%p", + NULL, NULL, psurf->pid, psurf, psurf->tzpol); + + if (!eina_list_data_find(psurf->tzpol->pending_bg, psurf)) + psurf->tzpol->pending_bg = + eina_list_append(psurf->tzpol->pending_bg, psurf); + } + } + else + { + if (psurf->ec) + e_client_background_state_set(psurf->ec, EINA_FALSE); + else + { + ELOGF("TZPOL", + "UNSET PENDING BACKGROUND STATE for PID(%u) psurf:%p tzpol:%p", + NULL, NULL, psurf->pid, psurf, psurf->tzpol); + + if (eina_list_data_find(psurf->tzpol->pending_bg, psurf)) + psurf->tzpol->pending_bg = + eina_list_remove(psurf->tzpol->pending_bg, psurf); + } + } +} + +static void +_tzpol_iface_cb_background_state_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, uint32_t pid) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf; + Eina_List *psurfs = NULL, *clients = NULL; + E_Client *ec; + + tzpol = _e_policy_wl_tzpol_get(res_tzpol); + EINA_SAFETY_ON_NULL_RETURN(tzpol); + + if ((psurfs = _e_policy_wl_tzpol_surf_find_by_pid(tzpol, pid))) + { + EINA_LIST_FREE(psurfs, psurf) + { + if (psurf->is_background) continue; + + _e_policy_wl_background_state_set(psurf, EINA_TRUE); + } + + return; + } + + clients = _e_policy_wl_e_clients_find_by_pid(pid); + + if (clients) + { + EINA_LIST_FREE(clients, ec) + { + psurf = _e_policy_wl_surf_add(ec, res_tzpol); + + ELOGF("TZPOL", + "Register PID(%u) for BACKGROUND STATE psurf:%p tzpol:%p", + ec->pixmap, ec, pid, psurf, psurf ? psurf->tzpol : NULL); + } + } + else + { + psurf = E_NEW(E_Policy_Wl_Surface, 1); + EINA_SAFETY_ON_NULL_RETURN(psurf); + + psurf->tzpol = tzpol; + psurf->pid = pid; + psurf->ec = NULL; + + tzpol->psurfs = eina_list_append(tzpol->psurfs, psurf); + + ELOGF("TZPOL", + "Register PID(%u) for BACKGROUND STATE psurf:%p tzpol:%p", + NULL, NULL, pid, psurf, psurf->tzpol); + } + + psurf->is_background = EINA_TRUE; + _e_policy_wl_background_state_set(psurf, EINA_TRUE); +} + +static void +_tzpol_iface_cb_background_state_unset(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, uint32_t pid) +{ + E_Policy_Wl_Surface *psurf = NULL; + E_Policy_Wl_Tzpol *tzpol; + Eina_List *psurfs = NULL; + + tzpol = _e_policy_wl_tzpol_get(res_tzpol); + EINA_SAFETY_ON_NULL_RETURN(tzpol); + + if ((psurfs = _e_policy_wl_tzpol_surf_find_by_pid(tzpol, pid))) + { + EINA_LIST_FREE(psurfs, psurf) + { + if (!psurf->is_background) continue; + psurf->is_background = EINA_FALSE; + _e_policy_wl_background_state_set(psurf, EINA_FALSE); + } + return; + } +} + +static void +_e_policy_wl_floating_mode_apply(E_Client *ec, Eina_Bool floating) +{ + if (ec->floating == floating) return; + + ec->floating = floating; + + if (ec->frame) + { + if (floating) + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_ABOVE); + else + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NORMAL); + } + + EC_CHANGED(ec); +} + +static void +_tzpol_iface_cb_floating_mode_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + ELOGF("TZPOL", "FLOATING Set", ec->pixmap, ec); + + _e_policy_wl_floating_mode_apply(ec, EINA_TRUE); +} + +static void +_tzpol_iface_cb_floating_mode_unset(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + ELOGF("TZPOL", "FLOATING Unset", ec->pixmap, ec); + + _e_policy_wl_floating_mode_apply(ec, EINA_FALSE); +} + +static void +_tzpol_iface_cb_stack_mode_set(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzpol, struct wl_resource *surf, uint32_t mode) +{ + E_Client *ec; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + ELOGF("TZPOL", "STACK Mode Set. mode:%d", ec->pixmap, ec, mode); + + if (ec->frame) + { + if (mode == TIZEN_POLICY_STACK_MODE_ABOVE) + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_ABOVE); + } + else if (mode == TIZEN_POLICY_STACK_MODE_BELOW) + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_BELOW); + } + else + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NORMAL); + } + EC_CHANGED(ec); + } +} + +// -------------------------------------------------------- +// E_Policy_Wl_Tz_Dpy_Pol +// -------------------------------------------------------- +static E_Policy_Wl_Tz_Dpy_Pol * +_e_policy_wl_tz_dpy_pol_add(struct wl_resource *res_tz_dpy_pol) +{ + E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol; + + tz_dpy_pol = E_NEW(E_Policy_Wl_Tz_Dpy_Pol, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(tz_dpy_pol, NULL); + + tz_dpy_pol->res_tz_dpy_pol = res_tz_dpy_pol; + + polwl->tz_dpy_pols = eina_list_append(polwl->tz_dpy_pols, tz_dpy_pol); + + return tz_dpy_pol; +} + +static void +_e_policy_wl_tz_dpy_pol_del(E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol) +{ + E_Policy_Wl_Dpy_Surface *dpy_surf; + + EINA_SAFETY_ON_NULL_RETURN(tz_dpy_pol); + + polwl->tz_dpy_pols = eina_list_remove(polwl->tz_dpy_pols, tz_dpy_pol); + + EINA_LIST_FREE(tz_dpy_pol->dpy_surfs, dpy_surf) + { + E_FREE(dpy_surf); + } + + E_FREE(tz_dpy_pol); +} + +static E_Policy_Wl_Tz_Dpy_Pol * +_e_policy_wl_tz_dpy_pol_get(struct wl_resource *res_tz_dpy_pol) +{ + Eina_List *l; + E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol; + + EINA_LIST_FOREACH(polwl->tz_dpy_pols, l, tz_dpy_pol) + { + if (tz_dpy_pol->res_tz_dpy_pol == res_tz_dpy_pol) + return tz_dpy_pol; + } + + return NULL; +} + +// -------------------------------------------------------- +// E_Policy_Wl_Dpy_Surface +// -------------------------------------------------------- +static E_Policy_Wl_Dpy_Surface * +_e_policy_wl_dpy_surf_find(E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol, E_Client *ec) +{ + Eina_List *l; + E_Policy_Wl_Dpy_Surface *dpy_surf; + + EINA_LIST_FOREACH(tz_dpy_pol->dpy_surfs, l, dpy_surf) + { + if (dpy_surf->ec == ec) + return dpy_surf; + } + + return NULL; +} + +static E_Policy_Wl_Dpy_Surface * +_e_policy_wl_dpy_surf_add(E_Client *ec, struct wl_resource *res_tz_dpy_pol) +{ + E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol = NULL; + E_Policy_Wl_Dpy_Surface *dpy_surf = NULL; + + tz_dpy_pol = _e_policy_wl_tz_dpy_pol_get(res_tz_dpy_pol); + EINA_SAFETY_ON_NULL_RETURN_VAL(tz_dpy_pol, NULL); + + dpy_surf = _e_policy_wl_dpy_surf_find(tz_dpy_pol, ec); + if (dpy_surf) + return dpy_surf; + + dpy_surf = E_NEW(E_Policy_Wl_Dpy_Surface, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(dpy_surf, NULL); + + dpy_surf->surf = ec->comp_data->surface; + dpy_surf->tz_dpy_pol = tz_dpy_pol; + dpy_surf->ec = ec; + dpy_surf->brightness = -1; + + tz_dpy_pol->dpy_surfs = eina_list_append(tz_dpy_pol->dpy_surfs, dpy_surf); + return dpy_surf; +} + +static void +_e_policy_wl_dpy_surf_del(E_Client *ec) +{ + Eina_List *l; + E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol; + E_Policy_Wl_Dpy_Surface *dpy_surf; + + EINA_SAFETY_ON_NULL_RETURN(ec); + + EINA_LIST_FOREACH(polwl->tz_dpy_pols, l, tz_dpy_pol) + { + dpy_surf = _e_policy_wl_dpy_surf_find(tz_dpy_pol, ec); + if (dpy_surf) + { + tz_dpy_pol->dpy_surfs = eina_list_remove(tz_dpy_pol->dpy_surfs, dpy_surf); + E_FREE(dpy_surf); + } + } +} + +// -------------------------------------------------------- +// brightness +// -------------------------------------------------------- +static Eina_Bool +_e_policy_system_brightness_get(int *brightness) +{ + int error; + int sys_brightness = -1; + + if (!brightness) return EINA_FALSE; + + error = device_display_get_brightness(0, &sys_brightness); + if (error != DEVICE_ERROR_NONE) + { + // error + return EINA_FALSE; + } + + *brightness = sys_brightness; + + return EINA_TRUE; +} + +static Eina_Bool +_e_policy_system_brightness_set(int brightness) +{ + Eina_Bool ret; + int error; + int num_of_dpy; + int id; + + ret = EINA_TRUE; + + error = device_display_get_numbers(&num_of_dpy); + if (error != DEVICE_ERROR_NONE) + { + // error + return EINA_FALSE; + } + + for (id = 0; id < num_of_dpy; id++) + { + error = device_display_set_brightness(id, brightness); + if (error != DEVICE_ERROR_NONE) + { + // error + ret = EINA_FALSE; + break; + } + } + + return ret; +} + +static Eina_Bool +_e_policy_change_system_brightness(int new_brightness) +{ + Eina_Bool ret; + int sys_brightness; + + if (!e_policy_system_info.brightness.use_client) + { + // save system brightness + ret = _e_policy_system_brightness_get(&sys_brightness); + if (!ret) + { + return EINA_FALSE; + } + e_policy_system_info.brightness.system = sys_brightness; + } + + ret = _e_policy_system_brightness_set(new_brightness); + if (!ret) + { + return EINA_FALSE; + } + e_policy_system_info.brightness.client = new_brightness; + e_policy_system_info.brightness.use_client = EINA_TRUE; + + return EINA_TRUE; +} + +static Eina_Bool +_e_policy_restore_system_brightness(void) +{ + Eina_Bool ret; + + if (!e_policy_system_info.brightness.use_client) return EINA_TRUE; + + // restore system brightness + ret = _e_policy_system_brightness_set(e_policy_system_info.brightness.system); + if (!ret) + { + return EINA_FALSE; + } + e_policy_system_info.brightness.use_client = EINA_FALSE; + + // Todo: + // if there are another window which set brighteness, then we change brighteness of it + // if no, then we rollback system brightness + + return EINA_TRUE; +} + +Eina_Bool +e_policy_wl_win_brightness_apply(E_Client *ec) +{ + Eina_Bool ret; + Eina_List *l; + E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol; + E_Policy_Wl_Dpy_Surface *dpy_surf = NULL; + int ec_visibility; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); + if (e_object_is_del(E_OBJECT(ec))) + ec_visibility = E_VISIBILITY_FULLY_OBSCURED; + else + ec_visibility = ec->visibility.obscured; + + EINA_LIST_FOREACH(polwl->tz_dpy_pols, l, tz_dpy_pol) + { + dpy_surf = _e_policy_wl_dpy_surf_find(tz_dpy_pol, ec); + if (dpy_surf) + break; + } + + if (!dpy_surf) return EINA_FALSE; + if (!dpy_surf->set) return EINA_FALSE; + + // use system brightness + if (dpy_surf->brightness < 0) + { + ELOGF("TZ_DPY_POL", "Restore system brightness. Win(0x%08x)'s brightness:%d", ec->pixmap, ec, e_client_util_win_get(ec), dpy_surf->brightness); + ret = _e_policy_restore_system_brightness(); + return ret; + } + + if (ec_visibility == E_VISIBILITY_UNOBSCURED) + { + ELOGF("TZ_DPY_POL", "Change system brightness(%d). Win(0x%08x) is un-obscured", ec->pixmap, ec, dpy_surf->brightness, e_client_util_win_get(ec)); + ret = _e_policy_change_system_brightness(dpy_surf->brightness); + if (!ret) return EINA_FALSE; + } + else + { + ELOGF("TZ_DPY_POL", "Restore system brightness. Win(0x%08x) is obscured", ec->pixmap, ec, e_client_util_win_get(ec)); + ret = _e_policy_restore_system_brightness(); + if (!ret) return EINA_FALSE; + } + + return EINA_TRUE; +} + +static void +_tz_dpy_pol_iface_cb_brightness_set(struct wl_client *client, struct wl_resource *res_tz_dpy_pol, struct wl_resource *surf, int32_t brightness) +{ + E_Client *ec; + E_Policy_Wl_Dpy_Surface *dpy_surf; + int fd; + + ec = wl_resource_get_user_data(surf); + EINA_SAFETY_ON_NULL_RETURN(ec); + + dpy_surf = _e_policy_wl_dpy_surf_add(ec, res_tz_dpy_pol); + EINA_SAFETY_ON_NULL_RETURN(dpy_surf); + + fd = wl_client_get_fd(client); + if (!_e_policy_wl_privilege_check(fd, PRIVILEGE_BRIGHTNESS_SET)) + { + ELOGF("TZ_DPY_POL", + "Privilege Check Failed! DENY set_brightness", + ec->pixmap, ec); + + tizen_display_policy_send_window_brightness_done + (res_tz_dpy_pol, + surf, + -1, + TIZEN_DISPLAY_POLICY_ERROR_STATE_PERMISSION_DENIED); + return; + } + ELOGF("TZ_DPY_POL", "Set Win(0x%08x)'s brightness:%d", ec->pixmap, ec, e_client_util_win_get(ec), brightness); + dpy_surf->set = EINA_TRUE; + dpy_surf->brightness = brightness; + + e_policy_wl_win_brightness_apply(ec); + + tizen_display_policy_send_window_brightness_done + (res_tz_dpy_pol, surf, brightness, TIZEN_DISPLAY_POLICY_ERROR_STATE_NONE); +} + +// -------------------------------------------------------- +// tizen_policy_interface +// -------------------------------------------------------- +static const struct tizen_policy_interface _tzpol_iface = +{ + _tzpol_iface_cb_vis_get, + _tzpol_iface_cb_pos_get, + _tzpol_iface_cb_activate, + _tzpol_iface_cb_activate_below_by_res_id, + _tzpol_iface_cb_raise, + _tzpol_iface_cb_lower, + _tzpol_iface_cb_lower_by_res_id, + _tzpol_iface_cb_focus_skip_set, + _tzpol_iface_cb_focus_skip_unset, + _tzpol_iface_cb_role_set, + _tzpol_iface_cb_type_set, + _tzpol_iface_cb_conformant_set, + _tzpol_iface_cb_conformant_unset, + _tzpol_iface_cb_conformant_get, + _tzpol_iface_cb_notilv_set, + _tzpol_iface_cb_transient_for_set, + _tzpol_iface_cb_transient_for_unset, + _tzpol_iface_cb_win_scrmode_set, + _tzpol_iface_cb_subsurf_place_below_parent, + _tzpol_iface_cb_subsurf_stand_alone_set, + _tzpol_iface_cb_subsurface_get, + _tzpol_iface_cb_opaque_state_set, + _tzpol_iface_cb_iconify, + _tzpol_iface_cb_uniconify, + _tzpol_iface_cb_aux_hint_add, + _tzpol_iface_cb_aux_hint_change, + _tzpol_iface_cb_aux_hint_del, + _tzpol_iface_cb_supported_aux_hints_get, + _tzpol_iface_cb_background_state_set, + _tzpol_iface_cb_background_state_unset, + _tzpol_iface_cb_floating_mode_set, + _tzpol_iface_cb_floating_mode_unset, + _tzpol_iface_cb_stack_mode_set, +}; + +static void +_tzpol_cb_unbind(struct wl_resource *res_tzpol) +{ + E_Policy_Wl_Tzpol *tzpol; + + tzpol = _e_policy_wl_tzpol_get(res_tzpol); + EINA_SAFETY_ON_NULL_RETURN(tzpol); + + eina_hash_del_by_key(polwl->tzpols, &res_tzpol); +} + +static void +_tzpol_cb_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t ver, uint32_t id) +{ + E_Policy_Wl_Tzpol *tzpol; + struct wl_resource *res_tzpol; + + EINA_SAFETY_ON_NULL_GOTO(polwl, err); + + res_tzpol = wl_resource_create(client, + &tizen_policy_interface, + ver, + id); + EINA_SAFETY_ON_NULL_GOTO(res_tzpol, err); + + tzpol = _e_policy_wl_tzpol_add(res_tzpol); + EINA_SAFETY_ON_NULL_GOTO(tzpol, err); + + wl_resource_set_implementation(res_tzpol, + &_tzpol_iface, + NULL, + _tzpol_cb_unbind); + return; + +err: + ERR("Could not create tizen_policy_interface res: %m"); + wl_client_post_no_memory(client); +} + +// -------------------------------------------------------- +// tizen_display_policy_interface +// -------------------------------------------------------- +static const struct tizen_display_policy_interface _tz_dpy_pol_iface = +{ + _tz_dpy_pol_iface_cb_brightness_set, +}; + +static void +_tz_dpy_pol_cb_unbind(struct wl_resource *res_tz_dpy_pol) +{ + E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol; + + tz_dpy_pol = _e_policy_wl_tz_dpy_pol_get(res_tz_dpy_pol); + EINA_SAFETY_ON_NULL_RETURN(tz_dpy_pol); + + _e_policy_wl_tz_dpy_pol_del(tz_dpy_pol); +} + +static void +_tz_dpy_pol_cb_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t ver, uint32_t id) +{ + E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol; + struct wl_resource *res_tz_dpy_pol; + + EINA_SAFETY_ON_NULL_GOTO(polwl, err); + + res_tz_dpy_pol = wl_resource_create(client, + &tizen_display_policy_interface, + ver, + id); + EINA_SAFETY_ON_NULL_GOTO(res_tz_dpy_pol, err); + + tz_dpy_pol = _e_policy_wl_tz_dpy_pol_add(res_tz_dpy_pol); + EINA_SAFETY_ON_NULL_GOTO(tz_dpy_pol, err); + + wl_resource_set_implementation(res_tz_dpy_pol, + &_tz_dpy_pol_iface, + NULL, + _tz_dpy_pol_cb_unbind); + return; + +err: + ERR("Could not create tizen_display_policy_interface res: %m"); + wl_client_post_no_memory(client); +} + +// -------------------------------------------------------- +// tizen_ws_shell_interface::service +// -------------------------------------------------------- +static void +_tzsh_srv_iface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_srv) +{ + wl_resource_destroy(res_tzsh_srv); +} + +static void +_tzsh_srv_iface_cb_region_set(struct wl_client *client, struct wl_resource *res_tzsh_srv, int32_t type, int32_t angle, struct wl_resource *res_reg) +{ + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + E_Policy_Wl_Tzsh_Region *tzsh_reg; + + tzsh_srv = wl_resource_get_user_data(res_tzsh_srv); + EINA_SAFETY_ON_NULL_RETURN(tzsh_srv); + + if (!eina_list_data_find(polwl->tzsh_srvs, tzsh_srv)) + return; + + tzsh_reg = wl_resource_get_user_data(res_reg); + EINA_SAFETY_ON_NULL_RETURN(tzsh_reg); + + if (tzsh_srv->role == TZSH_SRV_ROLE_QUICKPANEL) + e_service_quickpanel_region_set(type, angle, tzsh_reg->tiler); + else if (tzsh_srv->role == TZSH_SRV_ROLE_VOLUME) + e_service_volume_region_set(type, angle, tzsh_reg->tiler); +} + +static void +_tzsh_srv_iface_cb_indicator_get(struct wl_client *client, struct wl_resource *res_tzsh_srv, uint32_t id) +{ + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + + tzsh_srv = wl_resource_get_user_data(res_tzsh_srv); + + if (!eina_list_data_find(polwl->tzsh_srvs, tzsh_srv)) + return; + + /* TODO: create tws_indicator_service resource. */ +} + +static void +_tzsh_srv_qp_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +_tzsh_srv_qp_cb_msg(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t msg) +{ + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + + tzsh_srv = wl_resource_get_user_data(resource); + + EINA_SAFETY_ON_NULL_RETURN(tzsh_srv); + EINA_SAFETY_ON_NULL_RETURN(tzsh_srv->tzsh); + +#define EC tzsh_srv->tzsh->ec + EINA_SAFETY_ON_NULL_RETURN(EC); + + switch (msg) + { + case TWS_SERVICE_QUICKPANEL_MSG_SHOW: + e_service_quickpanel_show(); + break; + case TWS_SERVICE_QUICKPANEL_MSG_HIDE: + e_service_quickpanel_hide(); + break; + default: + ERR("Unknown message!! msg %d", msg); + break; + } +#undef EC +} + +static const struct tws_service_quickpanel_interface _tzsh_srv_qp_iface = +{ + _tzsh_srv_qp_cb_destroy, + _tzsh_srv_qp_cb_msg +}; + +static void +_tzsh_srv_iface_cb_quickpanel_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); + + if (!eina_list_data_find(polwl->tzsh_srvs, tzsh_srv)) + return; + + res = wl_resource_create(client, &tws_service_quickpanel_interface, 1, id); + if (!res) + { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(res, &_tzsh_srv_qp_iface, tzsh_srv, NULL); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// +static void +_tzsh_srv_scrsaver_cb_release(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct tws_service_screensaver_interface _tzsh_srv_scrsaver_iface = +{ + _tzsh_srv_scrsaver_cb_release +}; + +static void +_tzsh_srv_iface_cb_scrsaver_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); + + if (!eina_list_data_find(polwl->tzsh_srvs, tzsh_srv)) + return; + + res = wl_resource_create(client, &tws_service_screensaver_interface, 1, id); + if (!res) + { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(res, &_tzsh_srv_scrsaver_iface, tzsh_srv, NULL); +} + +static void +_tzsh_srv_scrsaver_mng_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + _scrsaver_mng_res = NULL; + wl_resource_destroy(resource); +} + +static void +_tzsh_srv_scrsaver_mng_cb_idle_time_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t time) +{ + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + double timeout; + + tzsh_srv = wl_resource_get_user_data(resource); + + EINA_SAFETY_ON_NULL_RETURN(tzsh_srv); + EINA_SAFETY_ON_NULL_RETURN(tzsh_srv->tzsh); + + /* convert time to seconds (double) from milliseconds (unsigned int) */ + timeout = (double)time * 0.001f; + + e_screensaver_timeout_set(timeout); +} + +static const struct tws_service_screensaver_manager_interface _tzsh_srv_scrsaver_mng_iface = +{ + _tzsh_srv_scrsaver_mng_cb_destroy, + _tzsh_srv_scrsaver_mng_cb_idle_time_set +}; + +static void +_tzsh_srv_iface_cb_scrsaver_mng_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); + + if (!eina_list_data_find(polwl->tzsh_srvs, tzsh_srv)) + return; + + res = wl_resource_create(client, &tws_service_screensaver_manager_interface, 1, id); + if (!res) + { + wl_client_post_no_memory(client); + return; + } + + _scrsaver_mng_res = res; + + wl_resource_set_implementation(res, &_tzsh_srv_scrsaver_mng_iface, tzsh_srv, NULL); +} + +static const struct tws_service_interface _tzsh_srv_iface = +{ + _tzsh_srv_iface_cb_destroy, + _tzsh_srv_iface_cb_region_set, + _tzsh_srv_iface_cb_indicator_get, + _tzsh_srv_iface_cb_quickpanel_get, + _tzsh_srv_iface_cb_scrsaver_mng_get, + _tzsh_srv_iface_cb_scrsaver_get +}; + +static void +_tzsh_cb_srv_destroy(struct wl_resource *res_tzsh_srv) +{ + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + + tzsh_srv = wl_resource_get_user_data(res_tzsh_srv); + EINA_SAFETY_ON_NULL_RETURN(tzsh_srv); + + if (!eina_list_data_find(polwl->tzsh_srvs, tzsh_srv)) + return; + + _e_policy_wl_tzsh_srv_del(tzsh_srv); +} + +static void +_tzsh_iface_cb_srv_create(struct wl_client *client, struct wl_resource *res_tzsh, uint32_t id, uint32_t surf_id, const char *name) +{ + E_Policy_Wl_Tzsh *tzsh; + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + struct wl_resource *res_tzsh_srv; + E_Client *ec; + E_Pixmap *cp; + int role; + + role = _e_policy_wl_tzsh_srv_role_get(name); + if (role == TZSH_SRV_ROLE_UNKNOWN) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid res_tzsh"); + return; + } + + tzsh = wl_resource_get_user_data(res_tzsh); + if (!tzsh) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid res_tzsh's user data"); + return; + } + + cp = _e_policy_wl_e_pixmap_get_from_id(client, surf_id); + if (!cp) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid surface id"); + return; + } + + ec = e_pixmap_client_get(cp); + if (ec) + { + if (!_e_policy_wl_e_client_is_valid(ec)) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid surface id"); + return; + } + } + + res_tzsh_srv = wl_resource_create(client, + &tws_service_interface, + wl_resource_get_version(res_tzsh), + id); + if (!res_tzsh_srv) + { + ERR("Could not create tws_service resource: %m"); + wl_client_post_no_memory(client); + return; + } + + _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); + if (!tzsh_srv) + { + ERR("Could not create WS_Shell_Service"); + wl_client_post_no_memory(client); + wl_resource_destroy(res_tzsh_srv); + return; + } + + wl_resource_set_implementation(res_tzsh_srv, + &_tzsh_srv_iface, + tzsh_srv, + _tzsh_cb_srv_destroy); + + if (role == TZSH_SRV_ROLE_QUICKPANEL) + e_service_quickpanel_client_set(tzsh->ec); + else if (role == TZSH_SRV_ROLE_VOLUME) + e_service_volume_client_set(tzsh->ec); + else if (role == TZSH_SRV_ROLE_LOCKSCREEN) + e_service_lockscreen_client_set(tzsh->ec); + else if (role == TZSH_SRV_ROLE_SCREENSAVER_MNG) + e_service_lockscreen_client_set(tzsh->ec); + else if (role == TZSH_SRV_ROLE_SCREENSAVER) + e_service_lockscreen_client_set(tzsh->ec); +} + +// -------------------------------------------------------- +// tizen_ws_shell_interface::region +// -------------------------------------------------------- +static void +_tzsh_reg_cb_shell_destroy(struct wl_listener *listener, void *data) +{ + E_Policy_Wl_Tzsh_Region *tzsh_reg; + + tzsh_reg = container_of(listener, E_Policy_Wl_Tzsh_Region, destroy_listener); + + if (tzsh_reg->res_tzsh_reg) + { + wl_resource_destroy(tzsh_reg->res_tzsh_reg); + tzsh_reg->res_tzsh_reg = NULL; + } +} + +static void +_tzsh_reg_iface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_reg) +{ + wl_resource_destroy(res_tzsh_reg); +} + +static void +_tzsh_reg_iface_cb_add(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_reg, int32_t x, int32_t y, int32_t w, int32_t h) +{ + E_Policy_Wl_Tzsh_Region *tzsh_reg; + Eina_Tiler *src; + int area_w = 0, area_h = 0; + + tzsh_reg = wl_resource_get_user_data(res_tzsh_reg); + EINA_SAFETY_ON_NULL_RETURN(tzsh_reg); + EINA_SAFETY_ON_NULL_RETURN(tzsh_reg->tiler); + + eina_tiler_area_size_get(tzsh_reg->tiler, &area_w, &area_h); + src = eina_tiler_new(area_w, area_h); + eina_tiler_tile_size_set(src, 1, 1); + eina_tiler_rect_add(src, &(Eina_Rectangle){x, y, w, h}); + eina_tiler_union(tzsh_reg->tiler, src); + eina_tiler_free(src); +} + +static void +_tzsh_reg_iface_cb_subtract(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_reg, int32_t x, int32_t y, int32_t w, int32_t h) +{ + E_Policy_Wl_Tzsh_Region *tzsh_reg; + Eina_Tiler *src; + int area_w = 0, area_h = 0; + + tzsh_reg = wl_resource_get_user_data(res_tzsh_reg); + EINA_SAFETY_ON_NULL_RETURN(tzsh_reg); + EINA_SAFETY_ON_NULL_RETURN(tzsh_reg->tiler); + + eina_tiler_area_size_get(tzsh_reg->tiler, &area_w, &area_h); + src = eina_tiler_new(area_w, area_h); + eina_tiler_tile_size_set(src, 1, 1); + eina_tiler_rect_add(src, &(Eina_Rectangle){x, y, w, h}); + eina_tiler_subtract(tzsh_reg->tiler, src); + eina_tiler_free(src); +} + +static const struct tws_region_interface _tzsh_reg_iface = +{ + _tzsh_reg_iface_cb_destroy, + _tzsh_reg_iface_cb_add, + _tzsh_reg_iface_cb_subtract +}; + +static void +_tzsh_reg_cb_destroy(struct wl_resource *res_tzsh_reg) +{ + E_Policy_Wl_Tzsh_Region *tzsh_reg; + + tzsh_reg = wl_resource_get_user_data(res_tzsh_reg); + EINA_SAFETY_ON_NULL_RETURN(tzsh_reg); + + wl_list_remove(&tzsh_reg->destroy_listener.link); + eina_tiler_free(tzsh_reg->tiler); + + E_FREE(tzsh_reg); +} + +static void +_tzsh_iface_cb_reg_create(struct wl_client *client, struct wl_resource *res_tzsh, uint32_t id) +{ + E_Policy_Wl_Tzsh *tzsh; + E_Policy_Wl_Tzsh_Region *tzsh_reg = NULL; + Eina_Tiler *tz = NULL; + struct wl_resource *res_tzsh_reg; + int zw = 0, zh = 0; + + tzsh = wl_resource_get_user_data(res_tzsh); + if (!tzsh) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid res_tzsh's user data"); + return; + } + + tzsh_reg = E_NEW(E_Policy_Wl_Tzsh_Region, 1); + EINA_SAFETY_ON_NULL_RETURN(tzsh_reg); + + e_zone_useful_geometry_get(e_zone_current_get(), + NULL, NULL, &zw, &zh); + + tz = eina_tiler_new(zw, zh); + EINA_SAFETY_ON_NULL_GOTO(tz, err); + tzsh_reg->tiler = tz; + + eina_tiler_tile_size_set(tzsh_reg->tiler, 1, 1); + + if (!(res_tzsh_reg = wl_resource_create(client, + &tws_region_interface, + wl_resource_get_version(res_tzsh), + id))) + { + ERR("Could not create tws_service resource: %m"); + wl_client_post_no_memory(client); + goto err; + } + + wl_resource_set_implementation(res_tzsh_reg, + &_tzsh_reg_iface, + tzsh_reg, + _tzsh_reg_cb_destroy); + + tzsh_reg->tzsh = tzsh; + tzsh_reg->res_tzsh_reg = res_tzsh_reg; + tzsh_reg->destroy_listener.notify = _tzsh_reg_cb_shell_destroy; + + wl_resource_add_destroy_listener(res_tzsh, + &tzsh_reg->destroy_listener); + return; + +err: + if (tzsh_reg->tiler) eina_tiler_free(tzsh_reg->tiler); + E_FREE(tzsh_reg); +} + +// -------------------------------------------------------- +// tizen_ws_shell_interface::quickpanel +// -------------------------------------------------------- +EINTERN void +e_tzsh_qp_state_visible_update(E_Client *ec, Eina_Bool vis) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + struct wl_array states; + E_Tzsh_QP_Event *ev; + + tzsh_client = _e_policy_wl_tzsh_client_get_from_client(ec); + if (!tzsh_client) return; + + wl_array_init(&states); + + ev = wl_array_add(&states, sizeof(E_Tzsh_QP_Event)); + + ev->type = TWS_QUICKPANEL_STATE_TYPE_VISIBILITY; + ev->val = vis ? TWS_QUICKPANEL_STATE_VALUE_VISIBLE_SHOW : TWS_QUICKPANEL_STATE_VALUE_VISIBLE_HIDE; + + tws_quickpanel_send_state_changed(tzsh_client->res_tzsh_client, &states); + + wl_array_release(&states); +} + +EINTERN void +e_tzsh_qp_state_scrollable_update(E_Client *ec, Eina_Bool scrollable) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + struct wl_array states; + E_Tzsh_QP_Event *ev; + + tzsh_client = _e_policy_wl_tzsh_client_get_from_client(ec); + if (!tzsh_client) return; + + wl_array_init(&states); + + ev = wl_array_add(&states, sizeof(E_Tzsh_QP_Event)); + + ev->type = TWS_QUICKPANEL_STATE_TYPE_SCROLLABLE; + ev->val = scrollable ? TWS_QUICKPANEL_STATE_VALUE_SCROLLABLE_SET : TWS_QUICKPANEL_STATE_VALUE_SCROLLABLE_UNSET; + + tws_quickpanel_send_state_changed(tzsh_client->res_tzsh_client, &states); + + wl_array_release(&states); +} + +EINTERN void +e_tzsh_qp_state_orientation_update(E_Client *ec, int ridx) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + struct wl_array states; + E_Tzsh_QP_Event *ev; + + tzsh_client = _e_policy_wl_tzsh_client_get_from_client(ec); + if (!tzsh_client) return; + + wl_array_init(&states); + + ev = wl_array_add(&states, sizeof(E_Tzsh_QP_Event)); + + ev->type = TWS_QUICKPANEL_STATE_TYPE_ORIENTATION; + ev->val = TWS_QUICKPANEL_STATE_VALUE_ORIENTATION_0 + ridx; + + tws_quickpanel_send_state_changed(tzsh_client->res_tzsh_client, &states); + + wl_array_release(&states); +} + +static void +_tzsh_qp_iface_cb_release(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_qp) +{ + wl_resource_destroy(res_tzsh_qp); +} + +static void +_tzsh_qp_iface_cb_show(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_qp) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + E_Client *ec; + + tzsh_client = wl_resource_get_user_data(res_tzsh_qp); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh->ec); + + ec = tzsh_client->tzsh->ec; + + if (!eina_list_data_find(polwl->tzsh_clients, tzsh_client)) + return; + + e_qp_client_show(ec); +} + +static void +_tzsh_qp_iface_cb_hide(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_qp) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + E_Client *ec; + + tzsh_client = wl_resource_get_user_data(res_tzsh_qp); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh->ec); + + ec = tzsh_client->tzsh->ec; + + if (!eina_list_data_find(polwl->tzsh_clients, tzsh_client)) + return; + + e_qp_client_hide(ec); +} + +static void +_tzsh_qp_iface_cb_enable(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_qp) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + E_Client *ec; + + tzsh_client = wl_resource_get_user_data(res_tzsh_qp); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh->ec); + + ec = tzsh_client->tzsh->ec; + + if (!eina_list_data_find(polwl->tzsh_clients, tzsh_client)) + return; + + e_qp_client_scrollable_set(ec, EINA_TRUE); +} + +static void +_tzsh_qp_iface_cb_disable(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_qp) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + E_Client *ec; + + tzsh_client = wl_resource_get_user_data(res_tzsh_qp); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh->ec); + + ec = tzsh_client->tzsh->ec; + + if (!eina_list_data_find(polwl->tzsh_clients, tzsh_client)) + return; + + e_qp_client_scrollable_set(ec, EINA_FALSE); +} + +static void +_tzsh_qp_iface_cb_state_get(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_qp, int32_t type) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + E_Client *ec; + Eina_Bool vis, scrollable; + int ridx; + int val = TWS_QUICKPANEL_STATE_VALUE_UNKNOWN; + + tzsh_client = wl_resource_get_user_data(res_tzsh_qp); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client->tzsh->ec); + + ec = tzsh_client->tzsh->ec; + + if (!eina_list_data_find(polwl->tzsh_clients, tzsh_client)) + return; + + switch (type) + { + case TWS_QUICKPANEL_STATE_TYPE_VISIBILITY: + val = TWS_QUICKPANEL_STATE_VALUE_VISIBLE_HIDE; + vis = e_qp_visible_get(); + if (vis) val = TWS_QUICKPANEL_STATE_VALUE_VISIBLE_SHOW; + break; + case TWS_QUICKPANEL_STATE_TYPE_SCROLLABLE: + val = TWS_QUICKPANEL_STATE_VALUE_SCROLLABLE_UNSET; + scrollable = e_qp_client_scrollable_get(ec); + if (scrollable) val = TWS_QUICKPANEL_STATE_VALUE_SCROLLABLE_SET; + break; + case TWS_QUICKPANEL_STATE_TYPE_ORIENTATION: + ridx = e_qp_orientation_get(); + val = TWS_QUICKPANEL_STATE_VALUE_ORIENTATION_0 + ridx; + break; + default: + break; + } + + tws_quickpanel_send_state_get_done(res_tzsh_qp, type, val, 0); +} + +static const struct tws_quickpanel_interface _tzsh_qp_iface = +{ + _tzsh_qp_iface_cb_release, + _tzsh_qp_iface_cb_show, + _tzsh_qp_iface_cb_hide, + _tzsh_qp_iface_cb_enable, + _tzsh_qp_iface_cb_disable, + _tzsh_qp_iface_cb_state_get +}; + +static void +_tzsh_cb_qp_destroy(struct wl_resource *res_tzsh_qp) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + + tzsh_client = wl_resource_get_user_data(res_tzsh_qp); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client); + + _e_policy_wl_tzsh_client_del(tzsh_client); +} + +static void +_tzsh_iface_cb_qp_get(struct wl_client *client, struct wl_resource *res_tzsh, uint32_t id, uint32_t surf_id) +{ + E_Policy_Wl_Tzsh *tzsh; + E_Policy_Wl_Tzsh_Client *tzsh_client; + struct wl_resource *res_tzsh_qp; + E_Client *ec; + E_Pixmap *cp; + + tzsh = wl_resource_get_user_data(res_tzsh); + if (!tzsh) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid res_tzsh's user data"); + return; + } + + cp = _e_policy_wl_e_pixmap_get_from_id(client, surf_id); + if (!cp) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid surface id"); + return; + } + + ec = e_pixmap_client_get(cp); + if (ec) + { + if (!_e_policy_wl_e_client_is_valid(ec)) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid surface id"); + return; + } + } + + res_tzsh_qp = wl_resource_create(client, + &tws_quickpanel_interface, + wl_resource_get_version(res_tzsh), + id); + if (!res_tzsh_qp) + { + ERR("Could not create tws_quickpanel resource: %m"); + wl_client_post_no_memory(client); + return; + } + + _e_policy_wl_tzsh_data_set(tzsh, TZSH_TYPE_CLIENT, cp, ec); + + tzsh_client = _e_policy_wl_tzsh_client_add(tzsh, res_tzsh_qp); + if (!tzsh_client) + { + ERR("Could not create tzsh_client"); + wl_client_post_no_memory(client); + return; + } + + tzsh_client->qp_client = EINA_TRUE; + e_qp_client_add(tzsh->ec); + + wl_resource_set_implementation(res_tzsh_qp, + &_tzsh_qp_iface, + tzsh_client, + _tzsh_cb_qp_destroy); +} + +// -------------------------------------------------------- +// tizen_ws_shell_interface::tvservice +// -------------------------------------------------------- +static void +_tzsh_tvsrv_iface_cb_release(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_tvsrv) +{ + wl_resource_destroy(res_tzsh_tvsrv); +} + +static void +_tzsh_tvsrv_iface_cb_bind(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_tvsrv) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + + tzsh_client = wl_resource_get_user_data(res_tzsh_tvsrv); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client); + + if (!eina_list_data_find(polwl->tzsh_clients, tzsh_client)) + return; + + polwl->tvsrv_bind_list = eina_list_append(polwl->tvsrv_bind_list, tzsh_client); + + _e_policy_wl_tzsh_srv_tvsrv_bind_update(); +} + +static void +_tzsh_tvsrv_iface_cb_unbind(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh_tvsrv) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + + tzsh_client = wl_resource_get_user_data(res_tzsh_tvsrv); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client); + + if (!eina_list_data_find(polwl->tzsh_clients, tzsh_client)) + return; + + polwl->tvsrv_bind_list = eina_list_remove(polwl->tvsrv_bind_list, tzsh_client); + + _e_policy_wl_tzsh_srv_tvsrv_bind_update(); +} + +static const struct tws_tvsrv_interface _tzsh_tvsrv_iface = +{ + _tzsh_tvsrv_iface_cb_release, + _tzsh_tvsrv_iface_cb_bind, + _tzsh_tvsrv_iface_cb_unbind +}; + +static void +_tzsh_cb_tvsrv_destroy(struct wl_resource *res_tzsh_tvsrv) +{ + E_Policy_Wl_Tzsh_Client *tzsh_client; + + tzsh_client = wl_resource_get_user_data(res_tzsh_tvsrv); + EINA_SAFETY_ON_NULL_RETURN(tzsh_client); + + if (!eina_list_data_find(polwl->tzsh_clients, tzsh_client)) + return; + + polwl->tvsrv_bind_list = eina_list_remove(polwl->tvsrv_bind_list, tzsh_client); + + _e_policy_wl_tzsh_srv_tvsrv_bind_update(); + _e_policy_wl_tzsh_client_del(tzsh_client); +} + +static void +_tzsh_iface_cb_tvsrv_get(struct wl_client *client, struct wl_resource *res_tzsh, uint32_t id, uint32_t surf_id) +{ + E_Policy_Wl_Tzsh *tzsh; + E_Policy_Wl_Tzsh_Client *tzsh_client; + struct wl_resource *res_tzsh_tvsrv; + E_Pixmap *cp; + E_Client *ec; + + tzsh = wl_resource_get_user_data(res_tzsh); + if (!tzsh) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid res_tzsh's user data"); + return; + } + + cp = _e_policy_wl_e_pixmap_get_from_id(client, surf_id); + if (!cp) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid surface id"); + return; + } + + ec = e_pixmap_client_get(cp); + if (ec) + { + if (!_e_policy_wl_e_client_is_valid(ec)) + { + wl_resource_post_error + (res_tzsh, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid surface id"); + return; + } + } + + res_tzsh_tvsrv = wl_resource_create(client, + &tws_tvsrv_interface, + wl_resource_get_version(res_tzsh), + id); + if (!res_tzsh_tvsrv) + { + ERR("Could not create tws_tvsrv resource: %m"); + wl_client_post_no_memory(client); + return; + } + + _e_policy_wl_tzsh_data_set(tzsh, TZSH_TYPE_CLIENT, cp, ec); + + tzsh_client = _e_policy_wl_tzsh_client_add(tzsh, res_tzsh_tvsrv); + if (!tzsh_client) + { + ERR("Could not create tzsh_client"); + wl_client_post_no_memory(client); + wl_resource_destroy(res_tzsh_tvsrv); + return; + } + + wl_resource_set_implementation(res_tzsh_tvsrv, + &_tzsh_tvsrv_iface, + tzsh_client, + _tzsh_cb_tvsrv_destroy); +} + +// -------------------------------------------------------- +// tizen_ws_shell_interface +// -------------------------------------------------------- +static void +_tzsh_iface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzsh) +{ + wl_resource_destroy(res_tzsh); +} + +static const struct tizen_ws_shell_interface _tzsh_iface = +{ + _tzsh_iface_cb_destroy, + _tzsh_iface_cb_srv_create, + _tzsh_iface_cb_reg_create, + _tzsh_iface_cb_qp_get, + _tzsh_iface_cb_tvsrv_get +}; + +static void +_tzsh_cb_unbind(struct wl_resource *res_tzsh) +{ + E_Policy_Wl_Tzsh *tzsh; + + tzsh = wl_resource_get_user_data(res_tzsh); + EINA_SAFETY_ON_NULL_RETURN(tzsh); + + _e_policy_wl_tzsh_del(tzsh); +} + +static void +_tzsh_cb_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t ver, uint32_t id) +{ + E_Policy_Wl_Tzsh *tzsh; + struct wl_resource *res_tzsh; + + EINA_SAFETY_ON_NULL_GOTO(polwl, err); + + res_tzsh = wl_resource_create(client, + &tizen_ws_shell_interface, + ver, + id); + EINA_SAFETY_ON_NULL_GOTO(res_tzsh, err); + + tzsh = _e_policy_wl_tzsh_add(res_tzsh); + EINA_SAFETY_ON_NULL_GOTO(tzsh, err); + + wl_resource_set_implementation(res_tzsh, + &_tzsh_iface, + tzsh, + _tzsh_cb_unbind); + + _e_policy_wl_tzsh_registered_srv_send(tzsh); + return; + +err: + ERR("Could not create tizen_ws_shell_interface res: %m"); + wl_client_post_no_memory(client); +} + +// -------------------------------------------------------- +// tizen_launchscreen_interface +// -------------------------------------------------------- +static void +_launchscreen_hide(uint32_t pid) +{ + Eina_List *l, *ll; + E_Policy_Wl_Tzlaunch *plauncher; + E_Policy_Wl_Tzlaunch_Img *pimg; + + if(pid <= 0) return; + + EINA_LIST_FOREACH(polwl->tzlaunchs, l, plauncher) + { + EINA_LIST_FOREACH(plauncher->imglist, ll, pimg) + if (pimg->pid == pid) + { + DBG("Launch Screen hide | pid %d", pid); + _launch_img_off(pimg); + } + } + + return; +} + +static void +_launch_img_cb_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + E_Policy_Wl_Tzlaunch_Img *tzlaunchimg = data; + + if ((tzlaunchimg) && (tzlaunchimg->obj == obj)) + tzlaunchimg->obj = NULL; +} + +static void +_launch_img_off(E_Policy_Wl_Tzlaunch_Img *tzlaunchimg) +{ + E_Client *ec = NULL; + + if (!tzlaunchimg->valid) return; + if (!tzlaunchimg->ec) return; + + ec = tzlaunchimg->ec; + + if ((ec->pixmap) && + (ec->pixmap == tzlaunchimg->ep)) + { + if (ec->visible) + { + ec->visible = EINA_FALSE; + evas_object_hide(ec->frame); + ec->ignored = EINA_TRUE; + } + + e_comp->launchscrns = eina_list_remove(e_comp->launchscrns, ec); + + e_pixmap_del(tzlaunchimg->ep); + e_object_del(E_OBJECT(ec)); + } + + tzlaunchimg->ep = NULL; + tzlaunchimg->ec = NULL; + if (tzlaunchimg->timeout) ecore_timer_del(tzlaunchimg->timeout); + tzlaunchimg->timeout = NULL; + tzlaunchimg->valid = EINA_FALSE; +} + +static Eina_Bool +_launch_timeout(void *data) +{ + E_Policy_Wl_Tzlaunch_Img *tzlaunchimg; + tzlaunchimg = (E_Policy_Wl_Tzlaunch_Img *)data; + + EINA_SAFETY_ON_NULL_RETURN_VAL(tzlaunchimg, 0); + + _launch_img_off(tzlaunchimg); + + return ECORE_CALLBACK_CANCEL; +} + +static void +_tzlaunchimg_iface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzlaunchimg) +{ + wl_resource_destroy(res_tzlaunchimg); +} + +static void +_tzlaunchimg_iface_cb_launch(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzlaunchimg, + const char *pfname, uint32_t ftype, + uint32_t depth, uint32_t angle, + uint32_t indicator, struct wl_array *options) +{ + E_Policy_Wl_Tzlaunch_Img *tzlaunchimg; + Evas_Load_Error err; + E_Client *ec = NULL; + E_Comp_Object_Content_Type content_type = 0; + + tzlaunchimg = wl_resource_get_user_data(res_tzlaunchimg); + EINA_SAFETY_ON_NULL_RETURN(tzlaunchimg); + EINA_SAFETY_ON_NULL_RETURN(tzlaunchimg->ec); + EINA_SAFETY_ON_NULL_RETURN(tzlaunchimg->ec->frame); + + ec = tzlaunchimg->ec; + + // TO DO + // invaid parameter handle + DBG("%s | path %s(%d), indicator(%d), angle(%d)", __FUNCTION__, pfname, ftype, indicator, angle); + tzlaunchimg->path = pfname; + tzlaunchimg->type = ftype; + tzlaunchimg->indicator = indicator; + tzlaunchimg->angle = angle; + + if (tzlaunchimg->type == E_LAUNCH_FILE_TYPE_IMAGE) + { + content_type = E_COMP_OBJECT_CONTENT_TYPE_EXT_IMAGE; + tzlaunchimg->obj = evas_object_image_add(e_comp->evas); + EINA_SAFETY_ON_NULL_GOTO(tzlaunchimg->obj, error); + evas_object_image_file_set(tzlaunchimg->obj, tzlaunchimg->path, NULL); + + err = evas_object_image_load_error_get(tzlaunchimg->obj); + EINA_SAFETY_ON_FALSE_GOTO(err == EVAS_LOAD_ERROR_NONE, error); + + evas_object_image_fill_set(tzlaunchimg->obj, 0, 0, e_comp->w, e_comp->h); + evas_object_image_filled_set(tzlaunchimg->obj, EINA_TRUE); + } + else + { + content_type = E_COMP_OBJECT_CONTENT_TYPE_EXT_EDJE; + tzlaunchimg->obj = edje_object_add(e_comp->evas); + EINA_SAFETY_ON_NULL_GOTO(tzlaunchimg->obj, error); + edje_object_file_set (tzlaunchimg->obj, tzlaunchimg->path, APP_DEFINE_GROUP_NAME); + + evas_object_move(tzlaunchimg->obj, 0, 0); + evas_object_resize(tzlaunchimg->obj, e_comp->w, e_comp->h); + } + + if (depth == 32) ec->argb = EINA_TRUE; + else ec->argb = EINA_FALSE; + + if (!e_comp_object_content_set(ec->frame, tzlaunchimg->obj, content_type)) + { + ERR("Setting comp object content for %p failed!", ec); + goto error; + } + + evas_object_event_callback_add(tzlaunchimg->obj, + EVAS_CALLBACK_DEL, + _launch_img_cb_del, tzlaunchimg); + + tzlaunchimg->valid = EINA_TRUE; + + ec->ignored = EINA_FALSE; + ec->visible = EINA_TRUE; + ec->new_client = EINA_FALSE; + ec->icccm.accepts_focus = EINA_TRUE; + + evas_object_show(ec->frame); + evas_object_raise(ec->frame); + EC_CHANGED(ec); + + e_client_visibility_calculate(); + + if (tzlaunchimg->timeout) + ecore_timer_del(tzlaunchimg->timeout); + tzlaunchimg->timeout = ecore_timer_add(4.0f, _launch_timeout, tzlaunchimg); + + return; +error: + ERR("Could not complete %s", __FUNCTION__); + if (tzlaunchimg->obj) + evas_object_del(tzlaunchimg->obj); +} + +static void +_tzlaunchimg_iface_cb_show(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzlaunchimg) +{ + /* TODO: request launch img show */ + +} + +static void +_tzlaunchimg_iface_cb_hide(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzlaunchimg) +{ + /* TODO: request launch img hide */ +} + +static void +_tzlaunchimg_iface_cb_owner(struct wl_client *client EINA_UNUSED, struct wl_resource *res_tzlaunchimg, uint32_t pid) +{ + E_Policy_Wl_Tzlaunch_Img *tzlaunchimg; + + DBG("Launch img(%d) pid: %d", wl_resource_get_id(res_tzlaunchimg), pid); + + tzlaunchimg = wl_resource_get_user_data(res_tzlaunchimg); + EINA_SAFETY_ON_NULL_RETURN(tzlaunchimg); + + tzlaunchimg->pid = pid; + tzlaunchimg->ec->netwm.pid = pid; +} + + +static const struct tizen_launch_image_interface _tzlaunchimg_iface = +{ + _tzlaunchimg_iface_cb_destroy, + _tzlaunchimg_iface_cb_launch, + _tzlaunchimg_iface_cb_owner, + _tzlaunchimg_iface_cb_show, + _tzlaunchimg_iface_cb_hide +}; + +static E_Policy_Wl_Tzlaunch_Img * +_tzlaunch_img_add(struct wl_resource *res_tzlaunch, struct wl_resource *res_tzlaunch_img) +{ + E_Policy_Wl_Tzlaunch *tzlaunch; + E_Policy_Wl_Tzlaunch_Img *tzlaunchimg; + + tzlaunchimg = E_NEW(E_Policy_Wl_Tzlaunch_Img, 1); + EINA_SAFETY_ON_NULL_GOTO(tzlaunchimg, error); + + tzlaunch = wl_resource_get_user_data(res_tzlaunch); + EINA_SAFETY_ON_NULL_GOTO(tzlaunch, error); + + tzlaunch->imglist = eina_list_append(tzlaunch->imglist, tzlaunchimg); + + tzlaunchimg->tzlaunch = tzlaunch; + tzlaunchimg->res_tzlaunch_img = res_tzlaunch_img; + + tzlaunchimg->ep = e_pixmap_new(E_PIXMAP_TYPE_EXT_OBJECT, 0); + EINA_SAFETY_ON_NULL_GOTO(tzlaunchimg->ep, error); + tzlaunchimg->ec = e_client_new(tzlaunchimg->ep, 0, 1); + EINA_SAFETY_ON_NULL_GOTO(tzlaunchimg->ec, error); + + tzlaunchimg->ec->icccm.title = eina_stringshare_add("Launchscreen"); + tzlaunchimg->ec->icccm.name = eina_stringshare_add("Launchscreen"); + tzlaunchimg->ec->ignored = EINA_TRUE; + + e_comp->launchscrns = eina_list_append(e_comp->launchscrns, tzlaunchimg->ec); + + return tzlaunchimg; +error: + if (tzlaunchimg) + { + ERR("Could not initialize launchscreen client"); + if (tzlaunchimg->ep) + e_pixmap_del(tzlaunchimg->ep); + if (tzlaunchimg->ec) + e_object_del(E_OBJECT(tzlaunchimg->ec)); + E_FREE(tzlaunchimg); + } + return NULL; +} + +static void +_tzlaunch_img_destroy(struct wl_resource *res_tzlaunchimg) +{ + E_Policy_Wl_Tzlaunch_Img *tzlaunchimg; + E_Policy_Wl_Tzlaunch *tzlaunch; + + EINA_SAFETY_ON_NULL_RETURN(res_tzlaunchimg); + + tzlaunchimg = wl_resource_get_user_data(res_tzlaunchimg); + EINA_SAFETY_ON_NULL_RETURN(tzlaunchimg); + + if (tzlaunchimg->obj) + evas_object_event_callback_del_full(tzlaunchimg->obj, EVAS_CALLBACK_DEL, _launch_img_cb_del, tzlaunchimg); + + _launch_img_off(tzlaunchimg); + + tzlaunch = tzlaunchimg->tzlaunch; + tzlaunch->imglist = eina_list_remove(tzlaunch->imglist, tzlaunchimg); + + memset(tzlaunchimg, 0x0, sizeof(E_Policy_Wl_Tzlaunch_Img)); + E_FREE(tzlaunchimg); +} + + +static void +_tzlaunch_iface_cb_create_img(struct wl_client *client, struct wl_resource *res_tzlaunch, uint32_t id) +{ + + E_Policy_Wl_Tzlaunch_Img *plaunchimg; + struct wl_resource *res_tzlaunch_img; + + res_tzlaunch_img = wl_resource_create(client, + &tizen_launch_image_interface, + wl_resource_get_version(res_tzlaunch), + id); + if (!res_tzlaunch_img) + { + wl_resource_post_error + (res_tzlaunch, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Invalid res_tzlaunch's user data"); + return; + } + + plaunchimg = _tzlaunch_img_add(res_tzlaunch, res_tzlaunch_img); + EINA_SAFETY_ON_NULL_GOTO(plaunchimg, err); + + wl_resource_set_implementation(res_tzlaunch_img, + &_tzlaunchimg_iface, + plaunchimg, + _tzlaunch_img_destroy); + + return; + +err: + ERR("Could not create tizen_launch_image_interface res: %m"); + wl_client_post_no_memory(client); +} + + +static const struct tizen_launchscreen_interface _tzlaunch_iface = +{ + _tzlaunch_iface_cb_create_img +}; + +static void +_tzlaunch_del(E_Policy_Wl_Tzlaunch *tzlaunch) +{ + E_Policy_Wl_Tzlaunch_Img *plaunchimg; + Eina_List *l, *ll; + + EINA_SAFETY_ON_NULL_RETURN(tzlaunch); + + // remove tzlaunch created imglist + EINA_LIST_FOREACH_SAFE(tzlaunch->imglist, l, ll, plaunchimg) + { + if (plaunchimg->tzlaunch != tzlaunch) continue; + wl_resource_destroy(plaunchimg->res_tzlaunch_img); + break; + } + + polwl->tzlaunchs = eina_list_remove(polwl->tzlaunchs, tzlaunch); + + memset(tzlaunch, 0x0, sizeof(E_Policy_Wl_Tzlaunch)); + E_FREE(tzlaunch); +} + +static E_Policy_Wl_Tzlaunch * +_tzlaunch_add(struct wl_resource *res_tzlaunch) +{ + E_Policy_Wl_Tzlaunch *tzlaunch; + + tzlaunch = E_NEW(E_Policy_Wl_Tzlaunch, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(tzlaunch, NULL); + + tzlaunch->res_tzlaunch = res_tzlaunch; + + polwl->tzlaunchs = eina_list_append(polwl->tzlaunchs, tzlaunch); + + return tzlaunch; +} + +static void +_tzlaunch_cb_unbind(struct wl_resource *res_tzlaunch) +{ + E_Policy_Wl_Tzlaunch *tzlaunch = NULL; + Eina_List *l, *ll; + + EINA_LIST_FOREACH_SAFE(polwl->tzlaunchs, l, ll, tzlaunch) + { + if (tzlaunch->res_tzlaunch != res_tzlaunch) continue; + _tzlaunch_del(tzlaunch); + break; + } +} + +static void +_tzlaunch_cb_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t ver, uint32_t id) +{ + E_Policy_Wl_Tzlaunch *tzlaunch = NULL; + struct wl_resource *res_tzlaunch; + + EINA_SAFETY_ON_NULL_GOTO(polwl, err); + + res_tzlaunch = wl_resource_create(client, + &tizen_launchscreen_interface, + ver, + id); + EINA_SAFETY_ON_NULL_GOTO(res_tzlaunch, err); + + tzlaunch = _tzlaunch_add(res_tzlaunch); + EINA_SAFETY_ON_NULL_GOTO(tzlaunch, err); + + wl_resource_set_implementation(res_tzlaunch, + &_tzlaunch_iface, + tzlaunch, + _tzlaunch_cb_unbind); + + return; + +err: + ERR("Could not create tizen_launchscreen_interface res: %m"); + wl_client_post_no_memory(client); +} + +static Eina_Bool +_e_policy_wl_cb_scrsaver_on(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + if (_scrsaver_mng_res) + tws_service_screensaver_manager_send_idle(_scrsaver_mng_res); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_policy_wl_cb_scrsaver_off(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + if (_scrsaver_mng_res) + tws_service_screensaver_manager_send_active(_scrsaver_mng_res); + return ECORE_CALLBACK_PASS_ON; +} + +static void +_e_policy_wl_cb_hook_shell_surface_ready(void *d, E_Client *ec) +{ + Eina_Bool res; + + if (EINA_UNLIKELY(!ec)) + return; + + _e_policy_wl_aux_hint_apply(ec); + + res = e_policy_client_maximize(ec); + if (res) + { + if ((ec->comp_data->shell.configure_send) && + (ec->comp_data->shell.surface)) + { + ec->comp_data->shell.configure_send(ec->comp_data->shell.surface, + 0, ec->w, ec->h); + } + } +} + +// -------------------------------------------------------- +// public functions +// -------------------------------------------------------- +void +e_policy_wl_client_add(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (!ec->pixmap) return; + + _e_policy_wl_surf_client_set(ec); + _e_policy_wl_tzsh_client_set(ec); + _e_policy_wl_pending_bg_client_set(ec); +} + +void +e_policy_wl_client_del(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + if (!ec->pixmap) return; + + e_policy_wl_pixmap_del(ec->pixmap); + _e_policy_wl_tzsh_client_unset(ec); + _e_policy_wl_dpy_surf_del(ec); + + polwl->pending_vis = eina_list_remove(polwl->pending_vis, ec); +} + +void +e_policy_wl_pixmap_del(E_Pixmap *cp) +{ + E_Policy_Wl_Tzpol *tzpol; + E_Policy_Wl_Surface *psurf; + Eina_List *l, *ll; + Eina_Iterator *it; + + it = eina_hash_iterator_data_new(polwl->tzpols); + EINA_ITERATOR_FOREACH(it, tzpol) + EINA_LIST_FOREACH_SAFE(tzpol->psurfs, l, ll, psurf) + { + if (psurf->cp != cp) continue; + tzpol->psurfs = eina_list_remove_list(tzpol->psurfs, l); + _e_policy_wl_surf_del(psurf); + } + eina_iterator_free(it); +} + +void +e_policy_wl_aux_hint_init(void) +{ + int i, n; + n = (sizeof(hint_names) / sizeof(char *)); + + for (i = 0; i < n; i++) + { + e_hints_aux_hint_supported_add(hint_names[i]); + } + return; +} + +Eina_Bool +e_policy_wl_defer_job(void) +{ + struct wl_global *global = NULL; + EINA_SAFETY_ON_NULL_GOTO(polwl, err); + + global = wl_global_create(e_comp_wl->wl.disp, + &tizen_launchscreen_interface, + 1, + NULL, + _tzlaunch_cb_bind); + EINA_SAFETY_ON_NULL_GOTO(global, err); + + polwl->globals = eina_list_append(polwl->globals, global); + + return EINA_TRUE; + +err: + return EINA_FALSE; +} + +#undef E_COMP_WL_HOOK_APPEND +#define E_COMP_WL_HOOK_APPEND(l, t, cb, d) \ + do \ + { \ + E_Comp_Wl_Hook *_h; \ + _h = e_comp_wl_hook_add(t, cb, d); \ + assert(_h); \ + l = eina_list_append(l, _h); \ + } \ + while (0) + +Eina_Bool +e_policy_wl_init(void) +{ + struct wl_global *global; + + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->wl.disp, EINA_FALSE); + + polwl = E_NEW(E_Policy_Wl, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(polwl, EINA_FALSE); + + /* create globals */ + global = wl_global_create(e_comp_wl->wl.disp, + &tizen_policy_interface, + 1, + NULL, + _tzpol_cb_bind); + EINA_SAFETY_ON_NULL_GOTO(global, err); + polwl->globals = eina_list_append(polwl->globals, global); + + global = wl_global_create(e_comp_wl->wl.disp, + &tizen_display_policy_interface, + 1, + NULL, + _tz_dpy_pol_cb_bind); + EINA_SAFETY_ON_NULL_GOTO(global, err); + polwl->globals = eina_list_append(polwl->globals, global); + + global = wl_global_create(e_comp_wl->wl.disp, + &tizen_ws_shell_interface, + 1, + NULL, + _tzsh_cb_bind); + EINA_SAFETY_ON_NULL_GOTO(global, err); + polwl->globals = eina_list_append(polwl->globals, global); + + polwl->tzpols = eina_hash_pointer_new(_e_policy_wl_tzpol_del); + +#ifdef HAVE_CYNARA + if (cynara_initialize(&polwl->p_cynara, NULL) != CYNARA_API_SUCCESS) + ERR("cynara_initialize failed."); +#endif + + E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREENSAVER_ON, _e_policy_wl_cb_scrsaver_on, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREENSAVER_OFF, _e_policy_wl_cb_scrsaver_off, NULL); + + E_COMP_WL_HOOK_APPEND(hooks_cw, E_COMP_WL_HOOK_SHELL_SURFACE_READY, _e_policy_wl_cb_hook_shell_surface_ready, NULL); + + e_policy_display_init(); + + return EINA_TRUE; + +err: + if (polwl) + { + EINA_LIST_FREE(polwl->globals, global) + wl_global_destroy(global); + + E_FREE(polwl); + } + return EINA_FALSE; +} + +void +e_policy_wl_shutdown(void) +{ + E_Policy_Wl_Tzsh *tzsh; + E_Policy_Wl_Tzsh_Srv *tzsh_srv; + E_Policy_Wl_Tzlaunch *tzlaunch; + E_Policy_Wl_Tz_Dpy_Pol *tz_dpy_pol; + struct wl_global *global; + int i; + + e_policy_display_shutdown(); + + EINA_SAFETY_ON_NULL_RETURN(polwl); + + E_FREE_LIST(hooks_cw, e_comp_wl_hook_del); + E_FREE_LIST(handlers, ecore_event_handler_del); + + polwl->pending_vis = eina_list_free(polwl->pending_vis); + + for (i = 0; i < TZSH_SRV_ROLE_MAX; i++) + { + tzsh_srv = polwl->srvs[i]; + if (!tzsh_srv) continue; + + wl_resource_destroy(tzsh_srv->res_tzsh_srv); + } + + EINA_LIST_FREE(polwl->tzshs, tzsh) + wl_resource_destroy(tzsh->res_tzsh); + + EINA_LIST_FREE(polwl->tz_dpy_pols, tz_dpy_pol) + { + E_Policy_Wl_Dpy_Surface *dpy_surf; + EINA_LIST_FREE(tz_dpy_pol->dpy_surfs, dpy_surf) + { + E_FREE(dpy_surf); + } + wl_resource_destroy(tz_dpy_pol->res_tz_dpy_pol); + E_FREE(tz_dpy_pol); + } + + EINA_LIST_FREE(polwl->tzlaunchs, tzlaunch) + wl_resource_destroy(tzlaunch->res_tzlaunch); + + EINA_LIST_FREE(polwl->globals, global) + wl_global_destroy(global); + + E_FREE_FUNC(polwl->tzpols, eina_hash_free); + +#ifdef HAVE_CYNARA + if (polwl->p_cynara) + cynara_finish(polwl->p_cynara); +#endif + + E_FREE(polwl); +} diff --git a/src/bin/e_policy_wl.h b/src/bin/e_policy_wl.h new file mode 100644 index 0000000000..e1aa290b89 --- /dev/null +++ b/src/bin/e_policy_wl.h @@ -0,0 +1,43 @@ +#ifndef E_MOD_WL_H +#define E_MOD_WL_H + +#include "config.h" +#ifdef HAVE_WAYLAND_ONLY +#include + +Eina_Bool e_policy_wl_init(void); +void e_policy_wl_shutdown(void); +Eina_Bool e_policy_wl_defer_job(void); +void e_policy_wl_client_add(E_Client *ec); +void e_policy_wl_client_del(E_Client *ec); +void e_policy_wl_pixmap_del(E_Pixmap *cp); + +/* visibility */ +void e_policy_wl_visibility_send(E_Client *ec, int vis); + +/* iconify */ +void e_policy_wl_iconify_state_change_send(E_Client *ec, int iconic); + +/* position */ +void e_policy_wl_position_send(E_Client *ec); + +/* notification */ +void e_policy_wl_notification_level_fetch(E_Client *ec); + +/* window screenmode */ +void e_policy_wl_win_scrmode_apply(void); + +/* aux_hint */ +void e_policy_wl_aux_hint_init(void); +void e_policy_wl_eval_pre_post_fetch(E_Client *ec); + +/* window brightness */ +Eina_Bool e_policy_wl_win_brightness_apply(E_Client *ec); + +/* tzsh quickpanel */ +EINTERN void e_tzsh_qp_state_visible_update(E_Client *ec, Eina_Bool vis); +EINTERN void e_tzsh_qp_state_orientation_update(E_Client *ec, int ridx); +EINTERN void e_tzsh_qp_state_scrollable_update(E_Client *ec, Eina_Bool scrollable); + +#endif /* HAVE_WAYLAND_ONLY */ +#endif /* E_MOD_WL_H */ diff --git a/src/bin/e_policy_wl_display.c b/src/bin/e_policy_wl_display.c new file mode 100644 index 0000000000..d843496d7f --- /dev/null +++ b/src/bin/e_policy_wl_display.c @@ -0,0 +1,288 @@ +#include "e_policy_wl_display.h" + +typedef struct _E_Display_Dbus_Info +{ + Eldbus_Connection *conn; +} E_Display_Dbus_Info; + +#define BUS_NAME "org.enlightenment.wm" + +#define DEVICED_DEST "org.tizen.system.deviced" +#define DEVICED_PATH "/Org/Tizen/System/DeviceD/Display" +#define DEVICED_IFACE "org.tizen.system.deviced.display" +#define DEVICED_LOCK_STATE "lockstate" +#define DEVICED_UNLOCK_STATE "unlockstate" + +#define DEVICED_LCDON "lcdon" +#define DEVICED_STAY_CUR_STATE "staycurstate" +#define DEVICED_SLEEP_MARGIN "sleepmargin" + +/* static global variables */ +static E_Display_Dbus_Info _e_display_dbus_info; +static Eina_List *_display_control_hooks = NULL; + +/* for screen mode */ +static Eina_List *_screen_mode_client_list = NULL; +static E_Display_Screen_Mode _e_display_screen_mode; + +/* static functions */ +static Eina_Bool _e_policy_display_dbus_init(void); +static void _e_policy_display_dbus_shutdown(void); +static void _e_policy_display_dbus_request_name_cb(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED); + +static Eina_Bool _e_policy_wl_display_client_add_to_list(Eina_List** list, E_Client *ec); +static Eina_Bool _e_policy_wl_display_client_remove_from_list(Eina_List** list, E_Client *ec); + +static void _e_policy_wl_display_hook_client_del(void *d EINA_UNUSED, E_Client *ec); +static void _e_policy_wl_display_hook_client_visibility(void *d EINA_UNUSED, E_Client *ec); + +/* for screen mode */ +static Eina_Bool _e_policy_wl_display_screen_mode_find_visible_window(void); +static void _e_policy_wl_display_screen_mode_send(E_Display_Screen_Mode mode); + + +static Eina_Bool +_e_policy_display_dbus_init(void) +{ + if (eldbus_init() == 0) return EINA_FALSE; + + _e_display_dbus_info.conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM); + EINA_SAFETY_ON_NULL_GOTO(_e_display_dbus_info.conn, failed); + + eldbus_name_request(_e_display_dbus_info.conn, + BUS_NAME, + ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, + _e_policy_display_dbus_request_name_cb, + NULL); + + return EINA_TRUE; + +failed: + _e_policy_display_dbus_shutdown(); + return EINA_FALSE; +} + +static void +_e_policy_display_dbus_shutdown(void) +{ + if (_e_display_dbus_info.conn) + { + eldbus_name_release(_e_display_dbus_info.conn, BUS_NAME, NULL, NULL); + eldbus_connection_unref(_e_display_dbus_info.conn); + _e_display_dbus_info.conn = NULL; + } + + eldbus_shutdown(); +} + +static void +_e_policy_display_dbus_request_name_cb(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) +{ + unsigned int flag; + + if (eldbus_message_error_get(msg, NULL, NULL)) + { + ERR("Could not request bus name"); + return; + } + + if (!eldbus_message_arguments_get(msg, "u", &flag)) + { + ERR("Could not get arguments on on_name_request"); + return; + } + + if (!(flag & ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER)) + { + WRN("Name already in use\n"); + } +} + +static Eina_Bool +_e_policy_wl_display_client_add_to_list(Eina_List** list, E_Client *ec) +{ + if (!ec) return EINA_FALSE; + + if (eina_list_data_find(*list, ec) == ec) + return EINA_TRUE; + + *list = eina_list_append(*list, ec); + + return EINA_TRUE; +} + +static Eina_Bool +_e_policy_wl_display_client_remove_from_list(Eina_List** list, E_Client *ec) +{ + if (!ec) return EINA_FALSE; + + if (!eina_list_data_find(*list, ec)) + return EINA_FALSE; + + *list = eina_list_remove(*list, ec); + + return EINA_TRUE; +} + +static void +_e_policy_wl_display_hook_client_del(void *d EINA_UNUSED, E_Client *ec) +{ + _e_policy_wl_display_client_remove_from_list(&_screen_mode_client_list, ec); +} + +static void +_e_policy_wl_display_hook_client_visibility(void *d EINA_UNUSED, E_Client *ec) +{ + if (ec->visibility.changed) + { + e_policy_display_screen_mode_apply(); + } +} + +static Eina_Bool +_e_policy_wl_display_screen_mode_find_visible_window(void) +{ + Eina_List *l = NULL; + E_Client *ec = NULL; + Eina_Bool find = EINA_FALSE; + int ec_visibility; + + if (_screen_mode_client_list == NULL) return EINA_FALSE; + + EINA_LIST_FOREACH(_screen_mode_client_list, l, ec) + { + if (e_object_is_del(E_OBJECT(ec))) + ec_visibility = E_VISIBILITY_FULLY_OBSCURED; + else + ec_visibility = ec->visibility.obscured; + + if ((ec_visibility == E_VISIBILITY_UNOBSCURED) || + (ec_visibility == E_VISIBILITY_PARTIALLY_OBSCURED)) + { + find = EINA_TRUE; + break; + } + } + + return find; +} + +static void +_e_policy_wl_display_screen_mode_send(E_Display_Screen_Mode mode) +{ + Eldbus_Message *msg; + Eina_Bool ret; + unsigned int timeout = 0; + + if (!_e_display_dbus_info.conn) return; + + if (mode == E_DISPLAY_SCREEN_MODE_ALWAYS_ON) + { + msg = eldbus_message_method_call_new(DEVICED_DEST, + DEVICED_PATH, + DEVICED_IFACE, + DEVICED_LOCK_STATE); + if (!msg) return; + + ret = eldbus_message_arguments_append(msg, "sssi", + DEVICED_LCDON, + DEVICED_STAY_CUR_STATE, + "", + timeout); + } + else + { + msg = eldbus_message_method_call_new(DEVICED_DEST, + DEVICED_PATH, + DEVICED_IFACE, + DEVICED_UNLOCK_STATE); + if (!msg) return; + + ret = eldbus_message_arguments_append(msg, "ss", + DEVICED_LCDON, + DEVICED_SLEEP_MARGIN); + } + + if (!ret) + { + if (msg) + eldbus_message_unref(msg); + + return; + } + + _e_display_screen_mode = mode; + DBG("[SCREEN_MODE] Request screen mode:%d\n", mode); + + eldbus_connection_send(_e_display_dbus_info.conn, msg, NULL, NULL, -1); +} + +#undef E_CLIENT_HOOK_APPEND +#define E_CLIENT_HOOK_APPEND(l, t, cb, d) \ + do \ + { \ + E_Client_Hook *_h; \ + _h = e_client_hook_add(t, cb, d); \ + assert(_h); \ + l = eina_list_append(l, _h); \ + } \ + while (0) + +Eina_Bool +e_policy_display_init(void) +{ + if (!_e_policy_display_dbus_init()) return EINA_FALSE; + + _e_display_screen_mode = E_DISPLAY_SCREEN_MODE_DEFAULT; + + /* hook functions */ + E_CLIENT_HOOK_APPEND(_display_control_hooks, E_CLIENT_HOOK_DEL, _e_policy_wl_display_hook_client_del, NULL); + E_CLIENT_HOOK_APPEND(_display_control_hooks, E_CLIENT_HOOK_EVAL_VISIBILITY, _e_policy_wl_display_hook_client_visibility, NULL); + + return EINA_TRUE; +} + +void +e_policy_display_shutdown(void) +{ + E_FREE_LIST(_display_control_hooks, e_client_hook_del); + + if (_screen_mode_client_list) eina_list_free(_screen_mode_client_list); + + _e_policy_display_dbus_shutdown(); +} + +void +e_policy_display_screen_mode_set(E_Client *ec, int mode) +{ + if (!ec) return; + if (e_object_is_del(E_OBJECT(ec))) return; + + if (mode == 0) + { + _e_policy_wl_display_client_remove_from_list(&_screen_mode_client_list, ec); + e_policy_display_screen_mode_apply(); + } + else + { + _e_policy_wl_display_client_add_to_list(&_screen_mode_client_list, ec); + e_policy_display_screen_mode_apply(); + } +} + +void +e_policy_display_screen_mode_apply(void) +{ + /* check the _screen_mode_client_list and update the lcd locked status */ + if (_e_policy_wl_display_screen_mode_find_visible_window()) + { + if (_e_display_screen_mode == E_DISPLAY_SCREEN_MODE_DEFAULT) + _e_policy_wl_display_screen_mode_send(E_DISPLAY_SCREEN_MODE_ALWAYS_ON); + } + else + { + if (_e_display_screen_mode == E_DISPLAY_SCREEN_MODE_ALWAYS_ON) + _e_policy_wl_display_screen_mode_send(E_DISPLAY_SCREEN_MODE_DEFAULT); + } +} + diff --git a/src/bin/e_policy_wl_display.h b/src/bin/e_policy_wl_display.h new file mode 100644 index 0000000000..db35cad960 --- /dev/null +++ b/src/bin/e_policy_wl_display.h @@ -0,0 +1,18 @@ +#ifndef E_POLICY_WL_DISPLAY_H +#define E_POLICY_WL_DISPLAY_H + +#include + +typedef enum _E_Display_Screen_Mode +{ + E_DISPLAY_SCREEN_MODE_DEFAULT = 0, + E_DISPLAY_SCREEN_MODE_ALWAYS_ON = 1, +} E_Display_Screen_Mode; + +Eina_Bool e_policy_display_init(void); +void e_policy_display_shutdown(void); + +void e_policy_display_screen_mode_set(E_Client *ec, int mode); +void e_policy_display_screen_mode_apply(void); + +#endif diff --git a/src/bin/services/e_service_gesture.c b/src/bin/services/e_service_gesture.c new file mode 100644 index 0000000000..174f307cc2 --- /dev/null +++ b/src/bin/services/e_service_gesture.c @@ -0,0 +1,217 @@ +#include "e.h" +#include "services/e_service_gesture.h" + +struct _E_Policy_Gesture +{ + Evas_Object *obj; + E_Policy_Gesture_Type type; + + Eina_Bool active; + + struct + { + int x; + int y; + int timestamp; + Eina_Bool pressed; /* to avoid processing that happened mouse move right after mouse up */ + } mouse_info; + + struct + { + E_Policy_Gesture_Start_Cb start; + E_Policy_Gesture_Move_Cb move; + E_Policy_Gesture_End_Cb end; + void *data; + } cb; +}; + +static void +_gesture_obj_cb_mouse_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event) +{ + E_Policy_Gesture *gesture = data; + Evas_Event_Mouse_Up *ev = event; + + gesture->mouse_info.pressed = EINA_FALSE; + + if (!gesture->active) + return; + + gesture->active = EINA_FALSE; + + if (gesture->cb.end) + gesture->cb.end(gesture->cb.data, obj, ev->canvas.x, ev->canvas.y, ev->timestamp); +} + +static Eina_Bool +_gesture_line_check(E_Policy_Gesture *gesture, int x, int y) +{ + int dx, dy; + const int sensitivity = 50; /* FIXME: hard coded, it sould be configurable. */ + + dx = x - gesture->mouse_info.x; + dy = y - gesture->mouse_info.y; + if ((abs(dy) < sensitivity) && + (abs(dx) < sensitivity)) + return EINA_FALSE; + + return EINA_TRUE; +} + +static Eina_Bool +_gesture_flick_check(E_Policy_Gesture *gesture, Evas_Object *obj, int x, int y, unsigned int timestamp) +{ + int dy; + int ox, oy, ow, oh; + unsigned int dt; + float vel = 0.0; + const float sensitivity = 0.25; /* FIXME: hard coded, it sould be configurable. */ + + evas_object_geometry_get(obj, &ox, &oy, &ow, &oh); + if (!E_INSIDE(x, y, ox, oy, ow, oh)) + return EINA_FALSE; + + dy = y - gesture->mouse_info.y; + dt = timestamp - gesture->mouse_info.timestamp; + if (dt == 0) + return EINA_FALSE; + + vel = (float)dy / (float)dt; + if (fabs(vel) < sensitivity) + return EINA_FALSE; + + return EINA_TRUE; +} + +static Eina_Bool +_gesture_check(E_Policy_Gesture *gesture, Evas_Object *obj, int x, int y, unsigned int timestamp) +{ + Eina_Bool ret = EINA_FALSE; + + switch (gesture->type) + { + case POL_GESTURE_TYPE_NONE: + ret = EINA_TRUE; + break; + case POL_GESTURE_TYPE_LINE: + ret = _gesture_line_check(gesture, x, y); + break; + case POL_GESTURE_TYPE_FLICK: + ret = _gesture_flick_check(gesture, obj, x, y, timestamp); + break; + default: + ERR("Unknown gesture type %d", gesture->type); + break; + } + + return ret; +} + +static void +_gesture_obj_cb_mouse_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event) +{ + E_Policy_Gesture *gesture = data; + Evas_Event_Mouse_Move *ev = event; + int x, y; + unsigned int timestamp; + + if (!gesture->mouse_info.pressed) + return; + + x = ev->cur.canvas.x; + y = ev->cur.canvas.y; + timestamp = ev->timestamp; + + if (!gesture->active) + { + gesture->active = _gesture_check(gesture, obj, x, y, timestamp); + if (gesture->active) + { + /* if gesture is activated, terminate main touch event processing + * in enlightenment */ + if (gesture->type != POL_GESTURE_TYPE_NONE) + e_comp_wl_touch_cancel(); + + if (gesture->cb.start) + gesture->cb.start(gesture->cb.data, obj, x, y, timestamp); + } + return; + } + + if (gesture->cb.move) + gesture->cb.move(gesture->cb.data, obj, x, y, timestamp); +} + +static void +_gesture_obj_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event) +{ + E_Policy_Gesture *gesture = data; + Evas_Event_Mouse_Down *ev = event; + + gesture->active = EINA_FALSE; + gesture->mouse_info.pressed = EINA_TRUE; + gesture->mouse_info.x = ev->canvas.x; + gesture->mouse_info.y = ev->canvas.y; + gesture->mouse_info.timestamp = ev->timestamp; + + gesture->active = _gesture_check(gesture, obj, ev->canvas.x, ev->canvas.y, ev->timestamp); + if (gesture->active) + { + if (gesture->cb.start) + gesture->cb.start(gesture->cb.data, obj, ev->canvas.x, ev->canvas.y, ev->timestamp); + } +} + +EINTERN E_Policy_Gesture * +e_service_gesture_add(Evas_Object *obj, E_Policy_Gesture_Type type) +{ + E_Policy_Gesture *gesture; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + + gesture = E_NEW(E_Policy_Gesture, 1); + if (EINA_UNLIKELY(gesture == NULL)) + return NULL; + + gesture->obj = obj; + gesture->type = type; + + /* we should to repeat mouse event to below object + * until we can make sure gesture */ + if (type != POL_GESTURE_TYPE_NONE) + evas_object_repeat_events_set(obj, EINA_TRUE); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, + _gesture_obj_cb_mouse_down, gesture); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE, + _gesture_obj_cb_mouse_move, gesture); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP, + _gesture_obj_cb_mouse_up, gesture); + + return gesture; +} + +EINTERN void +e_service_gesture_del(E_Policy_Gesture *gesture) +{ + EINA_SAFETY_ON_NULL_RETURN(gesture); + + evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MOUSE_DOWN, + _gesture_obj_cb_mouse_down); + evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MOUSE_MOVE, + _gesture_obj_cb_mouse_move); + evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MOUSE_UP, + _gesture_obj_cb_mouse_up); + + free(gesture); +} + +EINTERN void +e_service_gesture_cb_set(E_Policy_Gesture *gesture, E_Policy_Gesture_Start_Cb cb_start, E_Policy_Gesture_Move_Cb cb_move, E_Policy_Gesture_End_Cb cb_end, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(gesture); + + gesture->cb.start = cb_start; + gesture->cb.move = cb_move; + gesture->cb.end = cb_end; + gesture->cb.data = data; +} diff --git a/src/bin/services/e_service_gesture.h b/src/bin/services/e_service_gesture.h new file mode 100644 index 0000000000..836bf05a74 --- /dev/null +++ b/src/bin/services/e_service_gesture.h @@ -0,0 +1,23 @@ +#ifndef E_SERVICE_GESTURE +#define E_SERVICE_GESTURE + +#include "e_policy_private_data.h" + +typedef struct _E_Policy_Gesture E_Policy_Gesture; + +typedef enum +{ + POL_GESTURE_TYPE_NONE, + POL_GESTURE_TYPE_LINE, + POL_GESTURE_TYPE_FLICK, +} E_Policy_Gesture_Type; + +typedef void (*E_Policy_Gesture_Start_Cb)(void *data, Evas_Object *obj, int x, int y, unsigned int timestamp); +typedef void (*E_Policy_Gesture_Move_Cb)(void *data, Evas_Object *obj, int x, int y, unsigned int timestamp); +typedef void (*E_Policy_Gesture_End_Cb)(void *data, Evas_Object *obj, int x, int y, unsigned int timestamp); + +EINTERN E_Policy_Gesture *e_service_gesture_add(Evas_Object *obj, E_Policy_Gesture_Type type); +EINTERN void e_service_gesture_del(E_Policy_Gesture *gesture); +EINTERN void e_service_gesture_cb_set(E_Policy_Gesture *gesture, E_Policy_Gesture_Start_Cb cb_start, E_Policy_Gesture_Move_Cb cb_move, E_Policy_Gesture_End_Cb cb_end, void *data); + +#endif /* E_SERVICE_GESTURE */ diff --git a/src/bin/services/e_service_lockscreen.c b/src/bin/services/e_service_lockscreen.c new file mode 100644 index 0000000000..1bb4c037a2 --- /dev/null +++ b/src/bin/services/e_service_lockscreen.c @@ -0,0 +1,23 @@ +#include "e.h" +#include "services/e_service_lockscreen.h" + +EINTERN Eina_Bool +e_service_lockscreen_client_set(E_Client *ec) +{ + if (!ec) return EINA_TRUE; + if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE; + + ELOGF("LOCKSCREEN","Set Client", ec->pixmap, ec); + + eina_stringshare_replace(&ec->icccm.window_role, "lockscreen"); + + // set lockscreen layer + if (E_LAYER_CLIENT_NOTIFICATION_LOW > evas_object_layer_get(ec->frame)) + { + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_NOTIFICATION_LOW); + ec->layer = E_LAYER_CLIENT_NOTIFICATION_LOW; + } + + return EINA_TRUE; +} + diff --git a/src/bin/services/e_service_lockscreen.h b/src/bin/services/e_service_lockscreen.h new file mode 100644 index 0000000000..51350221b2 --- /dev/null +++ b/src/bin/services/e_service_lockscreen.h @@ -0,0 +1,8 @@ +#ifndef E_SERVICE_LOCKSCREEN_H +#define E_SERVICE_LOCKSCREEN_H + +#include "e_policy_private_data.h" + +EINTERN Eina_Bool e_service_lockscreen_client_set(E_Client *ec); + +#endif diff --git a/src/bin/services/e_service_quickpanel.c b/src/bin/services/e_service_quickpanel.c new file mode 100644 index 0000000000..eec0408c81 --- /dev/null +++ b/src/bin/services/e_service_quickpanel.c @@ -0,0 +1,1613 @@ +#include "e.h" +#include "services/e_service_quickpanel.h" +#include "services/e_service_gesture.h" +#include "services/e_service_region.h" +#include "e_policy_wl.h" + +#define SMART_NAME "quickpanel_object" +#define INTERNAL_ENTRY \ + Mover_Data *md; \ + md = evas_object_smart_data_get(obj) + +#define QP_SHOW(EC) \ +do \ +{ \ + EC->visible = EINA_TRUE; \ + evas_object_show(EC->frame); \ +} while (0) + +#define QP_HIDE(EC) \ +do \ +{ \ + EC->visible = EINA_FALSE; \ + evas_object_hide(EC->frame); \ +} while (0) + +#define QP_VISIBLE_SET(EC, VIS) \ +do \ +{ \ + if (VIS) QP_SHOW(EC); \ + else QP_HIDE(EC); \ +} while(0) + +typedef struct _E_Policy_Quickpanel E_Policy_Quickpanel; +typedef struct _Mover_Data Mover_Data; +typedef struct _Mover_Effect_Data Mover_Effect_Data; + +typedef struct _E_QP_Client E_QP_Client; + +struct _E_Policy_Quickpanel +{ + E_Client *ec; + E_Client *below; + E_Client *stacking; + Evas_Object *mover; + Evas_Object *indi_obj; + Evas_Object *handler_obj; + + Eina_List *intercept_hooks; + Eina_List *hooks; + Eina_List *events; + Ecore_Idle_Enterer *idle_enterer; + Ecore_Event_Handler *buf_change_hdlr; + + struct + { + Eina_Bool below; + } changes; + + E_Policy_Angle_Map rotation; + + Eina_Bool show_block; + + Eina_List *clients; /* list of E_QP_Client */ +}; + +struct _Mover_Data +{ + E_Policy_Quickpanel *qp; + E_Client *ec; + + Evas_Object *smart_obj; //smart object + Evas_Object *qp_layout_obj; // quickpanel's e_layout_object + Evas_Object *handler_mirror_obj; // quickpanel handler mirror object + Evas_Object *base_clip; // clipper for quickapnel base object + Evas_Object *handler_clip; // clipper for quickpanel handler object + + Eina_Rectangle handler_rect; + E_Policy_Angle_Map rotation; + + struct + { + Ecore_Animator *animator; + Mover_Effect_Data *data; + int x, y; + unsigned int timestamp; + float accel; + Eina_Bool visible; + } effect_info; +}; + +struct _Mover_Effect_Data +{ + Ecore_Animator *animator; + Evas_Object *mover; + int from; + int to; + Eina_Bool visible : 1; +}; + +struct _E_QP_Client +{ + E_Client *ec; + struct + { + Eina_Bool vis; + Eina_Bool scrollable; + } hint; +}; + +static E_Policy_Quickpanel *_pol_quickpanel = NULL; +static Evas_Smart *_mover_smart = NULL; +static Eina_Bool _changed = EINA_FALSE; + +static E_QP_Client * _e_qp_client_ec_get(E_Client *ec); +static Eina_Bool _e_qp_client_scrollable_update(void); + +static E_Policy_Quickpanel * +_quickpanel_get() +{ + return _pol_quickpanel; +} + +static void +_mover_intercept_show(void *data, Evas_Object *obj) +{ + Mover_Data *md; + E_Client *ec; + Evas *e; + + md = data; + md->qp->show_block = EINA_FALSE; + + ec = md->ec; + QP_SHOW(ec); + + /* force update */ + e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h); + e_comp_object_dirty(ec->frame); + e_comp_object_render(ec->frame); + + // create base_clip + e = evas_object_evas_get(obj); + md->base_clip = evas_object_rectangle_add(e); + e_layout_pack(md->qp_layout_obj, md->base_clip); + e_layout_child_move(md->base_clip, 0, 0); + e_layout_child_resize(md->base_clip, ec->w, ec->h); + evas_object_color_set(md->base_clip, 255, 255, 255, 255); + evas_object_show(md->base_clip); + evas_object_clip_set(ec->frame, md->base_clip); + + // create handler_mirror_obj + md->handler_mirror_obj = e_comp_object_util_mirror_add(ec->frame); + e_layout_pack(md->qp_layout_obj, md->handler_mirror_obj); + e_layout_child_move(md->handler_mirror_obj, ec->x, ec->y); + e_layout_child_resize(md->handler_mirror_obj, ec->w, ec->h); + evas_object_show(md->handler_mirror_obj); + + // create handler_clip + md->handler_clip = evas_object_rectangle_add(e); + e_layout_pack(md->qp_layout_obj, md->handler_clip); + e_layout_child_move(md->handler_clip, md->handler_rect.x, md->handler_rect.y); + e_layout_child_resize(md->handler_clip, md->handler_rect.w, md->handler_rect.h); + evas_object_color_set(md->handler_clip, 255, 255, 255, 255); + evas_object_show(md->handler_clip); + evas_object_clip_set(md->handler_mirror_obj, md->handler_clip); + + evas_object_show(obj); +} + +static void +_mover_smart_add(Evas_Object *obj) +{ + Mover_Data *md; + + md = E_NEW(Mover_Data, 1); + if (EINA_UNLIKELY(!md)) + return; + + md->smart_obj = obj; + md->qp_layout_obj = e_layout_add(evas_object_evas_get(obj)); + evas_object_color_set(md->qp_layout_obj, 255, 255, 255, 255); + evas_object_smart_member_add(md->qp_layout_obj, md->smart_obj); + + evas_object_smart_data_set(obj, md); + + evas_object_move(obj, -1 , -1); + evas_object_layer_set(obj, EVAS_LAYER_MAX - 1); // EVAS_LAYER_MAX :L cursor layer + evas_object_intercept_show_callback_add(obj, _mover_intercept_show, md); +} + +static void +_mover_smart_del(Evas_Object *obj) +{ + E_Client *ec; + + INTERNAL_ENTRY; + + ec = md->qp->ec; + if (md->base_clip) + { + evas_object_clip_unset(md->base_clip); + e_layout_unpack(md->base_clip); + evas_object_del(md->base_clip); + } + if (md->handler_clip) + { + evas_object_clip_unset(md->handler_clip); + e_layout_unpack(md->handler_clip); + evas_object_del(md->handler_clip); + } + if (md->handler_mirror_obj) + { + e_layout_unpack(md->handler_mirror_obj); + evas_object_del(md->handler_mirror_obj); + } + + if (md->qp_layout_obj) evas_object_del(md->qp_layout_obj); + + evas_object_color_set(ec->frame, ec->netwm.opacity, ec->netwm.opacity, ec->netwm.opacity, ec->netwm.opacity); + + md->qp->mover = NULL; + + e_zone_orientation_block_set(md->qp->ec->zone, "quickpanel-mover", EINA_FALSE); + + free(md); +} + +static void +_mover_smart_show(Evas_Object *obj) +{ + INTERNAL_ENTRY; + + evas_object_show(md->qp_layout_obj); +} + +static void +_mover_smart_hide(Evas_Object *obj) +{ + INTERNAL_ENTRY; + + evas_object_hide(md->qp_layout_obj); +} + +static void +_mover_smart_move(Evas_Object *obj, int x, int y) +{ + INTERNAL_ENTRY; + + evas_object_move(md->qp_layout_obj, x, y); +} + +static void +_mover_smart_resize(Evas_Object *obj, int w, int h) +{ + INTERNAL_ENTRY; + + e_layout_virtual_size_set(md->qp_layout_obj, w, h); + evas_object_resize(md->qp_layout_obj, w, h); +} + +static void +_mover_smart_init(void) +{ + if (_mover_smart) return; + { + static const Evas_Smart_Class sc = + { + SMART_NAME, + EVAS_SMART_CLASS_VERSION, + _mover_smart_add, + _mover_smart_del, + _mover_smart_move, + _mover_smart_resize, + _mover_smart_show, + _mover_smart_hide, + NULL, /* color_set */ + NULL, /* clip_set */ + NULL, /* clip_unset */ + NULL, /* calculate */ + NULL, /* member_add */ + NULL, /* member_del */ + + NULL, /* parent */ + NULL, /* callbacks */ + NULL, /* interfaces */ + NULL /* data */ + }; + _mover_smart = evas_smart_class_new(&sc); + } +} + +static Eina_Bool +_mover_obj_handler_move(Mover_Data *md, int x, int y) +{ + E_Zone *zone; + E_Client *ec; + + ec = md->ec; + zone = ec->zone; + switch (md->rotation) + { + case E_POLICY_ANGLE_MAP_90: + if ((x + md->handler_rect.w) > zone->w) return EINA_FALSE; + + md->handler_rect.x = x; + e_layout_child_resize(md->base_clip, md->handler_rect.x, ec->h); + e_layout_child_move(md->handler_mirror_obj, md->handler_rect.x - ec->w + md->handler_rect.w, md->handler_rect.y); + e_layout_child_move(md->handler_clip, md->handler_rect.x, md->handler_rect.y); + break; + case E_POLICY_ANGLE_MAP_180: + if ((y - md->handler_rect.h) < 0) return EINA_FALSE; + + md->handler_rect.y = y; + e_layout_child_move(md->base_clip, md->handler_rect.x, md->handler_rect.y); + e_layout_child_resize(md->base_clip, ec->w, ec->h - md->handler_rect.y); + e_layout_child_move(md->handler_mirror_obj, md->handler_rect.x, md->handler_rect.y - md->handler_rect.h); + e_layout_child_move(md->handler_clip, md->handler_rect.x, md->handler_rect.y - md->handler_rect.h); + break; + case E_POLICY_ANGLE_MAP_270: + if ((x - md->handler_rect.w) < 0) return EINA_FALSE; + + md->handler_rect.x = x; + e_layout_child_move(md->base_clip, md->handler_rect.x, md->handler_rect.y); + e_layout_child_resize(md->base_clip, ec->w - md->handler_rect.x, ec->h); + e_layout_child_move(md->handler_mirror_obj, md->handler_rect.x - md->handler_rect.w, md->handler_rect.y); + e_layout_child_move(md->handler_clip, md->handler_rect.x - md->handler_rect.w, md->handler_rect.y); + break; + default: + if ((y + md->handler_rect.h) > zone->h) return EINA_FALSE; + + md->handler_rect.y = y; + e_layout_child_resize(md->base_clip, ec->w, md->handler_rect.y); + e_layout_child_move(md->handler_mirror_obj, md->handler_rect.x, md->handler_rect.y - ec->h + md->handler_rect.h); + e_layout_child_move(md->handler_clip, md->handler_rect.x, md->handler_rect.y); + } + + return EINA_TRUE; +} + +static Evas_Object * +_mover_obj_new(E_Policy_Quickpanel *qp) +{ + Evas_Object *mover; + Mover_Data *md; + int x, y, w, h; + + /* Pause changing zone orientation during mover object is working. */ + e_zone_orientation_block_set(qp->ec->zone, "quickpanel-mover", EINA_TRUE); + + _mover_smart_init(); + mover = evas_object_smart_add(evas_object_evas_get(qp->ec->frame), _mover_smart); + + /* Should setup 'md' before call evas_object_show() */ + md = evas_object_smart_data_get(mover); + md->qp = qp; + md->ec = qp->ec; + md->rotation = qp->rotation; + + e_service_region_rectangle_get(qp->handler_obj, qp->rotation, &x, &y, &w, &h); + EINA_RECTANGLE_SET(&md->handler_rect, x, y, w, h); + + evas_object_move(mover, 0, 0); + evas_object_resize(mover, qp->ec->w, qp->ec->h); + evas_object_show(mover); + + qp->mover = mover; + qp->show_block = EINA_FALSE; + + return mover; +} + +static Evas_Object * +_mover_obj_new_with_move(E_Policy_Quickpanel *qp, int x, int y, unsigned int timestamp) +{ + Evas_Object *mover; + Mover_Data *md; + + mover = _mover_obj_new(qp); + if (!mover) + return NULL; + + md = evas_object_smart_data_get(mover); + md->effect_info.x = x; + md->effect_info.y = y; + md->effect_info.timestamp = timestamp; + + _mover_obj_handler_move(md, x, y); + + return mover; +} + +static void +_mover_obj_visible_set(Evas_Object *mover, Eina_Bool visible) +{ + Mover_Data *md; + E_Client *ec; + int x = 0, y = 0; + + md = evas_object_smart_data_get(mover); + ec = md->ec; + + switch (md->rotation) + { + case E_POLICY_ANGLE_MAP_90: + x = visible ? ec->zone->w : 0; + break; + case E_POLICY_ANGLE_MAP_180: + y = visible ? 0 : ec->zone->h; + break; + case E_POLICY_ANGLE_MAP_270: + x = visible ? 0 : ec->zone->w; + break; + default: + y = visible ? ec->zone->h : 0; + break; + } + + _mover_obj_handler_move(md, x, y); +} + +static Eina_Bool +_mover_obj_move(Evas_Object *mover, int x, int y, unsigned int timestamp) +{ + Mover_Data *md; + int dp; + unsigned int dt; + + if (!mover) return EINA_FALSE; + + md = evas_object_smart_data_get(mover); + if (!_mover_obj_handler_move(md, x, y)) return EINA_FALSE; + + /* Calculate the acceleration of movement, + * determine the visibility of quickpanel based on the result. */ + dt = timestamp - md->effect_info.timestamp; + switch (md->rotation) + { + case E_POLICY_ANGLE_MAP_90: + dp = x - md->effect_info.x; + break; + case E_POLICY_ANGLE_MAP_180: + dp = md->effect_info.y - y; + break; + case E_POLICY_ANGLE_MAP_270: + dp = md->effect_info.x - x; + break; + default: + dp = y - md->effect_info.y; + break; + } + if (dt) md->effect_info.accel = (float)dp / (float)dt; + + /* Store current information to next calculation */ + md->effect_info.x = x; + md->effect_info.y = y; + md->effect_info.timestamp = timestamp; + + return EINA_TRUE; +} + +static Mover_Effect_Data * +_mover_obj_effect_data_new(Evas_Object *mover, int from, int to, Eina_Bool visible) +{ + Mover_Effect_Data *ed; + + ed = E_NEW(Mover_Effect_Data, 1); + if (!ed) return NULL; + + ed->mover = mover; + ed->visible = visible; + ed->from = from; + ed->to = to; + + return ed; +} + +static void +_mover_obj_effect_cb_mover_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Mover_Effect_Data *ed = data; + Mover_Data *md; + + ed = data; + md = evas_object_smart_data_get(ed->mover); + QP_VISIBLE_SET(md->qp->ec, ed->visible); + + /* make sure NULL before calling ecore_animator_del() */ + ed->mover = NULL; + + ecore_animator_del(ed->animator); + ed->animator = NULL; +} + +static void +_mover_obj_effect_data_free(Mover_Effect_Data *ed) +{ + E_Policy_Quickpanel *qp; + Mover_Data *md; + E_QP_Client *qp_client; + Eina_List *l; + + if (ed->mover) + { + md = evas_object_smart_data_get(ed->mover); + QP_VISIBLE_SET(md->qp->ec, ed->visible); + + evas_object_event_callback_del(ed->mover, EVAS_CALLBACK_DEL, _mover_obj_effect_cb_mover_obj_del); + evas_object_del(ed->mover); + } + + qp = _quickpanel_get(); + if (qp) + { + EINA_LIST_FOREACH(qp->clients, l, qp_client) + e_tzsh_qp_state_visible_update(qp_client->ec, + ed->visible); + } + + free(ed); +} + +static Eina_Bool +_mover_obj_effect_update(void *data, double pos) +{ + Mover_Effect_Data *ed = data; + Mover_Data *md; + int new_x = 0, new_y = 0; + double progress = 0; + + progress = ecore_animator_pos_map(pos, ECORE_POS_MAP_DECELERATE, 0, 0); + + md = evas_object_smart_data_get(ed->mover); + + switch (md->rotation) + { + case E_POLICY_ANGLE_MAP_90: + case E_POLICY_ANGLE_MAP_270: + new_x = ed->from + (ed->to * progress); + break; + default: + case E_POLICY_ANGLE_MAP_180: + new_y = ed->from + (ed->to * progress); + break; + } + _mover_obj_handler_move(md, new_x, new_y); + + if (pos == 1.0) + { + ecore_animator_del(ed->animator); + ed->animator = NULL; + + _mover_obj_effect_data_free(ed); + + return ECORE_CALLBACK_CANCEL; + } + + return ECORE_CALLBACK_PASS_ON; +} + +static void +_mover_obj_effect_start(Evas_Object *mover, Eina_Bool visible) +{ + Mover_Data *md; + E_Client *ec; + Mover_Effect_Data *ed; + int from; + int to; + double duration; + const double ref = 0.1; + + md = evas_object_smart_data_get(mover); + ec = md->qp->ec; + + switch (md->rotation) + { + case E_POLICY_ANGLE_MAP_90: + from = md->handler_rect.x; + to = (visible) ? (ec->zone->w - from) : (-from); + duration = ((double)abs(to) / (ec->zone->w / 2)) * ref; + break; + case E_POLICY_ANGLE_MAP_180: + from = md->handler_rect.y; + to = (visible) ? (-from) : (ec->zone->h - from); + duration = ((double)abs(to) / (ec->zone->h / 2)) * ref; + break; + case E_POLICY_ANGLE_MAP_270: + from = md->handler_rect.x; + to = (visible) ? (-from) : (ec->zone->w - from); + duration = ((double)abs(to) / (ec->zone->w / 2)) * ref; + break; + default: + from = md->handler_rect.y; + to = (visible) ? (ec->zone->h - from) : (-from); + duration = ((double)abs(to) / (ec->zone->h / 2)) * ref; + break; + } + + /* create effect data */ + ed = _mover_obj_effect_data_new(mover, from, to, visible); + + /* start move effect */ + ed->animator = ecore_animator_timeline_add(duration, + _mover_obj_effect_update, + ed); + + evas_object_event_callback_add(mover, EVAS_CALLBACK_DEL, _mover_obj_effect_cb_mover_obj_del, ed); + + md->effect_info.animator = ed->animator; + md->effect_info.visible = visible; + md->effect_info.data = ed; +} + +static void +_mover_obj_effect_stop(Evas_Object *mover) +{ + Mover_Data *md; + + md = evas_object_smart_data_get(mover); + md->effect_info.data->mover = NULL; + + evas_object_event_callback_del(mover, EVAS_CALLBACK_DEL, _mover_obj_effect_cb_mover_obj_del); + + E_FREE_FUNC(md->effect_info.animator, ecore_animator_del); +} + +static Eina_Bool +_mover_obj_visibility_eval(Evas_Object *mover) +{ + E_Client *ec; + Mover_Data *md; + Eina_Bool threshold; + const float sensitivity = 1.5; /* hard coded. (arbitrary) */ + + md = evas_object_smart_data_get(mover); + ec = md->ec; + + switch (md->rotation) + { + case E_POLICY_ANGLE_MAP_90: + threshold = (md->handler_rect.x > (ec->zone->w / 2)); + break; + case E_POLICY_ANGLE_MAP_180: + threshold = (md->handler_rect.y < (ec->zone->h / 2)); + break; + case E_POLICY_ANGLE_MAP_270: + threshold = (md->handler_rect.x < (ec->zone->w / 2)); + break; + default: + threshold = (md->handler_rect.y > (ec->zone->h / 2)); + break; + } + + if ((md->effect_info.accel > sensitivity) || + ((md->effect_info.accel > -sensitivity) && threshold)) + return EINA_TRUE; + + return EINA_FALSE; +} + +static Eina_Bool +_mover_obj_is_animating(Evas_Object *mover) +{ + Mover_Data *md; + + md = evas_object_smart_data_get(mover); + + return !!md->effect_info.animator; +} + +static Eina_Bool +_mover_obj_effect_visible_get(Evas_Object *mover) +{ + Mover_Data *md; + + md = evas_object_smart_data_get(mover); + + return md->effect_info.visible; +} + +static void +_region_obj_cb_gesture_start(void *data, Evas_Object *handler, int x, int y, unsigned int timestamp) +{ + E_Policy_Quickpanel *qp; + + qp = data; + if (EINA_UNLIKELY(!qp)) + return; + + if (EINA_UNLIKELY(!qp->ec)) + return; + + if (e_object_is_del(E_OBJECT(qp->ec))) + return; + + if (qp->mover) + { + if (_mover_obj_is_animating(qp->mover)) + return; + + DBG("Mover object already existed"); + evas_object_del(qp->mover); + } + + _mover_obj_new_with_move(qp, x, y, timestamp); +} + +static void +_region_obj_cb_gesture_move(void *data, Evas_Object *handler, int x, int y, unsigned int timestamp) +{ + E_Policy_Quickpanel *qp; + + qp = data; + if (!qp->mover) + return; + + if (_mover_obj_is_animating(qp->mover)) + return; + + _mover_obj_move(qp->mover, x, y, timestamp); +} + +static void +_region_obj_cb_gesture_end(void *data EINA_UNUSED, Evas_Object *handler, int x, int y, unsigned int timestamp) +{ + E_Policy_Quickpanel *qp; + Eina_Bool v; + + qp = data; + if (!qp->mover) + { + DBG("Could not find quickpanel mover object"); + return; + } + + if (_mover_obj_is_animating(qp->mover)) + return; + + v = _mover_obj_visibility_eval(qp->mover); + _mover_obj_effect_start(qp->mover, v); +} + +static void +_quickpanel_free(E_Policy_Quickpanel *qp) +{ + E_FREE_LIST(qp->clients, free); + E_FREE_FUNC(qp->mover, evas_object_del); + E_FREE_FUNC(qp->indi_obj, evas_object_del); + E_FREE_FUNC(qp->handler_obj, evas_object_del); + E_FREE_FUNC(qp->idle_enterer, ecore_idle_enterer_del); + E_FREE_LIST(qp->events, ecore_event_handler_del); + E_FREE_LIST(qp->hooks, e_client_hook_del); + E_FREE_LIST(qp->intercept_hooks, e_comp_object_intercept_hook_del); + E_FREE(_pol_quickpanel); +} + +static void +_quickpanel_hook_client_del(void *d, E_Client *ec) +{ + E_Policy_Quickpanel *qp; + + qp = d; + if (EINA_UNLIKELY(!qp)) + return; + + if (!ec) return; + + if (qp->ec != ec) + return; + + _quickpanel_free(qp); + + e_zone_orientation_force_update_del(ec->zone, ec); +} + +static void +_quickpanel_client_evas_cb_show(void *data, Evas *evas, Evas_Object *obj, void *event) +{ + E_Policy_Quickpanel *qp; + + qp = data; + if (EINA_UNLIKELY(!qp)) + return; + + evas_object_show(qp->handler_obj); + evas_object_raise(qp->handler_obj); + evas_object_hide(qp->indi_obj); + + E_FREE_FUNC(qp->buf_change_hdlr, ecore_event_handler_del); +} + +static Eina_Bool +_quickpanel_cb_buffer_change(void *data, int type, void *event) +{ + E_Policy_Quickpanel *qp; + E_Event_Client *ev; + E_Client *ec; + + qp = data; + if (!qp->ec) + goto end; + + ev = event; + ec = ev->ec; + if (qp->ec != ec) + goto end; + + /* render forcibly */ + e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h); + e_comp_object_dirty(ec->frame); + e_comp_object_render(ec->frame); + + /* make frame event */ + e_pixmap_image_clear(ec->pixmap, EINA_TRUE); + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static void +_quickpanel_client_evas_cb_hide(void *data, Evas *evas, Evas_Object *obj, void *event) +{ + E_Policy_Quickpanel *qp; + + qp = data; + if (EINA_UNLIKELY(!qp)) + return; + + evas_object_hide(qp->handler_obj); + evas_object_show(qp->indi_obj); +} + +static void +_quickpanel_client_evas_cb_move(void *data, Evas *evas, Evas_Object *obj, void *event) +{ + E_Policy_Quickpanel *qp; + int x, y, hx, hy; + + qp = data; + if (EINA_UNLIKELY(!qp)) + return; + + e_service_region_rectangle_get(qp->handler_obj, qp->rotation, &hx, &hy, NULL, NULL); + evas_object_geometry_get(obj, &x, &y, NULL, NULL); + evas_object_move(qp->handler_obj, x + hx, y + hy); +} + +static void +_quickpanel_handler_rect_add(E_Policy_Quickpanel *qp, E_Policy_Angle_Map ridx, int x, int y, int w, int h) +{ + E_Client *ec; + Evas_Object *obj; + + ec = qp->ec; + + ELOGF("QUICKPANEL", "Handler Geo Set | x %d, y %d, w %d, h %d", + NULL, NULL, x, y, w, h); + + if (qp->handler_obj) + goto end; + + obj = e_service_region_object_new(); + evas_object_name_set(obj, "qp::handler_obj"); + if (!obj) + return; + + e_service_region_cb_set(obj, + _region_obj_cb_gesture_start, + _region_obj_cb_gesture_move, + _region_obj_cb_gesture_end, qp); + + /* Add handler object to smart member to follow the client's stack */ + evas_object_smart_member_add(obj, ec->frame); + evas_object_propagate_events_set(obj, 0); + if (evas_object_visible_get(ec->frame)) + evas_object_show(obj); + + qp->handler_obj = obj; + +end: + e_service_region_rectangle_set(qp->handler_obj, ridx, x, y, w, h); +} + +static void +_quickpanel_handler_region_set(E_Policy_Quickpanel *qp, E_Policy_Angle_Map ridx, Eina_Tiler *tiler) +{ + Eina_Iterator *it; + Eina_Rectangle *r; + int x = 0, y = 0; + + /* FIXME supported single rectangle, not tiler */ + + it = eina_tiler_iterator_new(tiler); + EINA_ITERATOR_FOREACH(it, r) + { + _quickpanel_handler_rect_add(qp, ridx, r->x, r->y, r->w, r->h); + + /* FIXME: this should be set by another way like indicator */ + if (ridx == E_POLICY_ANGLE_MAP_180) + { + x = 0; + y = qp->ec->zone->h - r->h; + } + else if (ridx == E_POLICY_ANGLE_MAP_270) + { + x = qp->ec->zone->w - r->w; + y = 0; + } + e_service_region_rectangle_set(qp->indi_obj, ridx, x, y, r->w, r->h); + + break; + } + eina_iterator_free(it); +} + +static void +_e_qp_vis_change(E_Policy_Quickpanel *qp, Eina_Bool vis, Eina_Bool with_effect) +{ + E_Client *ec; + Evas_Object *mover; + Eina_Bool res, cur_vis = EINA_FALSE; + int x, y, w, h; + + res = _e_qp_client_scrollable_update(); + if (!res) return; + + ec = qp->ec; + + evas_object_geometry_get(ec->frame, &x, &y, &w, &h); + + if (E_INTERSECTS(x, y, w, h, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h)) + cur_vis = evas_object_visible_get(ec->frame); + + if (cur_vis == vis) + return; + + mover = qp->mover; + + if (with_effect) + { + if (mover) + { + if (_mover_obj_is_animating(mover)) + { + if (_mover_obj_effect_visible_get(mover) == vis) + return; + + _mover_obj_effect_stop(mover); + } + } + else + { + mover = _mover_obj_new(qp); + _mover_obj_visible_set(mover, !vis); + } + + _mover_obj_effect_start(mover, vis); + } + else + { + if (mover) + { + if (_mover_obj_is_animating(mover)) + _mover_obj_effect_stop(mover); + evas_object_del(mover); + } + + QP_VISIBLE_SET(ec, vis); + } +} + +static Eina_Bool +_quickpanel_cb_rotation_begin(void *data, int type, void *event) +{ + E_Policy_Quickpanel *qp; + E_Event_Client *ev = event; + E_Client *ec; + + qp = data; + if (EINA_UNLIKELY(!qp)) + goto end; + + ec = ev->ec; + if (EINA_UNLIKELY(!ec)) + goto end; + + if (qp->ec != ec) + goto end; + + E_FREE_FUNC(qp->mover, evas_object_del); + + evas_object_hide(qp->indi_obj); + evas_object_hide(qp->handler_obj); + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_quickpanel_cb_rotation_cancel(void *data, int type, void *event) +{ + E_Policy_Quickpanel *qp; + E_Event_Client *ev = event; + E_Client *ec; + + qp = data; + if (EINA_UNLIKELY(!qp)) + goto end; + + ec = ev->ec; + if (EINA_UNLIKELY(!ec)) + goto end; + + if (qp->ec != ec) + goto end; + + if (evas_object_visible_get(ec->frame)) + evas_object_show(qp->handler_obj); + else + evas_object_show(qp->indi_obj); + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_quickpanel_cb_rotation_done(void *data, int type, void *event) +{ + E_Policy_Quickpanel *qp; + E_Event_Client *ev = event; + E_Client *ec; + E_QP_Client *qp_client; + Eina_List *l; + + qp = data; + if (EINA_UNLIKELY(!qp)) + goto end; + + ec = ev->ec; + if (EINA_UNLIKELY(!ec)) + goto end; + + if (qp->ec != ec) + goto end; + + qp->rotation = e_policy_angle_map(ec->e.state.rot.ang.curr); + + if (evas_object_visible_get(ec->frame)) + evas_object_show(qp->handler_obj); + else + evas_object_show(qp->indi_obj); + + EINA_LIST_FOREACH(qp->clients, l, qp_client) + e_tzsh_qp_state_orientation_update(qp_client->ec, + qp->rotation); + +end: + return ECORE_CALLBACK_PASS_ON; +} + +/* NOTE: if the state(show/hide/stack) of windows which are stacked below + * quickpanel is changed, we close the quickpanel. + * the most major senario is that quickpanel should be closed when WiFi popup to + * show the available connection list is shown by click the button on + * the quickpanel to turn on the WiFi. + * @see _quickpanel_cb_client_show(), + * _quickpanel_cb_client_hide() + * _quickpanel_cb_client_stack() + * _quickpanel_cb_client_remove() + * _quickpanel_idle_enter() + */ +static E_Client * +_quickpanel_below_visible_client_get(E_Policy_Quickpanel *qp) +{ + E_Client *ec; + + for (ec = e_client_below_get(qp->ec); ec; ec = e_client_below_get(ec)) + { + if (!ec->visible) continue; + if (!ec->icccm.accepts_focus) continue; + + return ec; + } + + return NULL; +} + +static void +_quickpanel_below_change_eval(void *data, void *event) +{ + E_Policy_Quickpanel *qp; + E_Event_Client *ev; + + qp = data; + if (EINA_UNLIKELY(!qp)) + return; + + ev = event; + if (EINA_UNLIKELY((!ev) || (!ev->ec))) + return; + + if (e_policy_client_is_cursor(ev->ec)) + return; + + qp->changes.below = EINA_TRUE; + _changed = EINA_TRUE; +} + +static Eina_Bool +_quickpanel_cb_client_show(void *data, int type, void *event) +{ + _quickpanel_below_change_eval(data, event); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_quickpanel_cb_client_hide(void *data, int type, void *event) +{ + _quickpanel_below_change_eval(data, event); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_quickpanel_cb_client_stack(void *data, int type, void *event) +{ + E_Policy_Quickpanel *qp; + E_Event_Client *ev; + + qp = data; + EINA_SAFETY_ON_NULL_GOTO(qp, end); + + ev = event; + EINA_SAFETY_ON_NULL_GOTO(ev, end); + + qp->stacking = ev->ec; + + DBG("Stacking Client '%s'(%p)", + ev->ec->icccm.name ? ev->ec->icccm.name : "", ev->ec); + + _quickpanel_below_change_eval(data, event); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_quickpanel_cb_client_remove(void *data, int type, void *event) +{ + _quickpanel_below_change_eval(data, event); + return ECORE_CALLBACK_PASS_ON; +} + +static Evas_Object * +_quickpanel_indicator_object_new(E_Policy_Quickpanel *qp) +{ + Evas_Object *indi_obj; + + indi_obj = e_service_region_object_new(); + evas_object_name_set(indi_obj, "qp::indicator_obj"); + if (!indi_obj) + return NULL; + + evas_object_repeat_events_set(indi_obj, EINA_FALSE); + /* FIXME: make me move to explicit layer something like POL_LAYER */ + evas_object_layer_set(indi_obj, EVAS_LAYER_MAX - 1); + + e_service_region_cb_set(indi_obj, + _region_obj_cb_gesture_start, + _region_obj_cb_gesture_move, + _region_obj_cb_gesture_end, qp); + + evas_object_show(indi_obj); + + return indi_obj; +} + +static Eina_Bool +_quickpanel_idle_enter(void *data) +{ + E_Policy_Quickpanel *qp; + + if (!_changed) + goto end; + _changed = EINA_FALSE; + + qp = data; + if (EINA_UNLIKELY(!qp)) + goto end; + + if (qp->changes.below) + { + E_Client *below; + + below = _quickpanel_below_visible_client_get(qp); + if (qp->below != below) + { + DBG("qp->below '%s'(%p) new_below '%s'(%p)\n", + qp->below ? (qp->below->icccm.name ? qp->below->icccm.name : "") : "", + qp->below, + below ? (below->icccm.name ? below->icccm.name : "") : "", + below); + + qp->below = below; + + /* QUICKFIX + * hide the quickpanel, if below client is the stacking client. + * it means to find out whether or not it was launched. + */ + if ((qp->stacking == below) && + (qp->ec->visible)) + e_service_quickpanel_hide(); + + _e_qp_client_scrollable_update(); + } + + qp->stacking = NULL; + qp->changes.below = EINA_FALSE; + } + +end: + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_quickpanel_intercept_hook_show(void *data, E_Client *ec) +{ + E_Policy_Quickpanel *qp; + + qp = data; + if (EINA_UNLIKELY(!qp)) + goto end; + + if (qp->ec != ec) + goto end; + + if (qp->show_block) + { + ec->visible = EINA_FALSE; + return EINA_FALSE; + } + +end: + return EINA_TRUE; +} + +static E_QP_Client * +_e_qp_client_ec_get(E_Client *ec) +{ + E_Policy_Quickpanel *qp = _quickpanel_get(); + E_QP_Client *qp_client = NULL; + Eina_List *l; + + EINA_LIST_FOREACH(qp->clients, l, qp_client) + { + if (qp_client->ec == ec) + return qp_client; + } + + return qp_client; +} + +/* return value + * EINA_TRUE : user can scrool the QP. + * EINA_FALSE: user can't scroll QP since below window doesn't want. + */ +static Eina_Bool +_e_qp_client_scrollable_update(void) +{ + E_Policy_Quickpanel *qp; + E_QP_Client *qp_client; + Eina_Bool res = EINA_TRUE; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp->ec, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(qp->ec)), EINA_FALSE); + + if (!qp->below) + { + evas_object_pass_events_set(qp->handler_obj, EINA_FALSE); + evas_object_pass_events_set(qp->indi_obj, EINA_FALSE); + return EINA_TRUE; + } + + /* Do not show and scroll the quickpanel window if the qp_client winodw + * which is placed at the below of the quickpanel window doesn't want + * to show and scroll the quickpanel window. + */ + qp_client = _e_qp_client_ec_get(qp->below); + if ((qp_client) && (!qp_client->hint.scrollable)) + { + evas_object_pass_events_set(qp->handler_obj, EINA_TRUE); + evas_object_pass_events_set(qp->indi_obj, EINA_TRUE); + res = EINA_FALSE; + } + else + { + evas_object_pass_events_set(qp->handler_obj, EINA_FALSE); + evas_object_pass_events_set(qp->indi_obj, EINA_FALSE); + res = EINA_TRUE; + } + + return res; +} + + +#undef E_CLIENT_HOOK_APPEND +#define E_CLIENT_HOOK_APPEND(l, t, cb, d) \ + do \ + { \ + E_Client_Hook *_h; \ + _h = e_client_hook_add(t, cb, d); \ + assert(_h); \ + l = eina_list_append(l, _h); \ + } \ + while (0) + +#undef E_COMP_OBJECT_INTERCEPT_HOOK_APPEND +#define E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(l, t, cb, d) \ + do \ + { \ + E_Comp_Object_Intercept_Hook *_h; \ + _h = e_comp_object_intercept_hook_add(t, cb, d); \ + assert(_h); \ + l = eina_list_append(l, _h); \ + } \ + while (0) + +/* NOTE: supported single client for quickpanel for now. */ +EINTERN void +e_service_quickpanel_client_set(E_Client *ec) +{ + E_Policy_Quickpanel *qp; + + if (EINA_UNLIKELY(!ec)) + { + qp = _quickpanel_get(); + if (qp) + _quickpanel_free(qp); + return; + } + + /* check for client being deleted */ + if (e_object_is_del(E_OBJECT(ec))) return; + + /* check for wayland pixmap */ + if (e_pixmap_type_get(ec->pixmap) != E_PIXMAP_TYPE_WL) return; + + /* if we have not setup evas callbacks for this client, do it */ + if (_pol_quickpanel) return; + + ELOGF("QUICKPANEL", "Set Client | ec %p", NULL, NULL, ec); + + qp = calloc(1, sizeof(*qp)); + if (!qp) + return; + + _pol_quickpanel = qp; + + qp->ec = ec; + qp->show_block = EINA_TRUE; + qp->below = _quickpanel_below_visible_client_get(qp); + qp->indi_obj = _quickpanel_indicator_object_new(qp); + if (!qp->indi_obj) + { + free(qp); + return; + } + + eina_stringshare_replace(&ec->icccm.window_role, "quickpanel"); + + // set quickpanel layer + if (E_POLICY_QUICKPANEL_LAYER != evas_object_layer_get(ec->frame)) + { + evas_object_layer_set(ec->frame, E_POLICY_QUICKPANEL_LAYER); + } + ec->layer = E_POLICY_QUICKPANEL_LAYER; + + // set skip iconify + ec->exp_iconify.skip_iconify = 1; + ec->e.state.rot.type = E_CLIENT_ROTATION_TYPE_DEPENDENT; + + /* add quickpanel to force update list of zone */ + e_zone_orientation_force_update_add(ec->zone, ec); + + QP_HIDE(ec); + + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW, _quickpanel_client_evas_cb_show, qp); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE, _quickpanel_client_evas_cb_hide, qp); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE, _quickpanel_client_evas_cb_move, qp); + + E_CLIENT_HOOK_APPEND(qp->hooks, E_CLIENT_HOOK_DEL, _quickpanel_hook_client_del, qp); + E_LIST_HANDLER_APPEND(qp->events, E_EVENT_CLIENT_ROTATION_CHANGE_BEGIN, _quickpanel_cb_rotation_begin, qp); + E_LIST_HANDLER_APPEND(qp->events, E_EVENT_CLIENT_ROTATION_CHANGE_CANCEL, _quickpanel_cb_rotation_cancel, qp); + E_LIST_HANDLER_APPEND(qp->events, E_EVENT_CLIENT_ROTATION_CHANGE_END, _quickpanel_cb_rotation_done, qp); + E_LIST_HANDLER_APPEND(qp->events, E_EVENT_CLIENT_SHOW, _quickpanel_cb_client_show, qp); + E_LIST_HANDLER_APPEND(qp->events, E_EVENT_CLIENT_HIDE, _quickpanel_cb_client_hide, qp); + E_LIST_HANDLER_APPEND(qp->events, E_EVENT_CLIENT_STACK, _quickpanel_cb_client_stack, qp); + E_LIST_HANDLER_APPEND(qp->events, E_EVENT_CLIENT_REMOVE, _quickpanel_cb_client_remove, qp); + E_LIST_HANDLER_APPEND(qp->events, E_EVENT_CLIENT_BUFFER_CHANGE, _quickpanel_cb_buffer_change, qp); + + E_COMP_OBJECT_INTERCEPT_HOOK_APPEND(qp->intercept_hooks, E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER, _quickpanel_intercept_hook_show, qp); + + + qp->idle_enterer = ecore_idle_enterer_add(_quickpanel_idle_enter, qp); +} + +EINTERN E_Client * +e_service_quickpanel_client_get(void) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(_pol_quickpanel, NULL); + + return _pol_quickpanel->ec; +} + +EINTERN Eina_Bool +e_service_quickpanel_region_set(int type, int angle, Eina_Tiler *tiler) +{ + E_Policy_Quickpanel *qp; + E_Policy_Angle_Map ridx; + + qp = _quickpanel_get(); + if (EINA_UNLIKELY(!qp)) + return EINA_FALSE; + + if (EINA_UNLIKELY(!qp->ec)) + return EINA_FALSE; + + if (e_object_is_del(E_OBJECT(qp->ec))) + return EINA_FALSE; + + // FIXME: region type + if (type != 0) + return EINA_FALSE; + + ridx = e_policy_angle_map(angle); + _quickpanel_handler_region_set(qp, ridx, tiler); + + return EINA_TRUE; +} + +EINTERN void +e_service_quickpanel_show(void) +{ + E_Policy_Quickpanel *qp; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN(qp); + EINA_SAFETY_ON_NULL_RETURN(qp->ec); + EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(qp->ec))); + + _e_qp_vis_change(qp, EINA_TRUE, EINA_TRUE); +} + +EINTERN void +e_service_quickpanel_hide(void) +{ + E_Policy_Quickpanel *qp; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN(qp); + EINA_SAFETY_ON_NULL_RETURN(qp->ec); + EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(qp->ec))); + + _e_qp_vis_change(qp, EINA_FALSE, EINA_TRUE); +} + +EINTERN Eina_Bool +e_qp_visible_get(void) +{ + E_Policy_Quickpanel *qp; + E_Client *ec; + Eina_Bool vis = EINA_FALSE; + int x, y, w, h; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp->ec, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(qp->ec)), EINA_FALSE); + + ec = qp->ec; + evas_object_geometry_get(ec->frame, &x, &y, &w, &h); + + if (E_INTERSECTS(x, y, w, h, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h)) + vis = evas_object_visible_get(ec->frame); + + return vis; +} + +EINTERN int +e_qp_orientation_get(void) +{ + E_Policy_Quickpanel *qp; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp, E_POLICY_ANGLE_MAP_0); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp->ec, E_POLICY_ANGLE_MAP_0); + EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(qp->ec)), E_POLICY_ANGLE_MAP_0); + + return qp->rotation; +} + +EINTERN void +e_qp_client_add(E_Client *ec) +{ + E_Policy_Quickpanel *qp; + E_QP_Client *qp_client; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN(qp); + EINA_SAFETY_ON_NULL_RETURN(qp->ec); + EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(qp->ec))); + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(ec))); + + qp_client = E_NEW(E_QP_Client, 1); + qp_client->ec = ec; + qp_client->hint.vis = EINA_TRUE; + qp_client->hint.scrollable = EINA_TRUE; + + qp->clients = eina_list_append(qp->clients, qp_client); +} + +EINTERN void +e_qp_client_del(E_Client *ec) +{ + E_Policy_Quickpanel *qp; + E_QP_Client *qp_client; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN(qp); + EINA_SAFETY_ON_NULL_RETURN(ec); + + qp_client = _e_qp_client_ec_get(ec); + EINA_SAFETY_ON_NULL_RETURN(qp_client); + + qp->clients = eina_list_remove(qp->clients, qp_client); + + E_FREE(qp_client); +} + +EINTERN void +e_qp_client_show(E_Client *ec) +{ + E_Policy_Quickpanel *qp; + E_QP_Client *qp_client; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN(qp); + EINA_SAFETY_ON_NULL_RETURN(qp->ec); + EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(qp->ec))); + + qp_client = _e_qp_client_ec_get(ec); + EINA_SAFETY_ON_NULL_RETURN(qp_client); + EINA_SAFETY_ON_FALSE_RETURN(qp_client->hint.scrollable); + + _e_qp_vis_change(qp, EINA_TRUE, EINA_TRUE); +} + +EINTERN void +e_qp_client_hide(E_Client *ec) +{ + E_Policy_Quickpanel *qp; + E_QP_Client *qp_client; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN(qp); + EINA_SAFETY_ON_NULL_RETURN(qp->ec); + EINA_SAFETY_ON_TRUE_RETURN(e_object_is_del(E_OBJECT(qp->ec))); + + qp_client = _e_qp_client_ec_get(ec); + EINA_SAFETY_ON_NULL_RETURN(qp_client); + EINA_SAFETY_ON_FALSE_RETURN(qp_client->hint.scrollable); + + _e_qp_vis_change(qp, EINA_FALSE, EINA_TRUE); +} + +EINTERN Eina_Bool +e_qp_client_scrollable_set(E_Client *ec, Eina_Bool set) +{ + E_Policy_Quickpanel *qp; + E_QP_Client *qp_client; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp->ec, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(qp->ec)), EINA_FALSE); + + qp_client = _e_qp_client_ec_get(ec); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp_client, EINA_FALSE); + + if (qp_client->hint.scrollable != set) + qp_client->hint.scrollable = set; + + _e_qp_client_scrollable_update(); + + return EINA_FALSE; +} + +EINTERN Eina_Bool +e_qp_client_scrollable_get(E_Client *ec) +{ + E_Policy_Quickpanel *qp; + E_QP_Client *qp_client; + + qp = _quickpanel_get(); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp->ec, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(qp->ec)), EINA_FALSE); + + qp_client = _e_qp_client_ec_get(ec); + EINA_SAFETY_ON_NULL_RETURN_VAL(qp_client, EINA_FALSE); + + return qp_client->hint.scrollable; +} diff --git a/src/bin/services/e_service_quickpanel.h b/src/bin/services/e_service_quickpanel.h new file mode 100644 index 0000000000..d5989759e3 --- /dev/null +++ b/src/bin/services/e_service_quickpanel.h @@ -0,0 +1,24 @@ +#ifndef E_SERVICE_QUICKPANEL_H +#define E_SERVICE_QUICKPANEL_H + +#include "e_policy_private_data.h" + +EINTERN void e_service_quickpanel_client_set(E_Client *ec); +EINTERN E_Client *e_service_quickpanel_client_get(void); +EINTERN void e_service_quickpanel_show(void); +EINTERN void e_service_quickpanel_hide(void); +EINTERN Eina_Bool e_service_quickpanel_region_set(int type, int angle, Eina_Tiler *tiler); +EINTERN Evas_Object *e_service_quickpanel_handler_object_add(E_Client *ec, int x, int y, int w, int h); +EINTERN void e_service_quickpanel_handler_object_del(Evas_Object *handler); + +EINTERN Eina_Bool e_qp_visible_get(void); +EINTERN int e_qp_orientation_get(void); + +EINTERN void e_qp_client_add(E_Client *ec); +EINTERN void e_qp_client_del(E_Client *ec); +EINTERN void e_qp_client_show(E_Client *ec); +EINTERN void e_qp_client_hide(E_Client *ec); +EINTERN Eina_Bool e_qp_client_scrollable_set(E_Client *ec, Eina_Bool set); +EINTERN Eina_Bool e_qp_client_scrollable_get(E_Client *ec); + +#endif diff --git a/src/bin/services/e_service_region.c b/src/bin/services/e_service_region.c new file mode 100644 index 0000000000..331d23fc60 --- /dev/null +++ b/src/bin/services/e_service_region.c @@ -0,0 +1,202 @@ +#include "e.h" +#include "services/e_service_region.h" + +/* FIXME: temporary use quickpanel to find out ui orientation */ +#include "services/e_service_quickpanel.h" + +#define ENTRY(...) \ + E_Policy_Region *region; \ + EINA_SAFETY_ON_NULL_RETURN_VAL(ro, EINA_FALSE); \ + region = evas_object_data_get(ro, EO_DATA_KEY); \ + if (EINA_UNLIKELY(!region)) \ + return __VA_ARGS__ + +/* FIXME: Implementation for log that can access commonly */ +#ifdef INF +#undef INF +#endif + +#define INF(f, x...) NULL + +#define EO_DATA_KEY "pol-region" + +struct _E_Policy_Region +{ + Evas_Object *obj; + E_Policy_Gesture *gesture; + Eina_List *event_list; + Eina_Rectangle geom[E_POLICY_ANGLE_MAP_NUM]; + E_Policy_Angle_Map rotation; +}; + +static void +_region_rotation_set(E_Policy_Region *region, int angle) +{ + if (!e_policy_angle_valid_check(angle)) + return; + + region->rotation = e_policy_angle_map(angle); +} + +static void +_region_obj_geometry_update(E_Policy_Region *region) +{ + E_Policy_Angle_Map r; + + r = region->rotation; + + INF("Update Geometry: rotation %d x %d y %d w %d h %d", + e_policy_angle_get(r), region->geom[r].x, region->geom[r].y, region->geom[r].w, region->geom[r].h); + + evas_object_geometry_set(region->obj, + region->geom[r].x, region->geom[r].y, + region->geom[r].w, region->geom[r].h); +} + +static Eina_Bool +_region_rotation_cb_change_end(void *data, int type, void *event) +{ + E_Policy_Region *region; + E_Event_Client *ev; + E_Client *ec; + + region = data; + if (EINA_UNLIKELY(!region)) + goto end; + + ev = event; + if (EINA_UNLIKELY(!ev)) + goto end; + + ec = ev->ec; + if (EINA_UNLIKELY(!ec)) + goto end; + + if (e_service_quickpanel_client_get() != ec) + goto end; + + _region_rotation_set(region, ec->e.state.rot.ang.curr); + _region_obj_geometry_update(region); + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_region_rotation_init(E_Policy_Region *region) +{ + E_Client *ec; + + /* FIXME: temporary use quickpanel to find out ui orientation */ + ec = e_service_quickpanel_client_get(); + if (ec) + _region_rotation_set(region, ec->e.state.rot.ang.curr); + + E_LIST_HANDLER_APPEND(region->event_list, E_EVENT_CLIENT_ROTATION_CHANGE_END, _region_rotation_cb_change_end, region); + + return EINA_TRUE; +} + +static void +_region_free(E_Policy_Region *region) +{ + INF("Free Instant"); + E_FREE_LIST(region->event_list, ecore_event_del); + E_FREE_FUNC(region->gesture, e_service_gesture_del); + E_FREE_FUNC(region->obj, evas_object_del); + free(region); +} + +static void +_region_object_cb_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + E_Policy_Region *region; + + region = data; + if (EINA_UNLIKELY(!region)) + return; + + _region_free(region); +} + +EINTERN Evas_Object * +e_service_region_object_new(void) +{ + E_Policy_Region *region; + Evas_Object *o; + + INF("New Instant"); + + region = calloc(1, sizeof(*region)); + if (!region) + return NULL; + + o = evas_object_rectangle_add(e_comp->evas); + evas_object_color_set(o, 0, 0, 0, 0); + evas_object_repeat_events_set(o, EINA_TRUE); + region->obj = o; + + if (!_region_rotation_init(region)) + goto err_event; + + evas_object_data_set(o, EO_DATA_KEY, region); + evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _region_object_cb_del, region); + + return o; +err_event: + evas_object_del(o); + free(region); + + return NULL; +} + +EINTERN Eina_Bool +e_service_region_cb_set(Evas_Object *ro, E_Policy_Gesture_Start_Cb cb_start, E_Policy_Gesture_Move_Cb cb_move, E_Policy_Gesture_End_Cb cb_end, void *data) +{ + E_Policy_Gesture *gesture; + + ENTRY(EINA_FALSE); + + INF("Set Callback function"); + if (!region->gesture) + { + gesture = e_service_gesture_add(ro, POL_GESTURE_TYPE_LINE); + if (!gesture) + return EINA_FALSE; + + region->gesture = gesture; + } + + e_service_gesture_cb_set(region->gesture, cb_start, cb_move, cb_end, data); + + return EINA_TRUE; +} + +EINTERN Eina_Bool +e_service_region_rectangle_set(Evas_Object *ro, E_Policy_Angle_Map ridx, int x, int y, int w, int h) +{ + ENTRY(EINA_FALSE); + + INF("Add Rectangle: a %d x %d y %d w %d h %d", + e_policy_angle_get(ridx), x, y, w, h); + + EINA_RECTANGLE_SET(®ion->geom[ridx], x, y, w, h); + + if (ridx == region->rotation) + _region_obj_geometry_update(region); + + return EINA_TRUE; +} + +EINTERN Eina_Bool +e_service_region_rectangle_get(Evas_Object *ro, E_Policy_Angle_Map ridx, int *x, int *y, int *w, int *h) +{ + ENTRY(EINA_FALSE); + + if (x) *x = region->geom[ridx].x; + if (y) *y = region->geom[ridx].y; + if (w) *w = region->geom[ridx].w; + if (h) *h = region->geom[ridx].h; + + return EINA_TRUE; +} diff --git a/src/bin/services/e_service_region.h b/src/bin/services/e_service_region.h new file mode 100644 index 0000000000..93aa469bea --- /dev/null +++ b/src/bin/services/e_service_region.h @@ -0,0 +1,14 @@ +#ifndef E_SERVICE_REGION +#define E_SERVICE_REGION + +#include "services/e_service_gesture.h" +#include "e_policy_private_data.h" + +typedef struct _E_Policy_Region E_Policy_Region; + +EINTERN Evas_Object *e_service_region_object_new(void); +EINTERN Eina_Bool e_service_region_rectangle_set(Evas_Object *ro, E_Policy_Angle_Map ridx, int x, int y, int w, int h); +EINTERN Eina_Bool e_service_region_rectangle_get(Evas_Object *ro, E_Policy_Angle_Map ridx, int *x, int *y, int *w, int *h); +EINTERN Eina_Bool e_service_region_cb_set(Evas_Object *ro, E_Policy_Gesture_Start_Cb cb_start, E_Policy_Gesture_Move_Cb cb_move, E_Policy_Gesture_End_Cb cb_end, void *data); + +#endif diff --git a/src/bin/services/e_service_volume.c b/src/bin/services/e_service_volume.c new file mode 100644 index 0000000000..9c79e2a03c --- /dev/null +++ b/src/bin/services/e_service_volume.c @@ -0,0 +1,468 @@ +#include "e.h" +#include "services/e_service_volume.h" + +#include +#include + +#define REGION_OBJS_FOREACH(l, o) \ + EINA_LIST_FOREACH(_volume_region_objs[_volume_cur_angle_map], l, o) + +#define REGION_OBJS_VISIBLE_CHANGE(V) \ +do { \ + Eina_List *l; \ + Evas_Object *o; \ + EINA_LIST_FOREACH(_volume_region_objs[_volume_cur_angle_map], l, o) \ + { \ + if (V) evas_object_show(o); \ + else evas_object_hide(o); \ + } \ +} while(0) +#define REGION_OBJS_SHOW() REGION_OBJS_VISIBLE_CHANGE(EINA_TRUE) +#define REGION_OBJS_HIDE() REGION_OBJS_VISIBLE_CHANGE(EINA_FALSE) + +/* private data for volume */ +static struct wl_resource *_volume_wl_touch = NULL; +static E_Client *_volume_ec = NULL; +static Eina_List *_volume_region_objs[E_POLICY_ANGLE_MAP_NUM]; +static E_Policy_Angle_Map _volume_cur_angle_map = E_POLICY_ANGLE_MAP_0; +static Eina_Bool _volume_ec_ev_init = EINA_FALSE; + +/* event handler */ +static Ecore_Event_Handler *_rot_handler = NULL; +static E_Client_Hook *_volume_del_hook = NULL; + +EINTERN E_Client * +e_service_volume_client_get(void) +{ + return _volume_ec; +} + +static void +_volume_region_obj_cb_mouse_move(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) +{ + Evas_Event_Mouse_Move *e = event; + + wl_touch_send_motion(_volume_wl_touch, e->timestamp, 0, // id 0 for the 1st figner + wl_fixed_from_int(e->cur.canvas.x - _volume_ec->client.x), + wl_fixed_from_int(e->cur.canvas.y - _volume_ec->client.y)); +} + +static void +_volume_region_obj_cb_mouse_down(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) +{ + Evas_Event_Mouse_Down *e = event; + uint32_t serial; + + serial = wl_display_next_serial(e_comp_wl->wl.disp); + wl_touch_send_down(_volume_wl_touch, serial, e->timestamp, + _volume_ec->comp_data->surface, 0, + wl_fixed_from_int(e->canvas.x - _volume_ec->client.x), + wl_fixed_from_int(e->canvas.y - _volume_ec->client.y)); +} + +static void +_volume_region_obj_cb_mouse_up(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) +{ + Evas_Event_Mouse_Up *e = event; + uint32_t serial; + + serial = wl_display_next_serial(e_comp_wl->wl.disp); + wl_touch_send_up(_volume_wl_touch, serial, e->timestamp, 0); +} + +static void +_volume_region_obj_cb_multi_down(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) +{ + Evas_Event_Multi_Down *e = event; + uint32_t serial; + + serial = wl_display_next_serial(e_comp_wl->wl.disp); + wl_touch_send_down(_volume_wl_touch, serial, e->timestamp, + _volume_ec->comp_data->surface, e->device, + wl_fixed_from_int(e->canvas.x - _volume_ec->client.x), + wl_fixed_from_int(e->canvas.y - _volume_ec->client.y)); +} + +static void +_volume_region_obj_cb_multi_up(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) +{ + Evas_Event_Multi_Up *e = event; + uint32_t serial; + + serial = wl_display_next_serial(e_comp_wl->wl.disp); + wl_touch_send_up(_volume_wl_touch, serial, e->timestamp, e->device); +} + +static void +_volume_region_obj_cb_multi_move(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) +{ + Evas_Event_Multi_Move *e = event; + + wl_touch_send_motion(_volume_wl_touch, e->timestamp, e->device, + wl_fixed_from_int(e->cur.canvas.x - _volume_ec->client.x), + wl_fixed_from_int(e->cur.canvas.y - _volume_ec->client.y)); +} + +static void +_volume_client_evas_cb_show(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) +{ + /* show region objects in current rotation */ + REGION_OBJS_SHOW(); +} + +static void +_volume_client_evas_cb_hide(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) +{ + /* hide region objects in current rotation */ + REGION_OBJS_HIDE(); +} + +static void +_volume_client_evas_cb_move(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *volume_obj, void *event EINA_UNUSED) +{ + Eina_List *l; + Eina_Rectangle *r; + Evas_Object *region_obj; + int x, y; + + REGION_OBJS_FOREACH(l, region_obj) + { + r = evas_object_data_get(region_obj, "content_rect"); + if (EINA_UNLIKELY(r == NULL)) + continue; + + evas_object_geometry_get(volume_obj, &x, &y, NULL, NULL); + evas_object_move(region_obj, x + r->x, y + r->y); + } +} + +static void +_volume_client_evas_cb_restack(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) +{ + Eina_List *l; + Evas_Object *region_obj; + + REGION_OBJS_FOREACH(l, region_obj) + evas_object_stack_above(region_obj, _volume_ec->frame); +} + +static Eina_Bool +_region_objs_is_empty(void) +{ + int i; + + for (i = E_POLICY_ANGLE_MAP_0; i < E_POLICY_ANGLE_MAP_NUM; i++) + { + if (_volume_region_objs[i]) + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static void +_region_obj_del(Evas_Object *obj) +{ + Eina_Rectangle *r; + + r = evas_object_data_get(obj, "content_rect"); + E_FREE_FUNC(r, eina_rectangle_free); + evas_object_del(obj); +} + +static void +_region_objs_del(E_Policy_Angle_Map angle_map) +{ + Evas_Object *obj; + + EINA_LIST_FREE(_volume_region_objs[angle_map], obj) + _region_obj_del(obj); + + if ((_volume_ec_ev_init) && + (_region_objs_is_empty())) + { + _volume_ec_ev_init = EINA_FALSE; + + evas_object_event_callback_del(_volume_ec->frame, EVAS_CALLBACK_SHOW, + _volume_client_evas_cb_show); + evas_object_event_callback_del(_volume_ec->frame, EVAS_CALLBACK_HIDE, + _volume_client_evas_cb_hide); + evas_object_event_callback_del(_volume_ec->frame, EVAS_CALLBACK_MOVE, + _volume_client_evas_cb_move); + evas_object_event_callback_del(_volume_ec->frame, EVAS_CALLBACK_RESTACK, + _volume_client_evas_cb_restack); + } +} + +static void +_volume_client_unset(void) +{ + int i; + + for (i = E_POLICY_ANGLE_MAP_0; i < E_POLICY_ANGLE_MAP_NUM; i++) + _region_objs_del(i); + + E_FREE_FUNC(_rot_handler, ecore_event_handler_del); + E_FREE_FUNC(_volume_del_hook, e_client_hook_del); + + _volume_wl_touch = NULL; + _volume_ec = NULL; +} + +static void +_volume_hook_client_del(void *d EINA_UNUSED, E_Client *ec) +{ + if (EINA_UNLIKELY(!ec)) return; + if (EINA_LIKELY(_volume_ec != ec)) return; + + ELOGF("VOLUME","Del Client", ec->pixmap, ec); + + _volume_client_unset(); +} + +static Eina_Bool +_volume_client_cb_rot_done(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client_Rotation_Change_End *e = event; + E_Policy_Angle_Map new_idx; + + if (EINA_UNLIKELY(e == NULL)) + goto end; + + new_idx = e_policy_angle_map(_volume_ec->e.state.rot.ang.curr); + if (EINA_UNLIKELY(new_idx == -1)) + goto end; + + if (e->ec != _volume_ec) + goto end; + + /* is new rotation same with previous? */ + if (_volume_cur_angle_map == new_idx) + goto end; + + /* hide region object in current rotation */ + REGION_OBJS_HIDE(); + + /* update current rotation */ + _volume_cur_angle_map = new_idx; + + /* show region object in current rotation */ + REGION_OBJS_SHOW(); + +end: + return ECORE_CALLBACK_RENEW; +} + +EINTERN Eina_Bool +e_service_volume_client_set(E_Client *ec) +{ + if (!ec) + { + if (_volume_ec) + _volume_client_unset(); + + return EINA_TRUE; + } + + if (_volume_ec) + { + ERR("Volume client is already registered." + "Multi volume service is not supported."); + return EINA_FALSE; + } + + if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE; + + ELOGF("VOLUME","Set Client", ec->pixmap, ec); + + _volume_ec = ec; + _volume_cur_angle_map = e_policy_angle_map(ec->e.state.rot.ang.curr); + + /* repeat events for volume client. */ + evas_object_repeat_events_set(ec->frame, EINA_TRUE); + + _rot_handler = + ecore_event_handler_add(E_EVENT_CLIENT_ROTATION_CHANGE_END, + (Ecore_Event_Handler_Cb)_volume_client_cb_rot_done, + NULL); + _volume_del_hook = + e_client_hook_add(E_CLIENT_HOOK_DEL, _volume_hook_client_del, NULL); + + // set volume layer + if (E_POLICY_VOLUME_LAYER != evas_object_layer_get(ec->frame)) + { + evas_object_layer_set(ec->frame, E_POLICY_VOLUME_LAYER); + } + ec->layer = E_POLICY_VOLUME_LAYER; + + // set skip iconify + ec->exp_iconify.skip_iconify = 1; + + return EINA_TRUE; +} + +static Evas_Object * +_volume_content_region_obj_new(void) +{ + Evas_Object *obj; + + obj = evas_object_rectangle_add(evas_object_evas_get(_volume_ec->frame)); + + /* make it transparent */ + evas_object_color_set(obj, 0, 0, 0, 0); + + /* set stack of obj object on the volume object. */ + evas_object_layer_set(obj, evas_object_layer_get(_volume_ec->frame)); + evas_object_stack_above(obj, _volume_ec->frame); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE, + _volume_region_obj_cb_mouse_move, NULL); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, + _volume_region_obj_cb_mouse_down, NULL); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP, + _volume_region_obj_cb_mouse_up, NULL); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MULTI_DOWN, + _volume_region_obj_cb_multi_down, NULL); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MULTI_UP, + _volume_region_obj_cb_multi_up, NULL); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MULTI_MOVE, + _volume_region_obj_cb_multi_move, NULL); + + return obj; +} + +static void +_region_objs_tile_set(E_Policy_Angle_Map angle_map, Eina_Tiler *tiler) +{ + Eina_List *objs_list, *l, *ll; + Eina_Iterator *it; + Eina_Rectangle *r, *cr; + Evas_Object *obj; + + objs_list = _volume_region_objs[angle_map]; + it = eina_tiler_iterator_new(tiler); + EINA_ITERATOR_FOREACH(it, r) + { + /* trying to reuse allocated object */ + obj = eina_list_data_get(objs_list); + if (obj) + { + objs_list = eina_list_next(objs_list); + cr = evas_object_data_get(obj, "content_rect"); + E_FREE_FUNC(cr, eina_rectangle_free); + } + else + { + obj = _volume_content_region_obj_new(); + _volume_region_objs[angle_map] = eina_list_append(_volume_region_objs[angle_map], obj); + } + + INF("\t@@@@@ Region Set: %d %d %d %d", r->x, r->y, r->w, r->h); + /* set geometry of region object */ + evas_object_move(obj, _volume_ec->client.x + r->x, _volume_ec->client.y + r->y); + evas_object_resize(obj, r->w, r->h); + + /* store the value of reigon as a region object's data */ + cr = eina_rectangle_new(r->x, r->y, r->w, r->h); + evas_object_data_set(obj, "content_rect", cr); + + if (angle_map == _volume_cur_angle_map) + { + if (evas_object_visible_get(_volume_ec->frame)) + evas_object_show(obj); + } + } + eina_iterator_free(it); + + /* delete rest of objects after reusing */ + EINA_LIST_FOREACH_SAFE(objs_list, l, ll, obj) + { + _region_obj_del(obj); + _volume_region_objs[angle_map] = + eina_list_remove_list(_volume_region_objs[angle_map], l); + } +} + +static void +_volume_content_region_set(E_Policy_Angle_Map angle_map, Eina_Tiler *tiler) +{ + if (!tiler) + { + _region_objs_del(angle_map); + return; + } + + _region_objs_tile_set(angle_map, tiler); +} + +static struct wl_resource * +_volume_wl_touch_resource_get(void) +{ + Eina_List *l; + struct wl_client *wc; + struct wl_resource *res; + + if (_volume_wl_touch) goto end; + + wc = wl_resource_get_client(_volume_ec->comp_data->surface); + EINA_LIST_FOREACH(e_comp_wl->touch.resources, l, res) + { + if (wl_resource_get_client(res) != wc) continue; + + _volume_wl_touch = res; + goto end; + } + +end: + return _volume_wl_touch; +} + +EINTERN Eina_Bool +e_service_volume_region_set(int type, int angle, Eina_Tiler *tiler) +{ + E_Policy_Angle_Map angle_map; + + if (EINA_UNLIKELY(!_volume_ec)) + { + ERR("No registered volume client"); + return EINA_FALSE; + } + + angle_map = e_policy_angle_map(angle); + if (EINA_UNLIKELY(angle_map == -1)) + return EINA_FALSE; + + /* FIXME: use enum instead of constant */ + if (EINA_UNLIKELY(type != 1)) + { + ERR("Not supported region type %d", type); + return EINA_FALSE; + } + + if (EINA_UNLIKELY(_volume_wl_touch_resource_get() == NULL)) + { + ERR("Could not found wl_touch resource for volume"); + return EINA_FALSE; + } + + ELOGF("VOLUME","Content Region Set: angle %d, tiler %p", + NULL, NULL, angle, tiler); + + _volume_content_region_set(angle_map, tiler); + + if (!_volume_ec_ev_init) + { + _volume_ec_ev_init = EINA_TRUE; + + evas_object_event_callback_add(_volume_ec->frame, EVAS_CALLBACK_SHOW, + _volume_client_evas_cb_show, NULL); + evas_object_event_callback_add(_volume_ec->frame, EVAS_CALLBACK_HIDE, + _volume_client_evas_cb_hide, NULL); + evas_object_event_callback_add(_volume_ec->frame, EVAS_CALLBACK_MOVE, + _volume_client_evas_cb_move, NULL); + evas_object_event_callback_add(_volume_ec->frame, EVAS_CALLBACK_RESTACK, + _volume_client_evas_cb_restack, NULL); + } + + return EINA_TRUE; +} diff --git a/src/bin/services/e_service_volume.h b/src/bin/services/e_service_volume.h new file mode 100644 index 0000000000..7df57e4ba8 --- /dev/null +++ b/src/bin/services/e_service_volume.h @@ -0,0 +1,11 @@ +#ifndef E_SERVICE_VOLUME_H +#define E_SERVICE_VOLUME_H + +#include +#include "e_policy_private_data.h" + +EINTERN Eina_Bool e_service_volume_client_set(E_Client *ec); +EINTERN E_Client *e_service_volume_client_get(void); +EINTERN Eina_Bool e_service_volume_region_set(int region_type, int angle, Eina_Tiler *tiler); + +#endif /* E_SERVICE_VOLUME_H */