From 2e731255404e0efb0df1ede8d0b0a32ac011b420 Mon Sep 17 00:00:00 2001
From: Volodymyr Riazantsev <volodymyr.riazantsev@globallogic.com>
Date: Sat, 16 Jul 2016 02:53:25 -0400
Subject: [PATCH] ivi-shell: Add autolaunch and launch rules functionality

Add ability to select application for autolaunch.
Also launch rules settings are added.

Signed-off-by: Volodymyr Riazantsev <volodymyr.riazantsev@globallogic.com>
Signed-off-by: Karthik Ramanan <a0393906@ti.com>
---
 ivi-shell/ivi-layout-controller-ti.c | 293 +++++++++++++++++++++++++++++++----
 1 file changed, 259 insertions(+), 34 deletions(-)

diff --git a/ivi-shell/ivi-layout-controller-ti.c b/ivi-shell/ivi-layout-controller-ti.c
index b7cf436..4a2d648 100644
--- a/ivi-shell/ivi-layout-controller-ti.c
+++ b/ivi-shell/ivi-layout-controller-ti.c
@@ -27,6 +27,9 @@
 #include <string.h>
 #include <assert.h>
 
+#include <fcntl.h>
+#include <unistd.h>
+
 #include "ivi-layout-export.h"
 
 #ifndef container_of
@@ -56,13 +59,24 @@ if (__dl__ & debug_level) \
 #define pr_wrn(...) __print_log(DL_WRN, "W: " __VA_ARGS__)
 #define TRACE() __print_log(DL_DBG, "TR: %s - %d\n", __func__, __LINE__)
 
-
-#define WINDOWS_TITLE_HEIGHT 30
 #define DEFAULT_SURFACE_ID_FOR_WL_SHELL_APP 0x80000000
 
 /*****************************************************************************
  *  structure, globals
  ****************************************************************************/
