#include #include #include #include #include #include #include #include "jswm_ctl.h" #include "jswm_util.h" #include "config.h" #include #include #include "libjswm.h" #define JSWM_IPCON "Jswm" #define IVI_EVENT_IPCON "ivi_event" IPCON_HANDLER jswm_handler; unsigned char jswm_ctl_state = JSWM_CTL_IF_STATE_PENDING; struct surface_ctl; struct layer_ctl; static struct surface_ctl *get_surface_ctrl_by_id(t_ilm_surface id); static struct surface_ctl *surface_ctl_get(struct surface_ctl *ctl); static struct surface_ctl *surface_ctl_put(struct surface_ctl *ctl); static struct layer_ctl *layer_ctl_get(struct layer_ctl *ctl); static struct layer_ctl *layer_ctl_put(struct layer_ctl *ctl); static struct surface_ctl *register_anonymous_surface(t_ilm_surface id); static int update_surface(struct surface_ctl *sc, struct ilmSurfaceProperties *p); static void fix_layer_ctl_setting(struct layer_ctl *lc); t_ilm_string default_seats[] = {"seat_usb_input"}; #define MAX_LAYER_PER_SCREEN 32 struct screen_ctl { unsigned int num; t_ilm_uint id; t_ilm_layer layers[MAX_LAYER_PER_SCREEN]; unsigned char refcnt; struct layer_ctl *visible_layer_ctl; }; struct region { t_ilm_int x; t_ilm_int y; t_ilm_int w; t_ilm_int h; }; enum visibility_type { VISIBLE_ON = (0x1 << 0), VISIBLE_AUTO = (0x1 << 1), VISIBLE_CTRL = (0x1 << 2), VISIBLE_ALWAYS = ((0x1 << 3) | VISIBLE_ON), }; struct layer_ctl { struct screen_ctl *screen; t_ilm_layer id; t_ilm_uint width; t_ilm_uint height; struct region src; struct region dst; enum visibility_type visibility; char *role; struct surface_ctl *active_sc; UT_hash_handle hh; unsigned char refcnt; }; static inline void layer_ctl_set_visible(struct layer_ctl *lc) { lc->visibility |= VISIBLE_ON; } static inline void layer_ctl_clear_visible(struct layer_ctl *lc) { lc->visibility &= ~VISIBLE_ON; } static inline t_ilm_bool layer_ctl_is_visible(struct layer_ctl *lc) { return lc->visibility & VISIBLE_ON ? ILM_TRUE : ILM_FALSE; } static inline t_ilm_bool layer_ctl_visibility_is_auto(struct layer_ctl *lc) { return lc->visibility & VISIBLE_AUTO ? ILM_TRUE : ILM_FALSE; } static inline t_ilm_bool layer_ctl_visibility_is_ctl(struct layer_ctl *lc) { return lc->visibility & VISIBLE_CTRL ? ILM_TRUE : ILM_FALSE; } static inline t_ilm_bool layer_ctl_visibility_is_always_on(struct layer_ctl *lc) { return (lc->visibility & VISIBLE_ALWAYS) == VISIBLE_ALWAYS ? ILM_TRUE : ILM_FALSE; } struct layout_ctl { struct list_node node; t_ilm_uint org_w; t_ilm_uint org_h; t_ilm_uint sx; t_ilm_uint sy; t_ilm_uint s_width; t_ilm_uint s_height; t_ilm_uint dx; t_ilm_uint dy; t_ilm_uint d_width; t_ilm_uint d_height; }; enum surface_ctl_type { SCT_TYPE_NONE, SCT_TYPE_FIX, SCT_TYPE_TEMP, }; #define SC_MAX_LAYER_NUM 5 struct surface_ctl { t_ilm_surface id; ilmInputDevice input; t_ilm_float opacity; t_ilm_bool visibility; enum surface_ctl_type type; struct layer_ctl *layer[SC_MAX_LAYER_NUM]; struct list_node_head layouts; struct layout_ctl *default_layout; UT_hash_handle hh; unsigned char refcnt; }; #define JSWM_MAX_SCREEN 10 struct screen_ctl *jswm_screens[JSWM_MAX_SCREEN]; struct layer_ctl *_layer_hash; struct surface_ctl *_surface_hash; static void layer_hash_add(struct layer_ctl *lc) { do { if (!lc) break; layer_ctl_get(lc); HASH_ADD_INT(_layer_hash, id, lc); } while (0); } static void layer_hash_remove(struct layer_ctl *lc) { do { if (!lc) break; HASH_DEL(_layer_hash, lc); layer_ctl_put(lc); } while (0); } static void surface_hash_add(struct surface_ctl *sc) { do { if (!sc) break; surface_ctl_get(sc); HASH_ADD_INT(_surface_hash, id, sc); } while (0); } static void surface_hash_remove(struct surface_ctl *sc) { do { if (!sc) break; HASH_DEL(_surface_hash, sc); surface_ctl_put(sc); } while (0); } static struct layout_ctl *layout_ctl_alloc() { struct layout_ctl *ctl = malloc(sizeof(*ctl)); if (ctl) { list_init_node(&ctl->node); ctl->org_w = 0; ctl->org_h = 0; ctl->sx = 0; ctl->sy = 0; ctl->s_width = 0; ctl->s_height = 0; ctl->dx = 0; ctl->dy = 0; ctl->d_width = 0; ctl->d_height = 0; } return ctl; } static void layout_ctl_free(struct layout_ctl *lcc) { if (lcc) { assert(is_free_node(&lcc->node)); free(lcc); } } static struct screen_ctl *screen_ctl_alloc(int id) { int ret = -1; int i; struct screen_ctl *ctl = NULL; do { if (id >= 0 ) { if (jswm_screens[id] != NULL) id = -1; } else { for (i = 0; i < JSWM_MAX_SCREEN; i++) { if (!jswm_screens[i]) id = i; } } if (id < 0) break; ctl = calloc(1, sizeof(*ctl)); if (!ctl) break; jswm_screens[id] = ctl; ctl->id = id; ctl->refcnt = 1; ctl->visible_layer_ctl = NULL; } while (0); return ctl; } static struct screen_ctl *screen_ctl_get(struct screen_ctl *ctl) { if (ctl) ctl->refcnt++; return ctl; } static struct screen_ctl *screen_ctl_put(struct screen_ctl *ctl) { if (ctl) { ctl->refcnt--; if (!ctl->refcnt) { assert(ctl->num == 0); free(ctl); ctl = NULL; } } return ctl; } static void screen_add_layer(struct screen_ctl *scc, struct layer_ctl *lc) { do { if (!scc || !lc) break; scc->layers[scc->num++] = lc->id; lc->screen = scc; assert(scc->num < MAX_LAYER_PER_SCREEN); if (layer_ctl_visibility_is_auto(lc) && layer_ctl_is_visible(lc)) { /* * Only 1 layer on a screen can be visible, if multiple * layers are set to be visible. overrides the previous one. */ if (scc->visible_layer_ctl) layer_ctl_clear_visible(scc->visible_layer_ctl); scc->visible_layer_ctl = lc; } screen_ctl_get(scc); } while (0); } static void screen_remove_layer(struct layer_ctl *lc) { do { struct screen_ctl *scc = lc->screen; int i, j; if (!scc || !lc) break; for (i = 0; i < scc->num; i++) { if (scc->layers[i] == lc->id) break; } if (i == scc->num) break; j = i + 1; while (j < scc->num) { scc->layers[j - 1] = scc->layers[j]; j++; } scc->num--; lc->screen = NULL; screen_ctl_put(scc); } while (0); } static t_ilm_layer *screen_get_layer_array(struct screen_ctl *scc) { if (!scc) return NULL; return scc->layers; } static struct layer_ctl *layer_ctl_alloc() { struct layer_ctl *ctl = malloc(sizeof(*ctl)); if (ctl) { ctl->screen = NULL; ctl->id = 0; ctl->width = 0; ctl->height = 0; ctl->visibility = VISIBLE_AUTO & ~VISIBLE_ON; ctl->role = NULL; ctl->active_sc = NULL; ctl->refcnt = 1; memset(&ctl->src, 0, sizeof(struct region)); memset(&ctl->dst, 0, sizeof(struct region)); } return ctl; } static struct layer_ctl *layer_ctl_get(struct layer_ctl *ctl) { if (ctl) ctl->refcnt++; return ctl; } static struct layer_ctl *layer_ctl_put(struct layer_ctl *ctl) { if (ctl) { ctl->refcnt--; if (!ctl->refcnt) { free(ctl->role); free(ctl); ctl = NULL; } } return ctl; } static struct layer_ctl *get_layer_ctl_by_id(t_ilm_layer id) { struct layer_ctl *lc; HASH_FIND_INT(_layer_hash, &id, lc); return lc; } static struct layer_ctl *get_layer_ctl_by_role(char *role) { struct layer_ctl *it = NULL; do { if (!role) break; for (it = _layer_hash; it != NULL; it = it->hh.next) { if (!strcmp(it->role, role)) break; } } while (0); return it; } static void layer_add_surface(struct layer_ctl *lc, struct surface_ctl *sc) { do { int slot; if (!lc || !sc) break; for (slot = 0; slot < SC_MAX_LAYER_NUM; slot++) { if (sc->layer[slot] == NULL) break; } if (slot >= SC_MAX_LAYER_NUM) break; jswm_info("Add surface ctrl %d to layer ctrl %d\n", sc->id, lc->id); sc->layer[slot] = lc; layer_ctl_get(lc); if (!lc->active_sc) lc->active_sc = sc; } while (0); } static void layer_remove_surface(struct surface_ctl *sc) { do { int slot; if (!sc) break; for (slot = 0; slot < SC_MAX_LAYER_NUM; slot++) { if (sc->layer[slot]) { layer_ctl_put(sc->layer[slot]); sc->layer[slot] = NULL; } } } while (0); } static struct surface_ctl *layer_search_surface(struct layer_ctl *lc, t_ilm_surface surface) { struct surface_ctl *result = NULL; do { struct surface_ctl *sc = NULL; int slot; if (!lc) break; sc = get_surface_ctrl_by_id(surface); if (!sc) break; for (slot = 0; slot < SC_MAX_LAYER_NUM; slot++) { if (sc->layer[slot] == lc) { result = sc; break; } } } while (0); return result; } static void clean_all_ctls(void) { struct surface_ctl *sc, *stmp; struct layer_ctl *lc, *ltmp; struct screen_ctl *scc; struct list_node *it; int i; assert(jswm_ctl_state != JSWM_CTL_IF_STATE_RUN); HASH_ITER(hh, _surface_hash, sc, stmp) { layer_remove_surface(sc); HASH_DEL(_surface_hash, sc); surface_ctl_put(sc); } HASH_ITER(hh, _layer_hash, lc, ltmp) { screen_remove_layer(lc); HASH_DEL(_layer_hash, lc); layer_ctl_put(lc); } for (i = 0; i < JSWM_MAX_SCREEN; i++) { scc = jswm_screens[i]; if (scc) screen_ctl_put(scc); jswm_screens[i] = NULL; } } static struct surface_ctl *surface_ctl_alloc() { struct surface_ctl *ctl = malloc(sizeof(*ctl)); if (ctl) { int i; list_init_head(&ctl->layouts); ctl->type = SCT_TYPE_NONE; for (i = 0; i < SC_MAX_LAYER_NUM; i++) ctl->layer[i] = NULL; ctl->id = 0; ctl->opacity = 1.0; ctl->visibility = ILM_TRUE; ctl->default_layout = NULL; ctl->refcnt = 1; } return ctl; } static struct surface_ctl *surface_ctl_alloc_with_default() { struct surface_ctl *ctl = surface_ctl_alloc(); if (ctl) { struct layout_ctl *lac = layout_ctl_alloc(); ctl->default_layout = lac; list_append(&ctl->layouts, &lac->node); } return ctl; } static struct surface_ctl *surface_ctl_get(struct surface_ctl *ctl) { if (ctl) { ctl->refcnt++; assert(ctl->refcnt < 6); } return ctl; } static struct surface_ctl *surface_ctl_put(struct surface_ctl *ctl) { if (ctl) { ctl->refcnt--; if (!ctl->refcnt) { struct list_node *it; struct layout_ctl *lac; int id = ctl->id; int i; while (lac = LIST_POP(&ctl->layouts, struct layout_ctl, node, it)) { layout_ctl_free(lac); } for (i = 0; i < SC_MAX_LAYER_NUM; i++) layer_remove_surface(ctl); free(ctl); jswm_dbg("Surface %d ctrl is freed.\n", id); } } return ctl; } static struct surface_ctl *get_surface_ctrl_by_id(t_ilm_surface id) { struct surface_ctl *sc; HASH_FIND_INT(_surface_hash, &id, sc); return sc; } static struct layout_ctl *get_layout_ctrl_by_orig(struct surface_ctl *sc, t_ilm_uint org_w, t_ilm_uint org_h) { struct layout_ctl *lac; struct layout_ctl *default_layout; struct list_node *it; struct layout_ctl *result = NULL; FOR_EACH_TYPE_NODE(&sc->layouts, struct layout_ctl, it, lac) { if ((lac->org_w == org_w) && (lac->org_h == org_h)) { result = lac; break; } if ((lac->org_w == org_w) && (lac->org_h == 0)) { result = lac; continue; } if ((lac->org_w == 0) && (lac->org_h == org_h)) result = !result ? lac : result; } if (!result) result = sc->default_layout; return result; } static void clean_layer(struct layer_ctl *lc) { t_ilm_surface *array = NULL; do { ilmErrorTypes rc; t_ilm_int len; int i; if (!lc) break; rc = ilm_getSurfaceIDsOnLayer(lc->id, &len, &array); if (rc != ILM_SUCCESS) break; for (i = 0; i < len; i++) { struct surface_ctl *sc; sc = layer_search_surface(lc, array[i]); if (!sc) ilm_layerRemoveSurface(lc->id, array[i]); } } while (0); if (array) free(array); } static int jswm_refresh_screen(struct screen_ctl *scc) { int ret = -1; ilmErrorTypes rc; unsigned int *array = NULL; do { int count = 0; int i, j; rc = ilm_getLayerIDs(&count, &array); if (rc != ILM_SUCCESS) { jswm_err("Failed to get layers.\n"); break; } for (j = 0; j < scc->num; j++) { int created = 0; struct layer_ctl *lc; lc = get_layer_ctl_by_id(scc->layers[j]); assert(lc); if (count) { int i; for (i = 0; i < count; i++) { if (array[i] == lc->id) { created = 1; break; } } if (created) continue; } rc = ilm_layerCreateWithDimension( &lc->id, lc->width, lc->height); assert(rc == ILM_SUCCESS); ilm_commitChanges(); } ret = 0; } while (0); if (array) free(array); return ret; } static int jswm_ctl_refresh_begin(void) { int ret = -1; unsigned int *array = NULL; do { ilmErrorTypes rc; int count = 0; int i; rc = ilm_getSurfaceIDs(&count, &array); if (rc != ILM_SUCCESS) jswm_warn("Failed to get surfaces.\n"); if (array) { for (i = 0; i < count; i++) { if (!get_surface_ctrl_by_id(array[i])) register_anonymous_surface(array[i]); } free(array); } rc = ilm_getLayerIDs(&count, &array); if (rc != ILM_SUCCESS) jswm_warn("Failed to get layers.\n"); if (array) { for (i = 0; i < count; i++) { struct layer_ctl *lc; lc = get_layer_ctl_by_id(array[i]); if (lc) { clean_layer(lc); continue; } jswm_info("Remove Unknown layer %d.\n", array[i]); ilm_layerRemove(array[i]); } free(array); ilm_commitChanges(); } ret = 0; } while (0); return ret; } static int update_surface(struct surface_ctl *sc, struct ilmSurfaceProperties *p) { int ret = -1; ilmErrorTypes rc; do { t_ilm_uint x; t_ilm_uint y; t_ilm_uint width; t_ilm_uint height; struct layout_ctl *lac; lac = get_layout_ctrl_by_orig(sc, p->origSourceWidth, p->origSourceHeight); jswm_info("Using layout: %d %d %d %d %d %d %d %d %d %d\n", lac->org_w, lac->org_h, lac->sx, lac->sy, lac->s_width, lac->s_height, lac->dx, lac->dy, lac->d_width, lac->d_height); /* Source policy */ x = lac->sx; y = lac->sy; width = lac->s_width ? lac->s_width : p->origSourceWidth; height = lac->s_height ? lac->s_height : p->origSourceHeight; rc = ilm_surfaceSetSourceRectangle(sc->id, x, y, width, height); if (rc != ILM_SUCCESS) jswm_warn("Fail to set source region for %d\n", sc->id); /* Destination policy */ x = lac->dx; y = lac->dy; width = lac->d_width ? lac->d_width : p->origSourceWidth; height = lac->d_height ? lac->d_height : p->origSourceHeight; rc = ilm_surfaceSetDestinationRectangle(sc->id, x, y, width, height); if (rc != ILM_SUCCESS) jswm_warn("Faild to set dest region for %d\n", sc->id); rc = ilm_surfaceSetOpacity(sc->id, sc->opacity); if (rc != ILM_SUCCESS) jswm_warn("Faild to set opacity for %d\n", sc->id); jswm_info("Set opacity of surface %d to %f\n", sc->id, sc->opacity); rc = ilm_surfaceSetVisibility(sc->id, sc->visibility); if (rc != ILM_SUCCESS) jswm_warn("Faild to set visibility for %d to %s\n", sc->id, sc->visibility ? "on" : "off"); jswm_info("set visibility for %d to %s\n", sc->id, sc->visibility ? "on" : "off"); ilm_commitChanges(); } while (0); return ret; } static int jswm_ctl_refresh_end(void) { int ret = 0; unsigned int *array = NULL; do { ilmErrorTypes rc; int count = 0; int i; rc = ilm_getSurfaceIDs(&count, &array); if (rc != ILM_SUCCESS) jswm_warn("Failed to get surfaces.\n"); if (!array) break; for (i = 0; i < count; i++) { struct surface_ctl *sc; struct layer_ctl *lc = NULL; struct ilmSurfaceProperties lp; int slot; t_ilm_surface id = array[i]; sc = get_surface_ctrl_by_id(id); if (!sc) sc = register_anonymous_surface(id); for (slot = 0; slot < SC_MAX_LAYER_NUM; slot++) { lc = sc->layer[slot]; if (!lc) continue; rc = ilm_layerAddSurface(lc->id, id); jswm_info("Add %d to layer %d: %s\n", id, lc->id, rc == ILM_SUCCESS ? "success":"fail"); } rc = ilm_getPropertiesOfSurface(sc->id, &lp); if (rc == ILM_SUCCESS) update_surface(sc, &lp); } free(array); ilm_commitChanges(); } while (0); return ret; } static int jswm_ctl_refresh(void) { int ret = -1; ilmErrorTypes rc; do { t_ilm_uint screen_num; t_ilm_uint *screen_ids; jswm_ctl_refresh_begin(); rc = ilm_getScreenIDs(&screen_num, &screen_ids); if (rc != ILM_SUCCESS) { jswm_err("Fail to get screen IDs.\n"); break; } struct screen_ctl *scc; int j; for (j = 0; j < JSWM_MAX_SCREEN; j++) { int i; int screen_found = 0; scc = jswm_screens[j]; if (!scc) continue; for (i = 0; i < screen_num; i++) { if (scc->id == screen_ids[i]) { screen_found = 1; break; } } if (!screen_found) continue; if (jswm_refresh_screen(scc) < 0) break; rc = ilm_displaySetRenderOrder( scc->id, screen_get_layer_array(scc), scc->num); if (rc != ILM_SUCCESS) break; ilm_commitChanges(); ret = 0; } jswm_ctl_refresh_end(); } while (0); return ret; } static struct surface_ctl *register_anonymous_surface(t_ilm_surface id) { struct surface_ctl *result = NULL; do { struct layer_ctl *lc = NULL; struct surface_ctl *sc = NULL; lc = get_layer_ctl_by_role("ANONYMOUS"); if (!lc) { jswm_warn("No ANONYMOUS role layer for surface %d.\n", id); break; } jswm_info("Create surface ctl for %d.\n", id); sc = surface_ctl_alloc_with_default(); assert(sc); sc->id = id; sc->type = SCT_TYPE_TEMP; layer_add_surface(lc, sc); surface_hash_add(sc); result = sc; } while (0); return result; } static void surface_setup_input(struct surface_ctl* sc) { do { if (!sc->input) break; ilm_setInputAcceptanceOn(sc->id, 1, default_seats); ilm_setInputFocus(&sc->id, 1, sc->input, ILM_TRUE); } while (0); } static inline unsigned int json_to_uint(struct json_object *val) { int intval; intval = json_object_get_int(val); assert(intval >= 0); return (unsigned int) intval; } static char *json_to_role(struct json_object *val) { char *role = NULL; do { char *str = NULL; if (!val) break; str = (char *)json_object_to_json_string(val); if (!str) break; /* json_object_to_json_string() returns a pointer to a buffer in * json object. we should copy it*/ role = (char *)malloc(strlen(str) - 2 + 1); char *p = &str[1]; char *cp = &role[0]; while (*p != '\"') { *cp = *p; cp++; p++; } *cp = '\0'; } while (0); return role; } enum visibility_type json_to_visiblity(struct json_object *val) { char *visibility = NULL; int ret = VISIBLE_AUTO & ~VISIBLE_ON; do { char *str = NULL; if (!val) break; str = (char *)json_object_to_json_string(val); if (!str) break; /* json_object_to_json_string() returns a pointer to a buffer in * json object. we should copy it*/ visibility = (char *)malloc(strlen(str) - 2 + 1); char *p = &str[1]; char *cp = &visibility[0]; while (*p != '\"') { *cp = *p; cp++; p++; } *cp = '\0'; if (!strcmp(visibility, "on")) { ret = VISIBLE_AUTO | VISIBLE_ON; break; } if (!strcmp(visibility, "ctrl_on")) { ret = VISIBLE_CTRL | VISIBLE_ON; break; } if (!strcmp(visibility, "ctrl_off")) { ret = VISIBLE_CTRL & ~VISIBLE_ON; break; } if (!strcmp(visibility, "always_on")) ret = VISIBLE_ALWAYS; } while (0); if (visibility) free(visibility); return ret; } static inline float json_to_float(struct json_object *val) { char buf[32]; char *str = NULL; float ret = 0.0; do { if (!val) break; str = (char *)json_object_to_json_string(val); if (!str) break; char *p = &str[1]; char *cp = &buf[0]; while (*p != '\"') { *cp = *p; cp++; p++; } *cp = '\0'; ret = strtof(buf, NULL); jswm_dbg("Set opacity buf :%s val: %f\n", buf, ret); } while (0); return ret; } static int parse_layouts(struct surface_ctl *sc, struct json_object *jo) { int ret = 0; struct array_list *layouts = NULL; do { int it; layouts = json_object_get_array(jo); if (!layouts) break; for (it = 0; it < array_list_length(layouts); it++) { struct json_object *t = array_list_get_idx(layouts, it); struct layout_ctl *lac; if (!t) continue; lac = layout_ctl_alloc(); assert(lac); lac->org_w = json_to_uint( json_object_object_get(t, "org_w")); lac->org_h = json_to_uint( json_object_object_get(t, "org_h")); struct json_object *jo; jo = json_object_object_get(t, "sx"); lac->sx = jo ? json_to_uint(jo) : 0; jo = json_object_object_get(t, "sy"); lac->sy = jo ? json_to_uint(jo) : 0; jo = json_object_object_get(t, "sw"); lac->s_width = jo ? json_to_uint(jo) : 0; jo = json_object_object_get(t, "sh"); lac->s_height = jo ? json_to_uint(jo) : 0; jo = json_object_object_get(t, "dx"); lac->dx = jo ? json_to_uint(jo) : 0; jo = json_object_object_get(t, "dy"); lac->dy = jo ? json_to_uint(jo) : 0; jo = json_object_object_get(t, "dw"); lac->d_width = jo ? json_to_uint(jo) : 0; jo = json_object_object_get(t, "dh"); lac->d_height = jo ? json_to_uint(jo) : 0; if ((lac->org_w == 0) && (lac->org_h == 0)) { /* * Only one default_layout * (org_w == org_h == 0) */ assert(sc->default_layout == NULL); sc->default_layout = lac; } jswm_dbg("Adding layout: %d %d %d %d %d %d %d %d %d %d\n", lac->org_w, lac->org_h, lac->sx, lac->sy, lac->s_width, lac->s_height, lac->dx, lac->dy, lac->d_width, lac->d_height); list_append(&sc->layouts, &lac->node); } } while (0); return ret; } static int parse_surfaces(struct layer_ctl *lc, struct json_object *jo) { int ret = -1; struct array_list *surfaces = NULL; do { int it; surfaces = json_object_get_array(jo); if (!surfaces) break; for (it = 0; it < array_list_length(surfaces); it++) { struct json_object *t; struct json_object *layout = NULL; struct surface_ctl *sc; struct json_object *val = NULL; unsigned id; t = array_list_get_idx(surfaces, it); if (!t) continue; id = json_to_uint(json_object_object_get(t, "id")); sc = get_surface_ctrl_by_id(id); if (!sc) { jswm_info("Create surface ctrl for %d\n", id); sc = surface_ctl_alloc(); assert(sc); sc->id = id; sc->type = SCT_TYPE_FIX; sc->input = json_to_uint(json_object_object_get(t, "input")); val = json_object_object_get(t, "opacity"); if (val) sc->opacity = (t_ilm_float) json_to_float(val); val = json_object_object_get(t, "visibility"); if (val && !json_to_uint(val)) sc->visibility = ILM_FALSE; layout = json_object_object_get(t, "layout"); if (layout) parse_layouts(sc, layout); surface_hash_add(sc); } else { jswm_warn("Surface %d setting for layer %d neglected\n", id, lc->id); } layer_add_surface(lc, sc); } ret = 0; } while (0); return ret; } static int parse_layers(struct screen_ctl *scc, struct json_object *jo) { int ret = 0; struct array_list *layers = NULL; do { int it = 0; layers = json_object_get_array(jo); if (!layers) break; for (it = 0; it < array_list_length(layers); it++) { struct json_object *t = array_list_get_idx(layers, it); struct json_object *s; struct layer_ctl *lc; char *role = NULL; t_ilm_layer lid; if (!t) continue; lid = json_to_uint( json_object_object_get(t, "id")); role = json_to_role( json_object_object_get(t, "role")); if (!role) { jswm_warn("Skip no role Layer %d .\n", lid); continue; } lc = layer_ctl_alloc(); assert(lc); lc->id = lid; lc->role = role; jswm_info("Layer %d has a role of %s.\n", lc->id, lc->role); lc->width = json_to_uint( json_object_object_get(t, "width")); lc->height = json_to_uint( json_object_object_get(t, "height")); s = json_object_object_get(t, "sx"); lc->src.x = s ? json_to_uint(s) : 0; s = json_object_object_get(t, "sy"); lc->src.y = s ? json_to_uint(s) : 0; s = json_object_object_get(t, "sw"); lc->src.w = s ? json_to_uint(s) : lc->width; s = json_object_object_get(t, "sh"); lc->src.h = s ? json_to_uint(s) : lc->height; jswm_info("Layer %d source region %d %d %d %d.\n", lc->id, lc->src.x, lc->src.y, lc->src.w, lc->src.h); s = json_object_object_get(t, "dx"); lc->dst.x = s ? json_to_uint(s) : 0; s = json_object_object_get(t, "dy"); lc->dst.y = s ? json_to_uint(s) : 0; s = json_object_object_get(t, "dw"); lc->dst.w = s ? json_to_uint(s) : lc->width; s = json_object_object_get(t, "dh"); lc->dst.h = s ? json_to_uint(s) : lc->height; jswm_info("Layer %d dest region %d %d %d %d.\n", lc->id, lc->dst.x, lc->dst.y, lc->dst.w, lc->dst.h); s = json_object_object_get(t, "visibility"); if (s) lc->visibility = json_to_visiblity(s); s = json_object_object_get(t, "surfaces"); if (s) ret = parse_surfaces(lc, s); if (ret < 0) break; screen_add_layer(scc, lc); layer_hash_add(lc); } } while (0); return ret; } static int load_setting(void) { int ret = -1; unsigned char saved_state = jswm_ctl_state; struct json_object *root = NULL; struct array_list *screens= NULL; struct screen_ctl *scc = NULL; jswm_ctl_state = JSWM_CTL_IF_STATE_PENDING; do { jswm_info("Using %s\n", JSWM_CONFIG_FILE); root = json_object_from_file(JSWM_CONFIG_FILE); assert(root); int si; screens = json_object_get_array(root); for (si = 0; si < array_list_length(screens); si++) { struct json_object *sit = array_list_get_idx(screens, si); t_ilm_uint screen_id; struct json_object *l; screen_id = json_to_uint(json_object_object_get(sit, "id")); scc = screen_ctl_alloc(screen_id); assert(scc); l = json_object_object_get(sit, "layers"); if (!l) continue; ret = parse_layers(scc, l); if (ret < 0) break; } } while (0); /* json_object_put() here will free all json objects rooted at root */ if (root) json_object_put(root); if (ret < 0) clean_all_ctls(); jswm_ctl_state = saved_state; return ret; } void do_cmdGetRoleSurfaceId(struct ipcon_msg *im) { int ret = -1; do { char *role = libjswm_cmdGetRoleSurfaceId_get_role(im->buf); if (!role) break; struct layer_ctl *lc = get_layer_ctl_by_role(role); if (!lc || !lc->active_sc) { jswm_dbg("No layer with %s role found\n", role); break; } ret = lc->active_sc->id; jswm_dbg("layer %d with %s role found\n", ret, role); free(role); } while (0); char *rspmsg = libjswm_rspGetRoleSurfaceId(ret); if (rspmsg) { ret = ipcon_send_unicast(jswm_handler, im->peer, rspmsg, strlen(rspmsg) + 1); if (ret < 0) jswm_warn("Faild to send rspGetRoleSurfaceId to %s.\n", im->peer); free(rspmsg); } } void do_cmdShowRole(struct ipcon_msg *im) { char *role = libjswm_cmdShowRole_data(im->buf); do { struct layer_ctl *visible_layer_ctl = NULL; if (!role) break; struct layer_ctl *lc = get_layer_ctl_by_role(role); if (!lc) { jswm_dbg("No layer with %s role found\n", role); break; } assert(lc->screen); if (layer_ctl_visibility_is_auto(lc)) { visible_layer_ctl = lc->screen->visible_layer_ctl; if (visible_layer_ctl) { if (!strcmp(visible_layer_ctl->role, role)) break; jswm_info("Set Role %s layer on screen %d visibility off\n", visible_layer_ctl->role, lc->screen->id); ilm_layerSetVisibility(visible_layer_ctl->id, ILM_FALSE); layer_ctl_clear_visible(visible_layer_ctl); } } jswm_info("Set Role %s layer on screen %d visibility on\n", lc->role, lc->screen->id); ilm_layerSetVisibility(lc->id, ILM_TRUE); layer_ctl_set_visible(lc); ilm_commitChanges(); if (layer_ctl_visibility_is_auto(lc)) lc->screen->visible_layer_ctl = lc; } while (0); if (role) free(role); } static void fix_layer_ctl_setting(struct layer_ctl *lc) { assert(lc); if (lc->dst.x < 0) lc->dst.x = 0; if (lc->dst.y < 0) lc->dst.y = 0; if (lc->dst.w < 0) lc->dst.w = 0; if (lc->dst.h < 0) lc->dst.h = 0; } void do_cmdSetRolePos(struct ipcon_msg *im) { struct cmdSetRolePosData *data = libjswm_cmdSetRolePos_data(im->buf); do { if (!data) break; struct layer_ctl *lc = get_layer_ctl_by_role(data->role); if (!lc) { jswm_dbg("No layer with %s role found\n", data->role); break; } /* * Destination of layer can not be negative value, it will be * roundup to 0 by wayland-ivi extension. */ lc->dst.x = data->x; lc->dst.y = data->y; if (data->w) lc->dst.w = data->w; if (data->h) lc->dst.h = data->h; fix_layer_ctl_setting(lc); jswm_info("cmdSetRolePos: set layer %d dest region %d %d %d %d.\n", lc->id, lc->dst.x, lc->dst.y, lc->dst.w, lc->dst.h); ilm_layerSetDestinationRectangle(lc->id, lc->dst.x, lc->dst.y, lc->dst.w, lc->dst.h); ilm_commitChanges(); } while(0); cmdSetRolePosData_free(data); } void do_cmdSetRoleRelativePos(struct ipcon_msg *im) { struct cmdSetRoleRelativePosData *data = libjswm_cmdSetRoleRelativePos_data(im->buf); do { if (!data) break; struct layer_ctl *lc = get_layer_ctl_by_role(data->role); if (!lc) { jswm_dbg("No layer with %s role found\n", data->role); break; } /* * Destination of layer can not be negative value, it will be * roundup to 0 by wayland-ivi extension. */ lc->dst.x += data->off_x; lc->dst.y += data->off_y; if (data->w) lc->dst.w = data->w; if (data->h) lc->dst.h = data->h; fix_layer_ctl_setting(lc); jswm_info("cmdSetRoleRelativePos: set layer %d dest region %d %d %d %d.\n", lc->id, lc->dst.x, lc->dst.y, lc->dst.w, lc->dst.h); ilm_layerSetDestinationRectangle(lc->id, lc->dst.x, lc->dst.y, lc->dst.w, lc->dst.h); ilm_commitChanges(); } while(0); cmdSetRoleRelativePosData_free(data); } void do_cmdSetRoleVisibility(struct ipcon_msg *im) { struct cmdSetRoleVisibilityData *data = libjswm_cmdSetRoleVisibilityData(im->buf); do { struct layer_ctl *visible_layer_ctl = NULL; if (!data) break; struct layer_ctl *lc = get_layer_ctl_by_role(data->role); if (!lc) { jswm_err("No layer with %s role found\n", data->role); break; } assert(lc->screen); visible_layer_ctl = lc->screen->visible_layer_ctl; if (!data->onoff) { if (layer_ctl_visibility_is_always_on(lc)) { jswm_warn("Can not set off to an always visible role %s\n", data->role); break; } if (layer_ctl_visibility_is_auto(lc) && (visible_layer_ctl != lc)) break; jswm_info("Set Role %s layer on screen %d visibility off\n", lc->role, lc->screen->id); ilm_layerSetVisibility(lc->id, ILM_FALSE); ilm_commitChanges(); layer_ctl_clear_visible(lc); lc->screen->visible_layer_ctl = NULL; } else { if (layer_ctl_visibility_is_always_on(lc)) break; if (layer_ctl_visibility_is_auto(lc)) { if (visible_layer_ctl == lc) break; jswm_info("Set Role %s layer on screen %d visibility off\n", visible_layer_ctl->role, lc->screen->id); ilm_layerSetVisibility(visible_layer_ctl->id, ILM_FALSE); layer_ctl_clear_visible(visible_layer_ctl); } jswm_info("Set Role %s layer on screen %d visibility on\n", lc->role, lc->screen->id); ilm_layerSetVisibility(lc->id, ILM_TRUE); layer_ctl_set_visible(lc); ilm_commitChanges(); if (layer_ctl_visibility_is_auto(lc)) lc->screen->visible_layer_ctl = lc; } } while(0); cmdSetRoleVisibilityData_free(data); } static inline char *jswm_work_type_str(enum jswm_work_type jwt) { switch(jwt) { case JWT_SURFACE_CREATE: return "JWT_SURFACE_CREATE"; case JWT_SURFACE_DESTROY: return "JWT_SURFACE_DESTROY"; case JWT_LAYER_CREATE: return "JWT_LAYER_CREATE"; case JWT_LAYER_DESTROY: return "JWT_LAYER_DESTROY"; case JWT_SURFACE_EVENT: return "JWT_SURFACE_EVENT"; default: break; } return "INVALID_WORK_TYPE"; }; #define JSWM_MAX_WORK_PARA (LIBIPCON_MAX_PAYLOAD_LEN - sizeof(enum jswm_work_type)) struct jswm_work { enum jswm_work_type jwt; char para[JSWM_MAX_WORK_PARA]; }__attribute__((packed)); static struct jswm_work *jswm_alloc_work(enum jswm_work_type jwt) { struct jswm_work *jw = malloc(sizeof(*jw)); if (jw) jw->jwt = jwt; return jw; } static void jswm_free_work(struct jswm_work *jw) { do { if (!jw) break; free(jw); } while (0); } static void do_surface_create(struct jswm_work *jw) { do { ilmErrorTypes rc; t_ilm_layer layer_id; t_ilm_surface id = *(t_ilm_surface *)jw->para; int slot; int need_commit = 0; struct surface_ctl *sc = get_surface_ctrl_by_id(id); struct layer_ctl *lc = NULL; if (!sc) { sc = register_anonymous_surface(id); if (!sc) break; } for (slot = 0; slot < SC_MAX_LAYER_NUM; slot++) { lc = sc->layer[slot]; if (!lc) continue; need_commit = 1; rc = ilm_layerAddSurface(lc->id, id); jswm_info("Add %d to layer %d: %s\n", id, lc->id, rc == ILM_SUCCESS ? "success":"fail"); } if (need_commit) { ilm_commitChanges(); surface_setup_input(sc); } } while (0); } static void do_surface_destroy(struct jswm_work *jw) { do { t_ilm_surface id = *(t_ilm_surface *)jw->para; struct surface_ctl *sc = get_surface_ctrl_by_id(id); if (!sc) break; if (sc->type != SCT_TYPE_TEMP) break; layer_remove_surface(sc); surface_hash_remove(sc); surface_ctl_put(sc); } while (0); } static void do_layer_create(struct jswm_work *jw) { do { t_ilm_layer id = *(t_ilm_surface *)jw->para; int i; struct layer_ctl *lc = get_layer_ctl_by_id(id); if (lc) { jswm_info("set visibility for layer %d on screen %d to %s\n", id, lc->screen ? lc->screen->id : -1, layer_ctl_is_visible(lc) ? "on" : "off"); ilm_layerSetVisibility(id, layer_ctl_is_visible(lc)); fix_layer_ctl_setting(lc); jswm_info("set layer %d source region %d %d %d %d.\n", lc->id, lc->src.x, lc->src.y, lc->src.w, lc->src.h); ilm_layerSetSourceRectangle(id, lc->src.x, lc->src.y, lc->src.w, lc->src.h); jswm_info("set layer %d dest region %d %d %d %d.\n", lc->id, lc->dst.x, lc->dst.y, lc->dst.w, lc->dst.h); ilm_layerSetDestinationRectangle(id, lc->dst.x, lc->dst.y, lc->dst.w, lc->dst.h); ilm_commitChanges(); } } while (0); } static void do_layer_destroy(struct jswm_work *jw) { do { t_ilm_layer id = *(t_ilm_surface *)jw->para; int i; struct layer_ctl *lc = get_layer_ctl_by_id(id); if (lc) jswm_info(" registered layer %d destroyed\n", id); } while (0); } static void do_surface_event(struct jswm_work *jw) { do { struct surface_event_para *sep = (struct surface_event_para *)jw->para; struct surface_ctl *sc = get_surface_ctrl_by_id(sep->surface); assert(sc); if (sep->mask & ILM_NOTIFICATION_CONTENT_AVAILABLE) { struct ilmSurfaceProperties lp; ilmErrorTypes rc; /* This will trigger serval surface events */ jswm_info("Trigger events for surface %d \n", sep->surface); ilm_getPropertiesOfSurface(sep->surface, &lp); } if (sep->mask == ILM_NOTIFICATION_CONFIGURED) update_surface(sc, &sep->prop); } while (0); } IPCON_HANDLER ivi_event_handler; int jswm_ctl_commit(enum jswm_work_type jwt, void *para, int size) { int ret = -1; do { struct jswm_work jw; if (jswm_ctl_state != JSWM_CTL_IF_STATE_RUN) break; assert(size <= JSWM_MAX_WORK_PARA); jswm_info("Commit %s work\n", jswm_work_type_str(jwt)); jw.jwt = jwt; memcpy(jw.para, para, size); ret = ipcon_send_unicast(ivi_event_handler, JSWM_IPCON, &jw, sizeof(jw)); } while (0); return ret; } pthread_t com_thread_id; sem_t sem_com_worker; void *jswm_com_worker(void *para) { int ret = 0; sem_wait(&sem_com_worker); while (1) { struct ipcon_msg im; ret = ipcon_rcv(jswm_handler, &im); if (ret < 0) { jswm_err("ipcon_rcv() failed.\n"); continue; } if (im.type == LIBIPCON_NORMAL_MSG) { if (!strcmp(im.peer, IVI_EVENT_IPCON)) { struct jswm_work *jw = (struct jswm_work *)im.buf; switch(jw->jwt) { case JWT_SURFACE_CREATE: do_surface_create(jw); break; case JWT_SURFACE_DESTROY: do_surface_destroy(jw); break; case JWT_LAYER_CREATE: do_layer_create(jw); break; case JWT_LAYER_DESTROY: do_layer_destroy(jw); break; case JWT_SURFACE_EVENT: do_surface_event(jw); break; default: break; } continue; } enum LIBJSWM_CMD cmd = libjswm_getcmd(im.buf); switch (cmd) { case cmdGetRoleSurfaceId: jswm_dbg("CMD: cmdGetRoleSurfaceId\n"); do_cmdGetRoleSurfaceId(&im); break; case cmdShowRole: jswm_dbg("CMD: cmdShowRole\n"); do_cmdShowRole(&im); break; case cmdSetRolePos: jswm_dbg("CMD: cmdSetRolePos\n"); do_cmdSetRolePos(&im); break; case cmdSetRoleRelativePos: jswm_dbg("CMD: cmdSetRoleRelativePos\n"); do_cmdSetRoleRelativePos(&im); break; case cmdSetRoleVisibility: jswm_dbg("CMD: cmdSetRoleVisibility\n"); do_cmdSetRoleVisibility(&im); break; default: jswm_warn("Unexpected command: %d\n",cmd); break; } } } return NULL; } int jswm_ctl_init(void) { int ret = -1; do { jswm_handler = ipcon_create_handler(JSWM_IPCON, LIBIPCON_FLG_USE_RCV_IF | LIBIPCON_FLG_USE_SND_IF); if (!jswm_handler) { jswm_err("Failed to create ipcon handler.\n"); break; } ret = ipcon_join_group(jswm_handler, LIBIPCON_KERNEL_NAME, LIBIPCON_KERNEL_GROUP_NAME); if (ret < 0 ) { jswm_err("Failed to join ipcon kernel group.\n"); break; } ivi_event_handler = ipcon_create_handler(IVI_EVENT_IPCON, LIBIPCON_FLG_USE_SND_IF); if (!ivi_event_handler) { jswm_err("Failed to create ipcon handler for ive event.\n"); break; } sem_init(&sem_com_worker, 0, 0); ret = pthread_create(&com_thread_id, NULL, jswm_com_worker, NULL); if (ret < 0) break; ret = load_setting(); if (ret < 0) { jswm_ctl_state = JSWM_CTL_IF_STATE_DIE; break; } jswm_ctl_state = JSWM_CTL_IF_STATE_RUN; ret = jswm_ctl_refresh(); if (ret < 0) { jswm_ctl_state = JSWM_CTL_IF_STATE_DIE; break; } sem_post(&sem_com_worker); } while (0); if (ret < 0) { if (jswm_handler) { ipcon_free_handler(jswm_handler); jswm_handler = NULL; } if (ivi_event_handler) { ipcon_free_handler(ivi_event_handler); ivi_event_handler = NULL; } } return ret; }