--- /dev/null
+#include "e.h"
+#include "e_mod_split_screen_manager_log.h"
+#include "e_mod_split_screen_manager.h"
+#include "e_mod_split_screen_region.h"
+#include "e_mod_appinfo_ext.h"
+
+typedef Eina_Bool (*E_Mod_Split_Screen_Manager_Hint_Func)(E_Client *ec, const char *name, const char *value);
+struct _E_Mod_Split_Screen_Manager_Hint_Handler
+{
+ int type;
+ const char *name;
+ E_Mod_Split_Screen_Manager_Hint_Func func;
+};
+
+typedef struct _E_Mod_Split_Screen_Manager_Hint_Handler E_Mod_Split_Screen_Manager_Hint_Handler;
+
+enum _E_Mod_Split_Screen_Manager_Hint_Type
+{
+ E_MOD_SPLIT_SCREEN_MANAGER_HINT_ASSIGN_REGION = 0,
+ E_MOD_SPLIT_SCREEN_MANAGER_HINT_LAUNCHER_ROLE_SET,
+ E_MOD_SPLIT_SCREEN_MANAGER_HINT_ASSIGN_REGION_SUB1,
+ E_MOD_SPLIT_SCREEN_MANAGER_HINT_ASSIGN_REGION_SUB2,
+ E_MOD_SPLIT_SCREEN_MANAGER_HINT_ACTIVATE,
+ E_MOD_SPLIT_SCREEN_MANAGER_HINT_DEACTIVATE,
+ E_MOD_SPLIT_SCREEN_MANAGER_HINT_MAX,
+};
+
+static Eina_List *_e_mod_split_screen_manager_ec_hook_handlers = NULL;
+static Eina_List *_e_mod_split_screen_manager_ec_event_handlers = NULL;
+static Eina_List *_e_mod_split_screen_manager_desk_area_hook_handlers = NULL;
+static Eina_List *_e_mod_split_screen_manager_zone_hook_handlers = NULL;
+
+static Eina_List *_e_mod_split_screen_region_list = NULL;
+static E_Client *_e_mod_split_screen_launcher_ec = NULL;
+
+/* e_client hooks */
+static void _e_mod_split_screen_manager_cb_hook_aux_hint_change(void *data, E_Client *ec);
+
+/* e_client events */
+static Eina_Bool _e_mod_split_screen_manager_cb_ec_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+static Eina_Bool _e_mod_split_screen_manager_cb_ec_remove(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+/* Aux hint handlers */
+static Eina_Bool _e_mod_split_screen_manager_hint_launcher_role_set(E_Client *ec, const char *name, const char *value);
+static Eina_Bool _e_mod_split_screen_manager_hint_assign_region(E_Client *ec, const char *name, const char *value);
+static Eina_Bool _e_mod_split_screen_manager_hint_assign_region_sub1(E_Client *ec, const char *name, const char *value);
+static Eina_Bool _e_mod_split_screen_manager_hint_assign_region_sub2(E_Client *ec, const char *name, const char *value);
+static Eina_Bool _e_mod_split_screen_manager_hint_activate(E_Client *ec, const char *name, const char *value);
+static Eina_Bool _e_mod_split_screen_manager_hint_deactivate(E_Client *ec, const char *name, const char *value);
+
+/* e_mod_split_screen_manager internal functions */
+static void _e_mod_split_screen_manager_client_manager_role_set(E_Client *ec, Eina_Bool set);
+static Eina_Bool _e_mod_split_screen_activate(E_Zone *zone);
+static Eina_Bool _e_mod_split_screen_deactivate(E_Zone *zone);
+static void _e_mod_split_screen_launcher_ec_set(E_Client *ec);
+static E_Client * _e_mod_split_screen_launcher_ec_get(void);
+static E_Mod_Split_Screen_Region *_e_mod_split_screen_manager_find_region_by_name(const char *name);
+static E_Mod_Split_Screen_Region *_e_mod_split_screen_manager_find_region_by_desk_area(E_Desk_Area *eda);
+static void _e_mod_split_screen_manager_appid_assign(E_Mod_Split_Screen_Region *emssr, const char *appid);
+static Eina_Bool _e_mod_split_screen_manager_ec_assign_to_region_name(E_Client *ec, const char *region_name);
+static Eina_Bool _e_mod_split_screen_manager_ec_relocate(E_Client *ec);
+static Eina_Bool _e_mod_split_screen_manager_ec_relocate_to_region(E_Client *ec, E_Mod_Split_Screen_Region *emssr);
+
+/* initializer */
+static Eina_Bool _e_mod_split_screen_manager_handler_init(void);
+static Eina_Bool _e_mod_split_screen_manager_aux_hint_handler_init(void);
+static void _e_mod_split_screen_manager_handler_shutdown(void);
+static void _e_mod_split_screen_manager_aux_hint_handler_shutdown(void);
+static Eina_Bool _e_mod_split_screen_manager_region_init(void);
+static void _e_mod_split_screen_manager_region_shutdown(void);
+
+static const E_Mod_Split_Screen_Manager_Hint_Handler _e_mod_split_screen_manager_hint_handler[] =
+{
+ {E_MOD_SPLIT_SCREEN_MANAGER_HINT_ASSIGN_REGION, "wm.splitscreen.win.assign_region", _e_mod_split_screen_manager_hint_assign_region},
+ {E_MOD_SPLIT_SCREEN_MANAGER_HINT_LAUNCHER_ROLE_SET, "wm.splitscreen.win.launcher.role_set", _e_mod_split_screen_manager_hint_launcher_role_set},
+ {E_MOD_SPLIT_SCREEN_MANAGER_HINT_ASSIGN_REGION_SUB1, "wm.splitscreen.win.split_screen_manager.assign_region.sub1", _e_mod_split_screen_manager_hint_assign_region_sub1},
+ {E_MOD_SPLIT_SCREEN_MANAGER_HINT_ASSIGN_REGION_SUB2, "wm.splitscreen.win.split_screen_manager.assign_region.sub2", _e_mod_split_screen_manager_hint_assign_region_sub2},
+ {E_MOD_SPLIT_SCREEN_MANAGER_HINT_ACTIVATE, "wm.splitscreen.win.split_screen_manager.activate", _e_mod_split_screen_manager_hint_activate},
+ {E_MOD_SPLIT_SCREEN_MANAGER_HINT_DEACTIVATE, "wm.splitscreen.win.split_screen_manager.deactivate", _e_mod_split_screen_manager_hint_deactivate},
+ {E_MOD_SPLIT_SCREEN_MANAGER_HINT_MAX, NULL, NULL},
+};
+
+/* Hook handlers */
+static void
+_e_mod_split_screen_manager_cb_hook_aux_hint_change(void *data, E_Client *ec)
+{
+ const char *hint, *val;
+
+ if (!ec)
+ {
+ SSMINF("ec is NULL", NULL);
+ return;
+ }
+
+ for (int i=0 ; i<E_MOD_SPLIT_SCREEN_MANAGER_HINT_MAX ; i++)
+ {
+ hint = _e_mod_split_screen_manager_hint_handler[i].name;
+ val = e_hints_aux_hint_value_get(ec, hint);
+ if (!val) continue;
+
+ _e_mod_split_screen_manager_hint_handler[i].func(ec, hint, val);
+ }
+
+ return;
+}
+
+static void
+_e_mod_split_screen_manager_cb_hook_eval_fetch(void *data, E_Client *ec)
+{
+ if (!ec)
+ {
+ SSMINF("ec is NULL", NULL);
+ return;
+ }
+ // TODO: FIX blinking issue while launching child window
+ _e_mod_split_screen_manager_ec_relocate(ec);
+
+ return;
+}
+
+static void
+_e_mod_split_screen_manager_cb_hook_assign_appid(void *data EINA_UNUSED, E_Desk_Area *eda, void *appid_ptr)
+{
+ E_Mod_Split_Screen_Region *emssr;
+ Eina_Stringshare *appid;
+
+ EINA_SAFETY_ON_NULL_RETURN(eda);
+ EINA_SAFETY_ON_NULL_RETURN(appid_ptr);
+
+ appid = eina_stringshare_add(appid_ptr);
+ emssr = _e_mod_split_screen_manager_find_region_by_desk_area(eda);
+ if (!emssr)
+ {
+ SSMERR("Failed to find region for desk area %p", NULL, eda);
+ return;
+ }
+
+ _e_mod_split_screen_manager_appid_assign(emssr, appid);
+
+ return;
+}
+
+static void
+_e_mod_split_screen_manager_cb_hook_activate(void *data, E_Zone *zone)
+{
+ if (!zone) return;
+ _e_mod_split_screen_activate(zone);
+}
+
+static void
+_e_mod_split_screen_manager_cb_hook_deactivate(void *data, E_Zone *zone)
+{
+ if (!zone) return;
+ _e_mod_split_screen_deactivate(zone);
+}
+
+
+/* e_client events */
+static Eina_Bool
+_e_mod_split_screen_manager_cb_ec_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ E_Event_Client *ev;
+
+ ev = event;
+ if (!ev) return ECORE_CALLBACK_PASS_ON;
+
+ _e_mod_split_screen_manager_ec_relocate(ev->ec);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_cb_ec_remove(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ E_Event_Client *ev;
+
+ ev = event;
+ if (!ev) return ECORE_CALLBACK_PASS_ON;
+
+ e_mod_split_screen_region_ec_dismiss(ev->ec);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+/* Aux hint handlers */
+static Eina_Bool
+_e_mod_split_screen_manager_hint_launcher_role_set(E_Client *ec, const char *name, const char *value)
+{
+ if (!strncmp(value, "1", 1))
+ {
+ _e_mod_split_screen_manager_client_manager_role_set(ec, EINA_TRUE);
+ }
+ else
+ {
+ _e_mod_split_screen_manager_client_manager_role_set(ec, EINA_FALSE);
+ }
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_hint_assign_region(E_Client *ec, const char *name, const char *value)
+{
+ E_Mod_Split_Screen_Region *emssr;
+ Eina_Stringshare *appid;
+
+ char _region_name[10] = {0,};
+ char _appid[255] = {0,};
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+ // hint value format: region_name/appid
+ sscanf(value, "%[^/]/%s", _region_name, _appid);
+ SSMINF("client appid(%s) -> assign to region:%s", ec, _appid, _region_name);
+
+ if ((strlen(_region_name) <= 0) || strlen(_region_name) > 10)
+ {
+ SSMERR("invalid region name:%s", ec, _region_name);
+ return EINA_FALSE;
+ }
+
+ if ((strlen(_appid) <= 0) || (strlen(_appid) > 255))
+ {
+ SSMERR("invalid app id:%s", ec, _appid);
+ return EINA_FALSE;
+ }
+
+ emssr = _e_mod_split_screen_manager_find_region_by_name(_region_name);
+ if (!emssr)
+ {
+ SSMERR("invalid region name:%s", ec, _region_name);
+ return EINA_FALSE;
+ }
+
+ appid = eina_stringshare_add(_appid);
+
+ _e_mod_split_screen_manager_appid_assign(emssr, appid);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_hint_assign_region_sub1(E_Client *ec, const char *name, const char *value)
+{
+ E_Mod_Split_Screen_Region *emssr;
+ Eina_Stringshare *appid;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+ if ((strlen(value) <= 0) || strlen(value) > 255)
+ {
+ SSMERR("invalid app id:%s", ec, value);
+ return EINA_FALSE;
+ }
+
+ appid = eina_stringshare_add(value);
+
+ emssr = _e_mod_split_screen_manager_find_region_by_name("sub1");
+ if (!emssr)
+ {
+ SSMERR("invalid region name:%s", ec, "sub1");
+ return EINA_FALSE;
+ }
+
+ _e_mod_split_screen_manager_appid_assign(emssr, appid);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_hint_assign_region_sub2(E_Client *ec, const char *name, const char *value)
+{
+ E_Mod_Split_Screen_Region *emssr;
+ Eina_Stringshare *appid;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+ if ((strlen(value) <= 0) || strlen(value) > 255)
+ {
+ SSMERR("invalid app id:%s", ec, value);
+ return EINA_FALSE;
+ }
+
+ appid = eina_stringshare_add(value);
+
+ emssr = _e_mod_split_screen_manager_find_region_by_name("sub2");
+ if (!emssr)
+ {
+ SSMERR("invalid region name:%s", ec, "sub2");
+ return EINA_FALSE;
+ }
+
+ _e_mod_split_screen_manager_appid_assign(emssr, appid);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_hint_activate(E_Client *ec, const char *name, const char *value)
+{
+ return _e_mod_split_screen_activate(e_zone_current_get());
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_hint_deactivate(E_Client *ec, const char *name, const char *value)
+{
+ return _e_mod_split_screen_deactivate(e_zone_current_get());
+}
+
+/* internal functions */
+
+static void
+_e_mod_split_screen_manager_client_manager_role_set(E_Client *ec, Eina_Bool set)
+{
+ if (!ec) return;
+ if (ec->floating == set) return;
+
+ ec->floating = set;
+
+ if (ec->frame)
+ {
+ if (set)
+ {
+ _e_mod_split_screen_launcher_ec_set(ec);
+ ec->floating_saved_layer = ec->layer;
+ e_client_layer_set(ec, E_LAYER_CLIENT_ABOVE);
+ ec->netwm.type = E_WINDOW_TYPE_UTILITY;
+ _e_mod_split_screen_manager_ec_assign_to_region_name(ec, "above");
+ }
+ else
+ {
+ e_client_layer_set(ec, ec->floating_saved_layer);
+ ec->netwm.type = E_WINDOW_TYPE_NORMAL;
+ e_mod_split_screen_region_ec_dismiss(ec);
+ }
+ }
+
+ e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
+ e_comp_object_dirty(ec->frame);
+ e_comp_object_render(ec->frame);
+
+ EC_CHANGED(ec);
+}
+
+static Eina_Bool
+_e_mod_split_screen_activate(E_Zone *zone)
+{
+ E_Desk *desk;
+ E_Client *ec, *launcher;
+ Eina_Bool ret = EINA_FALSE;
+
+ SSMINF("ACTIVATE split screen", NULL);
+
+ desk = e_desk_current_get(zone);
+ ret = e_desk_desk_area_enable(desk);
+
+ // relocate all e clients
+ E_CLIENT_FOREACH(ec)
+ {
+ _e_mod_split_screen_manager_ec_relocate(ec);
+ }
+
+ // launcher window must be above desk group to unobscured by other windows
+ launcher = _e_mod_split_screen_launcher_ec_get();
+ if (launcher)
+ _e_mod_split_screen_manager_ec_assign_to_region_name(launcher, "above");
+
+ return ret;
+}
+
+static Eina_Bool
+_e_mod_split_screen_deactivate(E_Zone *zone)
+{
+ E_Desk *desk;
+ Eina_Bool ret = EINA_FALSE;
+
+ SSMINF("DEACTIVATE split screen", NULL);
+
+ desk = e_desk_current_get(zone);
+ ret = e_desk_desk_area_disable(desk);
+
+ return ret;
+}
+
+static void
+_e_mod_split_screen_launcher_ec_set(E_Client *ec)
+{
+ _e_mod_split_screen_launcher_ec = ec;
+}
+
+static E_Client *
+_e_mod_split_screen_launcher_ec_get(void)
+{
+ return _e_mod_split_screen_launcher_ec;
+}
+
+static E_Mod_Split_Screen_Region *
+_e_mod_split_screen_manager_find_region_by_name(const char *name)
+{
+ E_Mod_Split_Screen_Region *emssr = NULL;
+ Eina_List *l;
+ const char *region_name;
+
+ EINA_LIST_FOREACH(_e_mod_split_screen_region_list, l, emssr)
+ {
+ region_name = e_mod_split_screen_region_name_get(emssr);
+ if (region_name && !strncmp(region_name, name, strlen(region_name))) break;
+ }
+
+ return emssr;
+}
+
+static E_Mod_Split_Screen_Region *
+_e_mod_split_screen_manager_find_region_by_desk_area(E_Desk_Area *eda)
+{
+ E_Mod_Split_Screen_Region *emssr = NULL;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(_e_mod_split_screen_region_list, l, emssr)
+ {
+ if (e_mod_split_screen_region_desk_area_get(emssr) == eda) break;
+ }
+
+ return emssr;
+}
+
+static void
+_e_mod_split_screen_manager_appid_assign(E_Mod_Split_Screen_Region *emssr, const char *appid)
+{
+ E_Mod_Split_Screen_Region *emssr_iter;
+ E_Client *ec;
+ Eina_Stringshare *region_name;
+ Eina_List *l;
+
+ // reassign AppID to Split screen region
+ EINA_LIST_FOREACH(_e_mod_split_screen_region_list, l, emssr_iter)
+ {
+ e_mod_split_screen_region_appid_dismiss(emssr_iter, appid);
+ }
+ e_mod_split_screen_region_appid_assign(emssr, appid);
+
+ // assign clients of appID to Split screen region
+ l = e_mod_appinfo_ext_find_clients_by_appid(appid);
+ EINA_LIST_FREE(l, ec)
+ {
+ e_mod_split_screen_region_ec_assign(emssr, ec);
+ }
+
+ region_name = e_mod_split_screen_region_name_get(emssr);
+ SSMINF("from now on, appid %s will be assign to region:%s", NULL, appid, region_name);
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_util_client_special_check(E_Client *ec)
+{
+ if (!ec) return EINA_FALSE;
+
+ if (_e_mod_split_screen_launcher_ec_get() == ec) return EINA_TRUE;
+
+ if ((e_policy_client_is_lockscreen(ec)) ||
+ (e_policy_client_is_keyboard(ec)) ||
+ (e_policy_client_is_keyboard_sub(ec)) ||
+ (e_policy_client_is_noti(ec)) ||
+ (e_policy_client_is_quickpanel(ec)) ||
+ (e_policy_client_is_volume(ec)) ||
+ (e_policy_client_is_cursor(ec)) ||
+ (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role)))
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_ec_assign_to_region_name(E_Client *ec, const char *region_name)
+{
+ E_Mod_Split_Screen_Region *emssr = NULL;
+
+ if (!ec) return ECORE_CALLBACK_PASS_ON;
+ if (!region_name) return ECORE_CALLBACK_PASS_ON;
+
+ emssr = _e_mod_split_screen_manager_find_region_by_name(region_name);
+ if (!emssr)
+ {
+ SSMERR("invalid region name:%s", ec, region_name);
+ return EINA_FALSE;
+ }
+ return e_mod_split_screen_region_ec_assign(emssr, ec);
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_ec_relocate(E_Client *ec)
+{
+ E_Mod_Split_Screen_Region *emssr = NULL;
+ E_Client *parent_ec = NULL;
+ Eina_Bool res = EINA_FALSE;
+ Eina_List *l;
+
+ if (!ec) return ECORE_CALLBACK_PASS_ON;
+
+ if (_e_mod_split_screen_manager_util_client_special_check(ec))
+ {
+ // special prupose windows.
+ _e_mod_split_screen_manager_ec_assign_to_region_name(ec, "above");
+ return EINA_TRUE;
+ }
+
+ EINA_LIST_FOREACH(_e_mod_split_screen_region_list, l, emssr)
+ {
+ res |= _e_mod_split_screen_manager_ec_relocate_to_region(ec, emssr);
+ }
+
+ if (!res)
+ {
+ // find the parent ec that is in the region
+ for (parent_ec = ec->parent;
+ parent_ec != NULL;
+ parent_ec = parent_ec->parent)
+ {
+ EINA_LIST_FOREACH(_e_mod_split_screen_region_list, l, emssr)
+ {
+ res |= _e_mod_split_screen_manager_ec_relocate_to_region(parent_ec, emssr);
+ }
+ }
+ }
+
+ return res;
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_ec_relocate_to_region(E_Client *ec, E_Mod_Split_Screen_Region *emssr)
+{
+ Eina_Stringshare *appid;
+ Eina_List *appid_list, *l;
+ Eina_Bool res = EINA_FALSE;
+
+ if (!ec || !emssr) return EINA_FALSE;
+
+ appid_list = e_mod_split_screen_region_appid_list_get(emssr);
+
+ EINA_LIST_FOREACH(appid_list, l, appid)
+ if (ec->netwm.pid == e_mod_appinfo_ext_find_pid_by_appid(appid))
+ {
+ Eina_Stringshare *region_name = e_mod_split_screen_region_name_get(emssr);
+ SSMINF("client(%p):%s rearrange to region:%s",
+ ec, ec, ec ? ec->icccm.name : "NULL", region_name);
+ res |= e_mod_split_screen_region_ec_assign(emssr, ec);
+ }
+
+ return res;
+}
+
+/* split screen initializer */
+
+static Eina_Bool
+_e_mod_split_screen_manager_handler_init(void)
+{
+ E_Desk_Area_Hook *eda_hook;
+ E_Zone_Hook *ez_hook;
+
+ E_LIST_HANDLER_APPEND(_e_mod_split_screen_manager_ec_event_handlers, E_EVENT_CLIENT_ADD, _e_mod_split_screen_manager_cb_ec_add, NULL);
+ E_LIST_HANDLER_APPEND(_e_mod_split_screen_manager_ec_event_handlers, E_EVENT_CLIENT_REMOVE, _e_mod_split_screen_manager_cb_ec_remove, NULL);
+
+ E_LIST_HOOK_APPEND(_e_mod_split_screen_manager_ec_hook_handlers, E_CLIENT_HOOK_EVAL_FETCH, _e_mod_split_screen_manager_cb_hook_eval_fetch, NULL);
+
+ eda_hook = e_desk_area_hook_add(E_DESK_AREA_HOOK_SET_APPID, _e_mod_split_screen_manager_cb_hook_assign_appid, NULL);
+ if (eda_hook) _e_mod_split_screen_manager_desk_area_hook_handlers = eina_list_append(_e_mod_split_screen_manager_desk_area_hook_handlers, eda_hook);
+
+ ez_hook = e_zone_hook_add(E_ZONE_HOOK_SPLISCREEN_ACTIVATE, _e_mod_split_screen_manager_cb_hook_activate, NULL);
+ if (ez_hook) _e_mod_split_screen_manager_zone_hook_handlers = eina_list_append(_e_mod_split_screen_manager_zone_hook_handlers, ez_hook);
+
+ ez_hook = e_zone_hook_add(E_ZONE_HOOK_SPLISCREEN_DEACTIVATE, _e_mod_split_screen_manager_cb_hook_deactivate, NULL);
+ if (ez_hook) _e_mod_split_screen_manager_zone_hook_handlers = eina_list_append(_e_mod_split_screen_manager_zone_hook_handlers, ez_hook);
+
+ if (!_e_mod_split_screen_manager_ec_event_handlers ||
+ !_e_mod_split_screen_manager_ec_hook_handlers ||
+ !_e_mod_split_screen_manager_desk_area_hook_handlers)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_aux_hint_handler_init(void)
+{
+ E_LIST_HOOK_APPEND(_e_mod_split_screen_manager_ec_hook_handlers, E_CLIENT_HOOK_AUX_HINT_CHANGE, _e_mod_split_screen_manager_cb_hook_aux_hint_change, NULL);
+
+ if (!_e_mod_split_screen_manager_ec_hook_handlers)
+ return EINA_FALSE;
+
+ for (int i=0 ; i<E_MOD_SPLIT_SCREEN_MANAGER_HINT_MAX ; i++)
+ {
+ e_hints_aux_hint_supported_add(_e_mod_split_screen_manager_hint_handler[i].name);
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_e_mod_split_screen_manager_handler_shutdown(void)
+{
+ E_FREE_LIST(_e_mod_split_screen_manager_ec_event_handlers, ecore_event_handler_del);
+ E_FREE_LIST(_e_mod_split_screen_manager_desk_area_hook_handlers, e_desk_area_hook_del);
+}
+
+static void
+_e_mod_split_screen_manager_aux_hint_handler_shutdown(void)
+{
+ E_FREE_LIST(_e_mod_split_screen_manager_ec_hook_handlers, e_client_hook_del);
+
+ for (int i=0 ; i<E_MOD_SPLIT_SCREEN_MANAGER_HINT_MAX ; i++)
+ {
+ e_hints_aux_hint_supported_del(_e_mod_split_screen_manager_hint_handler[i].name);
+ }
+}
+
+static Eina_Bool
+_e_mod_split_screen_manager_region_init(void)
+{
+ E_Desk *desk;
+ E_Mod_Split_Screen_Region *emssr_sub1, *emssr_sub2, *emssr_above;
+ int desk_x, desk_y, desk_w, desk_h;
+
+ desk = e_desk_current_get(e_zone_current_get());
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desk, EINA_FALSE);
+
+ desk_x = desk->geom.x;
+ desk_y = desk->geom.y;
+ desk_w = desk->geom.w;
+ desk_h = desk->geom.h;
+
+ emssr_sub1 = e_mod_split_screen_region_new("sub1", desk_x, desk_y, desk_w, desk_h / 2);
+ if (!emssr_sub1) return EINA_FALSE;
+
+ _e_mod_split_screen_region_list = eina_list_append(_e_mod_split_screen_region_list, emssr_sub1);
+
+ emssr_sub2 = e_mod_split_screen_region_new("sub2", desk_x, desk_y + desk_h / 2, desk_w, desk_h / 2);
+ if (!emssr_sub2) return EINA_FALSE;
+
+ _e_mod_split_screen_region_list = eina_list_append(_e_mod_split_screen_region_list, emssr_sub2);
+
+ emssr_above = e_mod_split_screen_region_new("above", desk_x, desk_y, desk_w, desk_h);
+ if (!emssr_above) return EINA_FALSE;
+
+ _e_mod_split_screen_region_list = eina_list_append(_e_mod_split_screen_region_list, emssr_above);
+
+ return EINA_TRUE;
+}
+
+static void
+_e_mod_split_screen_manager_region_shutdown(void)
+{
+ E_Mod_Split_Screen_Region *emssr;
+
+ if (!_e_mod_split_screen_region_list) return;
+
+ EINA_LIST_FREE(_e_mod_split_screen_region_list, emssr)
+ {
+ e_mod_split_screen_region_del(emssr);
+ }
+}
+
+EINTERN Eina_Bool
+e_mod_split_screen_manager_init(void)
+{
+ Eina_Bool res;
+
+ SSMDBG("SPLIT_SCREEN_MANAGER module init", NULL);
+
+ e_zone_screen_splitscreen_enable(e_zone_current_get());
+
+ res = _e_mod_split_screen_manager_region_init();
+ EINA_SAFETY_ON_FALSE_GOTO(res, err);
+
+ res = _e_mod_split_screen_manager_handler_init();
+ EINA_SAFETY_ON_FALSE_GOTO(res, err);
+
+ res = _e_mod_split_screen_manager_aux_hint_handler_init();
+ EINA_SAFETY_ON_FALSE_GOTO(res, err);
+
+ return EINA_TRUE;
+
+err:
+ SSMINF("FAILED TO module init!!!", NULL);
+ e_mod_split_screen_manager_shutdown();
+
+ return EINA_FALSE;
+}
+
+EINTERN void
+e_mod_split_screen_manager_shutdown(void)
+{
+ SSMDBG("SPLIT_SCREEN_MANAGER module shutdown", NULL);
+ _e_mod_split_screen_manager_aux_hint_handler_shutdown();
+ _e_mod_split_screen_manager_handler_shutdown();
+ _e_mod_split_screen_manager_region_shutdown();
+}
--- /dev/null
+#include "e.h"
+#include "e_mod_split_screen_manager_log.h"
+#include "e_mod_split_screen_region.h"
+#include "e_mod_appinfo_ext.h"
+
+struct _E_Mod_Split_Screen_Region
+{
+ E_Zone *zone;
+ E_Desk *desk;
+ E_Desk_Area *eda;
+ Eina_Stringshare *name;
+ Eina_Bool is_del;
+ Eina_List *appid_list;
+ Eina_List *client_list;
+};
+
+/* e_mod_split_screen_region internal functions */
+static E_Mod_Split_Screen_Region * _e_mod_split_screen_region_new(const char *name, int x, int y, int w, int h);
+static void _e_mod_split_screen_region_del(E_Mod_Split_Screen_Region *emssr);
+static void _e_mod_split_screen_region_appid_assign(E_Mod_Split_Screen_Region *emssr, const char *appid);
+static void _e_mod_split_screen_region_appid_dismiss(E_Mod_Split_Screen_Region *emssr, const char *appid);
+static Eina_Bool _e_mod_split_screen_region_ec_assign(E_Mod_Split_Screen_Region *emssr, E_Client *ec);
+static Eina_Bool _e_mod_split_screen_region_ec_dismiss(E_Client *ec);
+
+
+/* internal functions */
+static E_Mod_Split_Screen_Region *
+_e_mod_split_screen_region_new(const char *name, int x, int y, int w, int h)
+{
+ E_Desk *desk;
+ E_Mod_Split_Screen_Region *emssr = NULL;
+ E_Desk_Area *eda = NULL;
+
+ emssr = E_NEW(E_Mod_Split_Screen_Region, 1);
+ if (!emssr) return NULL;
+
+ emssr->zone = e_zone_current_get();
+
+ desk = e_desk_current_get(emssr->zone);
+ EINA_SAFETY_ON_NULL_GOTO(desk, err);
+
+ emssr->desk = desk;
+ emssr->name = eina_stringshare_add(name);
+
+ eda = e_desk_desk_area_add(desk, x, y, w, h, E_DESK_AREA_LAYER_NORMAL);
+ EINA_SAFETY_ON_NULL_GOTO(eda, err);
+
+ e_desk_area_transform_enable_set(eda, EINA_FALSE);
+ eda->name = eina_stringshare_add(name);
+ emssr->eda = eda;
+
+ SSMINF("region added, desk_area:%p, name:%s, id:%d", NULL, emssr->eda, emssr->name, emssr->eda->id);
+
+ return emssr;
+
+err:
+ if (emssr) E_FREE(emssr);
+ if (eda) E_FREE(eda);
+ return NULL;
+}
+
+static void
+_e_mod_split_screen_region_del(E_Mod_Split_Screen_Region *emssr)
+{
+ emssr->is_del = EINA_TRUE;
+ e_desk_desk_area_disable(emssr->desk);
+ E_FREE(emssr);
+}
+
+static void
+_e_mod_split_screen_region_appid_assign(E_Mod_Split_Screen_Region *emssr, const char *appid)
+{
+ emssr->appid_list = eina_list_append(emssr->appid_list, appid);
+}
+
+static void
+_e_mod_split_screen_region_appid_dismiss(E_Mod_Split_Screen_Region *emssr, const char *appid)
+{
+ Eina_List *l, *ll;
+
+ EINA_LIST_FOREACH_SAFE(emssr->appid_list, l, ll, appid)
+ {
+ if (!e_util_strcmp(appid, appid))
+ {
+ eina_stringshare_del(appid);
+ emssr->appid_list = eina_list_remove_list(emssr->appid_list, ll);
+ }
+ }
+}
+
+static Eina_Bool
+_e_mod_split_screen_region_ec_assign(E_Mod_Split_Screen_Region *emssr, E_Client *ec)
+{
+ E_Client *child_ec;
+ Eina_List *l;
+
+ SSMDBG("set to region: %s", ec, emssr->name);
+
+ if (ec->lock_client_size)
+ {
+ ec->maximized = E_MAXIMIZE_NONE;
+ e_client_maximize(ec, E_MAXIMIZE_EXPAND | E_MAXIMIZE_BOTH);
+ }
+
+ e_client_desk_area_set(ec, emssr->eda);
+
+ // control transient for childs
+ EINA_LIST_FOREACH(ec->transients, l, child_ec)
+ {
+ _e_mod_split_screen_region_ec_assign(emssr, child_ec);
+ }
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_mod_split_screen_region_ec_dismiss(E_Client *ec)
+{
+ E_Client *child_ec;
+ Eina_List *l;
+
+ SSMINF("unset ec from regions", ec);
+
+ if (ec->lock_client_size)
+ {
+ ec->maximized = E_MAXIMIZE_NONE;
+ e_client_maximize(ec, E_MAXIMIZE_EXPAND | E_MAXIMIZE_BOTH);
+ }
+
+ e_client_desk_area_set(ec, NULL);
+
+ // control transient for childs
+ EINA_LIST_FOREACH(ec->transients, l, child_ec)
+ {
+ _e_mod_split_screen_region_ec_dismiss(child_ec);
+ }
+
+ return EINA_TRUE;
+}
+
+/* Internal APIs */
+EINTERN E_Mod_Split_Screen_Region *
+e_mod_split_screen_region_new(const char *name, int x, int y, int w, int h)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+ return _e_mod_split_screen_region_new(name, x, y, w, h);
+}
+
+EINTERN void
+e_mod_split_screen_region_del(E_Mod_Split_Screen_Region *emssr)
+{
+ EINA_SAFETY_ON_NULL_RETURN(emssr);
+ _e_mod_split_screen_region_del(emssr);
+}
+
+EINTERN const char *
+e_mod_split_screen_region_name_get(E_Mod_Split_Screen_Region *emssr)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(emssr, NULL);
+ return emssr->name;
+}
+
+EINTERN E_Desk *
+e_mod_split_screen_region_desk_get(E_Mod_Split_Screen_Region *emssr)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(emssr, NULL);
+ return emssr->desk;
+}
+
+EINTERN E_Desk_Area *
+e_mod_split_screen_region_desk_area_get(E_Mod_Split_Screen_Region *emssr)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(emssr, NULL);
+ return emssr->eda;
+}
+
+EINTERN void
+e_mod_split_screen_region_appid_assign(E_Mod_Split_Screen_Region *emssr, const char *appid)
+{
+ EINA_SAFETY_ON_NULL_RETURN(emssr);
+ EINA_SAFETY_ON_NULL_RETURN(appid);
+
+ _e_mod_split_screen_region_appid_dismiss(emssr, appid);
+ _e_mod_split_screen_region_appid_assign(emssr, appid);
+}
+
+EINTERN void
+e_mod_split_screen_region_appid_dismiss(E_Mod_Split_Screen_Region *emssr, const char *appid)
+{
+ EINA_SAFETY_ON_NULL_RETURN(emssr);
+ EINA_SAFETY_ON_NULL_RETURN(appid);
+
+ _e_mod_split_screen_region_appid_dismiss(emssr, appid);
+}
+
+EINTERN Eina_List *
+e_mod_split_screen_region_appid_list_get(E_Mod_Split_Screen_Region *emssr)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(emssr, NULL);
+ return emssr->appid_list;
+}
+
+EINTERN Eina_Bool
+e_mod_split_screen_region_ec_assign(E_Mod_Split_Screen_Region *emssr, E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(emssr, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+ return _e_mod_split_screen_region_ec_assign(emssr, ec);
+}
+
+EINTERN Eina_Bool
+e_mod_split_screen_region_ec_dismiss(E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+ return _e_mod_split_screen_region_ec_dismiss(ec);
+}