--- /dev/null
+#include "e_mod_main.h"
+#include "e_mod_ivi_home.h"
+
+typedef enum
+{
+ IVI_HOME_SIZE_MODE_NONE,
+ IVI_HOME_SIZE_MODE_HALF,
+ IVI_HOME_SIZE_MODE_FULL,
+ IVI_HOME_SIZE_MODE_SMALL,
+} IVI_Home_Size_Mode;
+
+typedef struct
+{
+ E_Client *ec;
+ IVI_Home_Size_Mode ivi_policy_mode;
+ Eina_Bool ivi_policy_state;
+} IVI_Home_Client;
+
+typedef enum
+{
+ IVI_HOME_HINT_SIZE_MODE,
+} IVI_Home_Hint;
+
+static const char *ivi_home_hint_names[] =
+{
+ "wm.policy.ivi.win.size.mode",
+};
+
+static Eina_Hash *hash_clients = NULL;
+static Eina_List *hooks_ec = NULL;
+static E_Client *ivi_clients[2] = {NULL, NULL};
+
+static void
+_ivi_home_policy_pre(IVI_Home_Client *ic, IVI_Home_Size_Mode mode, int slot)
+{
+ E_Client *ec;
+ int zx, zy, zw, zh;
+
+ ec = ic->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;
+ }
+
+ ic->ivi_policy_mode = mode;
+ switch (mode)
+ {
+ case IVI_HOME_SIZE_MODE_FULL:
+ if (slot)
+ {
+ ec->x = ec->client.x = zx;
+ ec->y = ec->client.y = zy;
+ ec->w = ec->client.w = zw;
+ ec->h = ec->client.h = zh;
+ }
+ break;;
+ case IVI_HOME_SIZE_MODE_SMALL:
+ if (!!!slot)
+ {
+ ec->x = ec->client.x = zx;
+ ec->y = ec->client.y = zy;
+ ec->w = ec->client.w = zw;
+ ec->h = ec->client.h = zh * 9 / 10;
+ }
+ else
+ {
+ ec->x = ec->client.x = zx;
+ ec->y = ec->client.y = zh - zh / 10;
+ ec->w = ec->client.w = zw;
+ ec->h = ec->client.h = zh / 10;
+ }
+ break;
+ case IVI_HOME_SIZE_MODE_HALF:
+ case IVI_HOME_SIZE_MODE_NONE:
+ default:
+ ic->ivi_policy_mode = IVI_HOME_SIZE_MODE_HALF;
+ if (!!!slot)
+ {
+ ec->x = ec->client.x = zx;
+ ec->y = ec->client.y = zy;
+ }
+ else
+ {
+ ec->x = ec->client.x = zx;
+ ec->y = ec->client.y = zh / 2;
+ }
+ ec->w = ec->client.w = zw;
+ ec->h = ec->client.h = zh / 2;
+ }
+
+ EC_CHANGED(ec);
+}
+
+static void
+_ivi_home_policy_apply(IVI_Home_Client *ic, int slot)
+{
+ E_Client *ec;
+
+ if (!ic) return;
+ if (ic->ivi_policy_state) return;
+
+ ic->ivi_policy_state = EINA_TRUE;
+ ec = ic->ec;
+
+ ivi_clients[slot] = ec;
+
+ 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(ec);
+ }
+
+ _ivi_home_policy_pre(ic, ic->ivi_policy_mode, slot);
+ evas_object_move(ec->frame, ec->x, ec->y);
+ evas_object_resize(ec->frame, ec->w, ec->h);
+ ec->placed = EINA_TRUE;
+ e_client_visibility_calculate();
+
+ /* 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;
+}
+
+static void
+_ivi_home_policy_change(IVI_Home_Client *ic, IVI_Home_Size_Mode mode, int slot)
+{
+ E_Client *ec;
+
+ if (!ic) return;
+ if (!ic->ec) return;
+ if (ic->ivi_policy_mode == mode);
+
+ ec = ic->ec;
+ if (!ic->ivi_policy_state)
+ {
+ _ivi_home_policy_apply(ic, slot);
+ return;
+ }
+
+ _ivi_home_policy_pre(ic, mode, slot);
+ evas_object_move(ec->frame, ec->x, ec->y);
+ evas_object_resize(ec->frame, ec->w, ec->h);
+ ec->placed = EINA_TRUE;
+ e_client_visibility_calculate();
+}
+
+static Eina_Bool
+_ivi_home_client_is_ivi_home(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("ivi-home", ec->icccm.window_role))
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ivi_home_client_is_ivi_navi(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("ivi-navi", ec->icccm.window_role))
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+static void
+_ivi_home_size_mode_set(E_Client *ec, IVI_Home_Size_Mode mode)
+{
+ IVI_Home_Client *ic;
+
+ if (!_ivi_home_client_is_ivi_home(ec)) return;
+
+ ic = eina_hash_find(hash_clients, &ec);
+ _ivi_home_policy_change(ic, mode, 1);
+
+ if (ivi_clients[0] && _ivi_home_client_is_ivi_navi(ivi_clients[0]))
+ {
+ ic = eina_hash_find(hash_clients, &ivi_clients[0]);
+ _ivi_home_policy_change(ic, mode, 0);
+ }
+}
+
+static void
+_ivi_home_cb_hook_client_new(void *d EINA_UNUSED, E_Client *ec)
+{
+ IVI_Home_Client *ic;
+
+ if (e_object_is_del(E_OBJECT(ec))) return;
+
+ ic = eina_hash_find(hash_clients, &ec);
+ if (ic) return;
+
+ ic = E_NEW(IVI_Home_Client, 1);
+ ic->ec = ec;
+
+ eina_hash_add(hash_clients, &ec, ic);
+}
+
+static void
+_ivi_home_cb_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
+{
+ if (ivi_clients[0] == ec)
+ ivi_clients[0] = NULL;
+ else if (ivi_clients[1] == ec)
+ ivi_clients[1] = NULL;
+
+ eina_hash_del_by_key(hash_clients, &ec);
+}
+
+static void
+_ivi_home_cb_hook_aux_hint_changed(void *d EINA_UNUSED, E_Client *ec)
+{
+ E_Comp_Wl_Client_Data *cdata;
+ Eina_List *l;
+ E_Comp_Wl_Aux_Hint *hint;
+
+ if (EINA_UNLIKELY(!ec))
+ return;
+
+ cdata = (E_Comp_Wl_Client_Data*)ec->comp_data;
+ if (cdata)
+ {
+ EINA_LIST_FOREACH(cdata->aux_hint.hints, l, hint)
+ {
+ if (!strcmp(hint->hint, ivi_home_hint_names[IVI_HOME_HINT_SIZE_MODE]))
+ {
+ if (hint->deleted)
+ _ivi_home_size_mode_set(ec, IVI_HOME_SIZE_MODE_NONE);
+ else if (!strcmp(hint->val, "half"))
+ _ivi_home_size_mode_set(ec, IVI_HOME_SIZE_MODE_HALF);
+ else if (!strcmp(hint->val, "full"))
+ _ivi_home_size_mode_set(ec, IVI_HOME_SIZE_MODE_FULL);
+ else if (!strcmp(hint->val, "small"))
+ _ivi_home_size_mode_set(ec, IVI_HOME_SIZE_MODE_SMALL);
+ }
+ }
+ }
+}
+
+static void
+_ivi_home_cb_hook_role_changed(void *d EINA_UNUSED, E_Client *ec)
+{
+ if (e_object_is_del(E_OBJECT(ec))) return;
+
+ if (_ivi_home_client_is_ivi_home(ec))
+ {
+ e_policy_allow_user_geometry_set(ec, EINA_TRUE);
+ evas_object_layer_set(ec->frame, E_LAYER_CLIENT_ABOVE);
+ }
+ else if (_ivi_home_client_is_ivi_navi(ec))
+ {
+ e_policy_allow_user_geometry_set(ec, EINA_TRUE);
+ evas_object_layer_set(ec->frame, E_LAYER_CLIENT_BELOW);
+ }
+}
+
+static void
+_ivi_home_cb_hook_eval_post_fetch(void *d EINA_UNUSED, E_Client *ec)
+{
+ IVI_Home_Client *ic;
+
+ if (e_object_is_del(E_OBJECT(ec))) return;
+ if ((ec->new_client) && (!e_pixmap_usable_get(ec->pixmap))) return;
+
+ ic = eina_hash_find(hash_clients, &ec);
+ if (!ic) return;
+
+ if (_ivi_home_client_is_ivi_home(ec))
+ {
+ _ivi_home_policy_apply(ic, 1);
+ }
+ else if (_ivi_home_client_is_ivi_navi(ec))
+ {
+ _ivi_home_policy_apply(ic, 0);
+ }
+}
+
+static void
+e_mod_ivi_home_aux_hint_init(void)
+{
+ int i, n;
+ n = (sizeof(ivi_home_hint_names) / sizeof(char *));
+
+ for (i = 0; i < n; i++)
+ {
+ e_hints_aux_hint_supported_add(ivi_home_hint_names[i]);
+ }
+}
+
+static void
+_ivi_home_cb_client_data_free(void *data)
+{
+ free(data);
+}
+
+EINTERN void
+e_mod_ivi_home_init(void)
+{
+ hash_clients = eina_hash_pointer_new(_ivi_home_cb_client_data_free);
+
+ E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_NEW_CLIENT, _ivi_home_cb_hook_client_new, NULL);
+ E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_DEL, _ivi_home_cb_hook_client_del, NULL);
+ E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_AUX_HINT_CHANGE, _ivi_home_cb_hook_aux_hint_changed, NULL);
+ E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_WINDOW_ROLE_CHANGE, _ivi_home_cb_hook_role_changed, NULL);
+ E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_EVAL_POST_FETCH, _ivi_home_cb_hook_eval_post_fetch, NULL);
+
+ e_mod_ivi_home_aux_hint_init();
+}
+
+EINTERN void
+e_mod_ivi_home_shutdown(void)
+{
+ E_FREE_LIST(hooks_ec, e_client_hook_del);
+ E_FREE_FUNC(hash_clients, eina_hash_free);
+}