Compare commits
3 Commits
master
...
devs/bu5hm
Author | SHA1 | Date |
---|---|---|
Marcel Hollerbach | 91a9f603ae | |
Marcel Hollerbach | bbf9c0bf16 | |
Marcel Hollerbach | ff09fd6dbc |
|
@ -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…
Reference in New Issue