static Edje_Program *current_program = NULL;
static Eina_List *current_program_lookups = NULL;
Eina_Bool current_group_inherit = EINA_FALSE;
-Eina_Bool script_override = EINA_FALSE;
+Eina_Bool script_is_replaceable = EINA_FALSE;
static Edje_Program *sequencing = NULL;
static Eina_List *sequencing_lookups = NULL;
static int *anonymous_delete = NULL;
static void st_collections_group_orientation(void);
static void st_collections_group_mouse_events(void);
static void st_collections_group_use_custom_seat_names(void);
+static void st_collections_group_inherit_script(void);
static void st_collections_group_limits_vertical(void);
static void st_collections_group_limits_horizontal(void);
static void st_collections_group_nomouse(void);
static void st_collections_group_broadcast(void);
static void st_collections_group_nobroadcast(void);
+static void st_collections_group_noinherit_script(void);
static void st_images_vector(void);
static void _handle_vector_image(void);
{"collections.group.broadcast_signal", st_collections_group_broadcast_signal},
{"collections.group.orientation", st_collections_group_orientation},
{"collections.group.mouse_events", st_collections_group_mouse_events},
+ {"collections.group.inherit_script", st_collections_group_inherit_script},
{"collections.group.data.item", st_collections_group_data_item},
{"collections.group.limits.horizontal", st_collections_group_limits_horizontal},
{"collections.group.limits.vertical", st_collections_group_limits_vertical},
nobroadcast; -> broadcast_signal: 0;
mouse; -> mouse_events: 1;
nomouse; -> mouse_events: 0;
+ inherit_script; -> inherit_script: 1;
+ noinherit_script; -> inherit_script: 0;
parts {
part {
mouse; -> mouse_events: 1;
{"collections.group.nomouse", st_collections_group_nomouse},
{"collections.group.broadcast", st_collections_group_broadcast},
{"collections.group.nobroadcast", st_collections_group_nobroadcast},
+ {"collections.group.inherit_script", st_collections_group_inherit_script},
+ {"collections.group.noinherit_script", st_collections_group_noinherit_script},
{"collections.group.parts.part.description.inherit", st_collections_group_parts_part_description_inherit},
};
current_desc = NULL;
current_group_inherit = EINA_FALSE;
- script_override = EINA_FALSE;
+ script_is_replaceable = EINA_FALSE;
current_de = mem_alloc(SZ(Edje_Part_Collection_Directory_Entry));
current_de->id = eina_list_count(edje_collections);
pcp = (Edje_Part_Collection_Parser *)pc;
pcp->default_mouse_events = 1;
+ pcp->inherit_script = EINA_FALSE;
pc->scene_size.width = 0;
pc->scene_size.height = 0;
pcp = (Edje_Part_Collection_Parser *)pc;
pcp2 = (Edje_Part_Collection_Parser *)pc2;
pcp->default_mouse_events = pcp2->default_mouse_events;
+ pcp->inherit_script = pcp2->inherit_script;
/* as of 7 April 2014, target groups cannot be modified and are not freed.
* this code will break if that ever changes.
cd = eina_list_data_get(eina_list_last(codes));
cd->is_lua = cd2->is_lua;
+ if (!cd2->is_lua)
+ pcp->base_codes = eina_list_append(pcp->base_codes, cd2);
+
if (cd2->shared)
{
if (cd->shared)
cd->shared = STRDUP(cd2->shared);
cd->original = STRDUP(cd2->original);
- script_override = EINA_TRUE;
+ script_is_replaceable = EINA_TRUE;
}
EINA_LIST_FOREACH(cd2->programs, l, cp2)
/**
@page edcref
@property
+ inherit_script
+ @parameters
+ [1 or 0]
+ @effect
+ Determine whether to inherit script block from parent group.
+ If it is set to 0, script from parent group will be replaced with
+ new script block.
+ Defaults to 0 if not set, to maintain compatibility.
+ @endproperty
+ */
+static void
+st_collections_group_inherit_script(void)
+{
+ Edje_Part_Collection_Parser *pcp;
+
+ pcp = eina_list_last_data_get(edje_collections);
+
+ if (get_arg_count() == 1)
+ pcp->inherit_script = parse_bool(0);
+ else
+ pcp->inherit_script = EINA_TRUE;
+}
+
+static void
+st_collections_group_noinherit_script(void)
+{
+ Edje_Part_Collection_Parser *pcp;
+
+ check_arg_count(0);
+
+ pcp = eina_list_last_data_get(edje_collections);
+ pcp->inherit_script = EINA_FALSE;
+}
+
+static void
+_script_flush(void)
+{
+ Edje_Part_Collection_Parser *pcp;
+ Code *code;
+
+ pcp = eina_list_last_data_get(edje_collections);
+ code = eina_list_last_data_get(codes);
+
+ if (!pcp->inherit_script || code->is_lua) return;
+
+ // If script is replaceable and overridable, code->shared will be inherited
+ // script. Free it to avoid duplication.
+ if (script_is_replaceable)
+ {
+ if (code->shared)
+ {
+ free(code->shared);
+ code->shared = NULL;
+ }
+ if (code->original)
+ {
+ free(code->original);
+ code->original = NULL;
+ }
+ }
+
+ script_rewrite(code);
+
+ eina_list_free(pcp->base_codes);
+}
+
+
+/**
+ @page edcref
+ @property
program_source
@parameters
[source name]
static void
ob_collections_group_script(void)
{
- Edje_Part_Collection *pc;
Code *cd;
- pc = eina_list_last_data_get(edje_collections);
cd = eina_list_data_get(eina_list_last(codes));
if (!is_verbatim()) track_verbatim(1);
cd->l2 = get_verbatim_line2();
if (cd->shared)
{
- if (script_override)
+ if (script_is_replaceable)
{
free(cd->shared);
free(cd->original);
- script_override = EINA_FALSE;
-
- WRN("%s:%i. Inherited script block in group \"%s\" is redefined. "
- "This can break inherited edje programs.", file_in, line - 1, pc->part);
+ script_is_replaceable = EINA_FALSE;
}
else
{
else if (current_program && (!strcmp(token, "link")))
current_program = NULL;
else if (current_de && (!strcmp(token, "group")))
- _link_combine();
+ {
+ _link_combine();
+ _script_flush();
+ }
else if (current_desc && (!strcmp(token, "description")))
free_anchors();
}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "edje_cc.h"
+
+#define MESSAGE_OVERRIDE
+
+typedef struct _Code_Symbol
+{
+ const char *name;
+ const char *tag;
+ Eina_List *args;
+ char *body;
+ Eina_Bool is_public : 1;
+} Code_Symbol;
+
+typedef enum
+{
+ TOKEN_TYPE_INVALID = -1,
+ TOKEN_TYPE_EOF,
+ TOKEN_TYPE_COLON = (1 << 0),
+ TOKEN_TYPE_SEMICOLON = (1 << 1),
+ TOKEN_TYPE_COMMA = (1 << 2),
+ TOKEN_TYPE_PARENS = (1 << 3),
+ TOKEN_TYPE_BRACES = (1 << 4),
+ TOKEN_TYPE_EQUAL_MARK = (1 << 5),
+ TOKEN_TYPE_PUBLIC = (1 << 6),
+ TOKEN_TYPE_IDENTIFIER = (1 << 7)
+} Token_Type;
+
+typedef struct _Token
+{
+ char *str;
+ Token_Type type;
+} Token;
+
+static void code_parse_internal(Code *code);
+static Token *next_token(char **begin, char *end);
+
+static void
+code_parse(Code *code)
+{
+ Edje_Part_Collection_Parser *pcp;
+ Code *base;
+ Eina_List *l;
+ int id;
+
+ if (code->is_lua) return;
+
+ id = eina_list_data_idx(codes, code);
+ pcp = eina_list_nth(edje_collections, id);
+
+ EINA_LIST_FOREACH(pcp->base_codes, l, base)
+ {
+ if (!base->parsed)
+ code_parse(base);
+ }
+
+ if (code->shared)
+ code_parse_internal(code);
+
+ code->parsed = EINA_TRUE;
+}
+
+static void
+code_parse_internal(Code *code)
+{
+ Code_Symbol *sym = NULL, *func;
+ Token *token, *tmp;
+ char *begin = code->shared;
+ char *end = begin + strlen(begin);
+ char *body;
+ Eina_Array *stack;
+ Eina_Bool is_args = EINA_FALSE;
+ Eina_Bool is_public = EINA_FALSE;
+ int depth = 0;
+
+ stack = eina_array_new(4);
+
+ while ((token = next_token(&begin, end)))
+ {
+ if (token->type == TOKEN_TYPE_EOF)
+ break;
+
+ // Variables in script cannot be initialized by assignment.
+ // Skip until value assignment expression ends.
+ if (token->type == TOKEN_TYPE_EQUAL_MARK)
+ {
+ while ((tmp = next_token(&begin, end)))
+ {
+ if ((tmp->type == TOKEN_TYPE_COMMA) ||
+ (tmp->type == TOKEN_TYPE_SEMICOLON))
+ {
+ token = tmp;
+ break;
+ }
+ }
+ }
+
+ switch (token->type)
+ {
+ case TOKEN_TYPE_COLON:
+ if (!sym)
+ sym = mem_alloc(SZ(Code_Symbol));
+ sym->tag = eina_array_pop(stack);
+ break;
+ case TOKEN_TYPE_SEMICOLON:
+ if (eina_array_count(stack))
+ {
+ if (!sym)
+ sym = mem_alloc(SZ(Code_Symbol));
+ sym->name = eina_array_pop(stack);
+ sym->is_public = is_public;
+ code->vars = eina_list_append(code->vars, sym);
+ sym = NULL;
+ }
+ is_public = EINA_FALSE;
+ break;
+ case TOKEN_TYPE_COMMA:
+ if (!sym)
+ sym = mem_alloc(SZ(Code_Symbol));
+ sym->name = eina_array_pop(stack);
+ if (is_args)
+ func->args = eina_list_append(func->args, sym);
+ else
+ {
+ sym->is_public = is_public;
+ code->vars = eina_list_append(code->vars, sym);
+ }
+ sym = NULL;
+ break;
+ case TOKEN_TYPE_PARENS:
+ is_args = !is_args;
+ if (is_args)
+ {
+ if (!sym)
+ func = mem_alloc(SZ(Code_Symbol));
+ else
+ {
+ func = sym;
+ sym = NULL;
+ }
+ func->name = eina_array_pop(stack);
+ }
+ else
+ {
+ if (eina_array_count(stack))
+ {
+ if (!sym)
+ sym = mem_alloc(SZ(Code_Symbol));
+ sym->name = eina_array_pop(stack);
+ func->args = eina_list_append(func->args, sym);
+ }
+ sym = func;
+ }
+ break;
+ case TOKEN_TYPE_BRACES:
+ depth = 1;
+ body = begin;
+ while ((tmp = next_token(&begin, end)))
+ {
+ if (tmp->type == TOKEN_TYPE_BRACES)
+ {
+ switch (tmp->str[0])
+ {
+ case '{':
+ depth++;
+ break;
+ case '}':
+ depth--;
+ break;
+ }
+ }
+ if (!depth)
+ break;
+ }
+ if ((begin - 1) > body)
+ {
+ sym->body = mem_alloc(sizeof(char) * (begin - body - 1));
+ strncpy(sym->body, body, (begin - body - 2));
+ }
+ sym->is_public = is_public;
+ code->func = eina_list_append(code->func, sym);
+ sym = NULL;
+ is_public = EINA_FALSE;
+ break;
+ case TOKEN_TYPE_PUBLIC:
+ is_public = EINA_TRUE;
+ break;
+ case TOKEN_TYPE_IDENTIFIER:
+ eina_array_push(stack, token->str);
+ token->str = NULL;
+ break;
+ default:
+ break;
+ }
+
+ if (token->str)
+ free(token->str);
+ free(token);
+ }
+
+ eina_array_free(stack);
+}
+
+static Token *
+next_token(char **begin, char *end)
+{
+ char buf[PATH_MAX] = { 0, };
+ char *src;
+ int index;
+ Token *token;
+ Eina_Bool parsed = EINA_FALSE;
+
+ if (!begin || (*begin >= end))
+ return NULL;
+
+ token = mem_alloc(SZ(Token));
+ token->type = TOKEN_TYPE_INVALID;
+
+ src = *begin - 1;
+ index = 0;
+
+ while (++src < end)
+ {
+ char ch = *src;
+
+ switch (ch)
+ {
+ case ' ':
+ case '\t':
+ case '\n':
+ if (index > 0)
+ parsed = EINA_TRUE;
+ break;
+ case ':':
+ case ';':
+ case ',':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '=':
+ if (!index)
+ {
+ buf[index++] = ch;
+ src++;
+ }
+ goto exit;
+ default:
+ if (parsed)
+ goto exit;
+ buf[index++] = ch;
+ break;
+ }
+ }
+
+exit:
+ switch (buf[0])
+ {
+ case ':':
+ token->type = TOKEN_TYPE_COLON;
+ break;
+ case ';':
+ token->type = TOKEN_TYPE_SEMICOLON;
+ break;
+ case ',':
+ token->type = TOKEN_TYPE_COMMA;
+ break;
+ case '(':
+ case ')':
+ token->type = TOKEN_TYPE_PARENS;
+ break;
+ case '{':
+ case '}':
+ token->type = TOKEN_TYPE_BRACES;
+ break;
+ case '=':
+ token->type = TOKEN_TYPE_EQUAL_MARK;
+ break;
+ case '\0':
+ token->type = TOKEN_TYPE_EOF;
+ break;
+ }
+
+ if (token->type < 0)
+ {
+ if (!strcmp(buf, "public"))
+ token->type = TOKEN_TYPE_PUBLIC;
+ else
+ token->type = TOKEN_TYPE_IDENTIFIER;
+ }
+
+ *begin = src;
+ token->str = strdup(buf);
+ return token;
+}
+
+static void
+_push_symbol(Eina_List **total, Code_Symbol *sym, Edje_Part_Collection *pc)
+{
+ Eina_List *list, *l;
+ Code_Symbol *sym2;
+
+ list = *total;
+
+ EINA_LIST_FOREACH(list, l, sym2)
+ {
+ if (!strcmp(sym2->name, sym->name))
+ {
+ WRN("Symbols in group \"%s\" have same name \"%s\". Latter defined "
+ "will shadow former one.", pc->part, sym->name);
+ list = eina_list_remove(list, sym2);
+ break;
+ }
+ }
+ list = eina_list_append(list, sym);
+ *total = list;
+}
+
+void
+script_rewrite(Code *code)
+{
+ Edje_Part_Collection *pc;
+ Edje_Part_Collection_Parser *pcp;
+ Code *base;
+ Eina_List *l, *ll;
+ int id, count;
+ Eina_Strbuf *buf;
+ Eina_List *vars = NULL;
+ Eina_List *func = NULL;
+#ifdef MESSAGE_OVERRIDE
+ Eina_List *message = NULL;
+#endif
+ Code_Symbol *sym, *arg;
+
+ code_parse(code);
+
+ id = eina_list_data_idx(codes, code);
+ pc = eina_list_nth(edje_collections, id);
+ pcp = (Edje_Part_Collection_Parser *)pc;
+
+ EINA_LIST_FOREACH(pcp->base_codes, l, base)
+ {
+ EINA_LIST_FOREACH(base->vars, ll, sym)
+ _push_symbol(&vars, sym, pc);
+
+ EINA_LIST_FOREACH(base->func, ll, sym)
+ {
+#ifndef MESSAGE_OVERRIDE
+ _push_symbol(&func, sym, pc);
+#else
+ if (strcmp(sym->name, "message"))
+ _push_symbol(&func, sym, pc);
+ else
+ message = eina_list_append(message, sym);
+#endif
+ }
+ }
+
+ EINA_LIST_FOREACH(code->vars, l, sym)
+ _push_symbol(&vars, sym, pc);
+ EINA_LIST_FOREACH(code->func, l, sym)
+ {
+#ifndef MESSAGE_OVERRIDE
+ _push_symbol(&func, sym, pc);
+#else
+ if (strcmp(sym->name, "message"))
+ _push_symbol(&func, sym, pc);
+ else
+ message = eina_list_append(message, sym);
+#endif
+ }
+
+ buf = eina_strbuf_new();
+
+ if (vars)
+ {
+ count = 0;
+ EINA_LIST_FOREACH(vars, l, sym)
+ {
+ if (!sym->is_public) continue;
+
+ if (count++)
+ eina_strbuf_append(buf, ", ");
+ else
+ eina_strbuf_append(buf, "public ");
+
+ if (sym->tag)
+ eina_strbuf_append_printf(buf, "%s:", sym->tag);
+ eina_strbuf_append(buf, sym->name);
+ }
+ if (count)
+ eina_strbuf_append(buf, ";\n");
+
+ count = 0;
+ EINA_LIST_FOREACH(vars, l, sym)
+ {
+ if (sym->is_public) continue;
+
+ if (count++)
+ eina_strbuf_append(buf, ", ");
+
+ if (sym->tag)
+ eina_strbuf_append_printf(buf, "%s:", sym->tag);
+ eina_strbuf_append(buf, sym->name);
+ }
+ if (count)
+ eina_strbuf_append(buf, ";\n");
+ }
+
+ if (func)
+ {
+ EINA_LIST_FOREACH(func, l, sym)
+ {
+ eina_strbuf_append(buf, "\n");
+ if (sym->is_public)
+ eina_strbuf_append(buf, "public ");
+
+ if (sym->tag)
+ eina_strbuf_append_printf(buf, "%s:", sym->tag);
+ eina_strbuf_append_printf(buf, "%s(", sym->name);
+
+ count = 0;
+ EINA_LIST_FOREACH(sym->args, ll, arg)
+ {
+ if (count++)
+ eina_strbuf_append(buf, ", ");
+
+ if (arg->tag)
+ eina_strbuf_append_printf(buf, "%s:", arg->tag);
+ eina_strbuf_append(buf, arg->name);
+ }
+ eina_strbuf_append(buf, ") {");
+ if (sym->body)
+ {
+ eina_strbuf_append(buf, sym->body);
+ eina_strbuf_rtrim(buf);
+ }
+ eina_strbuf_append(buf, "\n}\n");
+ }
+ }
+
+#ifdef MESSAGE_OVERRIDE
+ if (message)
+ {
+ eina_strbuf_append(buf, "\npublic message(Msg_Type:type, id, ...) {");
+ EINA_LIST_FOREACH(message, l, sym)
+ {
+ eina_strbuf_append(buf, sym->body);
+ eina_strbuf_rtrim(buf);
+ eina_strbuf_append(buf, "\n");
+ }
+ eina_strbuf_append(buf, "}\n");
+ }
+#endif
+
+ code->shared = eina_strbuf_string_steal(buf);
+ code->original = strdup(code->shared);
+ eina_strbuf_free(buf);
+
+ eina_list_free(vars);
+ eina_list_free(func);
+}