+
+struct hmi_launch_rule {
+#define MAX_APP_NAME_LEN	64
+	char      app_name[MAX_APP_NAME_LEN];
+	int       screen_id;
+	int       order;
+	int       autofocus;
+	int       mode;
+	int32_t   src_rect[4];
+	int32_t   dest_rect[4];
+	int32_t   crop_rect[4];
+};
+
 struct hmi_controller_layer {
 	struct ivi_layout_layer *ivilayer;
 	uint32_t id_layer;
@@ -75,6 +89,7 @@ struct hmi_controller_layer {
 	struct wl_list link;
 	struct wl_list screen_link;
 	struct wl_list surfaces_list;
+	struct hmi_launch_rule *rule;
 };
 
 struct hmi_controller_surface {
@@ -82,6 +97,7 @@ struct hmi_controller_surface {
 	void               *ivisurf;
 	struct wl_list     link;
 	struct wl_listener destroy_listener;
+	int                conf_num;
 };
 
 struct hmi_controller_screen {
@@ -93,6 +109,8 @@ struct hmi_server_setting {
 	uint32_t    base_layer_id;
 	int32_t     panel_height;
 	char       *ivi_homescreen;
+	char       *homescreen_app;
+	struct wl_array rules;
 };
 
 struct hmi_controller {
@@ -108,6 +126,7 @@ struct hmi_controller {
 	struct wl_listener                  destroy_listener;
 	struct wl_client                   *user_interface;
 	struct wl_list                      layers_list;
+
 };
 
 const struct ivi_controller_interface *ivi_controller_interface;
@@ -143,6 +162,42 @@ mem_alloc(size_t size, char *file, int32_t line)
 
 #define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
 
+static int
+get_process_name_by_pid(pid_t pid, char *name, int size)
+{
+	char proc_name[256] = "/proc/";
+	char n[512] = {0};
+	char *_n;
+
+	sprintf(&proc_name[strlen(proc_name)], "%d/exe", (int)pid);
+
+	if (!name
+	    || access(proc_name, R_OK)
+	    || (readlink(proc_name, n, sizeof(n)) <= 0)) {
+
+		return -1;
+	}
+
+	_n = strrchr(n, '/');
+	strncpy(name, _n ? (_n + 1) : n, size);
+
+	return 0;
+}
+
+static struct hmi_launch_rule
+*get_rule(struct wl_array *arr, const char *app_name)
+{
+	struct hmi_launch_rule *rule = NULL;
+
+	wl_array_for_each(rule, arr) {
+		if (!strcmp(app_name, rule->app_name))
+			return rule;
+	}
+
+	return NULL;
+}
+
+
 /**
  * Internal method to create ivi_layer with hmi_controller_layer and
  * add to a ivi_screen
@@ -177,6 +232,42 @@ create_layer(struct ivi_layout_screen *iviscrn,
 
 }
 
+static void
+register_layer_on_screen(struct hmi_controller *hmi_ctrl,
+				int i,
+				struct hmi_controller_layer *nlayer)
+{
+	unsigned cnt, j = 0;
+	struct hmi_controller_layer *layer = NULL;
+        struct ivi_layout_layer **layers;
+
+	if (nlayer->rule && nlayer->rule->order == 0) {
+		wl_list_insert(&hmi_ctrl->screens[i].layers_list, &nlayer->screen_link);
+	} else {
+		wl_list_for_each(layer, &hmi_ctrl->screens[i].layers_list, screen_link) {
+			if (layer->rule && (layer->rule->order == 0))
+				continue;
+			else
+				break;
+		}
+		wl_list_insert(layer->screen_link.prev, &nlayer->screen_link);
+	}
+
+	cnt = wl_list_length(&hmi_ctrl->screens[i].layers_list);
+
+	layers = calloc(cnt, sizeof(*layers));
+
+	wl_list_for_each_reverse(layer, &hmi_ctrl->screens[i].layers_list, screen_link) {
+		layers[j++] = layer->ivilayer;
+	}
+
+	ivi_controller_interface->screen_set_render_order(hmi_ctrl->screens[i].iviscrn, layers, cnt);
+
+	free(layers);
+
+	ivi_controller_interface->commit_changes();
+}
+
 static struct hmi_controller_layer
 *get_layer_for_surface(struct hmi_controller *hmi_ctrl
 			, struct ivi_layout_surface *ivisurf
@@ -188,6 +279,9 @@ static struct hmi_controller_layer
 	struct wl_client *client;
 	struct ivi_layout_screen *iviscrn  = NULL;
 	struct weston_output *output = NULL;
+	char proc_name[256];
+	struct hmi_launch_rule *rule;
+
 	pid_t pid;
 	uid_t uid;
 	gid_t gid;
@@ -213,13 +307,21 @@ static struct hmi_controller_layer
 
 	pr_dbg("Existed layer for PID=%d was not found. Creating new\n", pid);
 
-	for(;; i++) {
-		if (wl_list_empty(&hmi_ctrl->screens[i].layers_list) ||
-				(i == (hmi_ctrl->screens_count - 1)))
-			break;
-	};
+	get_process_name_by_pid(pid, proc_name, sizeof(proc_name));
 
-	iviscrn = hmi_ctrl->screens[i].iviscrn;
+	rule = get_rule(&hmi_ctrl->hmi_setting->rules, proc_name);
+
+	if (rule && (rule->screen_id >= 0) && (rule->screen_id < hmi_ctrl->screens_count)) {
+		iviscrn = hmi_ctrl->screens[rule->screen_id].iviscrn;
+		i = rule->screen_id;
+	} else {
+		for(;; i++) {
+			if (wl_list_empty(&hmi_ctrl->screens[i].layers_list) ||
+					(i == (hmi_ctrl->screens_count - 1)))
+				break;
+		};
+		iviscrn = hmi_ctrl->screens[i].iviscrn;
+	}
 
 	layer = calloc(1, sizeof *layer);
 
@@ -230,14 +332,16 @@ static struct hmi_controller_layer
 	wl_list_init(&layer->surfaces_list);
 
 	layer->width = output->width;
-	layer->height = output->height + WINDOWS_TITLE_HEIGHT;
+	layer->height = output->height;
 	layer->id_layer = hmi_ctrl->hmi_setting->base_layer_id++;
 	layer->pid = pid;
+	layer->rule = rule;
 
 	create_layer(iviscrn, layer);
 
 	wl_list_insert(&hmi_ctrl->layers_list, &layer->link);
-	wl_list_insert(&hmi_ctrl->screens[i].layers_list, &layer->screen_link);
+
+	register_layer_on_screen(hmi_ctrl, i, layer);
 
 	return layer;
 
@@ -350,41 +454,77 @@ set_notification_configure_surface(struct ivi_layout_surface *ivisurf,
 	struct hmi_controller_layer *hmi_ctrl_layer = NULL;
 	struct weston_surface *surface;
 	struct hmi_controller_surface *hmi_ctrl_surf = NULL;
+	int src_rect[4] = {0};
+	int dest_rect[4] = {0};
 
 	wl_list_for_each(hmi_ctrl_layer, &hmi_ctrl->layers_list, link) {
 		wl_list_for_each(hmi_ctrl_surf, &hmi_ctrl_layer->surfaces_list, link) {
 			if (hmi_ctrl_surf->ivisurf == ivisurf) {
-				pr_dbg("Surface was already configured. Skip add to list\n");
 				goto found;
 			}
 		}
 	}
 
-	hmi_ctrl_layer = NULL;
+	return;
 found:
 	surface = ivi_controller_interface->surface_get_weston_surface(ivisurf);
 
-	if (surface) {
-
-		ivi_controller_interface->surface_set_source_rectangle(
-			ivisurf, 0, WINDOWS_TITLE_HEIGHT, surface->width,
-			surface->height);
-
-#if 0
-		ivi_controller_interface->surface_set_destination_rectangle(
-			ivisurf, 0, 0, surface->width, surface->height);
-#else
-		if (hmi_ctrl_layer) {
-			ivi_controller_interface->surface_set_destination_rectangle(
-				ivisurf, 0, 0, hmi_ctrl_layer->width, hmi_ctrl_layer->height);
-		} else {
-			ivi_controller_interface->surface_set_destination_rectangle(
-				ivisurf, 0, 0, surface->width, surface->height);
+	if (!surface)
+		return;
+
+	src_rect[2] = dest_rect[2] = surface->width;
+	src_rect[3] = dest_rect[3] = surface->height;
+
+	if (hmi_ctrl_layer && hmi_ctrl_layer->rule) {
+
+		if (hmi_ctrl_layer->rule->mode >= 0) {
+			switch (hmi_ctrl_layer->rule->mode) {
+			case 1:
+				dest_rect[2] = hmi_ctrl_layer->width;
+				dest_rect[3] = hmi_ctrl_layer->height;
+			break;
+
+			default:
+				/* No changes, using requested size */
+			break;
+			}
+		}
+
+		if (hmi_ctrl_layer->rule->crop_rect[0] >= 0) {
+			src_rect[0] += hmi_ctrl_layer->rule->crop_rect[0];
+			src_rect[1] += hmi_ctrl_layer->rule->crop_rect[1];
+			src_rect[2] -= (hmi_ctrl_layer->rule->crop_rect[0]
+					 + hmi_ctrl_layer->rule->crop_rect[2]);
+			src_rect[3] -= (hmi_ctrl_layer->rule->crop_rect[1]
+					 + hmi_ctrl_layer->rule->crop_rect[3]);
+		}
+
+		if (hmi_ctrl_layer->rule->dest_rect[0] >= 0 ||
+				hmi_ctrl_layer->rule->dest_rect[1] >= 0 ||
+				hmi_ctrl_layer->rule->dest_rect[2] >= 0 ||
+				hmi_ctrl_layer->rule->dest_rect[3] >= 0) {
+
+			dest_rect[0] = hmi_ctrl_layer->rule->dest_rect[0];
+			dest_rect[1] = hmi_ctrl_layer->rule->dest_rect[1];
+			dest_rect[2] = hmi_ctrl_layer->rule->dest_rect[2] > 0 ?
+					hmi_ctrl_layer->rule->dest_rect[2] : dest_rect[2] ;
+			dest_rect[3] = hmi_ctrl_layer->rule->dest_rect[3] > 0 ?
+					hmi_ctrl_layer->rule->dest_rect[3] : dest_rect[3] ;
 		}
-#endif
-		ivi_controller_interface->surface_set_visibility(ivisurf, true);
-		ivi_controller_interface->commit_changes();
 	}
+
+	ivi_controller_interface->surface_set_source_rectangle(ivisurf
+			, src_rect[0], src_rect[1]
+			, src_rect[2], src_rect[3]);
+
+	ivi_controller_interface->surface_set_destination_rectangle(ivisurf
+			, dest_rect[0], dest_rect[1]
+			, dest_rect[2], dest_rect[3]);
+
+	ivi_controller_interface->surface_set_visibility(ivisurf, true);
+	ivi_controller_interface->commit_changes();
+
+	hmi_ctrl_surf->conf_num++;
 }
 
 static struct hmi_server_setting *
