From d57d17723e255883dda22b96b61ea5e7cd5f23f8 Mon Sep 17 00:00:00 2001 From: Bruno Dilly Date: Wed, 14 Dec 2016 02:55:59 -0200 Subject: [PATCH 1/5] edje: refactor _edje_program_run for FOCUS_SET action Improve code readability and avoid code repetition. --- src/lib/edje/edje_program.c | 80 ++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/src/lib/edje/edje_program.c b/src/lib/edje/edje_program.c index 695f57ccd8..df74b334ec 100644 --- a/src/lib/edje/edje_program.c +++ b/src/lib/edje/edje_program.c @@ -641,6 +641,38 @@ _edje_seat_name_emit(Edje *ed, const char *name, const char *sig, const char *sr _edje_emit_full(ed, buf, src, NULL, NULL); } +static void +_edje_part_focus_set(Edje *ed, const char *seat_name, Edje_Real_Part *rp) +{ + Edje_Real_Part *focused_part; + Eina_Stringshare *sname; + Efl_Input_Device *seat; + Evas *e; + + if (seat_name) + sname = eina_stringshare_add(seat_name); + else /* Use default seat name */ + { + e = evas_object_evas_get(ed->obj); + seat = evas_canvas_default_device_get(e, EFL_INPUT_DEVICE_CLASS_SEAT); + sname = eina_stringshare_ref(_edje_seat_name_get(ed, seat)); + } + + focused_part = _edje_focused_part_get(ed, sname); + + if (focused_part != rp) + { + if (focused_part) + _edje_seat_name_emit(ed, sname, "focus,part,out", + focused_part->part->name); + _edje_focused_part_set(ed, sname, rp); + if (rp) + _edje_seat_name_emit(ed, sname, "focus,part,in", rp->part->name); + } + + eina_stringshare_del(sname); +} + void _edje_program_run(Edje *ed, Edje_Program *pr, Eina_Bool force, const char *ssig, const char *ssrc) { @@ -970,35 +1002,8 @@ low_mem_current: case EDJE_ACTION_TYPE_FOCUS_SET: { - Edje_Real_Part *focused_part; - Eina_Stringshare *seat_name; - Eina_Bool unref_name = EINA_FALSE; - - if (pr->seat) - { - seat_name = eina_stringshare_add(pr->seat); - unref_name = EINA_TRUE; - } - else /* Use default seat name */ - { - Efl_Input_Device *seat; - Evas *e; - - e = evas_object_evas_get(ed->obj); - seat = evas_canvas_default_device_get(e, EFL_INPUT_DEVICE_CLASS_SEAT); - seat_name = _edje_seat_name_get(ed, seat); - if (!seat_name) - break; - } - if (!pr->targets) - { - focused_part = _edje_focused_part_get(ed, seat_name); - if (focused_part) - _edje_seat_name_emit(ed, seat_name, "focus,part,out", - focused_part->part->name); - _edje_focused_part_set(ed, seat_name, NULL); - } + _edje_part_focus_set(ed, pr->seat, NULL); else { EINA_LIST_FOREACH(pr->targets, l, pt) @@ -1007,27 +1012,10 @@ low_mem_current: { rp = ed->table_parts[pt->id % ed->table_parts_size]; if (rp) - { - focused_part = _edje_focused_part_get(ed, - seat_name); - if (focused_part != rp) - { - if (focused_part) - _edje_seat_name_emit(ed, seat_name, - "focus,part,out", - focused_part->part->name); - _edje_focused_part_set(ed, seat_name, rp); - _edje_seat_name_emit(ed, seat_name, - "focus,part,in", - rp->part->name); - } - } + _edje_part_focus_set(ed, pr->seat, rp); } } } - - if (unref_name) - eina_stringshare_del(seat_name); } break; From 9bc9fde90ec75e58162e94bca4e71b62920afc73 Mon Sep 17 00:00:00 2001 From: Bruno Dilly Date: Wed, 14 Dec 2016 02:58:53 -0200 Subject: [PATCH 2/5] edje: add function on embryo to control focus Add set_focus(part_id) and unset_focus(). Both functions accept an optional argument "seat_name". If not provided default seat will be assumed. --- data/edje/include/edje.inc | 6 ++++ src/lib/edje/edje_embryo.c | 59 +++++++++++++++++++++++++++++++++++++ src/lib/edje/edje_private.h | 1 + src/lib/edje/edje_program.c | 2 +- 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/data/edje/include/edje.inc b/data/edje/include/edje.inc index 7807383c3c..5fa08bf308 100644 --- a/data/edje/include/edje.inc +++ b/data/edje/include/edje.inc @@ -141,6 +141,12 @@ native set_mask_flags (part_id, flags); native get_mask_flags (part_id); native part_swallow (part_id, GROUP:str[]); +/* set_focus() and unset_focus() may receive an optional parameter + seat_name[], as set_focus(part_id, seat_name[]) and + unset_focus(seat_name[]) */ +native set_focus (part_id, ...); +native unset_focus (...); + native external_param_get_int(id, param_name[]); native external_param_set_int(id, param_name[], value); native Float:external_param_get_float(id, param_name[]); diff --git a/src/lib/edje/edje_embryo.c b/src/lib/edje/edje_embryo.c index bb46310ca8..f4d49d079e 100644 --- a/src/lib/edje/edje_embryo.c +++ b/src/lib/edje/edje_embryo.c @@ -196,6 +196,9 @@ * set_clip(part_id, clip_part_id) * get_clip(part_id) * + * set_focus(part_id, seat_name[]) + * unset_focus(seat_name[]) + * * part_swallow(part_id, group_name) * * external_param_get_int(id, param_name[]) @@ -3771,6 +3774,59 @@ _edje_embryo_fn_part_swallow(Embryo_Program *ep, Embryo_Cell *params) return 0; } +/* set_focus(part_id, seat_name[]) */ +static Embryo_Cell +_edje_embryo_fn_set_focus(Embryo_Program *ep, Embryo_Cell *params) +{ + Edje *ed; + int part_id; + Edje_Real_Part *rp; + char *seat_name = NULL; + + if (!(HASNPARAMS(1) || HASNPARAMS(2))) return -1; + ed = embryo_program_data_get(ep); + + part_id = params[1]; + if (part_id < 0) return 0; + rp = ed->table_parts[part_id % ed->table_parts_size]; + if (!rp) return 0; + + /* if no seat name is passed, that's fine. it means + it should be applied to default seat */ + if (HASNPARAMS(2)) + { + GETSTR(seat_name, params[2]); + if (!seat_name) return 0; + } + + _edje_part_focus_set(ed, seat_name, rp); + + return 0; +} + +/* unset_focus(seat_name[]) */ +static Embryo_Cell +_edje_embryo_fn_unset_focus(Embryo_Program *ep, Embryo_Cell *params) +{ + Edje *ed; + char *seat_name = NULL; + + if (!(HASNPARAMS(0) || HASNPARAMS(1))) return -1; + ed = embryo_program_data_get(ep); + + /* seat name is optional. no seat means + it should be applied to default seat */ + if (HASNPARAMS(1)) + { + GETSTR(seat_name, params[1]); + if (!seat_name) return 0; + } + + _edje_part_focus_set(ed, seat_name, NULL); + + return 0; +} + /* external_param_get_int(id, param_name[]) */ static Embryo_Cell _edje_embryo_fn_external_param_get_int(Embryo_Program *ep, Embryo_Cell *params) @@ -4510,6 +4566,9 @@ _edje_embryo_script_init(Edje_Part_Collection *edc) embryo_program_native_call_add(ep, "set_mask_flags", _edje_embryo_fn_set_mask_flags); embryo_program_native_call_add(ep, "get_mask_flags", _edje_embryo_fn_get_mask_flags); + embryo_program_native_call_add(ep, "set_focus", _edje_embryo_fn_set_focus); + embryo_program_native_call_add(ep, "unset_focus", _edje_embryo_fn_unset_focus); + embryo_program_native_call_add(ep, "part_swallow", _edje_embryo_fn_part_swallow); embryo_program_native_call_add(ep, "external_param_get_int", _edje_embryo_fn_external_param_get_int); diff --git a/src/lib/edje/edje_private.h b/src/lib/edje/edje_private.h index f04be21a86..1a2d7dbdea 100644 --- a/src/lib/edje/edje_private.h +++ b/src/lib/edje/edje_private.h @@ -2491,6 +2491,7 @@ void _edje_signals_sources_patterns_clean(Edje_Signals_Sources_Patterns *ssp); void _edje_focused_part_set(Edje *ed, const char *seat_name, Edje_Real_Part *rp); Edje_Real_Part *_edje_focused_part_get(Edje *ed, const char *seat_name); +void _edje_part_focus_set(Edje *ed, const char *seat_name, Edje_Real_Part *rp); Eina_Stringshare *_edje_seat_name_get(Edje *ed, Efl_Input_Device *device); Efl_Input_Device *_edje_seat_get(Edje *ed, Eina_Stringshare *name); diff --git a/src/lib/edje/edje_program.c b/src/lib/edje/edje_program.c index df74b334ec..ef4cf40d05 100644 --- a/src/lib/edje/edje_program.c +++ b/src/lib/edje/edje_program.c @@ -641,7 +641,7 @@ _edje_seat_name_emit(Edje *ed, const char *name, const char *sig, const char *sr _edje_emit_full(ed, buf, src, NULL, NULL); } -static void +void _edje_part_focus_set(Edje *ed, const char *seat_name, Edje_Real_Part *rp) { Edje_Real_Part *focused_part; From 65723a190ae34157b6e0335fc86ea70370d17b18 Mon Sep 17 00:00:00 2001 From: Bruno Dilly Date: Wed, 14 Dec 2016 03:02:00 -0200 Subject: [PATCH 3/5] edje: clean erroneous documentation Not implemented functions --- src/lib/edje/edje_embryo.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/edje/edje_embryo.c b/src/lib/edje/edje_embryo.c index f4d49d079e..c7c70f750e 100644 --- a/src/lib/edje/edje_embryo.c +++ b/src/lib/edje/edje_embryo.c @@ -193,8 +193,6 @@ * get_ignore_flags(part_id) * set_mask_flags(part_id, flags) * get_mask_flags(part_id) - * set_clip(part_id, clip_part_id) - * get_clip(part_id) * * set_focus(part_id, seat_name[]) * unset_focus(seat_name[]) From 9308410479b398169ec81daa6b77ef522a0f84ee Mon Sep 17 00:00:00 2001 From: Bruno Dilly Date: Wed, 7 Dec 2016 21:10:34 -0200 Subject: [PATCH 4/5] edje: support filtering allowed seats per part collections.group.parts.part.allowed_seats keeps a list of seat names to be used for events filter. So when evas devices of seat type are added, filters may be applied for each part. If no seat is listed, every seat may interact with such part. --- src/bin/edje/edje_cc_handlers.c | 89 +++++++++++++++++++++++++++++++++ src/lib/edje/edje_data.c | 13 +++++ src/lib/edje/edje_edit.c | 13 +++++ src/lib/edje/edje_load.c | 69 +++++++++++++++++++++++++ src/lib/edje/edje_private.h | 10 ++++ src/lib/edje/edje_program.c | 5 ++ 6 files changed, 199 insertions(+) diff --git a/src/bin/edje/edje_cc_handlers.c b/src/bin/edje/edje_cc_handlers.c index 188e169a07..c4968377aa 100644 --- a/src/bin/edje/edje_cc_handlers.c +++ b/src/bin/edje/edje_cc_handlers.c @@ -313,6 +313,7 @@ static void st_collections_group_parts_part_dragable_y(void); static void st_collections_group_parts_part_dragable_confine(void); static void st_collections_group_parts_part_dragable_threshold(void); static void st_collections_group_parts_part_dragable_events(void); +static void st_collections_group_parts_part_allowed_seats(void); /* box and table items share these */ static void ob_collections_group_parts_part_box_items_item(void); @@ -789,6 +790,7 @@ New_Statement_Handler statement_handlers[] = {"collections.group.parts.part.cursor_mode", st_collections_group_parts_part_cursor_mode}, {"collections.group.parts.part.multiline", st_collections_group_parts_part_multiline}, {"collections.group.parts.part.access", st_collections_group_parts_part_access}, + {"collections.group.parts.part.allowed_seats", st_collections_group_parts_part_allowed_seats}, IMAGE_SET_STATEMENTS("collections.group.parts.part") IMAGE_STATEMENTS("collections.group.parts.part.") {"collections.group.parts.part.font", st_fonts_font}, /* dup */ @@ -4418,6 +4420,36 @@ _part_copy(Edje_Part *ep, Edje_Part *ep2) ep->dragable.count_y = ep2->dragable.count_y; ep->nested_children_count = ep2->nested_children_count; + if (ep2->allowed_seats) + { + Edje_Part_Allowed_Seat *seat; + unsigned int s; + + ep->allowed_seats_count = ep2->allowed_seats_count; + ep->allowed_seats = calloc(ep2->allowed_seats_count, + sizeof(Edje_Part_Allowed_Seat *)); + if (!ep->allowed_seats) + { + ERR("Not enough memory."); + exit(-1); + } + + for (s = 0; s < ep->allowed_seats_count; s++) + { + seat = mem_alloc(SZ(Edje_Part_Allowed_Seat)); + if (ep2->allowed_seats[s]->name) + { + seat->name = strdup(ep2->allowed_seats[s]->name); + if (!seat->name) + { + ERR("Not enough memory."); + exit(-1); + } + } + ep->allowed_seats[s] = seat; + } + } + data_queue_copied_part_lookup(pc, &(ep2->dragable.confine_id), &(ep->dragable.confine_id)); data_queue_copied_part_lookup(pc, &(ep2->dragable.threshold_id), &(ep->dragable.threshold_id)); data_queue_copied_part_lookup(pc, &(ep2->dragable.event_id), &(ep->dragable.event_id)); @@ -5827,6 +5859,9 @@ edje_cc_handlers_part_make(int id) ep->items = NULL; ep->nested_children_count = 0; + ep->allowed_seats = NULL; + ep->allowed_seats_count = 0; + epp = (Edje_Part_Parser *)ep; epp->reorder.insert_before = NULL; epp->reorder.insert_after = NULL; @@ -6022,6 +6057,13 @@ _part_free(Edje_Part_Collection *pc, Edje_Part *ep) free(ep->items[j]); free(ep->items); + for (j = 0 ; j < ep->allowed_seats_count; j++) + { + free((void*)(ep->allowed_seats[j]->name)); + free(ep->allowed_seats[j]); + } + free(ep->allowed_seats); + free((void*)ep->name); free((void*)ep->source); free((void*)ep->source2); @@ -7398,6 +7440,53 @@ st_collections_group_parts_part_dragable_events(void) } } +/** + @page edcref + @property + allowed_seats + @parameters + [seat1] [seat2] [seat3] ... + @effect + List of seat names allowed to interact with the part. + + If no list is defined all seats are allowed. It's the + default behaviour. + + If a seat isn't allowed, no signals will be emitted + related to its actions, as mouse and focus events. + Also it won't be able to focus this part. + @since 1.19 + @endproperty +*/ +static void +st_collections_group_parts_part_allowed_seats(void) +{ + Edje_Part_Allowed_Seat *seat; + Edje_Part *ep; + int n, argc; + + check_min_arg_count(1); + + ep = current_part; + argc = get_arg_count(); + + ep->allowed_seats = calloc(argc, sizeof(Edje_Part_Allowed_Seat *)); + if (!ep->allowed_seats) + { + ERR("Not enough memory."); + exit(-1); + } + + for (n = 0; n < argc; n++) + { + seat = mem_alloc(SZ(Edje_Part_Allowed_Seat)); + seat->name = parse_str(n); + ep->allowed_seats[n] = seat; + } + + ep->allowed_seats_count = argc; +} + /** @edcsubsection{collections_group_parts_items, * Group.Parts.Part.Box/Table.Items} */ diff --git a/src/lib/edje/edje_data.c b/src/lib/edje/edje_data.c index 6c4ef6aec1..0af3b130fb 100644 --- a/src/lib/edje/edje_data.c +++ b/src/lib/edje/edje_data.c @@ -37,6 +37,8 @@ Eet_Data_Descriptor *_edje_edd_edje_pack_element = NULL; Eet_Data_Descriptor *_edje_edd_edje_pack_element_pointer = NULL; Eet_Data_Descriptor *_edje_edd_edje_part = NULL; Eet_Data_Descriptor *_edje_edd_edje_part_pointer = NULL; +Eet_Data_Descriptor *_edje_edd_edje_part_allowed_seat = NULL; +Eet_Data_Descriptor *_edje_edd_edje_part_allowed_seat_pointer = NULL; Eet_Data_Descriptor *_edje_edd_edje_part_description_variant = NULL; Eet_Data_Descriptor *_edje_edd_edje_part_description_rectangle = NULL; Eet_Data_Descriptor *_edje_edd_edje_part_description_snapshot = NULL; @@ -690,6 +692,8 @@ _edje_edd_shutdown(void) FREED(_edje_edd_edje_pack_element_pointer); FREED(_edje_edd_edje_part); FREED(_edje_edd_edje_part_pointer); + FREED(_edje_edd_edje_part_allowed_seat); + FREED(_edje_edd_edje_part_allowed_seat_pointer); FREED(_edje_edd_edje_part_description_variant); FREED(_edje_edd_edje_part_description_rectangle); FREED(_edje_edd_edje_part_description_snapshot); @@ -946,6 +950,11 @@ _edje_edd_init(void) EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_tag, Edje_Style_Tag, "key", key, EET_T_STRING); EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_tag, Edje_Style_Tag, "value", value, EET_T_STRING); + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Allowed_Seat); + _edje_edd_edje_part_allowed_seat = + eet_data_descriptor_file_new(&eddc); + EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_allowed_seat, Edje_Part_Allowed_Seat, "name", name, EET_T_STRING); + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Style); _edje_edd_edje_style = eet_data_descriptor_file_new(&eddc); @@ -1766,6 +1775,10 @@ _edje_edd_init(void) EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "nested_children_count", nested_children_count, EET_T_UCHAR); EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "required", required, EET_T_UCHAR); + EDJE_DEFINE_POINTER_TYPE(Part_Allowed_Seat, part_allowed_seat); + EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(_edje_edd_edje_part, Edje_Part, "allowed_seats", allowed_seats, _edje_edd_edje_part_allowed_seat_pointer); + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Limit); _edje_edd_edje_part_limit = eet_data_descriptor_file_new(&eddc); diff --git a/src/lib/edje/edje_edit.c b/src/lib/edje/edje_edit.c index de88db33e4..291b5afaf0 100644 --- a/src/lib/edje/edje_edit.c +++ b/src/lib/edje/edje_edit.c @@ -15248,6 +15248,19 @@ _edje_generate_source_of_part(Evas_Object *obj, Edje_Part *ep, Eina_Strbuf *buf) BUF_APPEND(I4 "precise_is_inside: 1;\n"); if (rp->part->access) BUF_APPEND(I4 "access: 1;\n"); + if (rp->part->allowed_seats) + { + Edje_Part_Allowed_Seat *seat; + unsigned int i; + + BUF_APPEND(I4 "allowed_seats:"); + for (i = 0; i < rp->part->allowed_seats_count; i++) + { + seat = rp->part->allowed_seats[i]; + BUF_APPENDF(" %s", seat->name); + } + BUF_APPEND(";\n"); + } if ((str = _edje_part_clip_to_get(ed, rp))) { diff --git a/src/lib/edje/edje_load.c b/src/lib/edje/edje_load.c index e530926c33..bdbf698ca7 100644 --- a/src/lib/edje/edje_load.c +++ b/src/lib/edje/edje_load.c @@ -507,6 +507,60 @@ _edje_physics_world_update_cb(void *data, EPhysics_World *world EINA_UNUSED, voi } #endif +Eina_Bool +_edje_part_allowed_seat_find(Edje_Real_Part *rp, const char *seat_name) +{ + const char *name; + unsigned int i; + + for (i = 0; i < rp->part->allowed_seats_count; i++) + { + name = rp->part->allowed_seats[i]->name; + if (!strcmp(seat_name, name)) + return EINA_TRUE; + } + + return EINA_FALSE; +} + +/* It goes throught the list of registered seats and + * set event filters for each of these seats. */ +static void +_edje_part_seat_filter_apply(Edje *ed, Edje_Real_Part *rp) +{ + Edje_Seat *seat; + Eina_List *l; + Eina_Bool found; + + EINA_LIST_FOREACH(ed->seats, l, seat) + { + found = _edje_part_allowed_seat_find(rp, seat->name); + efl_input_seat_event_filter_set(rp->object, seat->device, found); + } +} + +/* It goes throught the list of all edje parts and + * set event filters for each of these parts. Should be called when + * a new seat is added. + */ +static void +_edje_seat_event_filter_apply(Edje *ed, Edje_Seat *seat) +{ + Edje_Real_Part *rp; + unsigned short i; + Eina_Bool found; + + for (i = 0; i < ed->table_parts_size; i++) + { + rp = ed->table_parts[i]; + if (!rp->part->allowed_seats) + continue; + + found = _edje_part_allowed_seat_find(rp, seat->name); + efl_input_seat_event_filter_set(rp->object, seat->device, found); + } +} + static void _edje_device_add(Edje *ed, Efl_Input_Device *dev) { @@ -544,6 +598,7 @@ _edje_device_add(Edje *ed, Efl_Input_Device *dev) snprintf(sig, sizeof(sig), "seat,added,%s,%s", seat->name, efl_input_device_name_get(dev)); _edje_emit(ed, sig, ""); + _edje_seat_event_filter_apply(ed, seat); seat_err: eina_stringshare_del(name); @@ -645,6 +700,8 @@ _edje_device_changed_cb(void *data, const Efl_Event *event) eina_stringshare_del(seat->name); free(seat); + _edje_seat_event_filter_apply(ed, s); + return; } } @@ -652,6 +709,7 @@ _edje_device_changed_cb(void *data, const Efl_Event *event) snprintf(sig, sizeof(sig), "seat,renamed,%s,%s", seat->name, name); eina_stringshare_replace(&seat->name, name); _edje_emit(ed, sig, ""); + _edje_seat_event_filter_apply(ed, seat); } static void @@ -1093,6 +1151,9 @@ _edje_object_file_set_internal(Evas_Object *obj, const Eina_File *file, const ch nested_smart = NULL; } + if (ep->allowed_seats) + _edje_part_seat_filter_apply(ed, rp); + if (ep->no_render) efl_canvas_object_no_render_set(rp->object, 1); @@ -2228,6 +2289,14 @@ _edje_collection_free(Edje_File *edf, Edje_Part_Collection *ec, Edje_Part_Collec for (j = 0; j < ep->items_count; ++j) free(ep->items[j]); free(ep->items); + + for (j = 0; j < ep->allowed_seats_count; ++j) + { + if (edf->free_strings) + eina_stringshare_del(ep->allowed_seats[j]->name); + free(ep->allowed_seats[j]); + } + free(ep->allowed_seats); // technically need this - but we ASSUME we use "one_big" so everything gets // freed in one go lower down when we del the mempool... but what if pool goes // "over"? diff --git a/src/lib/edje/edje_private.h b/src/lib/edje/edje_private.h index 1a2d7dbdea..13dc7961dd 100644 --- a/src/lib/edje/edje_private.h +++ b/src/lib/edje/edje_private.h @@ -377,6 +377,7 @@ typedef struct _Edje_Part_Box_Animation Edje_Part_Box_Animation; typedef struct _Edje_Part_Limit Edje_Part_Limit; typedef struct _Edje_Part_Description_Vector Edje_Part_Description_Vector; typedef struct _Edje_Part_Description_Spec_Svg Edje_Part_Description_Spec_Svg; +typedef struct _Edje_Part_Allowed_Seat Edje_Part_Allowed_Seat; typedef struct _Edje_Real_Part_Vector Edje_Real_Part_Vector; typedef struct _Edje_Vector_Data Edje_Vector_Data; @@ -1195,6 +1196,8 @@ struct _Edje_Part unsigned int items_count; Edje_3D_Vec scale_3d; Edje_Part_Api api; + Edje_Part_Allowed_Seat **allowed_seats; + unsigned int allowed_seats_count; unsigned char type; /* what type (image, rect, text) */ #ifdef HAVE_EPHYSICS unsigned char physics_body; /* body (none, rigid box, soft circle, ...) */ @@ -1628,6 +1631,12 @@ struct _Edje_Part_Description_Vector Edje_Part_Description_Spec_Svg vg; }; +struct _Edje_Part_Allowed_Seat +{ + const char *name; +}; + + /*----------*/ struct _Edje_Signal_Source_Char @@ -2495,6 +2504,7 @@ void _edje_part_focus_set(Edje *ed, const char *seat_name, Edje_Real_Part *rp); Eina_Stringshare *_edje_seat_name_get(Edje *ed, Efl_Input_Device *device); Efl_Input_Device *_edje_seat_get(Edje *ed, Eina_Stringshare *name); +Eina_Bool _edje_part_allowed_seat_find(Edje_Real_Part *rp, const char *seat_name); const Edje_Signals_Sources_Patterns *_edje_signal_callback_patterns_ref(const Edje_Signal_Callback_Group *gp); void _edje_signal_callback_patterns_unref(const Edje_Signals_Sources_Patterns *essp); diff --git a/src/lib/edje/edje_program.c b/src/lib/edje/edje_program.c index ef4cf40d05..7ab1498814 100644 --- a/src/lib/edje/edje_program.c +++ b/src/lib/edje/edje_program.c @@ -662,6 +662,10 @@ _edje_part_focus_set(Edje *ed, const char *seat_name, Edje_Real_Part *rp) if (focused_part != rp) { + if ((rp->part->allowed_seats) && + (!_edje_part_allowed_seat_find(rp, sname))) + goto not_allowed; + if (focused_part) _edje_seat_name_emit(ed, sname, "focus,part,out", focused_part->part->name); @@ -670,6 +674,7 @@ _edje_part_focus_set(Edje *ed, const char *seat_name, Edje_Real_Part *rp) _edje_seat_name_emit(ed, sname, "focus,part,in", rp->part->name); } +not_allowed: eina_stringshare_del(sname); } From de183e16a30898b665f74ced42318c5a3ea2d56d Mon Sep 17 00:00:00 2001 From: Bruno Dilly Date: Fri, 9 Dec 2016 19:50:33 -0200 Subject: [PATCH 5/5] examples/edje: add seat filtering example 4 widgets: * seat1 only * seat2 only * seat1 + seat2 * any seat --- src/examples/edje/.gitignore | 1 + src/examples/edje/Makefile.am | 3 + src/examples/edje/edje-multiseat-filter.c | 130 ++++ src/examples/edje/multiseat_filter.edc | 811 ++++++++++++++++++++++ 4 files changed, 945 insertions(+) create mode 100644 src/examples/edje/edje-multiseat-filter.c create mode 100644 src/examples/edje/multiseat_filter.edc diff --git a/src/examples/edje/.gitignore b/src/examples/edje/.gitignore index 73b171ab35..027f4d35b8 100644 --- a/src/examples/edje/.gitignore +++ b/src/examples/edje/.gitignore @@ -15,6 +15,7 @@ /edje-focus /edje-multiseat /edje-multiseat-custom-names +/edje-multiseat-filter /edje-multisense /edje-perspective /edje-signals-messages diff --git a/src/examples/edje/Makefile.am b/src/examples/edje/Makefile.am index 2afacfc6fc..e34be1175c 100644 --- a/src/examples/edje/Makefile.am +++ b/src/examples/edje/Makefile.am @@ -47,6 +47,7 @@ lua_script.edc \ messages_echo.edc \ multiseat.edc \ multiseat_custom_names.edc \ +multiseat_filter.edc \ perspective.edc \ signals-messages.edc \ signalsBubble.edc \ @@ -148,6 +149,7 @@ edje-entry.c \ edje-focus.c \ edje-multiseat.c \ edje-multiseat-custom-names.c \ +edje-multiseat-filter.c \ edje-multisense.c \ edje-perspective.c \ edje-signals-messages.c \ @@ -225,6 +227,7 @@ edje-entry \ edje-focus \ edje-multiseat \ edje-multiseat-custom-names \ +edje-multiseat-filter \ edje-perspective \ edje-signals-messages \ edje-swallow \ diff --git a/src/examples/edje/edje-multiseat-filter.c b/src/examples/edje/edje-multiseat-filter.c new file mode 100644 index 0000000000..43ae82818f --- /dev/null +++ b/src/examples/edje/edje-multiseat-filter.c @@ -0,0 +1,130 @@ +/** + * Edje example demonstrating how to use multiseat filtering. + * + * It presents 4 widgets that can be controlled by: + * * seat1 only + * * seat2 only + * * seat1 + seat2 + * * any seat + * + * You'll need at least one Evas engine built for it (excluding the + * buffer one) that supports multiseat. It may be wayland or + * X11 with VNC support. Using other engines will lead you to a + * situation where all seats are reported as the same one ("default"). + * + * @verbatim + * edje_cc multiseat_filter.edc && gcc -o edje-multiseat-filter edje-multiseat-filter.c `pkg-config --libs --cflags evas ecore ecore-evas edje` + * @endverbatim + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define EINA_UNUSED +#endif + +#ifndef PACKAGE_DATA_DIR +#define PACKAGE_DATA_DIR "." +#endif + +#include +#include +#include + +#define WIDTH 400 +#define HEIGHT 400 + +static const char *GROUPNAME = "example/main"; +static const char *EDJE_FILE = PACKAGE_DATA_DIR"/multiseat_filter.edj"; + +static void +_on_destroy(Ecore_Evas *ee EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +static void +_on_canvas_resize(Ecore_Evas *ee) +{ + Evas_Object *edje_obj; + int w, h; + + edje_obj = ecore_evas_data_get(ee, "edje_obj"); + + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + evas_object_resize(edje_obj, w, h); +} + +static void +_device_added(void *data, const Efl_Event *event) +{ + Efl_Input_Device *dev = event->info; + Evas_Object *edje_obj = data; + + if (efl_input_device_type_get(dev) != EFL_INPUT_DEVICE_CLASS_SEAT) + return; + + efl_canvas_object_seat_focus_add(edje_obj, dev); +} + +int +main(int argc EINA_UNUSED, char *argv[] EINA_UNUSED) +{ + const Eina_List *devices, *l; + Efl_Input_Device *dev; + Evas_Object *edje_obj; + Ecore_Evas *ee; + Evas *evas; + + if (!ecore_evas_init()) + return EXIT_FAILURE; + + if (!edje_init()) + goto shutdown_ecore_evas; + + ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL); + if (!ee) goto shutdown_edje; + + ecore_evas_callback_destroy_set(ee, _on_destroy); + ecore_evas_callback_resize_set(ee, _on_canvas_resize); + ecore_evas_title_set(ee, "Edje Multiseat Filter Example"); + + evas = ecore_evas_get(ee); + + edje_obj = edje_object_add(evas); + + if (!edje_object_file_set(edje_obj, EDJE_FILE, GROUPNAME)) + printf("failed to set file %s.\n", EDJE_FILE); + + evas_object_move(edje_obj, 0, 0); + evas_object_resize(edje_obj, WIDTH, HEIGHT); + evas_object_show(edje_obj); + ecore_evas_data_set(ee, "edje_obj", edje_obj); + + devices = evas_device_list(evas, NULL); + EINA_LIST_FOREACH(devices, l, dev) + { + if (efl_input_device_type_get(dev) == EFL_INPUT_DEVICE_CLASS_SEAT) + efl_canvas_object_seat_focus_add(edje_obj, dev); + + } + efl_event_callback_add(evas, EFL_CANVAS_EVENT_DEVICE_ADDED, + _device_added, edje_obj); + + ecore_evas_show(ee); + + ecore_main_loop_begin(); + + ecore_evas_free(ee); + ecore_evas_shutdown(); + edje_shutdown(); + + return EXIT_SUCCESS; + +shutdown_edje: + edje_shutdown(); +shutdown_ecore_evas: + ecore_evas_shutdown(); + + return EXIT_FAILURE; +} diff --git a/src/examples/edje/multiseat_filter.edc b/src/examples/edje/multiseat_filter.edc new file mode 100644 index 0000000000..5a89503e27 --- /dev/null +++ b/src/examples/edje/multiseat_filter.edc @@ -0,0 +1,811 @@ +collections { + + styles { + style { + name: "entry_style"; + base: "font="sans" font_size=10 color=#000 wrap="word" left_margin=2 right_margin=2"; + } + } + + group { + name: "example/main"; + min: 400 400; + + parts { + part { + name: "bg"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + } + } + + part { + name: "title"; + type: TEXT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + to: "bg"; + } + rel2 { + relative: 1.0 0.2; + offset: -1 -1; + to: "bg"; + } + text { + text: "Multiseat Filter Example"; + size: 16; + font: "sans"; + min: 1 1; + } + } + } + + // focus_bt is important to test if focus action are + // respecting allowed seats list + part { + name: "focus_bt"; + type: RECT; + mouse_events: 1; + description { + state: "default" 0.0; + rel1.relative: 0.3 0.2; + rel2.relative: 0.7 0.25; + color: 192 50 50 255; + } + description { + state: "over" 0.0; + inherit: "default" 0.0; + color: 142 30 30 255; + } + description { + state: "pressed" 0.0; + inherit: "default" 0.0; + color: 220 70 70 255; + } + } + + part { + name: "focus_bt,label"; + type: TEXT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 92 0 0 255; + rel1 { + relative: 0.5 0.5; + to: "focus_bt"; + } + rel2 { + relative: 0.5 0.5; + to: "focus_bt"; + } + text { + text: "Focus 'Seat 1 Only' Entry"; + size: 11; + font: "sans"; + min: 1 1; + } + } + } + + part { + name: "widget1"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + rel1.relative: 0.0 0.3; + rel2.relative: 0.5 0.65; + color: 255 255 0 255; + } + } + + part { + name: "widget2"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + rel1.relative: 0.0 0.65; + rel2.relative: 0.5 1.0; + color: 255 0 255 255; + } + } + + part { + name: "widget3"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + rel1.relative: 0.5 0.3; + rel2.relative: 1.0 0.65; + color: 0 255 255 255; + } + } + + part { + name: "widget4"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + rel1.relative: 0.5 0.65; + rel2.relative: 1.0 1.0; + color: 130 255 130 255; + } + } + + part { + name: "widget1,title"; + type: TEXT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.02; + offset: 0 0; + to: "widget1"; + } + rel2 { + relative: 1.0 0.1; + offset: -1 -1; + to: "widget1"; + } + text { + text: "Seat1 Only"; + size: 10; + font: "sans"; + min: 1 1; + } + } + } + + part { + name: "widget1,drag_area"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 20 20 20 255; + rel1 { + relative: 0.1 0.2; + offset: -5 0; + to: "widget1"; + } + rel2 { + relative: 0.1 0.8; + offset: 4 0; + to: "widget1"; + } + } + } + + part { + name: "widget,knob,1"; + type: RECT; + mouse_events: 1; + allowed_seats: "seat1"; + dragable { + confine: "widget1,drag_area"; + x: 0 0 0; + y: 1 1 0; + } + description { + state: "default" 0.0; + min: 10 30; + color: 120 120 120 255; + } + description { + state: "focused" 0.0; + inherit: "default" 0.0; + color: 200 200 200 255; + } + } + + part { + name: "widget,bg_text,1"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + min: 10 50; + rel1 { + to: "widget1"; + relative: 0.25 0.2; + } + rel2 { + to: "widget1"; + relative: 0.85 0.8; + } + color: 120 120 120 255; + } + description { + state: "focused" 0.0; + inherit: "default" 0.0; + color: 200 200 200 255; + } + } + + part { + name: "widget,text,1"; + type: TEXTBLOCK; + scale: 1; + entry_mode: EDITABLE; + select_mode: DEFAULT; + cursor_mode: UNDER; + mouse_events: 1; + allowed_seats: "seat1"; + multiline: 1; + source: "example/selection"; + source4: "example/cursor"; + description { + state: "default" 0.0; + min: 12 50; + rel1 { + to: "widget,bg_text,1"; + offset: 2 2; + } + rel2 { + to: "widget,bg_text,1"; + offset: -3 -3; + } + text { + style: "entry_style"; + min: 0 1; + align: 0.0 0.0; + } + } + } + + part { + name: "widget2,title"; + type: TEXT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.02; + offset: 0 0; + to: "widget2"; + } + rel2 { + relative: 1.0 0.1; + offset: -1 -1; + to: "widget2"; + } + text { + text: "Seat2 Only"; + size: 10; + font: "sans"; + min: 1 1; + } + } + } + + part { + name: "widget2,drag_area"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 20 20 20 255; + rel1 { + relative: 0.1 0.2; + offset: -5 0; + to: "widget2"; + } + rel2 { + relative: 0.1 0.8; + offset: 4 0; + to: "widget2"; + } + } + } + + part { + name: "widget,knob,2"; + type: RECT; + mouse_events: 1; + allowed_seats: "seat2"; + dragable { + confine: "widget2,drag_area"; + x: 0 0 0; + y: 1 1 0; + } + description { + state: "default" 0.0; + min: 10 30; + color: 120 120 120 255; + } + description { + state: "focused" 0.0; + inherit: "default" 0.0; + color: 200 200 200 255; + } + } + + part { + name: "widget,bg_text,2"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + min: 10 50; + rel1 { + to: "widget2"; + relative: 0.25 0.2; + } + rel2 { + to: "widget2"; + relative: 0.85 0.8; + } + color: 120 120 120 255; + } + description { + state: "focused" 0.0; + inherit: "default" 0.0; + color: 200 200 200 255; + } + } + + part { + name: "widget,text,2"; + type: TEXTBLOCK; + scale: 1; + entry_mode: EDITABLE; + select_mode: DEFAULT; + cursor_mode: UNDER; + mouse_events: 1; + allowed_seats: "seat2"; + multiline: 1; + source: "example/selection"; + source4: "example/cursor"; + description { + state: "default" 0.0; + min: 12 50; + rel1 { + to: "widget,bg_text,2"; + offset: 2 2; + } + rel2 { + to: "widget,bg_text,2"; + offset: -3 -3; + } + text { + style: "entry_style"; + min: 0 1; + align: 0.0 0.0; + } + } + } + + part { + name: "widget3,title"; + type: TEXT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.02; + offset: 0 0; + to: "widget3"; + } + rel2 { + relative: 1.0 0.1; + offset: -1 -1; + to: "widget3"; + } + text { + text: "Seat 1 + Seat2"; + size: 10; + font: "sans"; + min: 1 1; + } + } + } + + part { + name: "widget3,drag_area"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 20 20 20 255; + rel1 { + relative: 0.1 0.2; + offset: -5 0; + to: "widget3"; + } + rel2 { + relative: 0.1 0.8; + offset: 4 0; + to: "widget3"; + } + } + } + + part { + name: "widget,knob,3"; + type: RECT; + mouse_events: 1; + allowed_seats: "seat1" "seat2"; + dragable { + confine: "widget3,drag_area"; + x: 0 0 0; + y: 1 1 0; + } + description { + state: "default" 0.0; + min: 10 30; + color: 120 120 120 255; + } + description { + state: "focused" 0.0; + inherit: "default" 0.0; + color: 200 200 200 255; + } + } + + part { + name: "widget,bg_text,3"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + min: 10 50; + rel1 { + to: "widget3"; + relative: 0.25 0.2; + } + rel2 { + to: "widget3"; + relative: 0.85 0.8; + } + color: 120 120 120 255; + } + description { + state: "focused" 0.0; + inherit: "default" 0.0; + color: 200 200 200 255; + } + } + + part { + name: "widget,text,3"; + type: TEXTBLOCK; + scale: 1; + entry_mode: EDITABLE; + select_mode: DEFAULT; + cursor_mode: UNDER; + mouse_events: 1; + allowed_seats: "seat1" "seat2"; + multiline: 1; + source: "example/selection"; + source4: "example/cursor"; + description { + state: "default" 0.0; + min: 12 50; + rel1 { + to: "widget,bg_text,3"; + offset: 2 2; + } + rel2 { + to: "widget,bg_text,3"; + offset: -3 -3; + } + text { + style: "entry_style"; + min: 0 1; + align: 0.0 0.0; + } + } + } + + part { + name: "widget4,title"; + type: TEXT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.02; + offset: 0 0; + to: "widget4"; + } + rel2 { + relative: 1.0 0.1; + offset: -1 -1; + to: "widget4"; + } + text { + text: "Any seat"; + size: 10; + font: "sans"; + min: 1 1; + } + } + } + + part { + name: "widget4,drag_area"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 20 20 20 255; + rel1 { + relative: 0.1 0.2; + offset: -5 0; + to: "widget4"; + } + rel2 { + relative: 0.1 0.8; + offset: 4 0; + to: "widget4"; + } + } + } + + part { + name: "widget,knob,4"; + type: RECT; + mouse_events: 1; + dragable { + confine: "widget4,drag_area"; + x: 0 0 0; + y: 1 1 0; + } + description { + state: "default" 0.0; + min: 10 30; + color: 120 120 120 255; + } + description { + state: "focused" 0.0; + inherit: "default" 0.0; + color: 200 200 200 255; + } + } + + part { + name: "widget,bg_text,4"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + min: 10 50; + rel1 { + to: "widget4"; + relative: 0.25 0.2; + } + rel2 { + to: "widget4"; + relative: 0.85 0.8; + } + color: 120 120 120 255; + } + description { + state: "focused" 0.0; + inherit: "default" 0.0; + color: 200 200 200 255; + } + } + + part { + name: "widget,text,4"; + type: TEXTBLOCK; + scale: 1; + entry_mode: EDITABLE; + select_mode: DEFAULT; + cursor_mode: UNDER; + mouse_events: 1; + multiline: 1; + source: "example/selection"; + source4: "example/cursor"; + description { + state: "default" 0.0; + min: 12 50; + rel1 { + to: "widget,bg_text,4"; + offset: 2 2; + } + rel2 { + to: "widget,bg_text,4"; + offset: -3 -3; + } + text { + style: "entry_style"; + min: 0 1; + align: 0.0 0.0; + } + } + } + } + + programs { + program { + name: "clicked"; + signal: "mouse,clicked,1,*"; + source: "widget,text,*"; + script { + new partid; + partid = get_part_id(src); + set_focus(partid, sig[strlen("mouse,clicked,1,")]); + } + } + + program { + name: "focused"; + signal: "focus,part,in,*"; + source: "widget,text,*"; + script { + new buf[256]; + new partid; + + snprintf(buf, 128, "widget,bg_text,%s", + src[strlen("widget,text,")]); + partid = get_part_id(buf); + set_state(partid, "focused", 0.0); + } + } + + program { + name: "unfocused"; + signal: "focus,part,out,*"; + source: "widget,text,*"; + script { + new buf[256]; + new partid; + + snprintf(buf, 128, "widget,bg_text,%s", + src[strlen("widget,text,")]); + partid = get_part_id(buf); + set_state(partid, "default", 0.0); + } + } + + program { + name: "drag,start"; + signal: "drag,start,*"; + source: "widget,knob,*"; + script { + new partid; + partid = get_part_id(src); + set_state(partid, "focused", 0.0); + } + } + + program { + name: "drag,stop"; + signal: "drag,stop,*"; + source: "widget,knob,*"; + script { + new partid; + partid = get_part_id(src); + set_state(partid, "default", 0.0); + } + } + + program { + name: "focus_bt,in"; + signal: "mouse,in"; + source: "focus_bt"; + action: STATE_SET "over" 0.0; + target: "focus_bt"; + } + + program { + name: "focus_bt,out"; + signal: "mouse,out"; + source: "focus_bt"; + action: STATE_SET "default" 0.0; + target: "focus_bt"; + } + + program { + name: "focus_bt,down"; + signal: "mouse,down,1"; + source: "focus_bt"; + action: STATE_SET "pressed" 0.0; + target: "focus_bt"; + } + + program { + name: "focus_bt,up"; + signal: "mouse,up,1"; + source: "focus_bt"; + action: STATE_SET "default" 0.0; + target: "focus_bt"; + } + + program { + name: "focus_bt,clicked"; + signal: "mouse,clicked,1,*"; + source: "focus_bt"; + script { + set_focus(PART:"widget,text,1", + sig[strlen("mouse,clicked,1,")]); + } + } + } + } + + group { + name: "example/selection"; + + parts { + part { + name: "selection"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 180 180 180 255; + } + } + } + } + + group { + name: "example/cursor"; + min: 1 0; + + parts { + part { + name: "cursor"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + min: 2 12; + color: 0 0 0 255; + } + description { + state: "hidden" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + } + } + } + + programs { + program { + name: "cursor_hide"; + signal: "load"; + source: ""; + action: STATE_SET "hidden" 0.0; + target: "cursor"; + transition: SINUSOIDAL 0.2; + after: "cursor_hide_timer"; + } + program { + name: "cursor_hide_timer"; + in: 0.2 0.0; + after: "cursor_show"; + } + program { + name: "cursor_show"; + action: STATE_SET "default" 0.0; + target: "cursor"; + after: "cursor_show_timer"; + } + program { + name: "cursor_show_timer"; + in: 0.5 0.0; + after: "cursor_hide"; + } + } + } +}