Compare commits

...

3 Commits

Author SHA1 Message Date
Marcel Hollerbach 91a9f603ae Introduce focus graph checker 6 years ago
Marcel Hollerbach bbf9c0bf16 clouseau_client: do not compact items which are bigger than 10 items 6 years ago
Marcel Hollerbach ff09fd6dbc closeau: highlight objects in the detail view 6 years ago
  1. 81
      src/bin/clouseau_client.c
  2. 8
      src/modules/Makefile.am
  3. 384
      src/modules/client/focus_graph_checker.c

@ -2257,19 +2257,96 @@ _obj_info_can_list_be_compacted(Efl_Dbg_Info *root_eo)
eina_value_pget(&(root_eo->value), &list);
// We check that there is no list into this list. If such list exists,
// we can't compact the list.
int number = 0;
EINA_LIST_FOREACH(list.list, l, eo)
{
number ++;
if (eina_value_type_get(&(eo->value)) == EINA_VALUE_TYPE_LIST)
return EINA_FALSE;
//this is very unreadable
if (number > 10)
return EINA_FALSE;
}
return EINA_TRUE;
}
static Clouseau_Tree_Item*
_rec_find(Clouseau_Tree_Item *item, unsigned long long ptr)
{
Eina_List *n;
Clouseau_Tree_Item *it;
if (item->ptr == ptr) return item;
EINA_LIST_FOREACH(item->children, n, it)
{
Clouseau_Tree_Item *ret = _rec_find(it, ptr);
if (ret) return ret;
}
return NULL;
}
static void
_send_highlight_ptr(App_Data_St *app, unsigned long long ptr)
{
Clouseau_Tree_Item *item;
Eina_List *n;
if (!ptr) return;
EINA_LIST_FOREACH(app->td->tree, n, item)
{
Clouseau_Tree_Item *ret = _rec_find(item, ptr);
if (ret)
{
_send_highlight(app, ret);
return;
}
}
printf("Error, ptr %p cannot be found\n", (void*)ptr);
}
static void
_obj_info_gl_selected(void *data EINA_UNUSED, Evas_Object *pobj EINA_UNUSED,
void *event_info EINA_UNUSED)
void *event_info)
{
/* Currently do nothing */
Efl_Dbg_Info *info = elm_object_item_data_get(event_info);
/* if the user clicks on a property which is a pointer, try to highlight it*/
if (eina_value_type_get(&info->value) == EINA_VALUE_TYPE_UINT64)
{
uint64_t ptr;
eina_value_get(&info->value, &ptr);
_send_highlight_ptr(gui->sel_app, ptr);
}
/* if the user is clicking on a list of pointers its usefull to highlight them */
if (eina_value_type_get(&info->value) == EINA_VALUE_TYPE_LIST)
{
Eina_Value_List list;
Eina_List *n;
uint64_t ptr;
Efl_Dbg_Info *eo;
eina_value_pget(&info->value, &list);
EINA_LIST_FOREACH(list.list, n, eo)
{
if (eina_value_type_get(&(eo->value)) == EINA_VALUE_TYPE_UINT64)
{
uint64_t ptr;
eina_value_get(&eo->value, &ptr);
_send_highlight_ptr(gui->sel_app, ptr);
}
}
}
return;
}

@ -10,7 +10,7 @@ AM_CPPFLAGS = \
@EFL_CFLAGS@
client_modulesdir = $(libdir)/clouseau/modules/client
client_modules_LTLIBRARIES = canvas_checker.la
client_modules_LTLIBRARIES = canvas_checker.la focus_graph_checker.la
canvas_checker_la_SOURCES = client/canvas_checker.c
@ -18,3 +18,9 @@ canvas_checker_la_LDFLAGS = -module -avoid-version -rdynamic
canvas_checker_la_DEPENDENCIES = $(top_builddir)/config.h
canvas_checker_la_LIBADD = @EFL_LIBS@
focus_graph_checker_la_SOURCES = client/focus_graph_checker.c
focus_graph_checker_la_LDFLAGS = -module -avoid-version -rdynamic
focus_graph_checker_la_DEPENDENCIES = $(top_builddir)/config.h
focus_graph_checker_checker_la_LIBADD = @EFL_LIBS@