@@ -393,6 +533,9 @@ hmi_server_setting_create(struct weston_compositor *ec)
 	struct hmi_server_setting *setting = MEM_ALLOC(sizeof(*setting));
 	struct weston_config *config = ec->config;
 	struct weston_config_section *shell_section = NULL;
+	const char *name = NULL;
+
+	setting->panel_height = 30;
 
 	shell_section = weston_config_get_section(config, "ivi-shell",
 						  NULL, NULL);
@@ -400,7 +543,78 @@ hmi_server_setting_create(struct weston_compositor *ec)
 	weston_config_section_get_uint(shell_section, "base-layer-id",
 				       &setting->base_layer_id, 1000);
 
-	setting->panel_height = 30;
+	if ((shell_section = weston_config_get_section(config, "ivi-autolaunch",
+						  NULL, NULL))) {
+		weston_config_section_get_string(shell_section, "path",
+				       &setting->homescreen_app, NULL);
+	}
+
+
+	wl_array_init(&setting->rules);
+
+	while (weston_config_next_section(config, &shell_section, &name)) {
+		int screen_id;
+		int order;
+		int mode;
+		int focus_on;
+		int crop_rect[4] = {-1, -1, -1, -1};
+		int src_rect[4]  = {-1, -1, -1, -1};
+		int dest_rect[4] = {-1, -1, -1, -1};
+		char *app_name;
+		char *buff;
+		struct hmi_launch_rule *rule = NULL;
+
+		if (0 != strcmp(name, "ivi-layout-rule"))
+			continue;
+
+		if (0 != weston_config_section_get_string(shell_section, "application",
+							&app_name, NULL))
+			continue;
+
+		weston_config_section_get_int(shell_section, "order", &order, -1);
+		weston_config_section_get_int(shell_section, "mode", &mode, -1);
+		weston_config_section_get_int(shell_section, "focus_on", &focus_on, -1);
+		weston_config_section_get_int(shell_section, "screen", &screen_id, -1);
+
+		if (0 == weston_config_section_get_string(shell_section, "crop_rect",
+							&buff, NULL)) {
+			sscanf(buff, "%d,%d,%d,%d", crop_rect + 0,
+						    crop_rect + 1,
+						    crop_rect + 2,
+						    crop_rect + 3);
+		}
+
+		if (0 == weston_config_section_get_string(shell_section, "src_rect",
+							&buff, NULL)) {
+			sscanf(buff, "%d,%d,%d,%d", src_rect + 0,
+						    src_rect + 1,
+						    src_rect + 2,
+						    src_rect + 3);
+		}
+
+		if (0 == weston_config_section_get_string(shell_section, "dest_rect",
+							&buff, NULL)) {
+			sscanf(buff, "%d,%d,%d,%d", dest_rect + 0,
+						    dest_rect + 1,
+						    dest_rect + 2,
+						    dest_rect + 3);
+		}
+
+		rule = wl_array_add(&setting->rules, sizeof(*rule));
+
+		if (rule) {
+			rule->screen_id = screen_id;
+			rule->order     = order;
+			rule->mode      = mode;
+			rule->autofocus = focus_on;
+
+			strncpy(rule->app_name, app_name, sizeof(rule->app_name));
+
+			memcpy(rule->src_rect, src_rect, sizeof(rule->src_rect));
+			memcpy(rule->dest_rect, dest_rect, sizeof(rule->dest_rect));
+			memcpy(rule->crop_rect, crop_rect, sizeof(rule->crop_rect));
+		}
+	}
 
 	return setting;
 }
