From 290a43b377d5ded556ba56c70e15474f5e8197c7 Mon Sep 17 00:00:00 2001 From: Daniel Zaoui Date: Tue, 23 May 2017 01:47:20 +0300 Subject: [PATCH] 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. --- src/bin/clouseau_client.c | 229 ++++++++- src/bin/gui.c | 4 + src/bin/gui.h | 1 + src/lib/Clouseau.h | 4 +- src/lib/clouseau_debug.c | 55 ++- src/lib/extensions/evlog/main.c | 8 +- .../extensions/objects_introspection/gui.c | 4 - .../extensions/objects_introspection/gui.h | 1 - .../extensions/objects_introspection/main.c | 441 +++++------------- 9 files changed, 408 insertions(+), 339 deletions(-) diff --git a/src/bin/clouseau_client.c b/src/bin/clouseau_client.c index 62496b2..cdd965b 100644 --- a/src/bin/clouseau_client.c +++ b/src/bin/clouseau_client.c @@ -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; } diff --git a/src/bin/gui.c b/src/bin/gui.c index d7fdb25..0279a5a 100644 --- a/src/bin/gui.c +++ b/src/bin/gui.c @@ -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); diff --git a/src/bin/gui.h b/src/bin/gui.h index 25fd373..d7ff97d 100644 --- a/src/bin/gui.h +++ b/src/bin/gui.h @@ -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; diff --git a/src/lib/Clouseau.h b/src/lib/Clouseau.h index ec69d7c..71bd450 100644 --- a/src/lib/Clouseau.h +++ b/src/lib/Clouseau.h @@ -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 */ diff --git a/src/lib/clouseau_debug.c b/src/lib/clouseau_debug.c index d699855..c0be8c9 100644 --- a/src/lib/clouseau_debug.c +++ b/src/lib/clouseau_debug.c @@ -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); diff --git a/src/lib/extensions/evlog/main.c b/src/lib/extensions/evlog/main.c index 29339ba..8f05624 100644 --- a/src/lib/extensions/evlog/main.c +++ b/src/lib/extensions/evlog/main.c @@ -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) { diff --git a/src/lib/extensions/objects_introspection/gui.c b/src/lib/extensions/objects_introspection/gui.c index 8690c5d..5f83493 100644 --- a/src/lib/extensions/objects_introspection/gui.c +++ b/src/lib/extensions/objects_introspection/gui.c @@ -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); diff --git a/src/lib/extensions/objects_introspection/gui.h b/src/lib/extensions/objects_introspection/gui.h index 25c9fb5..72eca3f 100644 --- a/src/lib/extensions/objects_introspection/gui.h +++ b/src/lib/extensions/objects_introspection/gui.h @@ -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; diff --git a/src/lib/extensions/objects_introspection/main.c b/src/lib/extensions/objects_introspection/main.c index 005e381..2418863 100644 --- a/src/lib/extensions/objects_introspection/main.c +++ b/src/lib/extensions/objects_introspection/main.c @@ -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);