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/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/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"; + } + } + } +} 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_embryo.c b/src/lib/edje/edje_embryo.c index bb46310ca8..c7c70f750e 100644 --- a/src/lib/edje/edje_embryo.c +++ b/src/lib/edje/edje_embryo.c @@ -193,8 +193,9 @@ * 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[]) * * part_swallow(part_id, group_name) * @@ -3771,6 +3772,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 +4564,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_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 f04be21a86..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 @@ -2491,9 +2500,11 @@ 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); +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 695f57ccd8..7ab1498814 100644 --- a/src/lib/edje/edje_program.c +++ b/src/lib/edje/edje_program.c @@ -641,6 +641,43 @@ _edje_seat_name_emit(Edje *ed, const char *name, const char *sig, const char *sr _edje_emit_full(ed, buf, src, NULL, NULL); } +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 ((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); + _edje_focused_part_set(ed, sname, rp); + if (rp) + _edje_seat_name_emit(ed, sname, "focus,part,in", rp->part->name); + } + +not_allowed: + eina_stringshare_del(sname); +} + void _edje_program_run(Edje *ed, Edje_Program *pr, Eina_Bool force, const char *ssig, const char *ssrc) { @@ -970,35 +1007,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 +1017,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;