diff --git a/configure.ac b/configure.ac index c1ceca6bb..f807de672 100644 --- a/configure.ac +++ b/configure.ac @@ -971,6 +971,7 @@ AC_E_OPTIONAL_MODULE([wl_x11], $have_wayland, $wl_x11) AC_E_OPTIONAL_MODULE([wl_fb], $have_wayland, [CHECK_MODULE_WL_FB]) AC_E_OPTIONAL_MODULE([wl_drm], $have_wayland, [CHECK_MODULE_WL_DRM]) #AC_E_OPTIONAL_MODULE([wl_screenshot], true, [CHECK_MODULE_WL_SCREENSHOT]) +AC_E_OPTIONAL_MODULE([policy_mobile], true) HALT="/sbin/shutdown -h now" REBOOT="/sbin/shutdown -r now" diff --git a/src/bin/e_module.c b/src/bin/e_module.c index a864ef879..49b4adc7e 100644 --- a/src/bin/e_module.c +++ b/src/bin/e_module.c @@ -938,6 +938,7 @@ _e_module_whitelist_check(void) "music-control", "appmenu", "packagekit", + "policy_mobile", NULL // end marker }; diff --git a/src/modules/Makefile.mk b/src/modules/Makefile.mk index bc2d69394..5b6bf8b17 100644 --- a/src/modules/Makefile.mk +++ b/src/modules/Makefile.mk @@ -130,3 +130,5 @@ include src/modules/Makefile_wl_fb.mk #if HAVE_WAYLAND_SCREENSHOT #include src/modules/Makefile_wl_screenshot.mk + +include src/modules/Makefile_policy_mobile.mk diff --git a/src/modules/Makefile_policy_mobile.mk b/src/modules/Makefile_policy_mobile.mk new file mode 100644 index 000000000..59ca42222 --- /dev/null +++ b/src/modules/Makefile_policy_mobile.mk @@ -0,0 +1,21 @@ +EXTRA_DIST += src/modules/policy_mobile/e-module-policy-mobile.edj +if USE_MODULE_POLICY_MOBILE +policy_mobiledir = $(MDIR)/policy_mobile +policy_mobile_DATA = src/modules/policy_mobile/e-module-policy-mobile.edj + +policy_mobilepkgdir = $(MDIR)/policy_mobile/$(MODULE_ARCH) +policy_mobilepkg_LTLIBRARIES = src/modules/policy_mobile/module.la + +src_modules_policy_mobile_module_la_LIBADD = $(MOD_LIBS) +src_modules_policy_mobile_module_la_CPPFLAGS = $(MOD_CPPFLAGS) +src_modules_policy_mobile_module_la_LDFLAGS = $(MOD_LDFLAGS) +src_modules_policy_mobile_module_la_SOURCES = \ +src/modules/policy_mobile/e_mod_main.h \ +src/modules/policy_mobile/e_mod_config.c \ +src/modules/policy_mobile/e_mod_softkey.c \ +src/modules/policy_mobile/e_mod_main.c + +PHONIES += policy_mobile install-policy_mobile +policy_mobile: $(policy_mobilepkg_LTLIBRARIES) $(policy_mobile_DATA) +install-policy_mobile: install-policy_mobileDATA install-policy_mobilepkgLTLIBRARIES +endif diff --git a/src/modules/policy_mobile/e-module-policy-mobile.edj b/src/modules/policy_mobile/e-module-policy-mobile.edj new file mode 100644 index 000000000..1a1c81cc4 Binary files /dev/null and b/src/modules/policy_mobile/e-module-policy-mobile.edj differ diff --git a/src/modules/policy_mobile/e_mod_config.c b/src/modules/policy_mobile/e_mod_config.c new file mode 100644 index 000000000..6df66f049 --- /dev/null +++ b/src/modules/policy_mobile/e_mod_config.c @@ -0,0 +1,387 @@ +#include "e_mod_main.h" + +static void _pol_conf_desk_add(Config *conf, E_Desk *desk); +static void _pol_conf_desk_del(Config *conf, Config_Desk *d); +static Config_Desk *_pol_conf_desk_get(Config *conf, Config_Desk *d); + +static void *_pol_cfd_data_create(E_Config_Dialog *cfd); +static void _pol_cfd_data_free(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata); +static int _pol_cfd_data_basic_apply(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata); +static void _pol_cfd_desk_list_update(E_Config_Dialog_Data *cfdata, E_Zone *zone); +static void _pol_cfd_hook_zone_change(void *data, Evas_Object *obj); +static Evas_Object *_pol_cfd_data_basic_widgets_create(E_Config_Dialog *cfd EINA_UNUSED, Evas *evas, E_Config_Dialog_Data *cfdata); + +static void +_pol_conf_desk_add(Config *conf, E_Desk *desk) +{ + Config_Desk *d; + + d = E_NEW(Config_Desk, 1); + d->comp_num = desk->zone->comp->num; + d->zone_num = desk->zone->num; + d->x = desk->x; + d->y = desk->y; + d->enable = 1; + + conf->desks = eina_list_append(conf->desks, d); +} + +static void +_pol_conf_desk_del(Config *conf, Config_Desk *d) +{ + conf->desks = eina_list_remove(conf->desks, d); + free(d); +} + +static Config_Desk * +_pol_conf_desk_get(Config *conf, Config_Desk *d) +{ + Eina_List *l; + Config_Desk *d2; + + EINA_LIST_FOREACH(conf->desks, l, d2) + { + if ((d2->comp_num == d->comp_num) && + (d2->zone_num == d->zone_num) && + (d2->x == d->x) && (d2->y == d->y)) + { + return d2; + } + } + + return NULL; +} + +static void * +_pol_cfd_data_create(E_Config_Dialog *cfd) +{ + E_Config_Dialog_Data *cfdata = NULL; + + cfdata = E_NEW(E_Config_Dialog_Data, 1); + cfdata->conf = E_NEW(Config, 1); + cfdata->conf->launcher.title = eina_stringshare_ref(_pol_mod->conf->launcher.title); + cfdata->conf->launcher.clas = eina_stringshare_ref(_pol_mod->conf->launcher.clas); + cfdata->conf->launcher.type = _pol_mod->conf->launcher.type; + cfdata->conf->use_softkey = _pol_mod->conf->use_softkey; + cfdata->conf->softkey_size = _pol_mod->conf->softkey_size; + + _pol_mod->conf_dialog = cfd; + + return cfdata; +} + +static void +_pol_cfd_data_free(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) +{ + _pol_mod->conf_dialog = NULL; + E_FREE_LIST(cfdata->conf->desks, free); + eina_stringshare_del(cfdata->conf->launcher.title); + eina_stringshare_del(cfdata->conf->launcher.clas); + free(cfdata->conf); + free(cfdata); +} + +static int +_pol_cfd_data_basic_apply(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) +{ + E_Comp *comp; + E_Zone *zone; + E_Desk *desk; + Pol_Softkey *softkey; + Pol_Desk *pd; + Config_Desk *d, *d2; + Eina_Bool changed = EINA_FALSE; + const Eina_List *l; + Eina_Inlist *il; + Eina_Iterator *it; + + if (_pol_mod->conf->use_softkey != cfdata->conf->use_softkey) + { + _pol_mod->conf->use_softkey = cfdata->conf->use_softkey; + if (_pol_mod->conf->use_softkey) + { + it = eina_hash_iterator_data_new(hash_pol_desks); + while (eina_iterator_next(it, (void **)&pd)) + { + softkey = e_mod_pol_softkey_get(pd->zone); + if (!softkey) + softkey = e_mod_pol_softkey_add(pd->zone); + if (e_desk_current_get(pd->zone) == pd->desk) + e_mod_pol_softkey_show(softkey); + } + eina_iterator_free(it); + } + else + { + EINA_INLIST_FOREACH_SAFE(_pol_mod->softkeys, il, softkey) + e_mod_pol_softkey_del(softkey); + } + + changed = EINA_TRUE; + } + + if (_pol_mod->conf->softkey_size != cfdata->conf->softkey_size) + { + _pol_mod->conf->softkey_size = cfdata->conf->softkey_size; + if (_pol_mod->conf->use_softkey) + { + EINA_INLIST_FOREACH(_pol_mod->softkeys, softkey) + e_mod_pol_softkey_update(softkey); + } + changed = EINA_TRUE; + } + + EINA_LIST_FOREACH(cfdata->conf->desks, l, d) + { + comp = e_comp_number_get(d->comp_num); + zone = e_comp_zone_number_get(comp, d->zone_num); + desk = e_desk_at_xy_get(zone, d->x, d->y); + if (!desk) continue; + + d2 = _pol_conf_desk_get(_pol_mod->conf, d); + if (d2) + { + /* disable policy for this desktop */ + if (d2->enable != d->enable) + { + pd = eina_hash_find(hash_pol_desks, &desk); + if (pd) e_mod_pol_desk_del(pd); + _pol_conf_desk_del(_pol_mod->conf, d2); + changed = EINA_TRUE; + } + } + else + { + /* apply policy for all clients in this desk, + * and add desk to configuration list and desk hash */ + if (d->enable) + { + e_mod_pol_desk_add(desk); + _pol_conf_desk_add(_pol_mod->conf, desk); + changed = EINA_TRUE; + } + } + } + + if (changed) + e_config_save_queue(); + + return 1; +} + +static void +_pol_cfd_desk_list_update(E_Config_Dialog_Data *cfdata, E_Zone *zone) +{ + Evas_Object *o, *ch; + Evas *evas; + E_Desk *desk; + Config_Desk *d, *d2; + int i, n; + + evas = evas_object_evas_get(cfdata->o_list); + evas_object_del(cfdata->o_desks); + E_FREE_LIST(cfdata->conf->desks, free); + + o = e_widget_list_add(evas, 1, 0); + cfdata->o_desks = o; + + n = zone->desk_y_count * zone->desk_x_count; + for (i = 0; i < n; i++) + { + desk = zone->desks[i]; + + d = E_NEW(Config_Desk, 1); + d->comp_num = zone->comp->num; + d->zone_num = zone->num; + d->x = desk->x; + d->y = desk->y; + d->enable = 0; + + d2 = _pol_conf_desk_get(_pol_mod->conf, d); + if (d2) + d->enable = d2->enable; + + ch = e_widget_check_add(evas, desk->name, &d->enable); + e_widget_list_object_append(o, ch, 1, 1, 0.5); + + cfdata->conf->desks = eina_list_append(cfdata->conf->desks, d); + } + + e_widget_list_object_append(cfdata->o_list, o, 1, 1, 0.5); +} + +static void +_pol_cfd_hook_zone_change(void *data, Evas_Object *obj) +{ + E_Config_Dialog_Data *cfdata; + E_Zone *zone; + int n; + + cfdata = data; + n = e_widget_ilist_selected_get(obj); + zone = e_widget_ilist_nth_data_get(obj, n); + if (zone) + _pol_cfd_desk_list_update(cfdata, zone); +} + +static Evas_Object * +_pol_cfd_data_basic_widgets_create(E_Config_Dialog *cfd EINA_UNUSED, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + Evas_Object *base, *fl, *lb, *lo, *o; + E_Comp *comp; + E_Zone *zone; + Eina_List *l; + + comp = e_comp_get(NULL); + + base = e_widget_list_add(evas, 0, 0); + + fl = e_widget_framelist_add(evas, _("Softkey"), 0); + o = e_widget_check_add(evas, _("Use softkey for navigation among the windows"), + &cfdata->conf->use_softkey); + e_widget_framelist_object_append(fl, o); + o = e_widget_label_add(evas, _("Icon Size")); + e_widget_framelist_object_append(fl, o); + o = e_widget_slider_add(evas, 1, 0, "%1.0f", 32, 256, 1, 0, NULL, + &(cfdata->conf->softkey_size), 150); + e_widget_framelist_object_append(fl, o); + e_widget_list_object_append(base, fl, 1, 1, 0.5); + + fl = e_widget_framelist_add(evas, _("Virtual Desktops"), 0); + lb = e_widget_label_add(evas, _("Enable mobile policy per desktop")); + e_widget_framelist_object_append(fl, lb); + + lo = e_widget_list_add(evas, 0, 1); + cfdata->o_list = lo; + o = e_widget_ilist_add(evas, 0, 0, NULL); + e_widget_ilist_multi_select_set(o, EINA_FALSE); + e_widget_size_min_set(o, 100, 100); + e_widget_on_change_hook_set(o, _pol_cfd_hook_zone_change, cfdata); + EINA_LIST_REVERSE_FOREACH(comp->zones, l, zone) + e_widget_ilist_append(o, NULL, zone->name, NULL, zone, NULL); + e_widget_ilist_go(o); + e_widget_ilist_selected_set(o, 0); + e_widget_list_object_append(lo, o, 1, 1, 0.5); + + /* update virtual desktops of first zone */ + zone = eina_list_data_get(comp->zones); + _pol_cfd_desk_list_update(cfdata, zone); + + e_widget_framelist_object_append(fl, lo); + e_widget_list_object_append(base, fl, 1, 1, 0.5); + + return base; +} + +void +e_mod_pol_conf_init(Mod *mod) +{ + E_Comp *comp; + E_Zone *zone; + E_Desk *desk; + Config *conf; + + mod->conf_desk_edd = E_CONFIG_DD_NEW("Policy_Mobile_Config_Desk", Config_Desk); +#undef T +#undef D +#define T Config_Desk +#define D mod->conf_desk_edd + E_CONFIG_VAL(D, T, comp_num, INT); + E_CONFIG_VAL(D, T, zone_num, UINT); + E_CONFIG_VAL(D, T, x, INT); + E_CONFIG_VAL(D, T, y, INT); + E_CONFIG_VAL(D, T, enable, INT); + + mod->conf_edd = E_CONFIG_DD_NEW("Policy_Mobile_Config", Config); +#undef T +#undef D +#define T Config +#define D mod->conf_edd + E_CONFIG_VAL(D, T, launcher.title, STR); + E_CONFIG_VAL(D, T, launcher.clas, STR); + E_CONFIG_VAL(D, T, launcher.type, UINT); + E_CONFIG_LIST(D, T, desks, mod->conf_desk_edd); + E_CONFIG_VAL(D, T, use_softkey, INT); + E_CONFIG_VAL(D, T, softkey_size, INT); + +#undef T +#undef D + + mod->conf = e_config_domain_load("module.policy-mobile", mod->conf_edd); + if (!mod->conf) + { + conf = E_NEW(Config, 1); + mod->conf = conf; + conf->launcher.title = eina_stringshare_add("Illume Home"); + conf->launcher.clas = eina_stringshare_add("Illume-Home"); + conf->launcher.type = E_WINDOW_TYPE_NORMAL; + conf->use_softkey = 1; + conf->softkey_size = 42; + + comp = e_comp_get(NULL); + zone = e_zone_current_get(comp); + desk = e_desk_current_get(zone); + _pol_conf_desk_add(conf, desk); + } +} + +void +e_mod_pol_conf_shutdown(Mod *mod) +{ + Config *conf; + + if (mod->conf) + { + conf = mod->conf; + E_FREE_LIST(conf->desks, free); + eina_stringshare_del(conf->launcher.title); + eina_stringshare_del(conf->launcher.clas); + free(mod->conf); + } + + E_CONFIG_DD_FREE(mod->conf_desk_edd); + E_CONFIG_DD_FREE(mod->conf_edd); +} + +Config_Desk * +e_mod_pol_conf_desk_get_by_nums(Config *conf, unsigned int comp_num, unsigned int zone_num, int x, int y) +{ + Eina_List *l; + Config_Desk *d2; + + EINA_LIST_FOREACH(conf->desks, l, d2) + { + if ((d2->comp_num == comp_num) && + (d2->zone_num == zone_num) && + (d2->x == x) && (d2->y == y)) + { + return d2; + } + } + + return NULL; +} + +E_Config_Dialog * +e_int_config_pol_mobile(E_Comp *comp, const char *params EINA_UNUSED) +{ + E_Config_Dialog *cfd; + E_Config_Dialog_View *v; + char buf[PATH_MAX]; + + if (e_config_dialog_find("E", "windows/policy-mobile")) + return NULL; + + v = E_NEW(E_Config_Dialog_View, 1); + v->create_cfdata = _pol_cfd_data_create; + v->free_cfdata = _pol_cfd_data_free; + v->basic.apply_cfdata = _pol_cfd_data_basic_apply; + v->basic.create_widgets = _pol_cfd_data_basic_widgets_create; + + snprintf(buf, sizeof(buf), "%s/e-module-policy-mobile.edj", + e_module_dir_get(_pol_mod->module)); + + cfd = e_config_dialog_new(comp, _("Mobile Policy Configuration"), "E", + "windows/policy-mobile", buf, 0, v, NULL); + return cfd; +} diff --git a/src/modules/policy_mobile/e_mod_main.c b/src/modules/policy_mobile/e_mod_main.c new file mode 100644 index 000000000..2d8b86e92 --- /dev/null +++ b/src/modules/policy_mobile/e_mod_main.c @@ -0,0 +1,646 @@ +#include "e_mod_main.h" + +EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Policy-Mobile" }; + +Mod *_pol_mod = NULL; +Eina_Hash *hash_pol_desks = NULL; +Eina_Hash *hash_pol_clients = NULL; + +static Eina_List *handlers = NULL; +static Eina_List *hooks = NULL; + +static Pol_Client *_pol_client_add(E_Client *ec); +static void _pol_client_del(Pol_Client *pc); +static Eina_Bool _pol_client_normal_check(E_Client *ec); +static void _pol_client_update(Pol_Client *pc); +static void _pol_client_launcher_set(Pol_Client *pc); + +static void _pol_hook_client_eval_post_fetch(void *d EINA_UNUSED, E_Client *ec); +static void _pol_hook_client_desk_set(void *d EINA_UNUSED, E_Client *ec); +static void _pol_cb_desk_data_free(void *data); +static void _pol_cb_client_data_free(void *data); +static Eina_Bool _pol_cb_zone_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _pol_cb_zone_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _pol_cb_zone_move_resize(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _pol_cb_zone_desk_count_set(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _pol_cb_desk_show(void *data EINA_UNUSED, int type EINA_UNUSED, void *event); +static Eina_Bool _pol_cb_client_remove(void *data EINA_UNUSED, int type, void *event); + +static void +_pol_client_launcher_set(Pol_Client *pc) +{ + Pol_Client *pc2; + + pc2 = e_mod_pol_client_launcher_get(pc->ec->zone); + if (pc2) return; + + if (pc->ec->netwm.type != _pol_mod->conf->launcher.type) + return; + + if (e_util_strcmp(pc->ec->icccm.class, + _pol_mod->conf->launcher.clas)) + return; + + + if (e_util_strcmp(pc->ec->icccm.title, + _pol_mod->conf->launcher.title)) + { + /* check netwm name instead, because comp_x had ignored + * icccm name when fetching */ + if (e_util_strcmp(pc->ec->netwm.name, + _pol_mod->conf->launcher.title)) + { + return; + } + } + + _pol_mod->launchers = eina_list_append(_pol_mod->launchers, pc); +} + +static Pol_Client * +_pol_client_add(E_Client *ec) +{ + Pol_Client *pc; + Pol_Desk *pd; + + if (e_object_is_del(E_OBJECT(ec))) return NULL; + if (!_pol_client_normal_check(ec)) return NULL; + + pc = eina_hash_find(hash_pol_clients, &ec); + if (pc) return NULL; + + pd = eina_hash_find(hash_pol_desks, &ec->desk); + if (!pd) return NULL; + + pc = E_NEW(Pol_Client, 1); + pc->ec = ec; + +#undef _SET +# define _SET(a) pc->orig.a = 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); +#undef _SET + + _pol_client_launcher_set(pc); + + eina_hash_add(hash_pol_clients, &ec, pc); + + _pol_client_update(pc); + + return pc; +} + +static void +_pol_client_del(Pol_Client *pc) +{ + E_Client *ec; + Eina_Bool changed = 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 + ec->changes.need_unmaximize = 1; + 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); +#undef _SET + + /* only set it if the border is changed or fullscreen/maximize has changed */ + if (changed) + EC_CHANGED(pc->ec); + + _pol_mod->launchers = eina_list_remove(_pol_mod->launchers, pc); + + eina_hash_del_by_key(hash_pol_clients, &pc->ec); +} + +static Eina_Bool +_pol_client_normal_check(E_Client *ec) +{ + if ((e_client_util_ignored_get(ec)) || + (!ec->pixmap)) + { + return EINA_FALSE; + } + + if ((ec->netwm.type == E_WINDOW_TYPE_NORMAL) || + (ec->netwm.type == E_WINDOW_TYPE_UNKNOWN)) + { + return EINA_TRUE; + } + + return EINA_FALSE; +} + +static void +_pol_client_update(Pol_Client *pc) +{ + E_Client *ec; + + ec = pc->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(pc->ec); + } + + if (!ec->maximized) + e_client_maximize(ec, E_MAXIMIZE_EXPAND | E_MAXIMIZE_BOTH); + + /* 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_client_stacking = 1; + ec->lock_user_shade = 1; + ec->lock_client_shade = 1; + ec->lock_user_maximize = 1; + ec->lock_client_maximize = 1; +} + +static void +_pol_hook_client_eval_post_fetch(void *d EINA_UNUSED, E_Client *ec) +{ + Pol_Client *pc; + Pol_Desk *pd; + + if (e_object_is_del(E_OBJECT(ec))) return; + if (!_pol_client_normal_check(ec)) return; + if (ec->new_client) return; + + pd = eina_hash_find(hash_pol_desks, &ec->desk); + if (!pd) return; + + pc = eina_hash_find(hash_pol_clients, &ec); + if (pc) + { + _pol_client_launcher_set(pc); + return; + } + + _pol_client_add(ec); +} + +static void +_pol_hook_client_desk_set(void *d EINA_UNUSED, E_Client *ec) +{ + Pol_Client *pc; + Pol_Desk *pd; + + if (e_object_is_del(E_OBJECT(ec))) return; + if (!_pol_client_normal_check(ec)) return; + + pc = eina_hash_find(hash_pol_clients, &ec); + pd = eina_hash_find(hash_pol_desks, &ec->desk); + + if ((!pc) && (pd)) + _pol_client_add(ec); + else if ((pc) && (!pd)) + _pol_client_del(pc); +} + +static void +_pol_cb_desk_data_free(void *data) +{ + free(data); +} + +static void +_pol_cb_client_data_free(void *data) +{ + free(data); +} + +static Eina_Bool +_pol_cb_zone_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Zone_Add *ev; + E_Zone *zone; + Config_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_mod_pol_conf_desk_get_by_nums(_pol_mod->conf, + zone->comp->num, + zone->num, + zone->desks[i]->x, + zone->desks[i]->y); + if (d) + e_mod_pol_desk_add(zone->desks[i]); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_pol_cb_zone_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Zone_Del *ev; + E_Zone *zone; + Pol_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_pol_desks, &zone->desks[i]); + if (pd) e_mod_pol_desk_del(pd); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_pol_cb_zone_move_resize(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Zone_Move_Resize *ev; + Pol_Softkey *softkey; + + ev = event; + + if (_pol_mod->conf->use_softkey) + { + softkey = e_mod_pol_softkey_get(ev->zone); + e_mod_pol_softkey_update(softkey); + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_pol_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; + Pol_Desk *pd; + Config_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_pol_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_pol_desks, &desk); + if (pd) e_mod_pol_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_mod_pol_conf_desk_get_by_nums(_pol_mod->conf, + zone->comp->num, + zone->num, + zone->desks[i]->x, + zone->desks[i]->y); + if (d) + e_mod_pol_desk_add(zone->desks[i]); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_pol_cb_desk_show(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Desk_Show *ev; + Pol_Softkey *softkey; + + ev = event; + + if (_pol_mod->conf->use_softkey) + { + softkey = e_mod_pol_softkey_get(ev->desk->zone); + if (eina_hash_find(hash_pol_desks, &ev->desk)) + e_mod_pol_softkey_show(softkey); + else + e_mod_pol_softkey_hide(softkey); + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_pol_cb_client_remove(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Client *ev; + Pol_Client *pc; + + ev = event; + pc = eina_hash_find(hash_pol_clients, &ev->ec); + if (!pc) return ECORE_CALLBACK_PASS_ON; + + eina_hash_del_by_key(hash_pol_clients, &ev->ec); + + return ECORE_CALLBACK_PASS_ON; +} + +void +e_mod_pol_desk_add(E_Desk *desk) +{ + Pol_Desk *pd; + E_Comp *comp; + E_Client *ec; + Pol_Softkey *softkey; + const Eina_List *l; + + pd = eina_hash_find(hash_pol_desks, &desk); + if (pd) return; + + pd = E_NEW(Pol_Desk, 1); + pd->desk = desk; + pd->zone = desk->zone; + + eina_hash_add(hash_pol_desks, &desk, pd); + + /* add clients */ + EINA_LIST_FOREACH(e_comp_list(), l, comp) + E_CLIENT_FOREACH(comp, ec) + { + if (pd->desk == ec->desk) + _pol_client_add(ec); + } + + /* add and show softkey */ + if (_pol_mod->conf->use_softkey) + { + softkey = e_mod_pol_softkey_get(desk->zone); + if (!softkey) + softkey = e_mod_pol_softkey_add(desk->zone); + if (e_desk_current_get(desk->zone) == desk) + e_mod_pol_softkey_show(softkey); + } +} + +void +e_mod_pol_desk_del(Pol_Desk *pd) +{ + Eina_Iterator *it; + Pol_Client *pc; + E_Client *ec; + Eina_List *clients_del = NULL; + Pol_Softkey *softkey; + Eina_Bool keep = EINA_FALSE; + int i, n; + + /* hide and delete softkey */ + if (_pol_mod->conf->use_softkey) + { + softkey = e_mod_pol_softkey_get(pd->zone); + if (e_desk_current_get(pd->zone) == pd->desk) + e_mod_pol_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_pol_desks, &pd->zone->desks[i])) + { + keep = EINA_TRUE; + break; + } + } + + if (!keep) + e_mod_pol_softkey_del(softkey); + } + + /* remove clients */ + it = eina_hash_iterator_data_new(hash_pol_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_pol_clients, &ec); + if (pc) _pol_client_del(pc); + } + + eina_hash_del_by_key(hash_pol_desks, &pd->desk); +} + +Pol_Client * +e_mod_pol_client_launcher_get(E_Zone *zone) +{ + Pol_Client *pc; + Eina_List *l; + + EINA_LIST_FOREACH(_pol_mod->launchers, l, pc) + { + if (pc->ec->zone == zone) + return pc; + } + return NULL; +} + +#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) + +EAPI void * +e_modapi_init(E_Module *m) +{ + Mod *mod; + E_Comp *comp; + E_Zone *zone; + Config_Desk *d; + const Eina_List *l, *ll; + int i, n; + char buf[PATH_MAX]; + + mod = E_NEW(Mod, 1); + mod->module = m; + _pol_mod = mod; + + hash_pol_clients = eina_hash_pointer_new(_pol_cb_client_data_free); + hash_pol_desks = eina_hash_pointer_new(_pol_cb_desk_data_free); + + /* initialize configure and config data type */ + snprintf(buf, sizeof(buf), "%s/e-module-policy-mobile.edj", + e_module_dir_get(m)); + + e_configure_registry_category_add("windows", 50, _("Windows"), NULL, + "preferences-system-windows"); + e_configure_registry_item_add("windows/policy-mobile", 150, + _("Mobile Policy"), NULL, buf, + e_int_config_pol_mobile); + + e_mod_pol_conf_init(mod); + + EINA_LIST_FOREACH(e_comp_list(), l, comp) + EINA_LIST_FOREACH(comp->zones, ll, zone) + { + //Eina_Bool home_add = EINA_FALSE; + n = zone->desk_y_count * zone->desk_x_count; + for (i = 0; i < n; i++) + { + d = e_mod_pol_conf_desk_get_by_nums(_pol_mod->conf, + comp->num, + zone->num, + zone->desks[i]->x, + zone->desks[i]->y); + if (d) + { + e_mod_pol_desk_add(zone->desks[i]); + //home_add = EINA_TRUE; + } + } + + /* FIXME: should consider the case that illume-home module + * is not loaded yet and make it configurable. + * and also, this code will be enabled when e_policy stuff lands in e. + */ + //if (home_add) + // e_policy_zone_home_add_request(zone); + } + + E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_ADD, _pol_cb_zone_add, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_DEL, _pol_cb_zone_del, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_MOVE_RESIZE, _pol_cb_zone_move_resize, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_DESK_COUNT_SET, _pol_cb_zone_desk_count_set, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_DESK_SHOW, _pol_cb_desk_show, NULL); + E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_REMOVE, _pol_cb_client_remove, NULL); + + E_CLIENT_HOOK_APPEND(hooks, E_CLIENT_HOOK_EVAL_POST_FETCH, + _pol_hook_client_eval_post_fetch, NULL); + E_CLIENT_HOOK_APPEND(hooks, E_CLIENT_HOOK_DESK_SET, + _pol_hook_client_desk_set, NULL); + + return mod; +} + +EAPI int +e_modapi_shutdown(E_Module *m) +{ + Mod *mod = m->data; + Eina_Inlist *l; + Pol_Softkey *softkey; + + eina_list_free(mod->launchers); + EINA_INLIST_FOREACH_SAFE(mod->softkeys, l, softkey) + e_mod_pol_softkey_del(softkey); + E_FREE_LIST(hooks, e_client_hook_del); + E_FREE_LIST(handlers, ecore_event_handler_del); + E_FREE_FUNC(hash_pol_desks, eina_hash_free); + E_FREE_FUNC(hash_pol_clients, eina_hash_free); + + e_configure_registry_item_del("windows/policy-mobile"); + e_configure_registry_category_del("windows"); + + if (mod->conf_dialog) + { + e_object_del(E_OBJECT(mod->conf_dialog)); + mod->conf_dialog = NULL; + } + + e_mod_pol_conf_shutdown(mod); + + E_FREE(mod); + + _pol_mod = NULL; + + return 1; +} + +EAPI int +e_modapi_save(E_Module *m) +{ + Mod *mod = m->data; + e_config_domain_save("module.policy-mobile", + mod->conf_edd, + mod->conf); + return 1; +} diff --git a/src/modules/policy_mobile/e_mod_main.h b/src/modules/policy_mobile/e_mod_main.h new file mode 100644 index 000000000..3e9850876 --- /dev/null +++ b/src/modules/policy_mobile/e_mod_main.h @@ -0,0 +1,108 @@ +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H +#include + +typedef struct _Pol_Desk Pol_Desk; +typedef struct _Pol_Client Pol_Client; +typedef struct _Pol_Softkey Pol_Softkey; +typedef struct _Config_Match Config_Match; +typedef struct _Config_Desk Config_Desk; +typedef struct _Config Config; +typedef struct _Mod Mod; + +struct _Pol_Desk +{ + E_Desk *desk; + E_Zone *zone; +}; + +struct _Pol_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; + } orig; +}; + +struct _Pol_Softkey +{ + EINA_INLIST; + + E_Zone *zone; + Evas_Object *home; + Evas_Object *back; +}; + +struct _Config_Match +{ + const char *title; /* icccm.title or netwm.name */ + const char *clas; /* icccm.class */ + unsigned int type; /* netwm.type */ +}; + +struct _Config_Desk +{ + unsigned int comp_num; + unsigned int zone_num; + int x, y; + int enable; +}; + +struct _Config +{ + Config_Match launcher; + Eina_List *desks; + int use_softkey; + int softkey_size; +}; + +struct _Mod +{ + E_Module *module; + E_Config_DD *conf_edd; + E_Config_DD *conf_desk_edd; + Config *conf; + E_Config_Dialog *conf_dialog; + Eina_List *launchers; /* launcher window per zone */ + Eina_Inlist *softkeys; /* softkey ui object per zone */ +}; + +struct _E_Config_Dialog_Data +{ + Config *conf; + Evas_Object *o_list; + Evas_Object *o_desks; +}; + +extern Mod *_pol_mod; +extern Eina_Hash *hash_pol_desks; +extern Eina_Hash *hash_pol_clients; + +EINTERN void e_mod_pol_conf_init(Mod *mod); +EINTERN void e_mod_pol_conf_shutdown(Mod *mod); +EINTERN Config_Desk *e_mod_pol_conf_desk_get_by_nums(Config *conf, unsigned int comp_num, unsigned int zone_num, int x, int y); +EINTERN E_Config_Dialog *e_int_config_pol_mobile(E_Comp *comp, const char *params EINA_UNUSED); +EINTERN void e_mod_pol_desk_add(E_Desk *desk); +EINTERN void e_mod_pol_desk_del(Pol_Desk *pd); +EINTERN Pol_Client *e_mod_pol_client_launcher_get(E_Zone *zone); + +EINTERN Pol_Softkey *e_mod_pol_softkey_add(E_Zone *zone); +EINTERN void e_mod_pol_softkey_del(Pol_Softkey *softkey); +EINTERN void e_mod_pol_softkey_show(Pol_Softkey *softkey); +EINTERN void e_mod_pol_softkey_hide(Pol_Softkey *softkey); +EINTERN void e_mod_pol_softkey_update(Pol_Softkey *softkey); +EINTERN Pol_Softkey *e_mod_pol_softkey_get(E_Zone *zone); + +#endif diff --git a/src/modules/policy_mobile/e_mod_softkey.c b/src/modules/policy_mobile/e_mod_softkey.c new file mode 100644 index 000000000..11bca2f7e --- /dev/null +++ b/src/modules/policy_mobile/e_mod_softkey.c @@ -0,0 +1,171 @@ +#include "e_mod_main.h" + +static void _pol_cb_softkey(void *data, Evas_Object *obj EINA_UNUSED, const char *emission, const char *source EINA_UNUSED); +static void _pol_softkey_iconify(E_Zone *zone, Eina_Bool all); +static Evas_Object *_pol_softkey_icon_add(E_Zone *zone, const char *name); +static void _pol_softkey_icon_del(Evas_Object *comp_obj); + +static void +_pol_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; + + _pol_softkey_iconify(zone, all); +} + +static void +_pol_softkey_iconify(E_Zone *zone, Eina_Bool all) +{ + E_Desk *desk; + E_Client *ec; + Pol_Client *launcher; + + desk = e_desk_current_get(zone); + launcher = e_mod_pol_client_launcher_get(zone); + + E_CLIENT_REVERSE_FOREACH(e_comp_get(desk), 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; + + e_client_iconify(ec); + + if (!all) return; + } +} + +static Evas_Object * +_pol_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_get(NULL)->evas); + + snprintf(group, sizeof(group), "e/modules/policy-mobile/softkey/%s", name); + snprintf(path, sizeof(path), "%s/e-module-policy-mobile.edj", + e_module_dir_get(_pol_mod->module)); + + 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", + _pol_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 +_pol_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", _pol_cb_softkey); + evas_object_hide(comp_obj); + evas_object_del(comp_obj); +} + +Pol_Softkey * +e_mod_pol_softkey_add(E_Zone *zone) +{ + Pol_Softkey *softkey; + + softkey = E_NEW(Pol_Softkey, 1); + + softkey->zone = zone; + softkey->home = _pol_softkey_icon_add(zone, "home"); + softkey->back = _pol_softkey_icon_add(zone, "back"); + + _pol_mod->softkeys = eina_inlist_append(_pol_mod->softkeys, EINA_INLIST_GET(softkey)); + + return softkey; +} + +void +e_mod_pol_softkey_del(Pol_Softkey *softkey) +{ + if (!softkey) return; + + _pol_softkey_icon_del(softkey->home); + _pol_softkey_icon_del(softkey->back); + + _pol_mod->softkeys = eina_inlist_remove(_pol_mod->softkeys, EINA_INLIST_GET(softkey)); + + free(softkey); +} + +void +e_mod_pol_softkey_show(Pol_Softkey *softkey) +{ + if (!softkey) return; + + e_mod_pol_softkey_update(softkey); + + evas_object_show(softkey->home); + evas_object_show(softkey->back); +} + +void +e_mod_pol_softkey_hide(Pol_Softkey *softkey) +{ + if (!softkey) return; + + evas_object_hide(softkey->home); + evas_object_hide(softkey->back); +} + +void +e_mod_pol_softkey_update(Pol_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 = _pol_mod->conf->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); +} + +Pol_Softkey * +e_mod_pol_softkey_get(E_Zone *zone) +{ + Pol_Softkey *softkey; + + EINA_INLIST_FOREACH(_pol_mod->softkeys, softkey) + { + if (softkey->zone == zone) + return softkey; + } + + return NULL; +}