@ -0,0 +1,384 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <Eina.h>
#include <stdio.h>
#include <Clouseau.h>
static int _focus_checker_dom = -1;
//critical errors are errors which can make the checks produce wrong results
#define CRIT(...) EINA_LOG_DOM_CRIT(_focus_checker_dom, __VA_ARGS__)
//errors are reporting failures of the test
#define ERR(...) EINA_LOG_DOM_ERR(_focus_checker_dom, __VA_ARGS__)
#define WRN(...) EINA_LOG_DOM_WARN(_focus_checker_dom, __VA_ARGS__)
#define INF(...) EINA_LOG_DOM_INFO(_focus_checker_dom, __VA_ARGS__)
#define DBG(...) EINA_LOG_DOM_DBG(_focus_checker_dom, __VA_ARGS__)
EAPI const char *clouseau_module_name = "Focus Graph Checker";
typedef struct {
Eina_List *right;
Eina_List *left;
Eina_List *top;
Eina_List *down;
void *next;
void *prev;
void *manager;
void *redirect;
} Focus_Relations;
typedef struct _Focus_Manager Focus_Manager;
struct _Focus_Manager {
void *ptr;
void *first_child;
Eina_Hash *objects;
Eina_List *redirects;
struct {
Focus_Manager *parent;
int depth;
} manager_tree_check; //only valid in execution of _managers_link_check();
};
static Eina_Hash *managers = NULL;
static Focus_Manager*
_manager_get(void *manager)
{
Focus_Manager *m;
m = eina_hash_find(managers, &manager);
if (!m)
{
m = calloc(1, sizeof(Focus_Manager));
m->ptr = manager;
m->objects = eina_hash_pointer_new(NULL);
eina_hash_add(managers, &manager, m);
}
return m;
}
static void
_focus_manager_redirect_add(Focus_Manager *m, void *redirect)
{
m->redirects = eina_list_append(m->redirects, redirect);
}
static void
_pointer_free(void *data)
{
free(data);
}
static Eina_Bool
_init(void)
{
eina_init();
_focus_checker_dom = eina_log_domain_register("Focus Checker", EINA_COLOR_CYAN);
eina_log_domain_level_set("Focus Checker", EINA_LOG_LEVEL_INFO);
managers = eina_hash_pointer_new(_pointer_free);
return EINA_TRUE;
}
static void
_shutdown(void)
{
eina_log_domain_unregister(_focus_checker_dom);
eina_shutdown();
}
static Eina_List*
_list_ptr_get(Efl_Dbg_Info *info)
{
Eina_Value_List list;
Efl_Dbg_Info *data;
Eina_List *n, *result = NULL;
if (eina_value_type_get(&info->value) != EINA_VALUE_TYPE_LIST)
{
CRIT("Expected list type");
return NULL;
}
eina_value_pget(&info->value, &list);
EINA_LIST_FOREACH(list.list, n, data)
{
unsigned long long ptr;
eina_value_get(&data->value, &ptr);
result = eina_list_append(result, (void*)ptr);
}
return result;
}
static Focus_Relations*
_tree_it_convert(Clouseau_Tree_Item *it)
{
Focus_Relations *ret;
Efl_Dbg_Info *widget, *focus, *next, *prev,
*right, *left, *top, *down,
*manager, *redirect;
clouseau_tree_item_from_legacy_convert(it);
widget = clouseau_eo_info_find(it->new_eo_info , "Elm_Widget");
if (!widget)
{
return NULL;
}
focus = clouseau_eo_info_find(widget, "Focus");
if (!focus)
{
return NULL;
}
next = clouseau_eo_info_find(focus, "next");
prev = clouseau_eo_info_find(focus, "prev");
right = clouseau_eo_info_find(focus, "right");
left = clouseau_eo_info_find(focus, "left");
top = clouseau_eo_info_find(focus, "top");
down = clouseau_eo_info_find(focus, "down");
manager = clouseau_eo_info_find(focus, "manager");
redirect = clouseau_eo_info_find(focus, "redirect");
if (!next || !prev || !right || !left || !top || !down || !manager || !redirect)
{
CRIT("Widget %p did not present the full set of properties.", (void*)it->ptr);
return NULL;
}
ret = calloc(1, sizeof(Focus_Relations));
eina_value_get(&next->value, &ret->next);
eina_value_get(&prev->value, &ret->prev);
ret->right = _list_ptr_get(right);
ret->left = _list_ptr_get(left);
ret->top = _list_ptr_get(top);
ret->down = _list_ptr_get(down);
eina_value_get(&manager->value, &ret->manager);
eina_value_get(&redirect->value, &ret->redirect);
return ret;
}
static void
_add(Clouseau_Tree_Item *it)
{
Clouseau_Tree_Item *treeit;
Focus_Relations *rel;
Focus_Manager *m;
Eina_List *n;
rel = _tree_it_convert(it);
if (rel)
{
m = _manager_get(rel->manager);
if (!m->first_child)
m->first_child = (void*)it->ptr;
if (rel->redirect)
_focus_manager_redirect_add(m, rel->redirect);
eina_hash_add(m->objects, &it->ptr, rel);
}
EINA_LIST_FOREACH(it->children , n, treeit)
{
_add(treeit);
}
}
/*
* Check that all widgets are linked to each other
*
* This is working by duplicating the hash of objects,.
* Exploring a item means that all the right left top
* down next and prev directions are added into the set of "need explotation".
* At first one random element is added to the set of need exploration.
* Then remove each time a element from the set, if the element is still
* in the duplicated hash, the element is explored, if not the element is ignored.
*
* If the set is now empty and the hash has still elements there must be a set
* of not linked elements to the other elements.
*/
Eina_Bool
_duplicate(const Eina_Hash *hash, const void *key, void *data, void *fdata)
{
eina_hash_add(fdata, key, data);
return EINA_TRUE;
}
Eina_Bool
_count(const Eina_Hash *hash, const void *key, void *data, void *fdata)
{
(*((int*)fdata))++;
return EINA_TRUE;
}
static void
_manager_check(Focus_Manager *manager)
{
Eina_Hash *dup;
Eina_Iterator *itr;
void *ptr;
Eina_List *runner = NULL, *n, *n_next;
dup = eina_hash_pointer_new(NULL);
eina_hash_foreach(manager->objects, _duplicate, dup);
runner = eina_list_append(runner, manager->first_child);
do
{
void *ptr;
Focus_Relations *rel;
ptr = eina_list_data_get(runner);
runner = eina_list_remove(runner, ptr);
rel = eina_hash_find(manager->objects, &ptr);
if (!rel)
{
ERR("In manager %p %p is used in a reference, but not part of the manager", manager->ptr , ptr);
continue;
}
rel = eina_hash_find(dup, &ptr);
if (!rel)
{
continue;
}
eina_hash_del_by_key(dup, &ptr);
runner = eina_list_merge(runner, rel->left);
runner = eina_list_merge(runner, rel->right);
runner = eina_list_merge(runner, rel->top);
runner = eina_list_merge(runner, rel->down);
runner = eina_list_append(runner, rel->next);
runner = eina_list_append(runner, rel->prev);
} while(eina_list_count(runner) != 0);
//if we are done and sonething is left in the hash we have a not connected subset in the manager. BAD
int count;
eina_hash_foreach(dup, _count, &count);
if (count > 0)
{
ERR("Manager %p has a disconnected set of widgets", manager->ptr);
/* FIXME print all the children */
}
else
INF("Manager %p is checked and fine", manager->ptr);
}
/**
* Functions to check that the with redirect created objects are a tree
*
* This works by iterating 3 times throuw the elements, at first, we are setting the parent of each child object
* In the second stage we are searching for the element with no parent, which is the root.
* And we ensure that there is just one root.
* In the last stage we are calculating the depth of each manager, if in some element a other depth is laready
* calculated we know that there is at least one cycle.
*/
static Eina_Bool
_depth_calc(Focus_Manager *m, int depth)
{
Eina_List *n;
Focus_Manager *m2;
Eina_Bool suc = EINA_TRUE;
if (m->manager_tree_check.depth != 0)
{
ERR("Manager %p is part of a cycle in the tree!", m->ptr);
return EINA_FALSE;
}
m->manager_tree_check.depth = depth;
EINA_LIST_FOREACH(m->redirects, n, m2)
{
if (!_depth_calc(m2, depth + 1))
suc = EINA_FALSE;
}
return suc;
}
static void
_managers_link_check(void)
{
Focus_Manager *root = NULL, *m;
Eina_Hash *manager_cache;
Eina_Iterator *itr;
//check if this things contains cycles
manager_cache = eina_hash_pointer_new(NULL);
//First stage set parents;
itr = eina_hash_iterator_data_new(managers);
EINA_ITERATOR_FOREACH(itr, m)
{
Focus_Manager *m2;
Eina_List *n;
//now we are setting the children
EINA_LIST_FOREACH(m->redirects, n, m2)
{
m2->manager_tree_check.parent = m;
}
}
eina_iterator_free(itr);
//second stage, search for the root
itr = eina_hash_iterator_data_new(managers);
EINA_ITERATOR_FOREACH(itr, m)
{
if (!m->manager_tree_check.parent && !root)
root = m;
else if (!m->manager_tree_check.parent && root)
ERR("Error, there is already a root manager (%p), but %p does not have any parents", root->ptr, m->ptr);
}
eina_iterator_free(itr);
//thirds stage, check that this is really a tree
if (_depth_calc(root, 1))
INF("All managers are linked in the form of a tree");
}
EAPI void
clouseau_client_module_run(Eina_List *tree)
{
Clouseau_Tree_Item *treeit;
Eina_List *n;
Eina_Iterator *managers_itr;
Focus_Manager *manager;
//move everything into a pointer hash
EINA_LIST_FOREACH(tree, n, treeit)
_add(treeit);
//check that there are no islands in the graph of a manager
managers_itr = eina_hash_iterator_data_new(managers);
EINA_ITERATOR_FOREACH(managers_itr, manager)
{
_manager_check(manager);
}
//check that all managers are linked to at least one other manager
_managers_link_check();
}
EINA_MODULE_INIT(_init);
EINA_MODULE_SHUTDOWN(_shutdown);
Loading…
Cancel
Save