@@ -415,6 +629,15 @@ hmi_controller_destroy(struct wl_listener *listener, void *data)
 	free(hmi_ctrl);
 }
 
+static void hmi_controller_launch_homescreen(struct hmi_controller *hmi_ctrl)
+{
+	if (hmi_ctrl->hmi_setting->homescreen_app) {
+		if(system(hmi_ctrl->hmi_setting->homescreen_app)) {
+			;
+		}
+	}
+}
+
 static struct hmi_controller *
 hmi_controller_create(struct weston_compositor *ec)
 {
@@ -429,9 +652,10 @@ hmi_controller_create(struct weston_compositor *ec)
 
 	ivi_controller_interface->get_screens(&screen_length, &pp_screen);
 
-	for (i = screen_length; i-- ; j++) {
+	for (i = screen_length; i--;) {
 
 		iviscrn = pp_screen[i];
+		j = ivi_controller_interface->get_id_of_screen(iviscrn);
 		hmi_ctrl->screens[j].iviscrn = iviscrn;
 		wl_list_init(&hmi_ctrl->screens[i].layers_list);
 
@@ -506,7 +730,6 @@ controller_module_init(struct weston_compositor *ec,
 {
 	struct hmi_controller *hmi_ctrl = NULL;
 
-
 	if (interface_version < sizeof(struct ivi_controller_interface)) {
 		weston_log("ivi-layout-controller-ti: version mismatch of controller interface");
 		return -1;
@@ -528,5 +751,7 @@ controller_module_init(struct weston_compositor *ec,
 
 	weston_log("ivi-layout-controller-ti: Successfully started.");
 
+	hmi_controller_launch_homescreen(hmi_ctrl);
+
 	return 0;
 }
-- 
2.4.5

