#include "Clouseau.h" #include #include #include #include #include #include #include #include "clouseau_private.h" static Eina_Bool _elm_is_init = EINA_FALSE; static const char *_my_app_name = NULL; static int _connect_to_daemon(void); /**************************************************************************/ /* This is an attempt to somehow replicate what's available in new versions * of clouseau. I.e the module interface. */ static int _clouseau_init_count = 0; static char *_module_my_app_name = NULL; EAPI Eina_Bool clouseau_app_connect(const char *appname) { _my_app_name = _module_my_app_name = strdup(appname); if(!_connect_to_daemon()) { printf("Failed to connect to server.\n"); return EINA_FALSE; } return EINA_TRUE; } EAPI int clouseau_init(void) { if (++_clouseau_init_count == 1) { eina_init(); ecore_init(); ecore_con_init(); clouseau_data_init(); } return _clouseau_init_count; } EAPI int clouseau_shutdown(void) { if (--_clouseau_init_count == 0) { clouseau_data_shutdown(); ecore_con_shutdown(); ecore_shutdown(); eina_shutdown(); free(_module_my_app_name); _my_app_name = _module_my_app_name = NULL; } else if (_clouseau_init_count < 0) { _clouseau_init_count = 0; printf("Tried to shutdown although not initiated.\n"); } return _clouseau_init_count; } /***************************** END OF EINA MODULE *************************/ static void libclouseau_item_add(Evas_Object *o, Clouseau_Tree_Item *parent) { Clouseau_Tree_Item *treeit; Eina_List *children; Evas_Object *child; treeit = calloc(1, sizeof(Clouseau_Tree_Item)); if (!treeit) return ; treeit->ptr = (uintptr_t) o; treeit->is_obj = EINA_TRUE; treeit->name = eina_stringshare_add(evas_object_type_get(o)); treeit->is_clipper = !!evas_object_clipees_get(o); treeit->is_visible = evas_object_visible_get(o); treeit->info = clouseau_object_information_get(treeit); parent->children = eina_list_append(parent->children, treeit); /* if (!evas_object_smart_data_get(o)) return ; */ /* Do this only for smart object */ children = evas_object_smart_members_get(o); EINA_LIST_FREE(children, child) libclouseau_item_add(child, treeit); } static void * _canvas_bmp_get(Ecore_Evas *ee, Evas_Coord *w_out, Evas_Coord *h_out) { Ecore_X_Image *img; Ecore_X_Window_Attributes att; unsigned char *src; unsigned int *dst; int bpl = 0, rows = 0, bpp = 0; Evas_Coord w, h; /* Check that this window still exists */ Eina_List *eeitr, *ees = ecore_evas_ecore_evas_list_get(); Ecore_Evas *eel; Eina_Bool found_evas = EINA_FALSE; EINA_LIST_FOREACH(ees, eeitr, eel) if (eel == ee) { found_evas = EINA_TRUE; break; } Ecore_X_Window xwin = (found_evas) ? (Ecore_X_Window) ecore_evas_window_get(ee) : 0; if (!xwin) { printf("Can't grab X window.\n"); *w_out = *h_out = 0; return NULL; } Evas *e = ecore_evas_get(ee); evas_output_size_get(e, &w, &h); memset(&att, 0, sizeof(Ecore_X_Window_Attributes)); ecore_x_window_attributes_get(xwin, &att); img = ecore_x_image_new(w, h, att.visual, att.depth); ecore_x_image_get(img, xwin, 0, 0, 0, 0, w, h); src = ecore_x_image_data_get(img, &bpl, &rows, &bpp); dst = malloc(w * h * sizeof(int)); /* Will be freed by the user */ if (!ecore_x_image_is_argb32_get(img)) { /* Fill dst buffer with image convert */ ecore_x_image_to_argb_convert(src, bpp, bpl, att.colormap, att.visual, 0, 0, w, h, dst, (w * sizeof(int)), 0, 0); } else { /* Fill dst buffer by copy */ memcpy(dst, src, (w * h * sizeof(int))); } /* dst now holds window bitmap */ ecore_x_image_free(img); *w_out = w; *h_out = h; return (void *) dst; } static Eina_List * _load_list(void) { Eina_List *tree = NULL; Eina_List *ees; Ecore_Evas *ee; ees = ecore_evas_ecore_evas_list_get(); EINA_LIST_FREE(ees, ee) { Eina_List *objs; Evas_Object *obj; Clouseau_Tree_Item *treeit; Evas *e; int w, h; e = ecore_evas_get(ee); evas_output_size_get(e, &w, &h); treeit = calloc(1, sizeof(Clouseau_Tree_Item)); if (!treeit) continue ; treeit->name = eina_stringshare_add(ecore_evas_title_get(ee)); treeit->ptr = (uintptr_t) ee; tree = eina_list_append(tree, treeit); objs = evas_objects_in_rectangle_get(e, SHRT_MIN, SHRT_MIN, USHRT_MAX, USHRT_MAX, EINA_TRUE, EINA_TRUE); EINA_LIST_FREE(objs, obj) libclouseau_item_add(obj, treeit); } return tree; /* User has to call clouseau_tree_free() */ } static Eina_Bool _add(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Ipc_Event_Server_Add *ev) { void *p; int size = 0; ecore_ipc_server_data_size_max_set(ev->server, -1); connect_st t = { getpid(), _my_app_name }; p = clouseau_data_packet_compose(CLOUSEAU_APP_CLIENT_CONNECT, &t, sizeof(t), &size, NULL, 0); if (p) { ecore_ipc_server_send(ev->server, 0,0,0,0,EINA_FALSE, p, size); ecore_ipc_server_flush(ev->server); free(p); } return ECORE_CALLBACK_RENEW; } static Eina_Bool _del(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Ipc_Event_Server_Del *ev) { if (!ev->server) { printf("Failed to establish connection to the server.\nExiting.\n"); ecore_main_loop_quit(); return ECORE_CALLBACK_RENEW; } printf("Lost server with ip %s!\n", ecore_ipc_server_ip_get(ev->server)); ecore_ipc_server_del(ev->server); ecore_main_loop_quit(); return ECORE_CALLBACK_RENEW; } static Eina_Bool _data(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Ipc_Event_Server_Data *ev) { Variant_st *v; v = clouseau_data_packet_info_get(ev->data, ev->size); switch (clouseau_data_packet_mapping_type_get(v->type)) { case CLOUSEAU_DATA_REQ: { /* data req includes ptr to GUI, to tell which client asking */ int size = 0; data_req_st *req = v->data; tree_data_st t; t.gui = req->gui; /* GUI client requesting data from daemon */ t.app = req->app; /* APP client sending data to daemon */ t.tree = _load_list(); if (t.tree) { /* Reply with tree data to data request */ void *p = clouseau_data_packet_compose(CLOUSEAU_TREE_DATA, &t, sizeof(t), &size, NULL, 0); if (p) { ecore_ipc_server_send(ev->server, 0,0,0,0, EINA_FALSE, p, size); ecore_ipc_server_flush(ev->server); free(p); } clouseau_data_tree_free(t.tree); } } break; case CLOUSEAU_HIGHLIGHT: { /* Highlight msg contains PTR of object to highlight */ highlight_st *ht = v->data; Evas_Object *obj = (Evas_Object *) (uintptr_t) ht->object; clouseau_data_object_highlight(obj, NULL, NULL); } break; case CLOUSEAU_BMP_REQ: { /* Bitmap req msg contains PTR of Ecore Evas */ bmp_req_st *req = v->data; Evas_Coord w, h; int size = 0; void *bmp = _canvas_bmp_get((Ecore_Evas *) (uintptr_t) req->object, &w, &h); bmp_info_st t = { req->gui, req->app, req->object , req->ctr, w, h, NULL,NULL, NULL, 1.0, NULL, NULL, NULL, NULL, NULL, NULL }; void *p = clouseau_data_packet_compose(CLOUSEAU_BMP_DATA, &t, sizeof(t), &size, bmp, (w * h * sizeof(int))); if (p) { ecore_ipc_server_send(ev->server, 0,0,0,0, EINA_FALSE, p, size); ecore_ipc_server_flush(ev->server); free(p); } if (bmp) free(bmp); } break; default: break; } clouseau_data_variant_free(v); return ECORE_CALLBACK_RENEW; } static int _connect_to_daemon(void) { Ecore_Ipc_Server *svr; const char *address = LOCALHOST; eina_init(); ecore_init(); ecore_ipc_init(); svr = ecore_ipc_server_connect(ECORE_IPC_REMOTE_SYSTEM, LOCALHOST, PORT, NULL); if (!svr) { printf("could not connect to the server: %s, port %d.\n", address, PORT); return EINA_FALSE; } ecore_ipc_server_data_size_max_set(svr, -1); /* set event handler for server connect */ ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, (Ecore_Event_Handler_Cb)_add, NULL); /* set event handler for server disconnect */ ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, (Ecore_Event_Handler_Cb)_del, NULL); /* set event handler for receiving server data */ ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, (Ecore_Event_Handler_Cb)_data, NULL); return EINA_TRUE; } /* Hook on the elm_init * We only do something here if we didn't already go into elm_init, * which probably means we are not using elm. */ EAPI int elm_init(int argc, char **argv) { int (*_elm_init)(int, char **) = dlsym(RTLD_NEXT, __func__); setenv("ELM_CLOUSEAU", "0", 1); if (!_elm_is_init) { _my_app_name = argv[0]; _elm_is_init = EINA_TRUE; } return _elm_init(argc, argv); } /* Hook on the main loop * We only do something here if we didn't already go into elm_init, * which probably means we are not using elm. */ EAPI void ecore_main_loop_begin(void) { void (*_ecore_main_loop_begin)(void) = dlsym(RTLD_NEXT, __func__); if (!_elm_is_init) { _my_app_name = "clouseau"; } clouseau_init(); if (!clouseau_app_connect(_my_app_name)) { printf("Failed to connect to server.\n"); return; } _ecore_main_loop_begin(); clouseau_shutdown(); return; } #define EINA_LOCK_DEBUG_BT_NUM 64 typedef void (*Eina_Lock_Bt_Func) (); EAPI Evas_Object * evas_object_new(Evas *e) { Eina_Lock_Bt_Func lock_bt[EINA_LOCK_DEBUG_BT_NUM]; int lock_bt_num; Evas_Object *(*_evas_object_new)(Evas *e) = dlsym(RTLD_NEXT, __func__); Eina_Strbuf *str; Evas_Object *r; char **strings; int i; r = _evas_object_new(e); if (!r) return NULL; lock_bt_num = backtrace((void **)lock_bt, EINA_LOCK_DEBUG_BT_NUM); strings = backtrace_symbols((void **)lock_bt, lock_bt_num); str = eina_strbuf_new(); for (i = 1; i < lock_bt_num; ++i) eina_strbuf_append_printf(str, "%s\n", strings[i]); evas_object_data_set(r, ".clouseau.bt", eina_stringshare_add(eina_strbuf_string_get(str))); free(strings); eina_strbuf_free(str); return r; } EAPI void evas_object_free(Evas_Object *obj, int clean_layer) { void (*_evas_object_free)(Evas_Object *obj, int clean_layer) = dlsym(RTLD_NEXT, __func__); const char *tmp; tmp = evas_object_data_get(obj, ".clouseau.bt"); eina_stringshare_del(tmp); _evas_object_free(obj, clean_layer); }