From 70f5b755b00d5eab576ed897a8301367b0e367a6 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: layer-controller-ti: Improve functionality

Functionality improved:

   * can launch multiple application on start
   * handle keyboard focus:
      - TAB-LEFTALT can be used for switch focus
      - focus history;
      - focus on new application.

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

diff --git a/ivi-shell/ivi-layout-controller-ti.c b/ivi-shell/ivi-layout-controller-ti.c
index 4a2d648..9be51d1 100644
--- a/ivi-shell/ivi-layout-controller-ti.c
+++ b/ivi-shell/ivi-layout-controller-ti.c
@@ -30,6 +30,8 @@
 #include <fcntl.h>
 #include <unistd.h>
 
+#include <linux/input.h>
+
 #include "ivi-layout-export.h"
 
 #ifndef container_of
@@ -85,6 +87,7 @@ struct hmi_controller_layer {
 	int32_t width;
 	int32_t height;
 	int32_t num_surfaces;
+	int32_t focus;
 	pid_t pid;
 	struct wl_list link;
 	struct wl_list screen_link;
@@ -96,8 +99,10 @@ struct hmi_controller_surface {
 	void               *controller;
 	void               *ivisurf;
 	struct wl_list     link;
+	struct wl_list     focus_link;
 	struct wl_listener destroy_listener;
 	int                conf_num;
+	int                focus;
 };
 
 struct hmi_controller_screen {
@@ -106,11 +111,12 @@ struct hmi_controller_screen {
 };
 
 struct hmi_server_setting {
-	uint32_t    base_layer_id;
-	int32_t     panel_height;
-	char       *ivi_homescreen;
-	char       *homescreen_app;
-	struct wl_array rules;
+	uint32_t         base_layer_id;
+	int32_t          panel_height;
+	char            *ivi_homescreen;
+	char            *homescreen_app;
+	struct wl_array  autolaunch_apps;
+	struct wl_array  rules;
 };
 
 struct hmi_controller {
@@ -126,6 +132,7 @@ struct hmi_controller {
 	struct wl_listener                  destroy_listener;
 	struct wl_client                   *user_interface;
 	struct wl_list                      layers_list;
+	struct wl_list                      focus_history_list;
 
 };
 
@@ -350,12 +357,59 @@ exit:
 }
 
 static void
+move_kbd_focus(struct hmi_controller_surface *ivisurf, struct hmi_controller *hmi_ctrl, bool history)
+{
+	struct hmi_controller_layer *layer;
+	struct hmi_controller_surface *surf;
+	struct weston_seat *seat;
+	struct weston_keyboard *keyboard;
+	struct weston_surface *surface;
+
+	wl_list_for_each(layer, &hmi_ctrl->layers_list, link) {
+		wl_list_for_each(surf, &layer->surfaces_list, link) {
+			if (surf->focus) {
+				surf->focus = 0;
+				wl_list_insert(&hmi_ctrl->focus_history_list, &surf->focus_link);
+				break;
+			}
+		}
+	}
+
+	wl_list_for_each(seat, &hmi_ctrl->compositor->seat_list, link) {
+		if(!strcmp("default", seat->seat_name))
+			break;
+	}
+
+	keyboard = weston_seat_get_keyboard(seat);
+
+	if (!keyboard)
+		return;
+
+	if (ivisurf) {
+		surface = ivi_controller_interface->surface_get_weston_surface(ivisurf->ivisurf);
+		weston_keyboard_set_focus(keyboard, surface);
+		ivisurf->focus = 1;
+
+		if (NULL != ivisurf->focus_link.next)
+			wl_list_remove(&ivisurf->focus_link);
+
+	} else if (history && !wl_list_empty(&hmi_ctrl->focus_history_list)) {
+		struct hmi_controller_surface *s =
+			wl_container_of(hmi_ctrl->focus_history_list.next, s, focus_link);
+		wl_list_remove(&s->focus_link);
+		surface = ivi_controller_interface->surface_get_weston_surface(s->ivisurf);
+		weston_keyboard_set_focus(keyboard, surface);
+		s->focus = 1;
+	}
+}
+
+static void
 set_notification_create_surface(struct ivi_layout_surface *ivisurf,
 				void *userdata)
 {
 	struct hmi_controller *hmi_ctrl = userdata;
-	struct hmi_controller_layer *hmi_ctrl_layer = NULL;
-	struct hmi_controller_surface *hmi_ctrl_surf = NULL;
+	struct hmi_controller_layer *hmi_ctrl_layer;
+	struct hmi_controller_surface *hmi_ctrl_surf;
 	struct ivi_layout_layer *dest_layer;
 	struct weston_surface *surface;
 
@@ -378,6 +432,7 @@ set_notification_create_surface(struct ivi_layout_surface *ivisurf,
 	hmi_ctrl_surf = calloc(1, sizeof(*hmi_ctrl_surf));
 	hmi_ctrl_surf->ivisurf = ivisurf;
 	wl_list_init(&hmi_ctrl_surf->link);
+	wl_list_init(&hmi_ctrl_surf->focus_link);
 	wl_list_insert(&hmi_ctrl_layer->surfaces_list, &hmi_ctrl_surf->link);
 
 
@@ -419,6 +474,9 @@ remove:
 
 	wl_list_remove(&surf->link);
 
+	if (surf->focus)
+		move_kbd_focus(NULL, hmi_ctrl, true);
+
 	ivi_controller_interface->layer_remove_surface(dest_layer, ivisurf);
 
 	if (wl_list_empty(&hmi_ctrl_layer->surfaces_list)) {
@@ -451,9 +509,10 @@ set_notification_configure_surface(struct ivi_layout_surface *ivisurf,
 				   void *userdata)
 {
 	struct hmi_controller *hmi_ctrl = userdata;
-	struct hmi_controller_layer *hmi_ctrl_layer = NULL;
+	struct hmi_controller_layer *hmi_ctrl_layer;
 	struct weston_surface *surface;
-	struct hmi_controller_surface *hmi_ctrl_surf = NULL;
+	struct weston_seat *seat = NULL;
+	struct hmi_controller_surface *hmi_ctrl_surf;
 	int src_rect[4] = {0};
 	int dest_rect[4] = {0};
 
@@ -511,6 +570,16 @@ found:
 			dest_rect[3] = hmi_ctrl_layer->rule->dest_rect[3] > 0 ?
 					hmi_ctrl_layer->rule->dest_rect[3] : dest_rect[3] ;
 		}
+
+		if (hmi_ctrl_layer->rule->autofocus) {
+
+			wl_list_for_each(seat, &hmi_ctrl->compositor->seat_list, link) {
+				if(!strcmp("default", seat->seat_name))
+					break;
+			}
+
+			move_kbd_focus(hmi_ctrl_surf, hmi_ctrl, false);
+		}
 	}
 
 	ivi_controller_interface->surface_set_source_rectangle(ivisurf
@@ -522,6 +591,7 @@ found:
 			, dest_rect[2], dest_rect[3]);
 
 	ivi_controller_interface->surface_set_visibility(ivisurf, true);
+
 	ivi_controller_interface->commit_changes();
 
 	hmi_ctrl_surf->conf_num++;
@@ -543,14 +613,9 @@ hmi_server_setting_create(struct weston_compositor *ec)
 	weston_config_section_get_uint(shell_section, "base-layer-id",
 				       &setting->base_layer_id, 1000);
 
-	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);
+	wl_array_init(&setting->autolaunch_apps);
+	wl_array_init(&setting->autolaunch_apps);
 
 	while (weston_config_next_section(config, &shell_section, &name)) {
 		int screen_id;
@@ -564,6 +629,12 @@ hmi_server_setting_create(struct weston_compositor *ec)
 		char *buff;
 		struct hmi_launch_rule *rule = NULL;
 
+		if (!strcmp(name, "ivi-autolaunch")) {
+			char **s = wl_array_add(&setting->autolaunch_apps, sizeof(*s));
+			weston_config_section_get_string(shell_section, "path", s, NULL);
+			continue;
+		}
+
 		if (0 != strcmp(name, "ivi-layout-rule"))
 			continue;
 
@@ -573,7 +644,7 @@ hmi_server_setting_create(struct weston_compositor *ec)
 
 		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, "focus_on", &focus_on, 0);
 		weston_config_section_get_int(shell_section, "screen", &screen_id, -1);
 
 		if (0 == weston_config_section_get_string(shell_section, "crop_rect",
@@ -631,8 +702,10 @@ hmi_controller_destroy(struct wl_listener *listener, void *data)
 
 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)) {
+	char **app;
+
+	wl_array_for_each(app, &hmi_ctrl->hmi_setting->autolaunch_apps) {
+		if(system(*app)) {
 			;
 		}
 	}
@@ -674,6 +747,7 @@ hmi_controller_create(struct weston_compositor *ec)
 		      &hmi_ctrl->destroy_listener);
 
 	wl_list_init(&hmi_ctrl->layers_list);
+	wl_list_init(&hmi_ctrl->focus_history_list);
 
 	free(pp_screen);
 	pp_screen = NULL;
@@ -719,6 +793,57 @@ initialize(struct hmi_controller *hmi_ctrl)
 	return 1;
 }
 
+static void
+switch_focus_bindings(struct weston_keyboard *keyboard, uint32_t time,
+		 uint32_t key, void *data)
+{
+	struct hmi_controller *hmi_ctrl = data;
+	struct hmi_controller_layer *hmi_ctrl_layer, *next_l, *cycle_l = NULL;
+	struct hmi_controller_surface *hmi_ctrl_surf;
+	bool pp = false;
+
+	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->focus) {
+				goto ff;
+			}
+		}
+	}
+
+	hmi_ctrl_surf = NULL;
+	pp = true;
+
+ff:
+	wl_list_for_each(next_l, &hmi_ctrl->layers_list, link) {
+
+		if (pp) {
+			if (next_l->rule && next_l->rule->autofocus) {
+				cycle_l = next_l;
+				break;
+			}
+		} else {
+			if (next_l == hmi_ctrl_layer) {
+				pp = true;
+				continue;
+			} else {
+				if (next_l->rule && next_l->rule->autofocus) {
+					cycle_l = next_l;
+					break;
+				}
+			}
+		}
+	}
+
+	if (!cycle_l)
+		return;
+
+	move_kbd_focus(container_of(cycle_l->surfaces_list.next
+					, struct hmi_controller_surface
+					, link)
+						, hmi_ctrl, false);
+}
+
+
 /*****************************************************************************
  *  exported functions
  ****************************************************************************/
@@ -753,5 +878,9 @@ controller_module_init(struct weston_compositor *ec,
 
 	hmi_controller_launch_homescreen(hmi_ctrl);
 
+	weston_compositor_add_key_binding(ec, KEY_TAB , MODIFIER_ALT,
+						switch_focus_bindings, hmi_ctrl);
+	weston_install_debug_key_binding(ec, 0);
+
 	return 0;
 }
-- 
2.4.5

