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],
[
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
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 \
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
$(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
#ifdef HAVE_WAYLAND_TBM
# include "e_comp_wl_tbm.h"
#endif
+#include "e_policy.h"
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");
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");
--- /dev/null
+#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;
+}
--- /dev/null
+# 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
--- /dev/null
+#include "e.h"
+
+#include <wayland-server.h>
+#include <tizen-extension-server-protocol.h>
+
+#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);
+}
--- /dev/null
+#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
--- /dev/null
+#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
+}
--- /dev/null
+#ifndef E_POLICY_KEYBOARD_H
+#define E_POLICY_KEYBOARD_H
+#include <e.h>
+
+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
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+
+}
+
--- /dev/null
+#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;
+}
--- /dev/null
+#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 */
--- /dev/null
+#include "e.h"
+#include "e_comp_wl.h"
+#include "e_policy_wl.h"
+
+#ifdef ENABLE_TTRACE
+# include <ttrace.h>
+# 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);
+}
--- /dev/null
+#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 <device/display.h>
+#include <wayland-server.h>
+#include <tizen-extension-server-protocol.h>
+#include <tzsh_server.h>
+
+#ifdef HAVE_CYNARA
+# include <cynara-session.h>
+# include <cynara-client.h>
+# include <cynara-creds-socket.h>
+#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);
+}
--- /dev/null
+#ifndef E_MOD_WL_H
+#define E_MOD_WL_H
+
+#include "config.h"
+#ifdef HAVE_WAYLAND_ONLY
+#include <e.h>
+
+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 */
--- /dev/null
+#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);
+ }
+}
+
--- /dev/null
+#ifndef E_POLICY_WL_DISPLAY_H
+#define E_POLICY_WL_DISPLAY_H
+
+#include <e.h>
+
+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
--- /dev/null
+#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;
+}
--- /dev/null
+#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 */
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#include "e.h"
+#include "services/e_service_volume.h"
+
+#include <wayland-server.h>
+#include <tzsh_server.h>
+
+#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;
+}
--- /dev/null
+#ifndef E_SERVICE_VOLUME_H
+#define E_SERVICE_VOLUME_H
+
+#include <e.h>
+#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 */