Support storing snapshot of all the running extensions into one file

When the user wants to save the data (snapshot), Clouseau requests from
every running extension the data that is "exported".
All the data are then encapsulated into one single file.
The first idea was to use EET to store the extensions blobs as basic var
arrays. But it was taking so much time that is has been chosen that the
data itself is appended in the file after the EET blob. This one only
contains the app name/pid and the number of bytes of the blob, per
extension.
Additionnally, the objects introspection extension has been modified to
behave as the first Clouseau, i.e taking all the objects information in
one shot and using it during the interaction with the user.
The Save/Load button is now a part of the main toolbar.
This commit is contained in:
Daniel Zaoui 2017-05-23 01:47:20 +03:00
parent 2388fde7ed
commit 290a43b377
9 changed files with 408 additions and 339 deletions

View File

@ -24,6 +24,8 @@
#define _EET_ENTRY "config"
#define _SNAPSHOT_EET_ENTRY "Clouseau_Snapshot"
static int _cl_stat_reg_op = EINA_DEBUG_OPCODE_INVALID;
static Gui_Main_Win_Widgets *_main_widgets = NULL;
@ -74,6 +76,7 @@ struct _Extension_Config
const char *lib_path;
Eina_Module *module;
const char *name;
const char *nickname;
Ext_Start_Cb start_fn;
Ext_Stop_Cb stop_fn;
Eina_Bool ready : 1;
@ -84,13 +87,27 @@ typedef struct
Eina_List *extensions_cfgs;
} Config;
typedef struct
{
const char *nickname;
void *data;
int data_count;
int version;
} Extension_Snapshot;
typedef struct
{
const char *app_name;
int app_pid;
Eina_List *ext_snapshots; /* List of Extension_Snapshot */
} Snapshot;
static Connection_Type _conn_type = OFFLINE;
static Eina_Debug_Session *_session = NULL;
static Eina_List *_apps = NULL;
static App_Info *_selected_app = NULL;
static Eina_Stringshare *_offline_filename = NULL;
static Eet_Data_Descriptor *_profile_edd = NULL, *_config_edd = NULL;
static Eet_Data_Descriptor *_profile_edd = NULL, *_config_edd = NULL, *_snapshot_edd = NULL;
static Eina_List *_profiles = NULL;
static Config *_config = NULL;
static Eina_List *_extensions = NULL;
@ -209,6 +226,26 @@ _profile_remove(Profile *p)
free(p);
}
static void
_snapshot_eet_load()
{
Eet_Data_Descriptor *ext_edd;
if (_snapshot_edd) return;
Eet_Data_Descriptor_Class eddc;
EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Extension_Snapshot);
ext_edd = eet_data_descriptor_stream_new(&eddc);
EET_DATA_DESCRIPTOR_ADD_BASIC(ext_edd, Extension_Snapshot, "nickname", nickname, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(ext_edd, Extension_Snapshot, "data_count", data_count, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(ext_edd, Extension_Snapshot, "version", version, EET_T_INT);
EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Snapshot);
_snapshot_edd = eet_data_descriptor_stream_new(&eddc);
EET_DATA_DESCRIPTOR_ADD_BASIC(_snapshot_edd, Snapshot, "app_name", app_name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_snapshot_edd, Snapshot, "app_pid", app_pid, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_LIST(_snapshot_edd, Snapshot, "ext_snapshots", ext_snapshots, ext_edd);
}
static Eo *
_inwin_create(void)
{
@ -235,6 +272,18 @@ _ext_cfg_find_by_path(const char *path)
return NULL;
}
static Extension_Config *
_ext_cfg_find_by_nickname(const char *nick)
{
Extension_Config *cfg;
Eina_List *itr;
EINA_LIST_FOREACH(_config->extensions_cfgs, itr, cfg)
{
if (!strcmp(cfg->nickname, nick)) return cfg;
}
return NULL;
}
static void
_configs_load()
{
@ -304,6 +353,14 @@ _configs_load()
continue;
}
ext_cfg->name = name_fn();
const char *(*nickname_fn)(void) = eina_module_symbol_get(ext_cfg->module, "extension_nickname_get");
if (!nickname_fn)
{
printf("Can not find extension_nickname_get function for %s\n", ext_cfg->name);
ext_cfg->nickname = ext_cfg->lib_path;
continue;
}
ext_cfg->nickname = nickname_fn();
Ext_Start_Cb start_fn = eina_module_symbol_get(ext_cfg->module, "extension_start");
if (!start_fn)
{
@ -383,6 +440,7 @@ _app_populate()
ext->app_changed_cb(ext);
}
}
elm_object_item_disabled_set(_main_widgets->save_load_bt, !sel_app_id);
}
static void
@ -565,6 +623,7 @@ _connection_type_change(Connection_Type conn_type)
ext->app_id = 0;
}
eina_debug_session_terminate(_session);
_session = NULL;
_apps_free();
_cl_stat_reg_op = EINA_DEBUG_OPCODE_INVALID;
elm_object_item_text_set(_main_widgets->apps_selector, "Select App");
@ -597,6 +656,18 @@ _connection_type_change(Connection_Type conn_type)
elm_object_item_text_set(_main_widgets->conn_selector, _conn_strs[conn_type]);
_conn_type = conn_type;
_session_populate();
if (_session)
{
elm_object_item_text_set(_main_widgets->save_load_bt, "Save");
elm_toolbar_item_icon_set(_main_widgets->save_load_bt, "document-import");
elm_object_item_disabled_set(_main_widgets->save_load_bt, EINA_TRUE);
}
else
{
elm_object_item_text_set(_main_widgets->save_load_bt, "Load");
elm_toolbar_item_icon_set(_main_widgets->save_load_bt, "document-export");
elm_object_item_disabled_set(_main_widgets->save_load_bt, EINA_FALSE);
}
}
static void
@ -756,26 +827,29 @@ _file_get(const char *filename, char **buffer_out)
}
static void
_extension_offline_load(void *data, Evas_Object *obj,
_extension_file_import(void *data, Evas_Object *obj,
void *event_info EINA_UNUSED)
{
Extension_Config *cfg = data;
Clouseau_Extension *ext = _extension_instantiate(cfg);
char *buffer = NULL;
int size = _file_get(_offline_filename, &buffer);
if (size <= 0) return;
int size = 0;
const char *filename = efl_key_data_get(obj, "_filename");
while (obj && strcmp(efl_class_name_get(obj), "Elm.Inwin"))
obj = efl_parent_get(obj);
if (obj) efl_del(obj);
size = _file_get(filename, &buffer);
if (size <= 0) return;
_ui_freeze(ext, EINA_TRUE);
if (ext->import_data_cb) ext->import_data_cb(ext, buffer, size);
if (ext->import_data_cb) ext->import_data_cb(ext, buffer, size, -1);
_ui_freeze(ext, EINA_FALSE);
}
static void
_extensions_cfgs_inwin_create()
_extensions_cfgs_inwin_create(const char *filename)
{
Eina_List *itr;
Extension_Config *ext_cfg;
@ -798,10 +872,14 @@ _extensions_cfgs_inwin_create()
elm_list_mode_set(list, ELM_LIST_EXPAND);
evas_object_size_hint_weight_set(list, 1, 1);
evas_object_size_hint_align_set(list, -1, -1);
efl_key_data_set(list, "_filename", filename);
EINA_LIST_FOREACH(_config->extensions_cfgs, itr, ext_cfg)
{
if (ext_cfg->ready)
elm_list_item_append(list, ext_cfg->name, NULL, NULL, _extension_offline_load, ext_cfg);
{
elm_list_item_append(list, ext_cfg->name, NULL, NULL,
_extension_file_import, ext_cfg);
}
}
evas_object_show(list);
elm_box_pack_end(box, list);
@ -809,12 +887,136 @@ _extensions_cfgs_inwin_create()
elm_win_inwin_activate(inwin);
}
static void
_export_to_file(void *_data EINA_UNUSED, Evas_Object *fs EINA_UNUSED, void *ev)
{
const char *filename = ev;
_snapshot_eet_load();
FILE *fp = fopen(filename, "w");
if (fp)
{
Snapshot s;
Extension_Snapshot *e_s;
Clouseau_Extension *e;
Eina_List *itr;
char *eet_buf;
int eet_size = 0;
s.app_name = _selected_app->name;
s.app_pid = _selected_app->pid;
s.ext_snapshots = NULL;
EINA_LIST_FOREACH(_extensions, itr, e)
{
if (e->export_data_cb)
{
int data_count = 0;
int version = 1;
void *data = e->export_data_cb(e, &data_count, &version);
if (!data) continue;
e_s = alloca(sizeof(*e_s));
e_s->nickname = e->ext_cfg->nickname;
e_s->data = data;
e_s->data_count = data_count;
e_s->version = version;
s.ext_snapshots = eina_list_append(s.ext_snapshots, e_s);
}
}
eet_buf = eet_data_descriptor_encode(_snapshot_edd, &s, &eet_size);
fwrite(&eet_size, sizeof(int), 1, fp);
fwrite(eet_buf, 1, eet_size, fp);
EINA_LIST_FREE(s.ext_snapshots, e_s)
{
fwrite(e_s->data, 1, e_s->data_count, fp);
free(e_s->data);
}
fclose(fp);
}
}
static void
_file_import(void *_data EINA_UNUSED, Evas_Object *fs EINA_UNUSED, void *ev)
{
const char *filename = ev;
FILE *fp = fopen(filename, "r");
void *eet_buf;
Snapshot *s;
int eet_size;
if (!fp) return;
_snapshot_eet_load();
fread(&eet_size, sizeof(int), 1, fp);
eet_buf = malloc(eet_size);
fread(eet_buf, 1, eet_size, fp);
s = eet_data_descriptor_decode(_snapshot_edd, eet_buf, eet_size);
if (s)
{
Extension_Snapshot *e_s;
char name[100];
EINA_LIST_FREE(s->ext_snapshots, e_s)
{
void *data = malloc(e_s->data_count);
fread(data, 1, e_s->data_count, fp);
Extension_Config *e_cfg = _ext_cfg_find_by_nickname(e_s->nickname);
if (e_cfg)
{
Clouseau_Extension *e = _extension_instantiate(e_cfg);
if (e->import_data_cb)
e->import_data_cb(e, data, e_s->data_count, e_s->version);
}
free(data);
free(e_s);
}
snprintf(name, sizeof(name) - 1, "%s [%d]", s->app_name, s->app_pid);
elm_object_item_text_set(_main_widgets->apps_selector, name);
free(s);
}
else
_extensions_cfgs_inwin_create(eina_stringshare_add(filename));
if (fp) fclose(fp);
}
static void
_inwin_del(void *data, Evas_Object *obj EINA_UNUSED, void *ev EINA_UNUSED)
{
Eo *inwin = data;
efl_del(inwin);
}
static void
_fs_activate(Eina_Bool is_save)
{
Eo *inwin = _inwin_create();
Eo *fs = elm_fileselector_add(inwin);
elm_fileselector_is_save_set(fs, is_save);
elm_fileselector_path_set(fs, getenv("HOME"));
evas_object_size_hint_weight_set
(fs, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(fs, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_smart_callback_add(fs, "done", _inwin_del, inwin);
evas_object_smart_callback_add(fs, "done",
is_save?_export_to_file:_file_import, NULL);
evas_object_show(fs);
elm_win_inwin_content_set(inwin, fs);
elm_win_inwin_activate(inwin);
}
void
save_load_perform(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
if (_session) _fs_activate(EINA_TRUE);
else _fs_activate(EINA_FALSE);
}
EAPI_MAIN int
elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
{
Connection_Type conn_type = OFFLINE;
Eina_List *itr;
Extension_Config *ext_cfg;
Eina_Stringshare *offline_filename = NULL;
int i, long_index = 0, opt;
Eina_Bool help = EINA_FALSE;
@ -833,7 +1035,7 @@ elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
};
while ((opt = getopt_long(argc, argv,"hlr:f:", long_options, &long_index )) != -1)
{
if (conn_type != OFFLINE || _offline_filename)
if (conn_type != OFFLINE || offline_filename)
{
printf("You cannot use more than one option at a time\n");
help = EINA_TRUE;
@ -859,7 +1061,7 @@ elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
case 'f':
{
conn_type = OFFLINE;
_offline_filename = eina_stringshare_add(optarg);
offline_filename = eina_stringshare_add(optarg);
break;
}
case 'h': help = EINA_TRUE; break;
@ -906,14 +1108,11 @@ elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
_connection_type_change(conn_type);
if (conn_type == OFFLINE && _offline_filename)
{
_extensions_cfgs_inwin_create();
}
if (conn_type == OFFLINE && offline_filename)
_file_import(NULL, NULL, (void *)offline_filename);
elm_run();
_connection_type_change(OFFLINE);
eina_shutdown();
return 0;
}

View File

@ -18,6 +18,8 @@ extern void gui_new_profile_win_create_done(Gui_New_Profile_Win_Widgets *wdgs);
extern void
conn_menu_show(void *data, Evas_Object *obj, void *event_info);
extern void
save_load_perform(void *data, Evas_Object *obj, void *event_info);
static void
_pubs_free_cb(void *data, const Efl_Event *event EINA_UNUSED)
@ -70,6 +72,8 @@ gui_main_win_create(Eo *__main_parent)
pub_widgets->apps_selector_menu = elm_toolbar_item_menu_get(pub_widgets->apps_selector);
pub_widgets->save_load_bt = elm_toolbar_item_append(tb, "document-export", "Save", save_load_perform, NULL);
ext_selector = elm_toolbar_item_append(tb, "system-reboot", "Extensions", NULL, NULL);
elm_toolbar_item_menu_set(ext_selector, EINA_TRUE);

View File

@ -11,6 +11,7 @@ typedef struct
Eo *conn_selector_menu;
Eo *apps_selector;
Eo *apps_selector_menu;
Eo *save_load_bt;
Eo *ext_selector_menu;
Eo *freeze_pulse;
Eo *freeze_inwin;

View File

@ -35,7 +35,8 @@ typedef struct _Clouseau_Extension Clouseau_Extension;
typedef Eo *(*Ui_Get_Cb)(Clouseau_Extension *ext, Eo *parent);
typedef void (*Session_Changed_Cb)(Clouseau_Extension *ext);
typedef void (*App_Changed_Cb)(Clouseau_Extension *ext);
typedef void (*Import_Data_Cb)(Clouseau_Extension *ext, char *buffer, int size);
typedef void (*Import_Data_Cb)(Clouseau_Extension *ext, void *buffer, int size, int version);
typedef void *(*Export_Data_Cb)(Clouseau_Extension *ext, int *size, int *version);
typedef Eo *(*Inwin_Create_Cb)();
typedef void (*Ui_Freeze_Cb)(Clouseau_Extension *ext, Eina_Bool freeze);
@ -50,6 +51,7 @@ struct _Clouseau_Extension
Session_Changed_Cb session_changed_cb; /* Function called when the session changed */
App_Changed_Cb app_changed_cb; /* Function called when the app changed */
Import_Data_Cb import_data_cb; /* Function called when data has to be imported */
Export_Data_Cb export_data_cb; /* Function called when data has to be exported */
Inwin_Create_Cb inwin_create_cb; /* Function to call to create a Inwin */
Ui_Freeze_Cb ui_freeze_cb; /* Function to call to freeze/thaw the UI */
void *data; /* Data allocated and managed by the extension */

View File

@ -36,11 +36,45 @@ static int _eoids_get_op = EINA_DEBUG_OPCODE_INVALID;
static int _obj_info_op = EINA_DEBUG_OPCODE_INVALID;
static int _snapshot_objs_get_op = EINA_DEBUG_OPCODE_INVALID;
typedef struct
{
Eina_List *kls_strs;
uint64_t *kls;
int nb_kls;
} _KlIds_Walk_Data;
static Eina_Bool
_klids_walk_cb(void *_data, Efl_Class *kl)
{
_KlIds_Walk_Data *data = _data;
const char *kl_name = efl_class_name_get(kl), *kls_str;
Eina_List *itr;
EINA_LIST_FOREACH(data->kls_strs, itr, kls_str)
{
if (!strcmp(kl_name, kls_str))
{
int i;
for (i = 0; i < data->nb_kls; i++)
{
if (!data->kls[i])
{
data->kls[i] = (uint64_t)kl;
return EINA_TRUE;
}
}
}
}
return EINA_TRUE;
}
static Eina_Debug_Error
_snapshot_do_cb(Eina_Debug_Session *session, int srcid, void *buffer, int size)
{
static Eina_Bool (*foo)(Eo_Debug_Class_Iterator_Cb, void *) = NULL;
char *buf = alloca(sizeof(Eina_Debug_Packet_Header) + size);
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buf;
char *tmp;
hdr->size = sizeof(Eina_Debug_Packet_Header);
hdr->cid = srcid;
@ -48,8 +82,27 @@ _snapshot_do_cb(Eina_Debug_Session *session, int srcid, void *buffer, int size)
hdr->opcode = _klids_get_op;
eina_debug_dispatch(session, buf);
_KlIds_Walk_Data data;
data.kls_strs = NULL;
tmp = buffer;
while (size > 0)
{
data.kls_strs = eina_list_append(data.kls_strs, tmp);
size -= strlen(tmp) + 1;
tmp += strlen(tmp) + 1;
}
data.nb_kls = eina_list_count(data.kls_strs);
size = data.nb_kls * sizeof(uint64_t);
if (data.nb_kls)
{
data.kls = alloca(size);
memset(data.kls, 0, size);
if (!foo) foo = dlsym(RTLD_DEFAULT, "eo_debug_classes_iterate");
foo(_klids_walk_cb, &data);
}
hdr->size = sizeof(Eina_Debug_Packet_Header) + size;
if (size) memcpy(buf + sizeof(Eina_Debug_Packet_Header), buffer, size);
if (size) memcpy(buf + sizeof(Eina_Debug_Packet_Header), data.kls, size);
hdr->thread_id = 0xFFFFFFFF;
hdr->opcode = _snapshot_objs_get_op;
eina_debug_dispatch(session, buf);

View File

@ -1404,7 +1404,7 @@ _evlog_view_add(Inf *inf)
}
static void
_evlog_import(Clouseau_Extension *ext, char *buffer, int size)
_evlog_import(Clouseau_Extension *ext, void *buffer, int size, int version EINA_UNUSED)
{
Evlog *evlog = calloc(1, sizeof(Evlog));
Inf *inf = ext->data;
@ -1468,6 +1468,12 @@ extension_name_get()
return "Event log";
}
EAPI const char *
extension_nickname_get()
{
return "evlog";
}
EAPI Eina_Bool
extension_start(Clouseau_Extension *ext, Eo *parent)
{

View File

@ -33,8 +33,6 @@ screenshot_req_cb(void *data, const Efl_Event *event);
extern void
reload_perform(void *data, Evas_Object *obj, void *event_info);
extern void
save_load_perform(void *data, Evas_Object *obj, void *event_info);
extern void
take_screenshot_button_clicked(void *data, const Efl_Event *event);
extern void
show_screenshot_button_clicked(void *data, const Efl_Event *event);
@ -108,8 +106,6 @@ gui_win_create(Eo *__main_parent)
pub_widgets->highlight_ck = ck;
}
pub_widgets->save_load_bt = elm_toolbar_item_append(tb, "document-export", "Save", save_load_perform, NULL);
panes = efl_add(ELM_PANES_CLASS, box);
elm_obj_panes_content_right_size_set(panes, 0.600000);
evas_object_size_hint_weight_set(panes, 1.000000, 1.000000);

View File

@ -10,7 +10,6 @@ typedef struct
Eo *reload_button;
Eo *objs_type_radio;
Eo *highlight_ck;
Eo *save_load_bt;
Eo *object_infos_list;
Eo *objects_list;
} Gui_Win_Widgets;

View File

@ -40,17 +40,17 @@ typedef struct
typedef struct
{
Eina_Stringshare *out_file;
void *buffer;
int cur_len;
int max_len;
} Snapshot_Buffer;
Eina_List *screenshots;
char *buffer;
unsigned int max_len;
unsigned int cur_len;
int klids_op;
int eoids_op;
int obj_info_op;
typedef struct
{
Snapshot_Buffer klids_buf;
Snapshot_Buffer eoids_buf;
Snapshot_Buffer obj_infos_buf;
Snapshot_Buffer screenshots_buf;
} Snapshot;
typedef struct
@ -62,7 +62,7 @@ typedef struct
typedef struct
{
Gui_Win_Widgets *wdgs;
Snapshot *snapshot;
Snapshot snapshot;
Obj_Info *selected_obj;
Eina_Hash *classes_hash_by_id;
Eina_Hash *classes_hash_by_name;
@ -76,7 +76,6 @@ typedef struct
Eina_Bool clouseau_init_done;
} Instance;
static Eet_Data_Descriptor *_snapshot_edd = NULL;
static Eet_Data_Descriptor *_config_edd = NULL;
static Config *_config = NULL;
@ -185,6 +184,10 @@ _app_changed(Clouseau_Extension *ext)
{
static int app_id = -1;
Instance *inst = ext->data;
Snapshot *s = &(inst->snapshot);
elm_genlist_clear(inst->wdgs->objects_list);
elm_genlist_clear(inst->wdgs->object_infos_list);
if (inst->objs_list_tree)
{
_objs_tree_free(inst->objs_list_tree);
@ -194,58 +197,41 @@ _app_changed(Clouseau_Extension *ext)
eina_hash_free_buckets(inst->classes_hash_by_id);
eina_hash_free_buckets(inst->classes_hash_by_name);
elm_genlist_clear(inst->wdgs->objects_list);
elm_genlist_clear(inst->wdgs->object_infos_list);
eina_hash_free_buckets(inst->objs_hash);
s->klids_buf.cur_len = 0;
s->eoids_buf.cur_len = 0;
s->obj_infos_buf.cur_len = 0;
s->screenshots_buf.cur_len = 0;
if (app_id != ext->app_id)
{
inst->eo_init_done = EINA_FALSE;
inst->eolian_init_done = EINA_FALSE;
inst->evas_init_done = EINA_FALSE;
inst->clouseau_init_done = EINA_FALSE;
if (ext->app_id)
eina_debug_session_send(ext->session, ext->app_id, _module_init_op, "eo", 3);
}
else
{
if (ext->app_id)
eina_debug_session_send(ext->session, ext->app_id, _klids_get_op, NULL, 0);
}
if (ext->app_id)
eina_debug_session_send(ext->session, ext->app_id, _module_init_op, "eo", 3);
app_id = ext->app_id;
if (app_id)
{
elm_object_item_disabled_set(inst->wdgs->reload_button, EINA_FALSE);
elm_object_item_disabled_set(inst->wdgs->save_load_bt, EINA_FALSE);
}
}
static void
_snapshot_buffer_append(Clouseau_Extension *ext, void *buffer)
_snapshot_buffer_append(Snapshot_Buffer *sb, void *buffer)
{
Instance *inst = ext->data;
Snapshot *s = inst->snapshot;
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buffer;
unsigned int size = hdr->size;
if (s->max_len < s->cur_len + size)
int size = hdr->size;
if (sb->max_len < sb->cur_len + size)
{
/* Realloc with addition of 1MB+size */
s->max_len += size + 1000000;
s->buffer = realloc(s->buffer, s->max_len);
sb->max_len += size + 1000000;
sb->buffer = realloc(sb->buffer, sb->max_len);
}
memcpy(s->buffer + s->cur_len, buffer, size);
s->cur_len += size;
}
static Eina_Bool
_snapshot_is_candidate(void *buffer)
{
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buffer;
if (hdr->opcode == _eoids_get_op ||
hdr->opcode == _klids_get_op ||
hdr->opcode == _obj_info_op ||
hdr->opcode == _win_screenshot_op) return EINA_TRUE;
else return EINA_FALSE;
memcpy((char *)sb->buffer + sb->cur_len, buffer, size);
sb->cur_len += size;
}
Eina_Debug_Error
@ -254,15 +240,18 @@ _disp_cb(Eina_Debug_Session *session, void *buffer)
Clouseau_Extension *ext = eina_debug_session_data_get(session);
if (!ext) return EINA_DEBUG_OK;
Instance *inst = ext->data;
if (inst->snapshot && _snapshot_is_candidate(buffer))
if (inst)
{
_snapshot_buffer_append(ext, buffer);
Snapshot *s = &inst->snapshot;
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buffer;
Snapshot_Buffer *sb = NULL;
if (hdr->opcode == _eoids_get_op) sb = &(s->eoids_buf);
else if (hdr->opcode == _klids_get_op) sb = &(s->klids_buf);
else if (hdr->opcode == _obj_info_op) sb = &(s->obj_infos_buf);
else if (hdr->opcode == _win_screenshot_op) sb = &(s->screenshots_buf);
if (sb) _snapshot_buffer_append(sb, buffer);
}
else
{
return inst->old_disp_cb(session, buffer);
}
return EINA_DEBUG_OK;
return inst->old_disp_cb(session, buffer);
}
static void
@ -291,205 +280,48 @@ _session_changed(Clouseau_Extension *ext)
inst->old_disp_cb = eina_debug_session_dispatch_get(ext->session);
eina_debug_session_dispatch_override(ext->session, _disp_cb);
eina_debug_opcodes_register(ext->session, _ops, _post_register_handle, ext);
elm_object_item_text_set(inst->wdgs->save_load_bt, "Save");
elm_toolbar_item_icon_set(inst->wdgs->save_load_bt, "document-import");
elm_object_item_disabled_set(inst->wdgs->save_load_bt, EINA_TRUE);
}
else
{
elm_object_item_text_set(inst->wdgs->save_load_bt, "Load");
elm_toolbar_item_icon_set(inst->wdgs->save_load_bt, "document-export");
elm_object_item_disabled_set(inst->wdgs->save_load_bt, EINA_FALSE);
}
elm_object_item_disabled_set(inst->wdgs->reload_button, EINA_TRUE);
}
static void
_snapshot_eet_load()
{
if (_snapshot_edd) return;
Eet_Data_Descriptor_Class eddc;
Evas_Debug_Screenshot s;
EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Evas_Debug_Screenshot);
Eet_Data_Descriptor *evas_shot_edd = eet_data_descriptor_stream_new(&eddc);
#define SHOT_ADD_BASIC(member, eet_type)\
EET_DATA_DESCRIPTOR_ADD_BASIC\
(evas_shot_edd, Evas_Debug_Screenshot, # member, member, eet_type)
SHOT_ADD_BASIC(obj, EET_T_ULONG_LONG);
SHOT_ADD_BASIC(w, EET_T_INT);
SHOT_ADD_BASIC(h, EET_T_INT);
eet_data_descriptor_element_add(evas_shot_edd,
"img", EET_T_CHAR, EET_G_VAR_ARRAY,
(char *)(&(s.img)) - (char *)(&s),
(char *)(&(s.img_size)) - (char *)(&s),
NULL, NULL);
SHOT_ADD_BASIC(tm_sec, EET_T_INT);
SHOT_ADD_BASIC(tm_min, EET_T_INT);
SHOT_ADD_BASIC(tm_hour, EET_T_INT);
#undef SHOT_ADD_BASIC
EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Snapshot);
_snapshot_edd = eet_data_descriptor_stream_new(&eddc);
#define SNP_ADD_BASIC(member, eet_type)\
EET_DATA_DESCRIPTOR_ADD_BASIC\
(_snapshot_edd, Snapshot, # member, member, eet_type)
SNP_ADD_BASIC(cur_len, EET_T_INT);
SNP_ADD_BASIC(eoids_op, EET_T_INT);
SNP_ADD_BASIC(klids_op, EET_T_INT);
SNP_ADD_BASIC(obj_info_op, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_LIST(_snapshot_edd, Snapshot,
"screenshots", screenshots, evas_shot_edd);
#undef SNP_ADD_BASIC
}
static Eina_Bool
_snapshot_save(Clouseau_Extension *ext)
{
Instance *inst = ext->data;
Snapshot *s = inst->snapshot;
FILE *fp = fopen(s->out_file, "w");
void *out_buf = NULL;
int out_size = 0;
Eina_Bool ret = EINA_FALSE;
if (!fp)
{
printf("Can not open file: \"%s\".\n", s->out_file);
return EINA_FALSE;
}
if (!ext->app_id) goto end;
_snapshot_eet_load();
s->eoids_op = _eoids_get_op;
s->klids_op = _klids_get_op;
s->obj_info_op = _obj_info_op;
s->screenshots = inst->screenshots;
out_buf = eet_data_descriptor_encode(_snapshot_edd, s, &out_size);
fwrite(&out_size, sizeof(int), 1, fp);
fwrite(out_buf, 1, out_size, fp);
printf("Snapshot buffer size %d max %d\n", s->cur_len, s->max_len);
fwrite(s->buffer, 1, s->cur_len, fp);
ret = EINA_TRUE;
end:
fclose(fp);
return ret;
}
static Snapshot *
_snapshot_buffer_parse(char *buffer, int size)
{
Snapshot *s = NULL;
int eet_size = 0;
if (size < eet_size) return NULL;
memcpy(&eet_size, buffer, sizeof(int));
buffer += sizeof(int);
_snapshot_eet_load();
s = eet_data_descriptor_decode(_snapshot_edd, buffer, eet_size);
buffer += eet_size;
if (s->cur_len) s->buffer = buffer;
return s;
}
static void
_snapshot_load(Clouseau_Extension *ext, char *buffer, int size)
_snapshot_load(Clouseau_Extension *ext, void *buffer, int size, int version EINA_UNUSED)
{
Evas_Debug_Screenshot *shot;
unsigned int idx = 0;
char *buf = buffer;
int klids_op, eoids_op, obj_info_op, screenshot_op;
if (!ext) return;
Instance *inst = ext->data;
Snapshot *s = _snapshot_buffer_parse(buffer, size);
if (!s) return;
#define EXTRACT(_buf, pval, sz) \
{ \
memcpy(pval, _buf, sz); \
_buf += sz; \
}
EXTRACT(buf, &klids_op, sizeof(int));
EXTRACT(buf, &eoids_op, sizeof(int));
EXTRACT(buf, &obj_info_op, sizeof(int));
EXTRACT(buf, &screenshot_op, sizeof(int));
#undef EXTRACT
_session_changed(ext);
_eoids_get_op = s->eoids_op;
_klids_get_op = s->klids_op;
_obj_info_op = s->obj_info_op;
/* Prevent free of the buffer */
while (idx < s->cur_len)
while (size > 0)
{
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)(s->buffer + idx);
void *payload = (s->buffer + idx) + sizeof(*hdr);
size = hdr->size - sizeof(*hdr);
if (hdr->opcode == _eoids_get_op) _eoids_get((Eina_Debug_Session *)ext, -1, payload, size);
else if (hdr->opcode == _klids_get_op) _klids_get((Eina_Debug_Session *)ext, -1, payload, size);
else if (hdr->opcode == _obj_info_op) _obj_info_get((Eina_Debug_Session *)ext, -1, payload, size);
idx += hdr->size;
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buf;
void *payload = buf + sizeof(*hdr);
int psize = hdr->size - sizeof(*hdr);
if (hdr->opcode == eoids_op)
_eoids_get((Eina_Debug_Session *)ext, -1, payload, psize);
else if (hdr->opcode == klids_op)
_klids_get((Eina_Debug_Session *)ext, -1, payload, psize);
else if (hdr->opcode == obj_info_op)
_obj_info_get((Eina_Debug_Session *)ext, -1, payload, psize);
else if (hdr->opcode == screenshot_op)
_win_screenshot_get((Eina_Debug_Session *)ext, -1, payload, psize);
else return;
buf += hdr->size;
size -= hdr->size;
}
EINA_LIST_FREE(s->screenshots, shot)
{
Obj_Info *info = eina_hash_find(inst->objs_hash, &(shot->obj));
if (!info) continue;
info->screenshots = eina_list_append(info->screenshots, shot);
if (info->glitem) elm_genlist_item_update(info->glitem);
}
free(s);
free(buffer);
}
static int
_file_get(const char *filename, char **buffer_out)
{
char *file_data = NULL;
int file_size;
FILE *fp = fopen(filename, "r");
if (!fp)
{
printf("Can not open file: \"%s\".\n", filename);
return -1;
}
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
if (file_size <= 0)
{
fclose(fp);
if (file_size < 0) printf("Can not ftell file: \"%s\".\n", filename);
return -1;
}
rewind(fp);
file_data = (char *) calloc(1, file_size);
if (!file_data)
{
fclose(fp);
printf("Calloc failed\n");
return -1;
}
int res = fread(file_data, 1, file_size, fp);
if (!res)
{
free(file_data);
file_data = NULL;
if (!feof(fp)) printf("fread failed\n");
}
fclose(fp);
if (file_data && buffer_out) *buffer_out = file_data;
return file_size;
}
static void
_snapshot_load_from_fs(void *data, Evas_Object *fs EINA_UNUSED, void *ev)
{
char *buffer = NULL;
int size = _file_get(ev, &buffer);
if (size <= 0) return;
_snapshot_load(data, buffer, size);
}
static void
@ -761,8 +593,6 @@ _objs_sel_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event_info)
eina_debug_session_send_to_thread(ext->session, ext->app_id, info->thread_id,
_obj_highlight_op, &(info->obj), sizeof(uint64_t));
}
eina_debug_session_send_to_thread(ext->session, ext->app_id, info->thread_id,
_obj_info_op, &(info->obj), sizeof(uint64_t));
if (info->eolian_info) _obj_info_realize(ext, info->eolian_info);
}
@ -809,8 +639,18 @@ static Eina_Debug_Error
_win_screenshot_get(Eina_Debug_Session *session EINA_UNUSED, int src EINA_UNUSED,
void *buffer, int size)
{
Clouseau_Extension *ext = eina_debug_session_data_get(session);
Instance *inst = ext->data;
Clouseau_Extension *ext = NULL;
Instance *inst = NULL;
if (src == -1)
{
ext = (Clouseau_Extension *)session;
session = NULL;
}
else
{
ext = eina_debug_session_data_get(session);
}
inst = ext->data;
Evas_Debug_Screenshot *s = evas_debug_screenshot_decode(buffer, size);
if (!s) return EINA_DEBUG_ERROR;
Obj_Info *info = eina_hash_find(inst->objs_hash, &(s->obj));
@ -895,49 +735,43 @@ show_screenshot_button_clicked(void *data EINA_UNUSED, const Efl_Event *event)
}
}
static void *
_eoids_request_prepare(Clouseau_Extension *ext, int *size)
{
uint64_t obj_kl = 0, canvas_kl = 0;
Instance *inst = ext->data;
Class_Info *info = eina_hash_find(inst->classes_hash_by_name,
_config->wdgs_show_type == 0 ? "Efl.Canvas.Object" : "Elm.Widget");
if (info) obj_kl = info->id;
info = eina_hash_find(inst->classes_hash_by_name, "Efl.Canvas");
if (info) canvas_kl = info->id;
return eo_debug_eoids_request_prepare(size, obj_kl, canvas_kl, NULL);
}
static Eina_Debug_Error
_snapshot_done_cb(Eina_Debug_Session *session, int src EINA_UNUSED,
void *buffer EINA_UNUSED, int size EINA_UNUSED)
{
Clouseau_Extension *ext = eina_debug_session_data_get(session);
Instance *inst = ext->data;
Snapshot *s = inst->snapshot;
if (!s) return EINA_DEBUG_OK;
_snapshot_save(ext);
free(s->buffer);
free(s);
inst->snapshot = NULL;
ext->ui_freeze_cb(ext, EINA_FALSE);
return EINA_DEBUG_OK;
}
static void
_snapshot_do(void *data, Evas_Object *fs EINA_UNUSED, void *ev)
static void *
_snapshot_save(Clouseau_Extension *ext, int *size, int *version)
{
void *buf;
Clouseau_Extension *ext = data;
int size;
if (!ext || !ext->app_id) return;
Instance *inst = ext->data;
ext->ui_freeze_cb(ext, EINA_TRUE);
inst->snapshot = calloc(1, sizeof(Snapshot));
inst->snapshot->out_file = eina_stringshare_add(ev);
buf = _eoids_request_prepare(ext, &size);
eina_debug_session_send(ext->session, ext->app_id, _snapshot_do_op, buf, size);
free(buf);
Snapshot *s = &(inst->snapshot);
void *buffer = malloc(4 * sizeof(int) +
s->klids_buf.cur_len + s->eoids_buf.cur_len +
s->obj_infos_buf.cur_len + s->screenshots_buf.cur_len);
char *tmp = buffer;
#define STORE(_buf, pval, sz) \
{ \
memcpy(_buf, pval, sz); \
_buf += sz; \
}
STORE(tmp, &_klids_get_op, sizeof(int));
STORE(tmp, &_eoids_get_op, sizeof(int));
STORE(tmp, &_obj_info_op, sizeof(int));
STORE(tmp, &_win_screenshot_op, sizeof(int));
STORE(tmp, s->klids_buf.buffer, s->klids_buf.cur_len);
STORE(tmp, s->eoids_buf.buffer, s->eoids_buf.cur_len);
STORE(tmp, s->obj_infos_buf.buffer, s->obj_infos_buf.cur_len);
STORE(tmp, s->screenshots_buf.buffer, s->screenshots_buf.cur_len);
#undef STORE
*version = 1;
*size = tmp - (char *)buffer;
return buffer;
}
void
@ -1014,10 +848,12 @@ _objs_item_content_get(void *data, Evas_Object *obj, const char *part)
static Eina_Debug_Error
_module_initted_cb(Eina_Debug_Session *session, int src, void *buffer, int size)
{
const char *obj_kl_name = NULL, *canvas_kl_name = NULL;
Clouseau_Extension *ext = eina_debug_session_data_get(session);
if (size <= 0) return EINA_DEBUG_ERROR;
if (!ext) return EINA_DEBUG_OK;
Instance *inst = ext->data;
char *buf;
Eina_Bool ret = !!((char *)buffer)[size - 1];
if (!ret)
@ -1049,7 +885,15 @@ _module_initted_cb(Eina_Debug_Session *session, int src, void *buffer, int size)
eina_debug_session_send(session, src, _module_init_op, "clouseau", 9);
return EINA_DEBUG_OK;
}
eina_debug_session_send(session, src, _klids_get_op, NULL, 0);
ext->ui_freeze_cb(ext, EINA_TRUE);
obj_kl_name = _config->wdgs_show_type == 0 ? "Efl.Canvas.Object" : "Elm.Widget";
canvas_kl_name = "Efl.Canvas";
size = strlen(obj_kl_name) + 1 + strlen(canvas_kl_name) + 1;
buf = alloca(size);
memcpy(buf, obj_kl_name, strlen(obj_kl_name) + 1);
memcpy(buf + strlen(obj_kl_name) + 1, canvas_kl_name, strlen(canvas_kl_name) + 1);
eina_debug_session_send(session, src, _snapshot_do_op, buf, size);
return EINA_DEBUG_OK;
}
@ -1067,8 +911,6 @@ _klid_walk(void *data, uint64_t kl, char *name)
static Eina_Debug_Error
_klids_get(Eina_Debug_Session *session, int src, void *buffer, int size)
{
uint64_t obj_kl = 0, canvas_kl = 0;
void *buf;
Clouseau_Extension *ext = NULL;
Instance *inst = NULL;
if (src == -1)
@ -1082,14 +924,7 @@ _klids_get(Eina_Debug_Session *session, int src, void *buffer, int size)
}
inst = ext->data;
eo_debug_klids_extract(buffer, size, _klid_walk, inst);
Class_Info *info = eina_hash_find(inst->classes_hash_by_name,
_config->wdgs_show_type == 0 ? "Efl.Canvas.Object" : "Elm.Widget");
if (info) obj_kl = info->id;
info = eina_hash_find(inst->classes_hash_by_name, "Efl.Canvas");
if (info) canvas_kl = info->id;
buf = eo_debug_eoids_request_prepare(&size, obj_kl, canvas_kl, NULL);
eina_debug_session_send_to_thread(session, src, 0xFFFFFFFF, _eoids_get_op, buf, size);
free(buf);
return EINA_DEBUG_OK;
}
@ -1223,33 +1058,6 @@ jump_to_ptr_inwin_show(void *data EINA_UNUSED, Evas_Object *obj, void *event_inf
elm_win_inwin_activate(inwin);
}
static void
_inwin_del(void *data, Evas_Object *obj EINA_UNUSED, void *ev EINA_UNUSED)
{
Eo *inwin = data;
efl_del(inwin);
}
static void
_fs_activate(Clouseau_Extension *ext, Eina_Bool is_save)
{
Eo *inwin = ext->inwin_create_cb();
Eo *fs = elm_fileselector_add(inwin);
elm_fileselector_is_save_set(fs, is_save);
elm_fileselector_path_set(fs, getenv("HOME"));
evas_object_size_hint_weight_set
(fs, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(fs, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_smart_callback_add(fs, "done", _inwin_del, inwin);
evas_object_smart_callback_add(fs, "done",
is_save?_snapshot_do:_snapshot_load_from_fs, ext);
evas_object_show(fs);
elm_win_inwin_content_set(inwin, fs);
elm_win_inwin_activate(inwin);
}
void
reload_perform(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
@ -1262,14 +1070,6 @@ reload_perform(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_U
}
}
void
save_load_perform(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Clouseau_Extension *ext = _ext_get(obj);
if (ext->session) _fs_activate(ext, EINA_TRUE);
else _fs_activate(ext, EINA_FALSE);
}
static Eo *
_ui_get(Clouseau_Extension *ext, Eo *parent)
{
@ -1321,6 +1121,12 @@ extension_name_get()
return "Objects introspection";
}
EAPI const char *
extension_nickname_get()
{
return "objs_intro";
}
EAPI Eina_Bool
extension_start(Clouseau_Extension *ext, Eo *parent)
{
@ -1333,12 +1139,15 @@ extension_start(Clouseau_Extension *ext, Eo *parent)
ext->session_changed_cb = _session_changed;
ext->app_changed_cb = _app_changed;
ext->import_data_cb = _snapshot_load;
ext->export_data_cb = _snapshot_save;
inst->classes_hash_by_id = eina_hash_pointer_new(NULL);
inst->classes_hash_by_name = eina_hash_string_small_new(NULL);
inst->objs_hash = eina_hash_pointer_new(NULL);
memset(&(inst->snapshot), 0, sizeof(inst->snapshot));
eolian_directory_scan(EOLIAN_EO_DIR);
_config_load(ext);