bu5hm4n pushed a commit to branch master. http://git.enlightenment.org/tools/clouseau.git/commit/?id=65d89b92c2795ce09435608de0d2404602c97a42
commit 65d89b92c2795ce09435608de0d2404602c97a42 Author: Marcel Hollerbach <marcel-hollerb...@t-online.de> Date: Sun Oct 29 14:33:13 2017 +0100 clouseau: introduce focus inspector This for now shows the nodes that are registered in a manager, in the hirarchy that is used. Redirects are displayed red, logicals gray and normals in a e-style blue. If something is part of the focus history its green. --- data/CMakeLists.txt | 9 +- data/focus_inspector.edc | 91 ++++++++++++++ data/images/focus_inspector_history.svg | 70 +++++++++++ data/images/focus_inspector_logical.svg | 70 +++++++++++ data/images/focus_inspector_redirect.svg | 70 +++++++++++ data/images/focus_inspector_regular.svg | 70 +++++++++++ src/lib/Clouseau_Debug.h | 14 +++ src/lib/clouseau_debug.c | 143 ++++++++++++++++++++++ src/lib/clouseau_focus_serialization.x | 38 ++++++ src/lib/extensions/CMakeLists.txt | 1 + src/lib/extensions/focus_inspector/CMakeLists.txt | 38 ++++++ src/lib/extensions/focus_inspector/gui.c | 118 ++++++++++++++++++ src/lib/extensions/focus_inspector/gui.h | 25 ++++ src/lib/extensions/focus_inspector/main.c | 119 ++++++++++++++++++ src/lib/extensions/focus_inspector/tree_view.c | 91 ++++++++++++++ 15 files changed, 966 insertions(+), 1 deletion(-) diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index be39b14..afb50a0 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -3,13 +3,20 @@ add_custom_command ( COMMAND edje_cc -id ${CMAKE_CURRENT_SOURCE_DIR}/images ${CMAKE_CURRENT_SOURCE_DIR}/evlog.edc clouseau_evlog.edj DEPENDS evlog.edc ) +add_custom_command ( + OUTPUT clouseau_focus_inspector.edj + COMMAND edje_cc -id ${CMAKE_CURRENT_SOURCE_DIR}/images ${CMAKE_CURRENT_SOURCE_DIR}/focus_inspector.edc clouseau_focus_inspector.edj + DEPENDS focus_inspector.edc +) add_custom_target ( clouseau_evlog_edj DEPENDS clouseau_evlog.edj evlog.edc ) +add_custom_target(focus_inspector_theme DEPENDS clouseau_focus_inspector.edj) + install ( - FILES ${CMAKE_CURRENT_BINARY_DIR}/clouseau_evlog.edj images/show-screenshot.png images/take-screenshot.png + FILES ${CMAKE_CURRENT_BINARY_DIR}/clouseau_focus_inspector.edj ${CMAKE_CURRENT_BINARY_DIR}/clouseau_evlog.edj images/show-screenshot.png images/take-screenshot.png DESTINATION share/${PROJECT_NAME_LOWER} ) diff --git a/data/focus_inspector.edc b/data/focus_inspector.edc new file mode 100644 index 0000000..c2ea227 --- /dev/null +++ b/data/focus_inspector.edc @@ -0,0 +1,91 @@ +collections { + images { + image: "focus_inspector_history.svg" COMP; + image: "focus_inspector_logical.svg" COMP; + image: "focus_inspector_regular.svg" COMP; + image: "focus_inspector_redirect.svg" COMP; + } + group { "focus_inspector/regular"; + parts { + image { "indicator"; + desc { "default"; + rel1.to: "widget_name"; + rel1.offset: -3px -3px; + rel2.to: "widget_name"; + rel2.offset: 3px 3px; + + image { + border: 1 1 1 1; + normal: "focus_inspector_regular.svg"; + } + } + } + text { "widget_name"; + desc { "default"; + text { + font: Sans; + text: "<widget-name>"; + size: 8; + min: 1 1; + max: 1 1; + } + } + } + + } + } + group { "focus_inspector/logical"; + inherit: "focus_inspector/regular"; + parts { + image { "indicator"; + desc { "default"; + rel1.to: "widget_name"; + rel1.offset: -3px -3px; + rel2.to: "widget_name"; + rel2.offset: 3px 3px; + + image { + border: 1 1 1 1; + normal: "focus_inspector_logical.svg"; + } + } + } + } + } + group { "focus_inspector/history"; + inherit: "focus_inspector/regular"; + parts { + image { "indicator"; + desc { "default"; + rel1.to: "widget_name"; + rel1.offset: -3px -3px; + rel2.to: "widget_name"; + rel2.offset: 3px 3px; + + image { + border: 1 1 1 1; + normal: "focus_inspector_history.svg"; + } + } + } + } + } + group { "focus_inspector/redirect"; + inherit: "focus_inspector/regular"; + parts { + image { "indicator"; + desc { "default"; + rel1.to: "widget_name"; + rel1.offset: -3px -3px; + rel2.to: "widget_name"; + rel2.offset: 3px 3px; + + image { + border: 1 1 1 1; + normal: "focus_inspector_redirect.svg"; + } + } + } + } + } +} diff --git a/data/images/focus_inspector_history.svg b/data/images/focus_inspector_history.svg new file mode 100644 index 0000000..e6aff24 --- /dev/null +++ b/data/images/focus_inspector_history.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="99.855179mm" + height="28.76149mm" + viewBox="0 0 99.855179 28.76149" + version="1.1" + id="svg8" + inkscape:version="0.92.2 5c3e80d, 2017-08-06" + sodipodi:docname="focus_inspector_history.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.98994949" + inkscape:cx="-3.7169149" + inkscape:cy="-166.01003" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1920" + inkscape:window-height="1057" + inkscape:window-x="1920" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Ebene 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-0.58634746,-0.38263321)"> + <rect + style="fill:#484e4d;fill-opacity:1;fill-rule:nonzero;stroke:#259700;stroke-width:1.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4504" + width="98.355179" + height="27.26149" + x="1.3363475" + y="1.1326332" + ry="8.5526237" + rx="0" /> + </g> +</svg> diff --git a/data/images/focus_inspector_logical.svg b/data/images/focus_inspector_logical.svg new file mode 100644 index 0000000..8caf99c --- /dev/null +++ b/data/images/focus_inspector_logical.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="99.855179mm" + height="28.76149mm" + viewBox="0 0 99.855179 28.76149" + version="1.1" + id="svg8" + inkscape:version="0.92.2 5c3e80d, 2017-08-06" + sodipodi:docname="focus_inspector_logical.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.98994949" + inkscape:cx="-3.7169149" + inkscape:cy="-166.01003" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1920" + inkscape:window-height="1057" + inkscape:window-x="1920" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Ebene 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-0.58634746,-0.38263321)"> + <rect + style="fill:#484e4d;fill-opacity:1;fill-rule:nonzero;stroke:#787878;stroke-width:1.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4504" + width="98.355179" + height="27.26149" + x="1.3363475" + y="1.1326332" + ry="8.5526237" + rx="0" /> + </g> +</svg> diff --git a/data/images/focus_inspector_redirect.svg b/data/images/focus_inspector_redirect.svg new file mode 100644 index 0000000..59f241e --- /dev/null +++ b/data/images/focus_inspector_redirect.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="99.855179mm" + height="28.76149mm" + viewBox="0 0 99.855179 28.76149" + version="1.1" + id="svg8" + inkscape:version="0.92.2 5c3e80d, 2017-08-06" + sodipodi:docname="focus_inspector_redirect.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.98994949" + inkscape:cx="-3.7169149" + inkscape:cy="-166.01003" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1920" + inkscape:window-height="1057" + inkscape:window-x="1920" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Ebene 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-0.58634746,-0.38263321)"> + <rect + style="fill:#484e4d;fill-opacity:1;fill-rule:nonzero;stroke:#c0392b;stroke-width:1.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4504" + width="98.355179" + height="27.26149" + x="1.3363475" + y="1.1326332" + ry="8.5526237" + rx="0" /> + </g> +</svg> diff --git a/data/images/focus_inspector_regular.svg b/data/images/focus_inspector_regular.svg new file mode 100644 index 0000000..acb489f --- /dev/null +++ b/data/images/focus_inspector_regular.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="99.855179mm" + height="28.76149mm" + viewBox="0 0 99.855179 28.76149" + version="1.1" + id="svg8" + inkscape:version="0.92.2 5c3e80d, 2017-08-06" + sodipodi:docname="focus_inspector_regular.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.98994949" + inkscape:cx="-3.7169149" + inkscape:cy="-166.01003" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1920" + inkscape:window-height="1057" + inkscape:window-x="1920" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Ebene 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-0.58634746,-0.38263321)"> + <rect + style="fill:#484e4d;fill-opacity:1;fill-rule:nonzero;stroke:#2288ee;stroke-width:1.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4504" + width="98.355179" + height="27.26149" + x="1.3363475" + y="1.1326332" + ry="8.5526237" + rx="0" /> + </g> +</svg> diff --git a/src/lib/Clouseau_Debug.h b/src/lib/Clouseau_Debug.h index a93de1e..3f3b863 100644 --- a/src/lib/Clouseau_Debug.h +++ b/src/lib/Clouseau_Debug.h @@ -31,6 +31,7 @@ #include <Eo.h> #include <Eolian.h> +#include <Elementary.h> typedef void (*Eo_Debug_Class_Extract_Cb)(void *data, uint64_t kl, char *kl_name); @@ -107,6 +108,19 @@ typedef struct int tm_hour; } Evas_Debug_Screenshot; +typedef struct { + Eo *redirect_manager; + Eo *focused; + const char *class_name; + Eina_List *relations; +} Clouseau_Focus_Manager_Data; + +typedef struct { + Efl_Ui_Focus_Relations relation; + const char *class_name; +} Clouseau_Focus_Relation; + + EAPI void *eo_debug_eoids_request_prepare(int *size, ...); EAPI void eo_debug_klids_extract(void *buffer, int size, Eo_Debug_Class_Extract_Cb cb, void *data); diff --git a/src/lib/clouseau_debug.c b/src/lib/clouseau_debug.c index 5fb5c4e..6c0ee3f 100644 --- a/src/lib/clouseau_debug.c +++ b/src/lib/clouseau_debug.c @@ -71,6 +71,11 @@ static int _eoids_get_op = EINA_DEBUG_OPCODE_INVALID; static int _obj_info_op = EINA_DEBUG_OPCODE_INVALID; static int _obj_highlight_op = EINA_DEBUG_OPCODE_INVALID; static int _win_screenshot_op = EINA_DEBUG_OPCODE_INVALID; +static int _focus_manager_list_op = EINA_DEBUG_OPCODE_INVALID; +static int _focus_manager_detail_op = EINA_DEBUG_OPCODE_INVALID; + +static Eet_Data_Descriptor *managers = NULL, *manager_details = NULL; +#include "clouseau_focus_serialization.x" enum { HIGHLIGHT_R = 255, @@ -915,6 +920,142 @@ _main_loop_win_screenshot_cb(Eina_Debug_Session *session, int srcid, void *buffe WRAPPER_TO_XFER_MAIN_LOOP(_win_screenshot_cb) +static Eina_Bool +_only_manager(const void *container, void *data, void *fdata) +{ + return efl_isa(data, EFL_UI_FOCUS_MANAGER_INTERFACE); +} + +static void +_main_loop_focus_manager_list_cb(Eina_Debug_Session *session, int srcid, void *buffer, int size) +{ + Eina_Iterator *obj_iterator, *manager_iterator; + Eina_Array *array; + Eo *obj; + + array = eina_array_new(10); + obj_iterator = eo_objects_iterator_new(); + manager_iterator = eina_iterator_filter_new(obj_iterator, _only_manager, NULL, NULL); + + EINA_ITERATOR_FOREACH(manager_iterator, obj) + { + eina_array_push(array, obj); + } + + eina_debug_session_send(session, srcid, _focus_manager_list_op, array->data, array->count * sizeof(void*)); +} + +WRAPPER_TO_XFER_MAIN_LOOP(_focus_manager_list_cb) + +EAPI Efl_Dbg_Info* +clouseau_eo_info_find(Efl_Dbg_Info *root, const char *name) +{ + Eina_Value_List eo_list; + Eina_List *n; + Efl_Dbg_Info *info; + + if (!root) return NULL; + + eina_value_pget(&(root->value), &eo_list); + + EINA_LIST_FOREACH(eo_list.list, n, info) + { + if (!strcmp(info->name, name)) + { + return info; + } + } + return NULL; +} + +static Eina_List* +_fetch_children(Efl_Ui_Focus_Manager *m) +{ + Efl_Dbg_Info *manager_data, *children_data, *root; + Eina_List *lst = NULL, *n; + Eina_Value_List result; + Efl_Dbg_Info *elem; + + root = EFL_DBG_INFO_LIST_APPEND(NULL, "Root"); + + efl_dbg_info_get(m, root); + + manager_data = clouseau_eo_info_find(root, "Efl.Ui.Focus.Manager"); + + EINA_SAFETY_ON_NULL_RETURN_VAL(manager_data, NULL); + + children_data = clouseau_eo_info_find(manager_data, "children"); + + EINA_SAFETY_ON_NULL_RETURN_VAL(children_data, NULL); + EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_get(&children_data->value) == EINA_VALUE_TYPE_LIST, NULL); + + eina_value_pget(&children_data->value, &result); + + EINA_LIST_FOREACH(result.list, n, elem) + { + void *ptr; + + EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_get(&elem->value) == EINA_VALUE_TYPE_UINT64, NULL); + eina_value_get(&elem->value, &ptr); + + lst = eina_list_append(lst, ptr); + } + + efl_dbg_info_free(root); + + return lst; +} + +static Eina_Bool +_main_loop_focus_manager_detail_cb(Eina_Debug_Session *session, int srcid, void *buffer, int size) +{ + Clouseau_Focus_Manager_Data *res; + uint64_t ptr64; + Eo *elem, *manager; + + if (!manager_details) _init_data_descriptors(); + + memcpy(&ptr64, buffer, sizeof(ptr64)); + manager = (Eo *)SWAP_64(ptr64); + if (!efl_isa(manager, EFL_UI_FOCUS_MANAGER_INTERFACE)) return EINA_TRUE; + + Eina_List *children = _fetch_children(manager); + + res = alloca(sizeof(Clouseau_Focus_Manager_Data)); + res->class_name = efl_class_name_get(manager); + res->relations = NULL; + res->focused = efl_ui_focus_manager_focus_get(manager); + res->redirect_manager = efl_ui_focus_manager_redirect_get(manager); + + EINA_LIST_FREE(children, elem) + { + Clouseau_Focus_Relation *crel = calloc(1, sizeof(Clouseau_Focus_Relation)); + Efl_Ui_Focus_Relations *rel; + + rel = efl_ui_focus_manager_fetch(manager, elem); + memcpy(&crel->relation, rel, sizeof(Efl_Ui_Focus_Relations)); + + crel->class_name = efl_class_name_get(elem); + + res->relations = eina_list_append(res->relations, crel); + + free(rel); + } + + int blob_size; + void *blob = eet_data_descriptor_encode(manager_details, res, &blob_size); + + Clouseau_Focus_Manager_Data *aaah = eet_data_descriptor_decode(manager_details, blob, blob_size); + + if (eina_list_count(aaah->relations) != eina_list_count(res->relations)) abort(); + + eina_debug_session_send(session, srcid, _focus_manager_detail_op, blob, blob_size); + + return EINA_TRUE; +} + +WRAPPER_TO_XFER_MAIN_LOOP(_focus_manager_detail_cb) + EINA_DEBUG_OPCODES_ARRAY_DEFINE(_debug_ops, {"Clouseau/Object_Introspection/snapshot_start", &_snapshot_start_op, &_snapshot_start_cb}, {"Clouseau/Object_Introspection/snapshot_done", &_snapshot_done_op, NULL}, @@ -923,6 +1064,8 @@ EINA_DEBUG_OPCODES_ARRAY_DEFINE(_debug_ops, {"Clouseau/Eolian/object/info_get", &_obj_info_op, &_obj_info_req_cb}, {"Clouseau/Evas/object/highlight", &_obj_highlight_op, &_obj_highlight_cb}, {"Clouseau/Evas/window/screenshot", &_win_screenshot_op, &_win_screenshot_cb}, + {"Clouseau/Elementary_Focus/list", &_focus_manager_list_op, &_focus_manager_list_cb}, + {"Clouseau/Elementary_Focus/detail", &_focus_manager_detail_op, &_focus_manager_detail_cb}, {NULL, NULL, NULL} ); diff --git a/src/lib/clouseau_focus_serialization.x b/src/lib/clouseau_focus_serialization.x new file mode 100644 index 0000000..6933035 --- /dev/null +++ b/src/lib/clouseau_focus_serialization.x @@ -0,0 +1,38 @@ + +static void +_init_data_descriptors(void) +{ + Eet_Data_Descriptor_Class klass; + Eet_Data_Descriptor *relations_eed; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&klass, Clouseau_Focus_Relation); + relations_eed = eet_data_descriptor_file_new(&klass); + #define BASIC(field, type) EET_DATA_DESCRIPTOR_ADD_BASIC(relations_eed, Clouseau_Focus_Relation, #field , field, type) + + BASIC(class_name, EET_T_STRING); + BASIC(relation.next, EET_T_UINT); + BASIC(relation.prev, EET_T_UINT); + BASIC(relation.logical, EET_T_CHAR); + BASIC(relation.parent, EET_T_UINT); + BASIC(relation.redirect, EET_T_UINT); + BASIC(relation.node, EET_T_UINT); + BASIC(relation.position_in_history, EET_T_INT); + + #undef BASIC + #define LIST(field, type) EET_DATA_DESCRIPTOR_ADD_LIST(relations_eed, Clouseau_Focus_Relation, #field , field, type) + + /*LIST(relation.right, EET_T_UINT); + LIST(relation.left, EET_T_UINT); + LIST(relation.top, EET_T_UINT); + LIST(relation.down, EET_T_UINT);*/ + + #undef LIST + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&klass, Clouseau_Focus_Manager_Data); + manager_details = eet_data_descriptor_file_new(&klass); + + EET_DATA_DESCRIPTOR_ADD_BASIC(manager_details, Clouseau_Focus_Manager_Data, "redirect_manager", redirect_manager, EET_T_UINT); + EET_DATA_DESCRIPTOR_ADD_BASIC(manager_details, Clouseau_Focus_Manager_Data, "focused", focused, EET_T_UINT); + EET_DATA_DESCRIPTOR_ADD_BASIC(manager_details, Clouseau_Focus_Manager_Data, "class_name", class_name, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_LIST(manager_details, Clouseau_Focus_Manager_Data, "relations", relations, relations_eed); +} diff --git a/src/lib/extensions/CMakeLists.txt b/src/lib/extensions/CMakeLists.txt index 6392e44..8e4cb22 100644 --- a/src/lib/extensions/CMakeLists.txt +++ b/src/lib/extensions/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(objects_introspection) add_subdirectory(evlog) +add_subdirectory(focus_inspector) if (${EFL_PROFILER_FOUND}) add_subdirectory(profiling_viewer) diff --git a/src/lib/extensions/focus_inspector/CMakeLists.txt b/src/lib/extensions/focus_inspector/CMakeLists.txt new file mode 100644 index 0000000..0a605cb --- /dev/null +++ b/src/lib/extensions/focus_inspector/CMakeLists.txt @@ -0,0 +1,38 @@ +set(CMAKE_BUILD_TYPE Debug) + +STRING(REGEX REPLACE "\n" "" EOLIAN_EO_DIR ${EOLIAN_EO_DIR}) +STRING(REGEX REPLACE " " "" EOLIAN_EO_DIR ${EOLIAN_EO_DIR}) +add_definitions(${CLI_COMMON_DEFINITIONS} -DEFL_EO_API_SUPPORT + -DEOLIAN_EO_DIR="${EOLIAN_EO_DIR}" -DFOCUS_EDJ="${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME_LOWER}/clouseau_focus_inspector.edj") + +add_definitions(-DEFL_EO_API_SUPPORT -DGUI_IMAGES_PATH="${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME_LOWER}") + +set(EOLIAN_INCLUDE_FLAG -I \"${EOLIAN_EO_DIR}/eo-1\" -I${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${ELEMENTARY_INCLUDE_DIRS} + ${EVAS_INCLUDE_DIRS} + ${EO_INCLUDE_DIRS} + ${EINA_INCLUDE_DIRS} + ${EET_INCLUDE_DIRS} + ${EOLIAN_INCLUDE_DIRS} + ) + +link_directories (${PC_LIBELEMENTARY_LIBRARY_DIRS}) + +add_library(focus_inspector SHARED main.c gui.c tree_view.c) + +target_link_libraries(focus_inspector + ${ELEMENTARY_LIBRARIES} + ${EVAS_LIBRARIES} + ${EO_LIBRARIES} + ${EINA_LIBRARIES} + ${EET_LIBRARIES} + ${EOLIAN_LIBRARIES} + clouseau_debug + ) + +add_dependencies(focus_inspector focus_inspector_theme) + +INSTALL(TARGETS focus_inspector LIBRARY DESTINATION lib) diff --git a/src/lib/extensions/focus_inspector/gui.c b/src/lib/extensions/focus_inspector/gui.c new file mode 100644 index 0000000..b5dd5e8 --- /dev/null +++ b/src/lib/extensions/focus_inspector/gui.c @@ -0,0 +1,118 @@ +#include <Elementary.h> +#include "../../Clouseau_Debug.h" +#include "gui.h" + +static Evas_Object *table, *managers, *redirect, *history, *scroller; +static Elm_Genlist_Item_Class *itc; + +static char* +_text_get(void *data, Elm_Genlist *list, const char *part) +{ + Efl_Ui_Focus_Manager *manager = data; + Eina_Strbuf *res = eina_strbuf_new(); + + eina_strbuf_append_printf(res, "%p", manager); + return eina_strbuf_release(res); +} + +EAPI Evas_Object* +ui_create(Instance *inst, Evas_Object *obj) +{ + Evas_Object *o; + + o = table = elm_table_add(obj); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(o); + + o = managers = elm_combobox_add(obj); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_object_part_text_set(o, "guide", "Manager to inspect"); + evas_object_show(o); + elm_table_pack(table, o, 0, 0, 1, 1); + itc = elm_genlist_item_class_new(); + itc->func.text_get = _text_get; + + o = elm_label_add(obj); + elm_object_text_set(o, "Redirect:"); + evas_object_show(o); + elm_table_pack(table, o, 1, 0, 1, 1); + + o = redirect = elm_label_add(obj); + evas_object_show(o); + elm_table_pack(table, o, 2, 0, 1, 1); + + o = history = elm_hoversel_add(obj); + elm_object_text_set(o, "History"); + evas_object_show(o); + elm_table_pack(table, o, 3, 0, 1, 1); + + o = scroller = elm_scroller_add(table); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(o); + elm_table_pack(table, o, 0, 1, 4, 1); + + return table; +} + +static void +_sel(void *data, Evas_Object *obj, void *event_info) +{ + com_defailt_manager(data, elm_object_item_data_get(event_info)); +} + +EAPI void +ui_managers_add(Instance *inst, Efl_Ui_Focus_Manager **manager, int size) +{ + elm_genlist_clear(managers); + + for (int i = 0; i < size; ++i) + { + elm_genlist_item_append(managers, itc, manager[i], NULL, 0, _sel, inst); + } +} + +static int +_sort(const void *a_raw, const void *b_raw) +{ + const Clouseau_Focus_Relation *a = a_raw; + const Clouseau_Focus_Relation *b = b_raw; + + int val_a, val_b; + + if (a) val_a = a->relation.position_in_history; + if (b) val_b = b->relation.position_in_history; + + return val_a - val_b; +} + +EAPI void +ui_manager_data_arrived(Instance *inst, Clouseau_Focus_Manager_Data *data) +{ + Clouseau_Focus_Relation *rel; + Evas_Object *box, *o; + Eina_List *n, *sorted = NULL; + + EINA_LIST_FREE(inst->realized.objects, o) + evas_object_del(o); + + inst->realized.data = data; + + elm_hoversel_clear(history); + + EINA_LIST_FOREACH(data->relations, n, rel) + { + if (rel->relation.position_in_history != -1) + sorted = eina_list_sorted_insert(sorted, _sort, rel); + } + + EINA_LIST_FOREACH(sorted, n, rel) + { + elm_hoversel_item_add(history, rel->class_name, NULL, 0, NULL, NULL); + } + + tree_view_update(inst, scroller); + +} diff --git a/src/lib/extensions/focus_inspector/gui.h b/src/lib/extensions/focus_inspector/gui.h new file mode 100644 index 0000000..683afe0 --- /dev/null +++ b/src/lib/extensions/focus_inspector/gui.h @@ -0,0 +1,25 @@ +#ifndef GUI_H +#define GUI_H + +#include "../../Clouseau.h" +#include "../../Clouseau_Debug.h" + +typedef struct { + Clouseau_Extension *ext; + struct { + Eina_List *objects; + Clouseau_Focus_Manager_Data *data; + } realized; +} Instance; + +#define PUSH_CLEANUP(inst, o) inst->realized.objects = eina_list_append(inst->realized.objects, o) + +EAPI void tree_view_update(Instance *inst, Evas_Object *scroller); + +EAPI void ui_managers_add(Instance *inst, Efl_Ui_Focus_Manager **manager, int size); +EAPI void ui_manager_data_arrived(Instance *inst, Clouseau_Focus_Manager_Data *data); +EAPI Evas_Object* ui_create(Instance *inst, Evas_Object *obj); + +EAPI void com_refresh_managers(Instance *inst); +EAPI void com_defailt_manager(Instance *inst, Efl_Ui_Focus_Manager *manager); +#endif diff --git a/src/lib/extensions/focus_inspector/main.c b/src/lib/extensions/focus_inspector/main.c new file mode 100644 index 0000000..e3244e4 --- /dev/null +++ b/src/lib/extensions/focus_inspector/main.c @@ -0,0 +1,119 @@ +#include <Eina.h> +#include <Elementary.h> +#include "../../Clouseau.h" +#include "../../Clouseau_Debug.h" +#include "gui.h" + +static Instance inst; + +static int _focus_manager_list_op = EINA_DEBUG_OPCODE_INVALID; +static int _focus_manager_detail_op = EINA_DEBUG_OPCODE_INVALID; + +static Eet_Data_Descriptor *managers = NULL, *manager_details = NULL; +#include "../../clouseau_focus_serialization.x" + +static Eina_Bool +_main_loop_focus_manager_list_cb(Eina_Debug_Session *session, int src, void *buffer, int size) +{ + int managers = size / sizeof(Efl_Ui_Focus_Manager*); + Efl_Ui_Focus_Manager *manager_arr[managers]; + Clouseau_Extension *ext = eina_debug_session_data_get(session); + + memcpy(manager_arr, buffer, size); + + ui_managers_add(ext->data, manager_arr, managers); + + return EINA_TRUE; +} + +WRAPPER_TO_XFER_MAIN_LOOP(_focus_manager_list_cb) + +static Eina_Bool +_main_loop_focus_manager_detail_cb(Eina_Debug_Session *session, int src, void *buffer, int size) +{ + Clouseau_Extension *ext = eina_debug_session_data_get(session); + Clouseau_Focus_Manager_Data *pd; + if (!manager_details) _init_data_descriptors(); + + pd = eet_data_descriptor_decode(manager_details, buffer, size); + + ui_manager_data_arrived(ext->data, pd); + return EINA_TRUE; +} + +WRAPPER_TO_XFER_MAIN_LOOP(_focus_manager_detail_cb) + +EINA_DEBUG_OPCODES_ARRAY_DEFINE(_ops, + {"Clouseau/Elementary_Focus/list", &_focus_manager_list_op, &_focus_manager_list_cb}, + {"Clouseau/Elementary_Focus/detail", &_focus_manager_detail_op, &_focus_manager_detail_cb}, + {NULL, NULL, NULL} +); + +static void +_session_changed(Clouseau_Extension *ext) +{ + int i = 0; + Instance *inst = ext->data; + Eina_Debug_Opcode *ops = _ops(); + + while (ops[i].opcode_name) + { + if (ops[i].opcode_id) *(ops[i].opcode_id) = EINA_DEBUG_OPCODE_INVALID; + i++; + } + if (ext->session) + { + eina_debug_session_data_set(ext->session, ext); + eina_debug_opcodes_register(ext->session, ops, NULL, ext); + } +} +static void +_app_changed(Clouseau_Extension *ext) +{ + com_refresh_managers(ext->data); +} + +EAPI void +com_refresh_managers(Instance *inst) +{ + int i = eina_debug_session_send(inst->ext->session, inst->ext->app_id, _focus_manager_list_op, NULL, 0); +} + +EAPI void +com_defailt_manager(Instance *inst, Efl_Ui_Focus_Manager *manager) +{ + void *tmp[1]; + tmp[0] = manager; + + int i = eina_debug_session_send(inst->ext->session, inst->ext->app_id, _focus_manager_detail_op, tmp, sizeof(void*)); +} + +EAPI const char * +extension_name_get() +{ + return "Focus Inspector"; +} + +EAPI Eina_Bool +extension_start(Clouseau_Extension *ext, Eo *parent) +{ + eina_init(); + + inst.ext = ext; + ext->data = &inst; + ext->ui_object = ui_create(ext->data, parent); + ext->session_changed_cb = _session_changed; + ext->app_changed_cb = _app_changed; + + return !!ext->ui_object; +} + +EAPI Eina_Bool +extension_stop(Clouseau_Extension *ext) +{ + efl_del(ext->ui_object); + + eina_shutdown(); + + return EINA_TRUE; +} diff --git a/src/lib/extensions/focus_inspector/tree_view.c b/src/lib/extensions/focus_inspector/tree_view.c new file mode 100644 index 0000000..94b652a --- /dev/null +++ b/src/lib/extensions/focus_inspector/tree_view.c @@ -0,0 +1,91 @@ +#include <Elementary.h> +#include "../../Clouseau_Debug.h" +#include "gui.h" + +static void +find(Instance *pd, void *parent, void (*found)(void *data, Instance *pd, Clouseau_Focus_Relation *relation), void *data) +{ + for (int i = 0; pd->realized.data->relations && i < eina_list_count(pd->realized.data->relations); ++i) + { + Clouseau_Focus_Relation *rel; + rel = eina_list_nth(pd->realized.data->relations, i); + if (rel->relation.parent == parent) + found(data, pd, rel); + } +} + +void +tree_level(void *data, Instance *inst, Clouseau_Focus_Relation *relation) +{ + Evas_Object *box, *childbox, *vis; + int maxw, maxh, minw, minh; + Eina_Strbuf *buf; + char group[PATH_MAX]; + + box = evas_object_box_add(evas_object_evas_get(data)); + evas_object_box_padding_set(box, 20, 20); + evas_object_show(box); + + PUSH_CLEANUP(inst, box); + + buf = eina_strbuf_new(); + eina_strbuf_append_printf(buf, "%p", relation->relation.node); + + vis = edje_object_add(evas_object_evas_get(data)); + evas_object_size_hint_weight_set(vis, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(vis, 0.0, EVAS_HINT_FILL); + + if (relation->relation.position_in_history != -1 ) + snprintf(group, sizeof(group), "focus_inspector/history"); + else if (relation->relation.redirect) + snprintf(group, sizeof(group), "focus_inspector/redirect"); + else if (relation->relation.logical) + snprintf(group, sizeof(group), "focus_inspector/logical"); + else + snprintf(group, sizeof(group), "focus_inspector/regular"); + + edje_object_file_set(vis, FOCUS_EDJ, group); + edje_object_part_text_set(vis, "widget_name", relation->class_name); + evas_object_show(vis); + evas_object_box_append(box, vis); + + edje_object_size_max_get(vis, &maxw, &maxh); + edje_object_size_min_get(vis, &minw, &minh); + if ((minw <= 0) && (minh <= 0)) + edje_object_size_min_calc(vis, &minw, &minh); + + evas_object_size_hint_max_set(vis, maxw, maxh); + evas_object_size_hint_min_set(vis, minw, minh); + + PUSH_CLEANUP(inst, vis); + + childbox = evas_object_box_add(evas_object_evas_get(data)); + evas_object_box_padding_set(childbox, 20, 20); + evas_object_box_layout_set(childbox, evas_object_box_layout_vertical, NULL, NULL); + evas_object_box_append(box, childbox); + evas_object_show(childbox); + + PUSH_CLEANUP(inst, childbox); + + find(inst, relation->relation.node, tree_level, childbox); + + evas_object_box_append(data, box); +} + +EAPI void +tree_view_update(Instance *inst, Evas_Object *scroller) +{ + Evas_Object *box; + + box = evas_object_box_add(evas_object_evas_get(scroller)); + evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_box_layout_set(box, evas_object_box_layout_vertical, NULL, NULL); + evas_object_show(box); + PUSH_CLEANUP(inst, box); + + if (inst->realized.data) + find(inst, NULL, tree_level, box); + + elm_object_content_set(scroller, box); +} --