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);
+}

-- 


Reply via email to