From: Anastasia Lyupa Date: Thu, 2 Jul 2015 08:41:57 +0000 (+0300) Subject: [FEATURE] start ui viewer implementation X-Git-Tag: SRR_20160331 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F85%2F42785%2F79;p=platform%2Fcore%2Fsystem%2Fswap-manager.git [FEATURE] start ui viewer implementation current protocol version : v0.6 add ui viewer lib files, build it with da_manager, set up connection with da_manager, get ui hierarchy, get ui properties for an object, get ui rendering time Change-Id: I5dd5fd22126fdc9dfc0faa4ca50ea1275c28fcb1 Signed-off-by: Anastasia Lyupa --- diff --git a/daemon/Makefile b/daemon/Makefile index ba5ef98..5d61d14 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -26,7 +26,8 @@ INCLUDE := \ -I/usr/include/eina-1/eina \ -I/usr/include/efl-1 \ -I/usr/include/json-c \ - -I/usr/include/eo-1 + -I/usr/include/eo-1 \ + -I/usr/include/evas-1 # CALL_MNGR ifeq ($(CALL_MNGR),y) INCLUDE += -I/usr/include/call-manager/ @@ -110,7 +111,8 @@ SRC_C := \ malloc_debug.c \ target.c \ thread.c \ - wsi.c + wsi.c \ + ui_viewer.c SRC_CPP := \ cpp/features/feature.cpp \ diff --git a/daemon/da_msg_ids.h b/daemon/da_msg_ids.h index 4dfd74c..bd29d30 100644 --- a/daemon/da_msg_ids.h +++ b/daemon/da_msg_ids.h @@ -38,6 +38,9 @@ X(NMSG_GET_PROBE_MAP, 0x000A) \ X(NMSG_KEEP_ALIVE, 0x000F) \ X(NMSG_GET_SCREENSHOT, 0x0010) \ X(NMSG_GET_PROCESS_ADD_INFO, 0x0011) \ +X(NMSG_GET_UI_HIERARCHY, 0x0012) \ +X(NMSG_GET_UI_SCREENSHOT, 0x0013) \ +X(NMSG_GET_UI_HIERARCHY_CANCEL, 0x0014) \ X(NMSG_GET_REAL_PATH, 0x0020) #define DATA_MSG_ID_LIST \ @@ -52,4 +55,5 @@ X(NMSG_FUNCTION_ENTRY, 0x0008) /* N irregular swap instrumentation, Instrumente X(NMSG_FUNCTION_EXIT, 0x0009) /* N irregular swap instrumentation, Instrumented functions by AppInst and LibInst */ \ X(NMSG_CONTEXT_SWITCH_ENTRY, 0x0010) /* N irregular swap instrumentation for kernel */ \ X(NMSG_CONTEXT_SWITCH_EXIT, 0x0011) /* N irregular swap instrumentation for kernel */ \ +X(NMSG_UI_HIERARCHY, 0x0021) /* N irregular ui hierarchy */ diff --git a/daemon/da_protocol.c b/daemon/da_protocol.c index 43b51c0..8689481 100644 --- a/daemon/da_protocol.c +++ b/daemon/da_protocol.c @@ -142,6 +142,12 @@ static char *msgErrStr(enum ErrorCode err) return "wrong message data"; case ERR_CANNOT_START_PROFILING: return "cannot start profiling"; + case ERR_UI_OBJ_NOT_FOUND: + return "requested ui object is not found"; + case ERR_UI_OBJ_SCREENSHOT_FAILED: + return "taking ui screenshot failed because App is in background"; + case ERR_NOT_SUPPORTED: + return "request not supported by security reason"; case ERR_SERV_SOCK_CREATE: return "server socket creation failed (written in /tmp/da.port file)"; case ERR_SERV_SOCK_BIND: @@ -207,6 +213,7 @@ void feature_code_str(uint64_t feature0, uint64_t feature1, char *to, print_feature_0(FL_WEB_PROFILING); print_feature_0(FL_WEB_STARTUP_PROFILING); print_feature_0(FL_SYSTEM_FILE_ACTIVITY); + print_feature_0(FL_UI_VIEWER_PROFILING); goto exit; err_exit: @@ -1342,6 +1349,90 @@ exit: return -(error_code != ERR_NO); } +static int process_msg_get_ui_hierarchy(struct msg_buf_t *msg) +{ + struct msg_target_t sendlog; + enum ErrorCode err_code = ERR_UNKNOWN; + uint8_t rendering; + + // get rendering time option + if (!parse_int8(msg, &rendering)) { + LOGE("NMSG_GET_UI_HIERARCHY error: No rendering time option\n"); + err_code = ERR_WRONG_MESSAGE_DATA; + goto send_fail; + } + + // send ui hierarchy request to target process + sendlog.type = APP_MSG_GET_UI_HIERARCHY; + *(uint8_t *)sendlog.data = rendering; + sendlog.length = sizeof(uint8_t); + + if (target_send_msg_to_all(&sendlog) == 0) + err_code = ERR_NO; + + if (!is_feature_enabled(FL_UI_VIEWER_PROFILING) || + (target_cnt_get() == 0)) + err_code = ERR_UNKNOWN; +send_fail: + // in case of success we send ack after a message from ui viewer lib + if (err_code != ERR_NO) + sendACKToHost(NMSG_GET_UI_HIERARCHY, err_code, 0, 0); + + return -(err_code != ERR_NO); +} + +static int process_msg_get_ui_hierarchy_cancel(void) +{ + struct msg_target_t sendlog; + enum ErrorCode err_code = ERR_UNKNOWN; + + // send ui hierarchy request to target process + sendlog.type = APP_MSG_GET_UI_HIERARCHY_CANCEL; + + if (target_send_msg_to_all(&sendlog) == 0) + err_code = ERR_NO; + + if (!is_feature_enabled(FL_UI_VIEWER_PROFILING) || + (target_cnt_get() == 0)) + err_code = ERR_UNKNOWN; + + sendACKToHost(NMSG_GET_UI_HIERARCHY_CANCEL, err_code, 0, 0); + + return -(err_code != ERR_NO); +} + +static int process_msg_get_ui_screenshot(struct msg_buf_t *msg) +{ + struct msg_target_t sendlog; + enum ErrorCode err_code = ERR_UNKNOWN; + uint64_t obj_id; + + // get ui object address + if (!parse_int64(msg, &obj_id)) { + LOGE("NMSG_GET_UI_PROPERTIES error: No object id\n"); + err_code = ERR_WRONG_MESSAGE_DATA; + goto send_fail; + } + + // send ui object properties request to target process + sendlog.type = APP_MSG_GET_UI_SCREENSHOT; + *(uint64_t *)sendlog.data = obj_id; + sendlog.length = sizeof(uint64_t); + + if (target_send_msg_to_all(&sendlog) == 0) + err_code = ERR_NO; + + if (!is_feature_enabled(FL_UI_VIEWER_PROFILING) || + (target_cnt_get() == 0)) + err_code = ERR_UNKNOWN; + +send_fail: + // in case of success we send ack after a message from ui viewer lib + if (err_code != ERR_NO) + sendACKToHost(NMSG_GET_UI_SCREENSHOT, err_code, 0, 0); + + return -(err_code != ERR_NO); +} int host_message_handler(struct msg_t *msg) { @@ -1473,6 +1564,12 @@ int host_message_handler(struct msg_t *msg) return process_msg_get_process_add_info(&msg_control); case NMSG_GET_REAL_PATH: return process_msg_get_real_path(&msg_control); + case NMSG_GET_UI_HIERARCHY: + return process_msg_get_ui_hierarchy(&msg_control); + case NMSG_GET_UI_HIERARCHY_CANCEL: + return process_msg_get_ui_hierarchy_cancel(); + case NMSG_GET_UI_SCREENSHOT: + return process_msg_get_ui_screenshot(&msg_control); default: LOGE("unknown message %d <0x%08X>\n", msg->id, msg->id); error_code = ERR_WRONG_MESSAGE_TYPE; diff --git a/daemon/da_protocol.h b/daemon/da_protocol.h index fb927ee..15193d4 100644 --- a/daemon/da_protocol.h +++ b/daemon/da_protocol.h @@ -67,26 +67,29 @@ enum DataMessageT { #define MSG_MAX_NUM NMSG_SWAP_INST_REMOVE enum ErrorCode { - ERR_NO = 0, /* success */ - ERR_LOCKFILE_CREATE_FAILED = -101, /* lock file create failed */ - ERR_ALREADY_RUNNING = -102, /* already running */ - ERR_INITIALIZE_SYSTEM_INFO_FAILED = -103, /* initialize system info failed */ - ERR_HOST_SERVER_SOCKET_CREATE_FAILED = -104, /* host server socket create failed */ - ERR_TARGET_SERVER_SOCKET_CREATE_FAILED = -105, /* target server socket create failed */ - - ERR_SIGNAL_MASK_SETTING_FAILED = -106, /* TODO del (old parametr) */ - - ERR_WRONG_MESSAGE_FORMAT = -201, /* wrong message format */ - ERR_WRONG_MESSAGE_TYPE = -202, /* wrong message type */ - ERR_WRONG_MESSAGE_DATA = -203, /* wrong message data */ - ERR_CANNOT_START_PROFILING = -204, /* cannot start profiling */ - ERR_TO_LONG_MESSAGE = -205, /* message is too long to process */ - ERR_TARGET_NOT_FOUND = -206, /* some target in message not found like file or some else */ - ERR_NOT_SUPPORTED = -207, /* request not supported by security reason */ - ERR_SERV_SOCK_CREATE = -900, /* server socket creation failed (written in /tmp/da.port file) */ - ERR_SERV_SOCK_BIND = -901, /* server socket bind failed (written in /tmp/da.port file) */ - ERR_SERV_SOCK_LISTEN = -902, /* server socket listen failed (written in /tmp/da.port file) */ - ERR_UNKNOWN = -999 /* unknown error */ + ERR_NO = 0, /* success */ + ERR_LOCKFILE_CREATE_FAILED = -101, /* lock file create failed */ + ERR_ALREADY_RUNNING = -102, /* already running */ + ERR_INITIALIZE_SYSTEM_INFO_FAILED = -103, /* initialize system info failed */ + ERR_HOST_SERVER_SOCKET_CREATE_FAILED = -104, /* host server socket create failed */ + ERR_TARGET_SERVER_SOCKET_CREATE_FAILED = -105, /* target server socket create failed */ + ERR_UI_TARGET_SERVER_SOCKET_CREATE_FAILED = -107, /* ui target server socket create failed */ + + ERR_SIGNAL_MASK_SETTING_FAILED = -106, /* TODO del (old parametr) */ + + ERR_WRONG_MESSAGE_FORMAT = -201, /* wrong message format */ + ERR_WRONG_MESSAGE_TYPE = -202, /* wrong message type */ + ERR_WRONG_MESSAGE_DATA = -203, /* wrong message data */ + ERR_CANNOT_START_PROFILING = -204, /* cannot start profiling */ + ERR_TO_LONG_MESSAGE = -205, /* message is too long to process */ + ERR_TARGET_NOT_FOUND = -206, /* some target in message not found like file or some else */ + ERR_UI_OBJ_NOT_FOUND = -207, /* requested ui object is not found */ + ERR_UI_OBJ_SCREENSHOT_FAILED = -208, /* taking ui screenshot failed because App is in background */ + ERR_NOT_SUPPORTED = -800, /* request not supported by security reason */ + ERR_SERV_SOCK_CREATE = -900, /* server socket creation failed (written in /tmp/da.port file) */ + ERR_SERV_SOCK_BIND = -901, /* server socket bind failed (written in /tmp/da.port file) */ + ERR_SERV_SOCK_LISTEN = -902, /* server socket listen failed (written in /tmp/da.port file) */ + ERR_UNKNOWN = -999 /* unknown error */ }; #define FL_SYSTEM_ENERGY_OLD (1<<26) @@ -140,7 +143,9 @@ enum feature_code{ FL_SYSTEM_FILE_ACTIVITY = 0x1000000000000ULL, // 0x1 * 0x10^12 function entry/exit for probe type 04 (File syscall) - FL_RESERVED4 = 0xe000000000000ULL, // reserved 1110 + FL_UI_VIEWER_PROFILING = 0x2000000000000ULL, // 0x2 * 0x10^12 load ui viewer library + + FL_RESERVED4 = 0xc000000000000ULL, // reserved 1110 FL_ALL_FEATURES = 0x7FFFFFFFFFFFFULL & (~FL_RESERVED1) & diff --git a/daemon/daemon.c b/daemon/daemon.c index a54b155..1395129 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -62,6 +62,7 @@ #include "smack.h" #include "swap_debug.h" #include "wsi.h" +#include "ui_viewer.h" #define DA_WORK_DIR "/home/developer/sdk_tools/da/" #define DA_READELF_PATH "/home/developer/sdk_tools/da/readelf" @@ -231,6 +232,7 @@ static int kill_app_by_info(const struct app_info_t *app_info) static int exec_app(const struct app_info_t *app_info) { int res = 0; + const char ui_viewer_log[] = "/tmp/uilib.log"; if (app_info == NULL) { LOGE("Cannot exec app. app_info is NULL"); @@ -239,6 +241,19 @@ static int exec_app(const struct app_info_t *app_info) switch (app_info->app_type) { case APP_TYPE_TIZEN: + if (is_feature_enabled(FL_UI_VIEWER_PROFILING)) { + if (ui_viewer_set_smack_rules(app_info)) { + LOGE("Cannot set smack rules for ui viewer\n"); + res = -1; + } + if (ui_viewer_set_app_info(app_info)) { + LOGE("Cannot set app info for ui viewer\n"); + res = -1; + } + } + if (access(ui_viewer_log, F_OK) != -1) { + remove(ui_viewer_log); + } if (exec_app_tizen(app_info->app_id, app_info->exe_path)) { LOGE("Cannot exec tizen app %s\n", app_info->app_id); res = -1; @@ -334,6 +349,32 @@ static void terminate_error(char *errstr, int send_to_host) terminate_all(); } +void restart_all(void) +{ + struct app_list_t *app = NULL; + const struct app_info_t *app_info = NULL; + + LOGI("Restart all profiled apps\n"); + + terminate_all_target(); + target_stop_all(); + target_wait_all(); + terminate_profiling_apps(); + + // exec all + app_info = app_info_get_first(&app); + if (app_info == NULL) { + LOGE("No app info found\n"); + return; + } + while (app_info != NULL) { + if (exec_app(app_info)) { + LOGE("Cannot exec app\n"); + } + app_info = app_info_get_next(&app); + } +} + static Ecore_Fd_Handler *connect_timer_handler; static Eina_Bool connect_timer_cb(void *data, Ecore_Fd_Handler *fd_handler) @@ -728,7 +769,7 @@ static Eina_Bool target_event_cb(void *data, Ecore_Fd_Handler *fd_handler) * return plus value if non critical error occur * return minus value if critical error occur */ -static int targetServerHandler(void) +static int targetServerHandler(bool is_probe_sock) { int err; struct msg_target_t log; @@ -740,7 +781,11 @@ static int targetServerHandler(void) return 1; } - err = target_accept(target, manager.target_server_socket); + if (is_probe_sock) + err = target_accept(target, manager.target_server_socket); + else + err = target_accept(target, manager.ui_target_server_socket); + if (err == 0) { /* send config message to target process */ log.type = APP_MSG_CONFIG; @@ -1015,6 +1060,7 @@ static int hostServerHandler(void) static Ecore_Fd_Handler *host_connect_handler; static Ecore_Fd_Handler *target_connect_handler; +static Ecore_Fd_Handler *ui_target_connect_handler; static Eina_Bool host_connect_cb(void *data, Ecore_Fd_Handler *fd_handler) { @@ -1029,7 +1075,9 @@ static Eina_Bool host_connect_cb(void *data, Ecore_Fd_Handler *fd_handler) static Eina_Bool target_connect_cb(void *data, Ecore_Fd_Handler *fd_handler) { - if (targetServerHandler() < 0) { + bool is_probe_sock = *(bool*)data; + + if (targetServerHandler(is_probe_sock) < 0) { // critical error terminate_error("Internal DA framework error, " "Please re-run the profiling " @@ -1039,8 +1087,12 @@ static Eina_Bool target_connect_cb(void *data, Ecore_Fd_Handler *fd_handler) return ECORE_CALLBACK_RENEW; } +static bool is_probe_true = true; +static bool is_probe_false = false; + static bool initialize_events(void) { + host_connect_handler = ecore_main_fd_handler_add(manager.host_server_socket, ECORE_FD_READ, @@ -1056,13 +1108,22 @@ static bool initialize_events(void) ecore_main_fd_handler_add(manager.target_server_socket, ECORE_FD_READ, target_connect_cb, - NULL, - NULL, NULL); + &is_probe_true, NULL, NULL); if (!target_connect_handler) { LOGE("Target server socket add error\n"); return false; } + ui_target_connect_handler = + ecore_main_fd_handler_add(manager.ui_target_server_socket, + ECORE_FD_READ, + target_connect_cb, + &is_probe_false, NULL, NULL); + if (!ui_target_connect_handler) { + LOGE("UI target server socket add error\n"); + return false; + } + return true; } diff --git a/daemon/daemon.h b/daemon/daemon.h index 1ae55f4..dcc6d1a 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -121,6 +121,7 @@ typedef struct { int host_server_socket; int target_server_socket; + int ui_target_server_socket; int apps_to_run; unsigned int config_flag; int app_launch_timerfd; @@ -160,6 +161,7 @@ int reconfigure(struct conf_t conf, struct msg_t **msg_reply, struct msg_t **msg int is_feature_enabled(enum feature_code fcode); int sendACKCodeToHost(enum HostMessageType resp, int msgcode); void terminate_all(void); +void restart_all(void); #ifdef __cplusplus } diff --git a/daemon/main.c b/daemon/main.c index c8b6a2f..8d148f5 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -55,6 +55,7 @@ #define SINGLETON_LOCKFILE "/tmp/da_manager.lock" #define PORTFILE "/tmp/port.da" #define UDS_NAME "/tmp/da.socket" +#define UIS_NAME "/tmp/da_ui.socket" #define INIT_PORT 8001 #define LIMIT_PORT 8100 @@ -65,6 +66,7 @@ __da_manager manager = { .host_server_socket = -1, .target_server_socket = -1, + .ui_target_server_socket = -1, .apps_to_run = 0, .config_flag = 0, .app_launch_timerfd = -1, @@ -117,6 +119,8 @@ static void _close_server_socket(void) close(manager.host_server_socket); if(manager.target_server_socket != -1) close(manager.target_server_socket); + if(manager.ui_target_server_socket != -1) + close(manager.ui_target_server_socket); } static void _unlink_files(void) @@ -137,31 +141,31 @@ void unlink_portfile(void) // ============================================================================= // return 0 for normal case -static int makeTargetServerSocket() +static int makeTargetServerSocket(int *target_server_socket, const char *S_NAME) { struct sockaddr_un serverAddrUn; - if(manager.target_server_socket != -1) + if(*target_server_socket != -1) return -1; // should be never happend // remove existed unix domain socket file - unlink(UDS_NAME); + unlink(S_NAME); - manager.target_server_socket = socket(AF_UNIX, + *target_server_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (manager.target_server_socket < 0) + if (*target_server_socket < 0) { LOGE("Target server socket creation failed\n"); return -1; } - fd_setup_attributes(manager.target_server_socket); + fd_setup_attributes(*target_server_socket); memset(&serverAddrUn, '\0', sizeof(serverAddrUn)); serverAddrUn.sun_family = AF_UNIX; - snprintf(serverAddrUn.sun_path, sizeof(serverAddrUn.sun_path), "%s", UDS_NAME); + snprintf(serverAddrUn.sun_path, sizeof(serverAddrUn.sun_path), "%s", S_NAME); - if (-1 == bind(manager.target_server_socket, (struct sockaddr*) &serverAddrUn, + if (-1 == bind(*target_server_socket, (struct sockaddr*) &serverAddrUn, sizeof(serverAddrUn))) { LOGE("Target server socket binding failed\n"); @@ -174,13 +178,13 @@ static int makeTargetServerSocket() } - if (-1 == listen(manager.target_server_socket, 5)) + if (-1 == listen(*target_server_socket, 5)) { LOGE("Target server socket listening failed\n"); return -1; } - LOGI("Created TargetSock %d\n", manager.target_server_socket); + LOGI("Created TargetSock %d\n", *target_server_socket); return 0; } @@ -301,11 +305,16 @@ static int initializeManager(FILE *portfile) write_int(portfile, ERR_INITIALIZE_SYSTEM_INFO_FAILED); return -1; } - // make server socket - if (makeTargetServerSocket() != 0) { + // make server socket for probe library + if (makeTargetServerSocket(&(manager.target_server_socket), UDS_NAME) != 0) { write_int(portfile, ERR_TARGET_SERVER_SOCKET_CREATE_FAILED); return -1; } + // make server socket for ui viewer + if (makeTargetServerSocket(&(manager.ui_target_server_socket), UIS_NAME) != 0) { + write_int(portfile, ERR_UI_TARGET_SERVER_SOCKET_CREATE_FAILED); + return -1; + } if (!initialize_pthread_sigmask()) { write_int(portfile, ERR_SIGNAL_MASK_SETTING_FAILED); return -1; diff --git a/daemon/target.c b/daemon/target.c index c16ebdc..8791632 100644 --- a/daemon/target.c +++ b/daemon/target.c @@ -112,7 +112,6 @@ int target_recv_msg(struct target *t, struct msg_target_t *msg) return recv_msg_from_sock(t->socket, msg); } - int target_start(struct target *t, void *(*start_routine) (void *)) { return thread_start(t->thread, start_routine, (void *)t); @@ -316,7 +315,25 @@ void target_wait_all(void) LOGI("target destroy [%d] start\n", i); target_dtor(t); LOGI("target destroy [%d] done\n", i); + target_use[i] = 0; + } +} + +void target_stop_all(void) +{ + int i; + struct target *t; + + target_array_lock(); + for (i = 0; i < MAX_TARGET_COUNT; ++i) { + if (target_use[i] == 0) + continue; + t = target_get(i); + ecore_main_fd_handler_del(t->handler); + t->event_fd_released = 1; + target_cnt_sub_and_fetch(); } + target_array_unlock(); } uint64_t target_get_total_alloc(pid_t pid) diff --git a/daemon/target.h b/daemon/target.h index ac09db9..bd6cbea 100644 --- a/daemon/target.h +++ b/daemon/target.h @@ -30,6 +30,7 @@ #include "malloc_debug_disable.h" #include +#include #include #include @@ -69,7 +70,6 @@ int target_accept(struct target *t, int sockfd); int target_send_msg(struct target *t, struct msg_target_t *msg); int target_recv_msg(struct target *t, struct msg_target_t *msg); - int target_start(struct target *t, void *(*start_routine) (void *)); int target_wait(struct target *t); @@ -91,6 +91,7 @@ struct target *target_get(int i); int target_send_msg_to_all(struct msg_target_t *msg); int target_send_terminate_to_all(void); void target_wait_all(void); +void target_stop_all(void); uint64_t target_get_total_alloc(pid_t pid); diff --git a/daemon/threads.c b/daemon/threads.c index 4c9d835..14e8040 100644 --- a/daemon/threads.c +++ b/daemon/threads.c @@ -184,7 +184,7 @@ static void* recvThread(void* data) if (chsmack(file_name) == 0) { /* exctract probe message */ p += strnlen(file_name, PATH_MAX) + 1; - struct msg_data_t *msg_data = (struct msg_data_t *)(p); + struct msg_data_t *msg_data; /* check packed size */ if (log.length != strnlen(file_name, PATH_MAX) + 1 + @@ -201,6 +201,82 @@ static void* recvThread(void* data) continue; + } else if (log.type == APP_MSG_GET_UI_HIERARCHY) { + enum ErrorCode err_code = ERR_UNKNOWN; + + if (log.length == sizeof(uint32_t)) { + err_code = *(uint32_t*)log.data; + } + + sendACKToHost(NMSG_GET_UI_HIERARCHY, err_code, 0, 0); + + continue; + } else if (log.type == APP_MSG_GET_UI_HIERARCHY_DATA) { + char *file_name = log.data; + FILE * fp; + struct msg_data_t *msg_data; + const int len = log.length; + char *p = NULL; + + if (len == sizeof(uint32_t)) { + enum ErrorCode err_code = *(uint32_t*)log.data; + + LOGE("APP_MSG_GET_UI_HIERARCHY_DATA error <%d>\n", err_code); + // TODO: system error + if (err_code == ERR_UNKNOWN) { + restart_all(); + continue; + } + } + + + msg_data = malloc(MSG_DATA_HDR_LEN + len); + if (!msg_data) { + LOGE("Cannot alloc message: %d bytes\n", MSG_DATA_HDR_LEN + len); + return NULL; + } + fill_data_msg_head(msg_data, NMSG_UI_HIERARCHY, 0, len); + memcpy(msg_data->payload, log.data, log.length); + + if (access(file_name, F_OK) != -1) { + LOGI("APP_MSG_GET_UI_HIERARCHY_DATA> File: <%s>\n", + file_name); + + if (chsmack(file_name) != 0) { + LOGE("chsmack failed\n"); + } + } else { + LOGE("APP_MSG_GET_UI_HIERARCHY> File not found <%s>\n", + file_name); + } + + if (write_to_buf(msg_data) != 0) + LOGE("write to buf fail\n"); + + continue; + } else if (log.type == APP_MSG_GET_UI_SCREENSHOT) { + enum ErrorCode err_code = ERR_UNKNOWN; + char *payload = log.data; + int payload_size = log.length; + + LOGI("APP_MSG_GET_UI_SCREENSHOT> log length = %d\n", log.length); + + if (payload_size >= sizeof(uint32_t)) { + char *file_name; + + err_code = *(uint32_t*)payload; + payload += sizeof(uint32_t); + payload_size -= sizeof(uint32_t); + + file_name = payload; + if (chsmack(file_name) != 0) { + LOGE("chsmack failed\n"); + } + } + + sendACKToHost(NMSG_GET_UI_SCREENSHOT, err_code, payload, payload_size); + + continue; } #ifdef PRINT_TARGET_LOG else if (log.type == APP_MSG_LOG) { diff --git a/daemon/ui_viewer.c b/daemon/ui_viewer.c new file mode 100644 index 0000000..9f3d6f8 --- /dev/null +++ b/daemon/ui_viewer.c @@ -0,0 +1,86 @@ +/* + * DA manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Anastasia Lyupa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + + +#include +#include +#include +#include + +#include "ui_viewer.h" +#include "da_protocol.h" +#include "swap_debug.h" +#include "smack.h" + +int ui_viewer_set_smack_rules(const struct app_info_t *app_info) +{ + const char OBJECT[] = "swap"; + const char ACCESS_TYPE[] = "r"; + int ret = 0; + + ret = apply_smack_rules(app_info->app_id, OBJECT, ACCESS_TYPE); + + return ret; +} + +int ui_viewer_set_app_info(const struct app_info_t *app_info) +{ + const char APP_INFO_FILE[] = + "/sys/kernel/debug/swap/preload/ui_viewer_app_info"; + FILE *fp; + int ret = 0, c = 0; + uint64_t main_offset; + + if (app_info->setup_data.data == NULL) { + LOGE("Setup data path is not correct\n"); + ret = -EINVAL; + goto fail; + } + + main_offset = *(uint64_t*)app_info->setup_data.data; + + if (app_info->exe_path == NULL || !strlen(app_info->exe_path)) { + LOGE("Executable path is not correct\n"); + ret = -EINVAL; + goto fail; + } + + fp = fopen(APP_INFO_FILE, "w"); + if (fp != NULL) { + c = fprintf(fp, "0x%lx:%s\n", (unsigned long)main_offset, + app_info->exe_path); + if (c < 0) { + LOGE("Can't write to file: %s\n", APP_INFO_FILE); + ret = -EIO; + } + fclose(fp); + } else { + LOGE("Can't open file: %s\n", APP_INFO_FILE); + ret = -ENOENT; + } +fail: + return ret; +} diff --git a/daemon/ui_viewer.h b/daemon/ui_viewer.h new file mode 100644 index 0000000..65f4d5c --- /dev/null +++ b/daemon/ui_viewer.h @@ -0,0 +1,36 @@ +/* + * DA manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Anastasia Lyupa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + + +#ifndef UI_VIEWER_H_ +#define UI_VIEWER_H_ + +#include "da_inst.h" + +int ui_viewer_set_smack_rules(const struct app_info_t *app_info); +int ui_viewer_set_app_info(const struct app_info_t *app_info); + +#endif /* UI_VIEWER_H_ */ diff --git a/daemon/utils.c b/daemon/utils.c index bb9e841..93c3c60 100644 --- a/daemon/utils.c +++ b/daemon/utils.c @@ -149,6 +149,7 @@ int exec_app_tizen(const char *app_id, const char *exec_path) LOGI("launch app path is %s, executable path is %s\n" "launch app name (%s), app_id (%s)\n", LAUNCH_APP_PATH, exec_path, LAUNCH_APP_NAME, app_id); + pid = fork(); if (pid == -1) return -1; diff --git a/packaging/swap-manager.spec b/packaging/swap-manager.spec index 7221946..ff178f8 100644 --- a/packaging/swap-manager.spec +++ b/packaging/swap-manager.spec @@ -42,9 +42,13 @@ BuildRequires: launchpad-loader BuildRequires: launchpad %endif BuildRequires: app-core-efl +BuildRequires: evas-devel +BuildRequires: elementary-devel +BuildRequires: libXext-devel %if "%{TIZEN_PRODUCT_TV}" != "1" BuildRequires: app-core-debuginfo %endif + %if "%_project" != "Kirana_SWA_OPEN:Build" && "%_project" != "Kirana_SWA_OPEN:Daily" Requires: swap-modules %endif @@ -85,6 +89,9 @@ SWAP_BUILD_CMD+=" WSP_SUPPORT=y" SWAP_BUILD_CMD+=" make" eval ${SWAP_BUILD_CMD} +cd ../ui_viewer +$SWAP_BUILD_CONF make + %install rm -rf ${RPM_BUILD_ROOT} mkdir -p %{buildroot}/usr/share/license @@ -92,6 +99,9 @@ cp LICENSE %{buildroot}/usr/share/license/%{name} cd daemon %make_install +cd ../ui_viewer +%make_install + %post mkdir -p /opt/usr/etc touch /opt/usr/etc/resourced_proc_exclude.ini @@ -106,5 +116,6 @@ touch /opt/usr/etc/resourced_proc_exclude.ini /usr/bin/swap_init_preload.sh /usr/bin/swap_init_wsp.sh -%changelog +%{_prefix}/lib/da_ui_viewer.so +%changelog diff --git a/scripts/gen_preload_header.sh b/scripts/gen_preload_header.sh index 5616a17..b7fc3ce 100755 --- a/scripts/gen_preload_header.sh +++ b/scripts/gen_preload_header.sh @@ -3,6 +3,7 @@ preload_library_pattern="libdl[.-].*" preload_library_path="/lib/" preload_open_function="dlopen" handlers_lib="/usr/lib/da_probe_tizen.so" +ui_viewer_lib="/usr/lib/da_ui_viewer.so" linker_path="/lib/" linker_sym="_r_debug" test_bin="/usr/bin/WebProcess" @@ -37,6 +38,12 @@ function print_probe_lib() echo -e "/bin/echo \"$handlers_lib\" > /sys/kernel/debug/swap/preload/handlers_path" >> $filename } +function print_ui_viewer_lib() +{ + filename=$1 + echo -e "/bin/echo \"$ui_viewer_lib\" > /sys/kernel/debug/swap/preload/ui_viewer_path" >> $filename +} + function print_linker() { filename=$1 @@ -95,6 +102,7 @@ function print_ignored() print_header $output print_loader $output print_probe_lib $output +print_ui_viewer_lib $output print_linker $output print_ignored $output diff --git a/ui_viewer/Makefile b/ui_viewer/Makefile new file mode 100644 index 0000000..36769e8 --- /dev/null +++ b/ui_viewer/Makefile @@ -0,0 +1,109 @@ +CC := gcc + +COMM_FLAGS := -Wall -g -O0 + +DEBUG_FLAGS = \ + -DDEBUG \ + -DUSE_LOG_ONCE \ +# -DMALLOC_DEBUG_LEVEL=1 \ +# -DMALLOC_DEBUG_LEVEL=2 \ +# -DDEB_PRINTBUF \ +# -DPARSE_DEBUG_ON \ +# -DTHREAD_SAMPLING_DEBUG \ +# -DTHREAD_REPLAY_DEBUG \ +# -DNOLOGI=1 + +INCLUDE := \ + -I/usr/include \ + -I/usr/include/elementary-1 \ + -I/usr/include/efl-1 \ + -I/usr/include/eina-1 \ + -I/usr/include/eina-1/eina \ + -I/usr/include/eet-1 \ + -I/usr/include/evas-1 \ + -I/usr/include/eo-1 \ + -I/usr/include/ecore-1 \ + -I/usr/include/ecore-evas-1 \ + -I/usr/include/ecore-file-1 \ + -I/usr/include/ecore-input-1 \ + -I/usr/include/ecore-imf-1 \ + -I/usr/include/ecore-con-1 \ + -I/usr/include/edje-1 \ + -I/usr/include/eldbus-1 \ + -I/usr/include/efreet-1 \ + -I/usr/include/ethumb-client-1 \ + -I/usr/include/ethumb-1 \ + -I/usr/include/e_dbus-1 \ + -I/usr/include/dbus-1.0 \ + -I/usr/lib/dbus-1.0/include + +WARN_CFLAGS = -g \ + -Wall \ + -funwind-tables \ + -fomit-frame-pointer \ + -Xlinker \ + --no-undefined \ + -Wextra \ + -O2 \ + -Wwrite-strings \ + -Wlogical-op \ + -Wpacked \ + -Winline \ + -Wno-psabi +# -Werror + +FLAGS := \ + $(COMM_FLAGS) \ + $(INCLUDE) \ + $(DEBUG_FLAGS) \ + $(WARN_CFLAGS) + +ifeq (arm, $(findstring arm, $(shell uname -sm))) + FLAGS += -DDEVICE_ONLY +endif + + +# compiler flags +CFLAGS := $(FLAGS) -D_GNU_SOURCE + +# linker flags +LDFLAGS := \ + -shared \ + -lpthread \ + -lecore \ + -levas \ + -lelementary \ + -ldl + + +SRC_C := \ + ui_viewer_lib.c \ + ui_viewer_utils.c \ + ui_viewer_data.c \ + ui_viewer_screenshot.c + +TARGET = da_ui_viewer.so + +all: debug + +release: CFLAGS += -DNOLOGI=1 +release: debug + +OBJS := $(SRC_C:.c=.o) + +.c.o: + $(CC) $(CFLAGS) -c -o $@ $< + +debug: $(OBJS) + $(CC) $(OBJS) -o $(TARGET) $(LDFLAGS) + + +install: BINDIR = $(DESTDIR)/usr/lib +install: $(TARGET) + mkdir -p $(BINDIR) + install $(TARGET) -t $(BINDIR) +clean: + rm -f $(TARGET) $(OBJS) + +.PHONY: all debug release clean install + diff --git a/ui_viewer/ui_viewer_data.c b/ui_viewer/ui_viewer_data.c new file mode 100644 index 0000000..c05add2 --- /dev/null +++ b/ui_viewer/ui_viewer_data.c @@ -0,0 +1,2001 @@ +/* + * DA manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Lyupa Anastasia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ui_viewer_lib.h" +#include "ui_viewer_utils.h" +#include "ui_viewer_data.h" + +static pthread_mutex_t request_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t hierarchy_lock = PTHREAD_MUTEX_INITIALIZER; +enum hierarchy_status_t hierarchy_status = HIERARCHY_NOT_RUNNING; + +static Eina_List *_get_obj(Eina_List *obj_list, Evas_Object *obj); +static char *pack_ui_obj_prop(char *to, Evas_Object *obj, const char *type_name); +static Eina_List *ui_viewer_get_all_objs(void); + +static enum ui_obj_category_t _get_object_category(const char *type_name) +{ + enum ui_obj_category_t category = UI_UNDEFINED; + const char evas_prefix[] = "Evas_"; + const char elm_prefix[] = "elm_"; + + if (!strcmp(type_name, "rectangle") || !strcmp(type_name, "line") || + !strcmp(type_name, "polygon") || !strcmp(type_name, "text") || + !strcmp(type_name, "textblock") || !strcmp(type_name, "image") || + !strcmp(type_name, "vectors") || !strcmp(type_name, "textgrid") || + !strncmp(type_name, evas_prefix, strlen(evas_prefix))) + category = UI_EVAS; + else if (!strncmp(type_name, elm_prefix, strlen(elm_prefix))) + category = UI_ELM; + else if (!strcmp(type_name, "edje")) + category = UI_EDJE; + else + ui_viewer_log("cannot get category for type = %s\n", type_name); + + return category; +} + +static enum ui_obj_code_t _get_object_type_code(const char *type_name) +{ + enum ui_obj_code_t type_code = UI_CODE_UNDEFINED; + const char evas_prefix[] = "Evas_"; + const char elm_prefix[] = "elm_"; + + if (!strcmp(type_name, "rectangle")) + type_code = UI_EVAS_RECTANGLE; + else if (!strcmp(type_name, "line")) + type_code = UI_EVAS_LINE; + else if (!strcmp(type_name, "polygon")) + type_code = UI_EVAS_POLYGON; + else if (!strcmp(type_name, "text")) + type_code = UI_EVAS_TEXT; + else if (!strcmp(type_name, "textblock")) + type_code = UI_EVAS_TEXTBLOCK; + else if (!strcmp(type_name, "image")) + type_code = UI_EVAS_IMAGE; + else if (!strcmp(type_name, "vectors")) + type_code = UI_EVAS_VECTORS; + else if (!strcmp(type_name, "Evas_Object_Table")) + type_code = UI_EVAS_TABLE; + else if (!strcmp(type_name, "Evas_Object_Box")) + type_code = UI_EVAS_BOX; + else if (!strcmp(type_name, "textgrid")) + type_code = UI_EVAS_TEXTGRID; + else if (!strcmp(type_name, "Evas_Object_Grid")) + type_code = UI_EVAS_GRID; + else if (!strcmp(type_name, "Evas_Object_Smart")) + type_code = UI_EVAS_SMART; + else if (!strncmp(type_name, evas_prefix, strlen(evas_prefix))) + type_code = UI_EVAS_UNDEFINED; + else if (!strcmp(type_name, "elm_bg")) + type_code = UI_ELM_BACKGROUND; + else if (!strcmp(type_name, "elm_button")) + type_code = UI_ELM_BUTTON; + else if (!strcmp(type_name, "elm_check")) + type_code = UI_ELM_CHECK; + else if (!strcmp(type_name, "elm_colorselector")) + type_code = UI_ELM_COLORSELECTOR; + else if (!strcmp(type_name, "elm_ctxpopup")) + type_code = UI_ELM_CTXPOPUP; + else if (!strcmp(type_name, "elm_datetime")) + type_code = UI_ELM_DATETIME; + else if (!strcmp(type_name, "elm_entry")) + type_code = UI_ELM_ENTRY; + else if (!strcmp(type_name, "elm_flip")) + type_code = UI_ELM_FLIP; + else if (!strcmp(type_name, "elm_gengrid")) + type_code = UI_ELM_GENGRID; + else if (!strcmp(type_name, "elm_genlist")) + type_code = UI_ELM_GENLIST; + else if (!strcmp(type_name, "elm_glview")) + type_code = UI_ELM_GLVIEW; + else if (!strcmp(type_name, "elm_icon")) + type_code = UI_ELM_ICON; + else if (!strcmp(type_name, "elm_image")) + type_code = UI_ELM_IMAGE; + else if (!strcmp(type_name, "elm_index")) + type_code = UI_ELM_INDEX; + else if (!strcmp(type_name, "elm_label")) + type_code = UI_ELM_LABEL; + else if (!strcmp(type_name, "elm_list")) + type_code = UI_ELM_LIST; + else if (!strcmp(type_name, "elm_map")) + type_code = UI_ELM_MAP; + else if (!strcmp(type_name, "elm_notify")) + type_code = UI_ELM_NOTIFY; + else if (!strcmp(type_name, "elm_panel")) + type_code = UI_ELM_PANEL; + else if (!strcmp(type_name, "elm_photo")) + type_code = UI_ELM_PHOTO; + else if (!strcmp(type_name, "elm_photocam")) + type_code = UI_ELM_PHOTOCAM; + else if (!strcmp(type_name, "elm_plug")) + type_code = UI_ELM_PLUG; + else if (!strcmp(type_name, "elm_popup")) + type_code = UI_ELM_POPUP; + else if (!strcmp(type_name, "elm_progressbar")) + type_code = UI_ELM_PROGRESSBAR; + else if (!strcmp(type_name, "elm_radio")) + type_code = UI_ELM_RADIO; + else if (!strcmp(type_name, "elm_segment_control")) + type_code = UI_ELM_SEGMENTCONTROL; + else if (!strcmp(type_name, "elm_slider")) + type_code = UI_ELM_SLIDER; + else if (!strcmp(type_name, "elm_spinner")) + type_code = UI_ELM_SPINNER; + else if (!strcmp(type_name, "elm_toolbar")) + type_code = UI_ELM_TOOLBAR; + else if (!strcmp(type_name, "elm_tooltip")) + type_code = UI_ELM_TOOLTIP; + else if (!strcmp(type_name, "elm_win")) + type_code = UI_ELM_WIN; + else if (!strncmp(type_name, elm_prefix, strlen(elm_prefix))) + type_code = UI_ELM_UNDEFINED; + else if (!strcmp(type_name, "edje")) + type_code = UI_EDJE_UNDEFINED; + else + ui_viewer_log("cannot get type code for type = %s\n", type_name); + + return type_code; +} + +static Eina_Bool _get_redraw(enum ui_obj_category_t category) +{ + Eina_Bool redraw = EINA_FALSE; + + if (category != UI_EDJE) + redraw = EINA_TRUE; + + return redraw; +} + +static void _render_obj(Evas *evas, Evas_Object *obj, enum ui_obj_category_t category, + enum ui_obj_code_t type_code EINA_UNUSED, struct timeval *tv, + enum rendering_option_t rendering) +{ + Eina_Bool redraw; + + if ((rendering == RENDER_NONE) || + (rendering == RENDER_NONE_HOST_OPT) || + (rendering == RENDER_ELM && category != UI_ELM)) { + timerclear(tv); + return; + } + + redraw = _get_redraw(category); + + if (redraw) { + struct timeval start_tv, finish_tv; + Eina_Bool visible; + + visible = evas_object_visible_get(obj); + if (visible) { + evas_object_hide(obj); + evas_render(evas); + } + gettimeofday(&start_tv, NULL); + evas_object_show(obj); + evas_render(evas); + gettimeofday(&finish_tv, NULL); + if (!visible) { + evas_object_hide(obj); + evas_render(evas); + } + timersub(&finish_tv, &start_tv, tv); + } else { + timerclear(tv); + } +} + +static Eina_List *_get_obj(Eina_List *obj_list, Evas_Object *obj) +{ + Eina_List *children; + Evas_Object *child; + char type_name[MAX_PATH_LENGTH]; + + evas_object_ref(obj); + obj_list = eina_list_append(obj_list, obj); + + _strncpy(type_name, evas_object_type_get(obj), MAX_PATH_LENGTH); + + evas_object_unref(obj); + + if (!strcmp(type_name, "rectangle") || !strcmp(type_name, "line") || + !strcmp(type_name, "polygon") || !strcmp(type_name, "text") || + !strcmp(type_name, "textblock") || !strcmp(type_name, "image") || + !strcmp(type_name, "vectors") || !strcmp(type_name, "textgrid")) + return obj_list; + + children = evas_object_smart_members_get(obj); + EINA_LIST_FREE(children, child) { + obj_list = _get_obj(obj_list, child); + } + eina_list_free(children); + + return obj_list; +} + +char *pack_string(char *to, const char *str) +{ + if (!str) { + *to = '\0'; + return to + 1; + } else { + size_t len = strlen(str) + 1; + strncpy(to, str, len); + return to + len; + } +} + +static Eina_Bool _get_obj_exists(Evas_Object *obj) +{ + Eina_Bool exists = EINA_FALSE; + + // this call is safe even if object doesn't exist (returns NULL) + if (evas_object_type_get(obj) != NULL) + exists = EINA_TRUE; + + return exists; +} + +static Evas_Object *_get_win_id(Evas *evas) +{ + Evas_Object *win_id = 0; + Eina_List *objs, *l; + Evas_Object *obj_i; + + objs = evas_objects_in_rectangle_get(evas, SHRT_MIN, SHRT_MIN, USHRT_MAX, USHRT_MAX, + EINA_TRUE, EINA_TRUE); + EINA_LIST_FOREACH(objs, l, obj_i) + { + if (!strcmp(evas_object_type_get(obj_i), "elm_win")) { + win_id = obj_i; + break; + } + } + eina_list_free(objs); + + return win_id; +} + +static char *_pack_ui_obj_info(char *to, Evas_Object *obj, + enum rendering_option_t rendering) +{ + ui_obj_info_t info; + Evas *evas; + + if (!_get_obj_exists(obj)) { + ui_viewer_log("object %p doesn't exist\n", obj); + set_hierarchy_status(HIERARCHY_CANCELLED); + print_log_ui_viewer_hierarchy_error(); + return to; + } + + evas = evas_object_evas_get(obj); + + info.id = obj; + _strncpy(info.name, evas_object_type_get(obj), MAX_PATH_LENGTH); + info.parent_id = evas_object_smart_parent_get(obj); + info.category = _get_object_category(info.name); + info.code = _get_object_type_code(info.name); + + // we set window as parent for objects without it + if (info.parent_id == 0 && strcmp(info.name, "elm_win")) + info.parent_id = _get_win_id(evas); + + _render_obj(evas, obj, info.category, info.code, &(info.rendering_tv), rendering); + + ui_viewer_log("object : 0x%lx, category : %x, type_code: %x, " + "type_name : %s, rendering time : %d sec, %d nano sec, parent : 0x%lx\n", + (unsigned long)info.id, info.category, info.code, + info.name, info.rendering_tv.tv_sec, info.rendering_tv.tv_usec * 1000, + (unsigned long)info.parent_id); + + + to = pack_ptr(to, info.id); + to = pack_int8(to, info.category); + to = pack_int32(to, info.code); + to = pack_string(to, info.name); + to = pack_timeval(to, info.rendering_tv); + to = pack_ptr(to, info.parent_id); + to = pack_ui_obj_prop(to, info.id, info.name); + + evas_object_unref(obj); + + return to; +} + +char *pack_ui_obj_info_list(char *to, enum rendering_option_t rendering, + Eina_Bool *cancelled) +{ + Eina_List *obj_list; + Evas_Object *obj; + unsigned int info_cnt; + char *start_ptr = to; + Eina_List *ee_list = NULL, *ee_list_tmp = NULL; + Ecore_Evas *ee; + + ee_list = ecore_evas_ecore_evas_list_get(); + EINA_LIST_FOREACH(ee_list, ee_list_tmp, ee) + { + Evas *evas = ecore_evas_get(ee); + evas_event_freeze(evas); + } + + pthread_mutex_lock(&request_lock); + obj_list = ui_viewer_get_all_objs(); + info_cnt = eina_list_count(obj_list); + to = pack_int8(to, rendering); + to = pack_int32(to, info_cnt); + pthread_mutex_unlock(&request_lock); + + *cancelled = EINA_FALSE; + + if (info_cnt == 0) { + ui_viewer_log("no objects exist\n"); + set_hierarchy_status(HIERARCHY_CANCELLED); + to = start_ptr; + *cancelled = EINA_TRUE; + print_log_ui_viewer_hierarchy_error(); + } + + EINA_LIST_FREE(obj_list, obj) + { + pthread_mutex_lock(&request_lock); + // check if hierarchy request is active + if (get_hierarchy_status() == HIERARCHY_RUNNING) { + to = _pack_ui_obj_info(to, obj, rendering); + } else { + ui_viewer_log("break packing hierarchy info\n"); + // don't save any data if request was cancelled + to = start_ptr; + *cancelled = EINA_TRUE; + pthread_mutex_unlock(&request_lock); + break; + } + pthread_mutex_unlock(&request_lock); + } + + pthread_mutex_lock(&request_lock); + + // unref remained objects + EINA_LIST_FREE(obj_list, obj) + { + evas_object_unref(obj); + } + eina_list_free(obj_list); + + EINA_LIST_FREE(ee_list, ee) + { + Evas *evas = ecore_evas_get(ee); + evas_event_thaw(evas); + } + eina_list_free(ee_list); + + pthread_mutex_unlock(&request_lock); + + return to; +} + +enum hierarchy_status_t get_hierarchy_status(void) +{ + enum hierarchy_status_t status; + + pthread_mutex_lock(&hierarchy_lock); + status = hierarchy_status; + pthread_mutex_unlock(&hierarchy_lock); + + return status; +} + +void set_hierarchy_status(enum hierarchy_status_t status) +{ + pthread_mutex_lock(&hierarchy_lock); + hierarchy_status = status; + pthread_mutex_unlock(&hierarchy_lock); +} + +static Eina_List *_get_all_objs_in_rect(Evas_Coord x, Evas_Coord y, Evas_Coord w, + Evas_Coord h, + Eina_Bool include_pass_events_objects, + Eina_Bool include_hidden_objects) +{ + Eina_List *ecore_evas_list = NULL, *obj_list = NULL; + Ecore_Evas *ee; + + ecore_evas_list = ecore_evas_ecore_evas_list_get(); + + EINA_LIST_FREE(ecore_evas_list, ee) + { + Evas *evas; + Eina_List *objs, *l; + Evas_Object *obj_i; + + evas = ecore_evas_get(ee); + + objs = evas_objects_in_rectangle_get(evas, x, y, w, h, + include_pass_events_objects, + include_hidden_objects); + + EINA_LIST_FOREACH(objs, l, obj_i) + { + obj_list = _get_obj(obj_list, obj_i); + } + eina_list_free(objs); + } + + eina_list_free(ecore_evas_list); + + return obj_list; +} + +static Eina_List *ui_viewer_get_all_objs(void) +{ + return _get_all_objs_in_rect(SHRT_MIN, SHRT_MIN, USHRT_MAX, USHRT_MAX, + EINA_TRUE, EINA_TRUE); +} + +static char *_pack_ui_obj_evas_prop(char *to, ui_obj_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("evas prop: geometry : [%d,%d,%d,%d], " + "focus : %d, name : %s, visible : %d, \n\t" + "color : [%d,%d,%d,%d], anti_alias : %d, scale : %f, " + "size_min : [%d,%d], size_max : [%d,%d], size_request : [%d,%d], \n\t" + "size_align : [%f,%f], size_weight : [%f,%f], " + "size_padding : [%d,%d,%d,%d], render_op : %d\n", + prop->geometry[0], prop->geometry[1], + prop->geometry[2], prop->geometry[3], + prop->focus, prop->name, prop->visible, + prop->color[0], prop->color[1], + prop->color[2], prop->color[3], + prop->anti_alias, prop->scale, + prop->size_min[0], prop->size_min[1], + prop->size_max[0], prop->size_max[1], + prop->size_request[0], prop->size_request[1], + prop->size_align[0], prop->size_align[1], + prop->size_weight[0], prop->size_weight[1], + prop->size_padding[0], prop->size_padding[1], + prop->size_padding[2], prop->size_padding[3], + prop->render_op); + + to = pack_int32(to, prop->geometry[0]); + to = pack_int32(to, prop->geometry[1]); + to = pack_int32(to, prop->geometry[2]); + to = pack_int32(to, prop->geometry[3]); + to = pack_int8(to, prop->focus); + to = pack_string(to, prop->name); + to = pack_int8(to, prop->visible); + to = pack_int32(to, prop->color[0]); + to = pack_int32(to, prop->color[1]); + to = pack_int32(to, prop->color[2]); + to = pack_int32(to, prop->color[3]); + to = pack_int8(to, prop->anti_alias); + to = pack_float(to, prop->scale); + to = pack_int32(to, prop->size_min[0]); + to = pack_int32(to, prop->size_min[1]); + to = pack_int32(to, prop->size_max[0]); + to = pack_int32(to, prop->size_max[1]); + to = pack_int32(to, prop->size_request[0]); + to = pack_int32(to, prop->size_request[1]); + to = pack_float(to, prop->size_align[0]); + to = pack_float(to, prop->size_align[1]); + to = pack_float(to, prop->size_weight[0]); + to = pack_float(to, prop->size_weight[1]); + to = pack_int32(to, prop->size_padding[0]); + to = pack_int32(to, prop->size_padding[1]); + to = pack_int32(to, prop->size_padding[2]); + to = pack_int32(to, prop->size_padding[3]); + to = pack_int8(to, prop->render_op); + + return to; +} + +static char *_pack_ui_obj_elm_prop(char *to, ui_obj_elm_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("elm prop: text : %s, style : %s, disabled : %d, type : %s\n", + prop->text, prop->style, prop->disabled, prop->type); + + to = pack_string(to, prop->text); + to = pack_string(to, prop->style); + to = pack_int8(to, prop->disabled); + to = pack_string(to, prop->type); + + return to; +} + +static char *_pack_ui_obj_edje_prop(char *to, ui_obj_edje_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("edje prop: animation : %d, play : %d, scale : %f, base_scale : %f, " + "size_min : [%d,%d], size_max : [%d,%d]\n", + prop->animation, prop->play, prop->scale, prop->base_scale, + prop->size_min[0], prop->size_min[1], prop->size_max[0], + prop->size_max[1]); + + to = pack_int8(to, prop->animation); + to = pack_int8(to, prop->play); + to = pack_float(to, prop->scale); + to = pack_float(to, prop->base_scale); + to = pack_int32(to, prop->size_min[0]); + to = pack_int32(to, prop->size_min[1]); + to = pack_int32(to, prop->size_max[0]); + to = pack_int32(to, prop->size_max[1]); + + return to; +} + +static char *_pack_image_prop(char *to, image_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("image prop: load_dpi : %f, source_clip : %d, filled : %d, content_hint : %d, " + "alpha : %d, border : [%d,%d,%d,%d], border_scale : %f, pixels_dirty : %d,\n\t" + "load_orientation : %d, border_center_fill : %d, size : [%d,%d], source_visible: %d, " + "fill : [%d,%d,%d,%d], load_scale_down : %d,\n\tscale_hint : %d, source_events : %d, " + "frame_count : %d, evas_image_stride : %d\n", + prop->load_dpi, prop->source_clip, prop->filled, prop->content_hint, + prop->alpha, prop->border[0], prop->border[1], prop->border[2], + prop->border[3], prop->border_scale, prop->pixels_dirty, prop->load_orientation, + prop->border_center_fill, prop->size[0], prop->size[1], prop->source_visible, + prop->fill[0], prop->fill[1], prop->fill[2], prop->fill[3], prop->load_scale_down, + prop->scale_hint, prop->source_events, prop->frame_count, prop->evas_image_stride); + + to = pack_float(to, prop->load_dpi); + to = pack_int8(to, prop->source_clip); + to = pack_int8(to, prop->filled); + to = pack_int8(to, prop->content_hint); + to = pack_int8(to, prop->alpha); + to = pack_int32(to, prop->border[0]); + to = pack_int32(to, prop->border[1]); + to = pack_int32(to, prop->border[2]); + to = pack_int32(to, prop->border[3]); + to = pack_float(to, prop->border_scale); + to = pack_int8(to, prop->pixels_dirty); + to = pack_int8(to, prop->load_orientation); + to = pack_int8(to, prop->border_center_fill); + to = pack_int32(to, prop->size[0]); + to = pack_int32(to, prop->size[1]); + to = pack_int8(to, prop->source_visible); + to = pack_int32(to, prop->fill[0]); + to = pack_int32(to, prop->fill[1]); + to = pack_int32(to, prop->fill[2]); + to = pack_int32(to, prop->fill[3]); + to = pack_int32(to, prop->load_scale_down); + to = pack_int8(to, prop->scale_hint); + to = pack_int8(to, prop->source_events); + to = pack_int32(to, prop->frame_count); + to = pack_int32(to, prop->evas_image_stride); + + return to; +} + +static char *_pack_line_prop(char *to, line_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("line prop: xy : [%d,%d,%d,%d]\n", + prop->xy[0], prop->xy[1], prop->xy[2], prop->xy[3]); + + to = pack_int32(to, prop->xy[0]); + to = pack_int32(to, prop->xy[1]); + to = pack_int32(to, prop->xy[2]); + to = pack_int32(to, prop->xy[3]); + + return to; +} + +static char *_pack_text_prop(char *to, text_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("text prop: font : %s, size : %d, text : %s, delim : %s, " + "ellipsis : %s, style : %d, shadow_color : [%d,%d,%d,%d], glow_color : [%d,%d,%d,%d],\n\t" + "glow2_color : [%d,%d,%d,%d], outline_color : [%d,%d,%d,%d], style_pad: [%d,%d,%d,%d], " + "direction : %d\n", + prop->font, prop->size, prop->text, prop->delim, prop->ellipsis, prop->style, + prop->shadow_color[0], prop->shadow_color[1], prop->shadow_color[2], prop->shadow_color[3], + prop->glow_color[0], prop->glow_color[1], prop->glow_color[2], prop->glow_color[3], + prop->glow2_color[0], prop->glow2_color[1], prop->glow2_color[2], prop->glow2_color[3], + prop->outline_color[0], prop->outline_color[1], prop->outline_color[2], prop->outline_color[3], + prop->style_pad[0], prop->style_pad[1], prop->style_pad[2], prop->style_pad[3], + prop->direction); + + to = pack_string(to, prop->font); + to = pack_int32(to, prop->size); + to = pack_string(to, prop->text); + to = pack_string(to, prop->delim); + to = pack_float(to, prop->ellipsis); + to = pack_int8(to, prop->style); + to = pack_int32(to, prop->shadow_color[0]); + to = pack_int32(to, prop->shadow_color[1]); + to = pack_int32(to, prop->shadow_color[2]); + to = pack_int32(to, prop->shadow_color[3]); + to = pack_int32(to, prop->glow_color[0]); + to = pack_int32(to, prop->glow_color[1]); + to = pack_int32(to, prop->glow_color[2]); + to = pack_int32(to, prop->glow_color[3]); + to = pack_int32(to, prop->glow2_color[0]); + to = pack_int32(to, prop->glow2_color[1]); + to = pack_int32(to, prop->glow2_color[2]); + to = pack_int32(to, prop->glow2_color[3]); + to = pack_int32(to, prop->outline_color[0]); + to = pack_int32(to, prop->outline_color[1]); + to = pack_int32(to, prop->outline_color[2]); + to = pack_int32(to, prop->outline_color[3]); + to = pack_int32(to, prop->style_pad[0]); + to = pack_int32(to, prop->style_pad[1]); + to = pack_int32(to, prop->style_pad[2]); + to = pack_int32(to, prop->style_pad[3]); + to = pack_int8(to, prop->direction); + + return to; +} + +static char *_pack_textblock_prop(char *to, textblock_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("textblock prop: replace_char : %s, valign : %f, delim : %s, newline : %d, " + "markup : %s\n", + prop->replace_char, prop->valign, prop->delim, prop->newline, + prop->markup); + + to = pack_string(to, prop->replace_char); + to = pack_float(to, prop->valign); + to = pack_string(to, prop->delim); + to = pack_int8(to, prop->newline); + to = pack_string(to, prop->markup); + + return to; +} + +static char *_pack_table_prop(char *to, table_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("table prop: homogeneous : %d, align : [%f,%f], padding : [%d,%d], mirrored : %d, " + "col_row_size : [%d,%d]\n", + prop->homogeneous, prop->align[0], prop->align[1], prop->padding[0], + prop->padding[1], prop->mirrored, prop->col_row_size[0], prop->col_row_size[1]); + + to = pack_int8(to, prop->homogeneous); + to = pack_float(to, prop->align[0]); + to = pack_float(to, prop->align[1]); + to = pack_int32(to, prop->padding[0]); + to = pack_int32(to, prop->padding[1]); + to = pack_int8(to, prop->mirrored); + to = pack_int32(to, prop->col_row_size[0]); + to = pack_int32(to, prop->col_row_size[1]); + + return to; +} + +static char *_pack_box_prop(char *to, box_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("box prop: align : [%f,%f]\n", + prop->align[0], prop->align[1]); + + to = pack_float(to, prop->align[0]); + to = pack_float(to, prop->align[1]); + + return to; +} + +static char *_pack_grid_prop(char *to, grid_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("grid prop: mirrored : %d\n", + prop->mirrored); + + to = pack_int8(to, prop->mirrored); + + return to; +} + +static char *_pack_textgrid_prop(char *to, textgrid_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("textgrid prop: size : [%d,%d], cell_size : [%d,%d]\n", + prop->size[0], prop->size[1], prop->cell_size[0], + prop->cell_size[1]); + + to = pack_int32(to, prop->size[0]); + to = pack_int32(to, prop->size[1]); + to = pack_int32(to, prop->cell_size[0]); + to = pack_int32(to, prop->cell_size[1]); + + return to; +} + +static char *_pack_bg_prop(char *to, bg_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("bg prop: color : [%d,%d,%d], option : %d\n", + prop->color[0], prop->color[1], prop->color[2], + prop->option); + + to = pack_int32(to, prop->color[0]); + to = pack_int32(to, prop->color[1]); + to = pack_int32(to, prop->color[2]); + to = pack_int8(to, prop->option); + + return to; +} + +static char *_pack_button_prop(char *to, button_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("button prop: initial_timeout : %f, gap_timeout : %f, autorepeat : %d\n", + prop->initial_timeout, prop->gap_timeout, prop->autorepeat); + + to = pack_float(to, prop->initial_timeout); + to = pack_float(to, prop->gap_timeout); + to = pack_int8(to, prop->autorepeat); + + return to; +} + +static char *_pack_check_prop(char *to, check_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("check prop: state : %d\n", + prop->state); + + to = pack_int8(to, prop->state); + + return to; +} + +static char *_pack_colorselector_prop(char *to, colorselector_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("colorselector prop: color : [%d,%d,%d,%d], palette_name : %s, " + "mode : %d\n", + prop->color[0], prop->color[1], prop->color[2], prop->color[3], prop->palette_name, + prop->mode); + + to = pack_int32(to, prop->color[0]); + to = pack_int32(to, prop->color[1]); + to = pack_int32(to, prop->color[2]); + to = pack_int32(to, prop->color[3]); + to = pack_string(to, prop->palette_name); + to = pack_int8(to, prop->mode); + + return to; +} + +static char *_pack_ctxpopup_prop(char *to, ctxpopup_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("ctxpopup prop: horizontal : %d\n", + prop->horizontal); + + to = pack_int8(to, prop->horizontal); + + return to; +} + +static char *_pack_datetime_prop(char *to, datetime_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("datetime prop: format : %s, value : [%d,%d,%d,%d,%d,%d,%d,%d]\n", + prop->format, prop->value[0], prop->value[1], prop->value[2], prop->value[3], + prop->value[4], prop->value[5], prop->value[6], prop->value[7]); + + to = pack_string(to, prop->format); + to = pack_int32(to, prop->value[0]); + to = pack_int32(to, prop->value[1]); + to = pack_int32(to, prop->value[2]); + to = pack_int32(to, prop->value[3]); + to = pack_int32(to, prop->value[4]); + to = pack_int32(to, prop->value[5]); + to = pack_int32(to, prop->value[6]); + to = pack_int32(to, prop->value[7]); + + return to; +} + +static char *_pack_entry_prop(char *to, entry_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("entry prop: entry : %s, scrollable : %d, panel_show_on_demand : %d, menu_disabled : %d, " + "cnp_mode : %d, editable : %d, hover_style : %s, single_line : %d,\n\t" + "password : %d, autosave : %d, prediction_allow : %d, panel_enabled: %d, " + "cursor_pos : %d, cursor_is_format : %d,\n\tcursor_content : %s, " + "selection : %s, is_visible_format : %d\n", + prop->entry, prop->scrollable, prop->panel_show_on_demand, prop->menu_disabled, + prop->cnp_mode, prop->editable, prop->hover_style, prop->single_line, + prop->password, prop->autosave, prop->prediction_allow, prop->panel_enabled, + prop->cursor_pos, prop->cursor_is_format, prop->cursor_content, prop->selection, + prop->is_visible_format); + + to = pack_string(to, prop->entry); + to = pack_int8(to, prop->scrollable); + to = pack_int8(to, prop->panel_show_on_demand); + to = pack_int8(to, prop->menu_disabled); + to = pack_int8(to, prop->cnp_mode); + to = pack_int8(to, prop->editable); + to = pack_string(to, prop->hover_style); + to = pack_int8(to, prop->single_line); + to = pack_int8(to, prop->password); + to = pack_int8(to, prop->autosave); + to = pack_int8(to, prop->prediction_allow); + to = pack_int8(to, prop->panel_enabled); + to = pack_int32(to, prop->cursor_pos); + to = pack_int8(to, prop->cursor_is_format); + to = pack_string(to, prop->cursor_content); + free(prop->cursor_content); // we need free it according to efl docs + to = pack_string(to, prop->selection); + to = pack_int8(to, prop->is_visible_format); + + return to; +} + +static char *_pack_flip_prop(char *to, flip_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("flip prop: interaction : %d, front_visible : %d\n", + prop->interaction, prop->front_visible); + + to = pack_int8(to, prop->interaction); + to = pack_int8(to, prop->front_visible); + + return to; +} + +static char *_pack_gengrid_prop(char *to, gengrid_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("gengrid prop: align : [%f,%f], filled : %d, relative : [%f,%f], " + "multi_select : %d, group_item_size : [%d,%d], select_mode : %d, render_mode : %d,\n\t" + "highlight_mode : %d, item_size : [%d,%d], multi_select_mode: %d, " + "horizontal : %d, wheel_disabled : %d, items_count : %d\n", + prop->align[0], prop->align[1], prop->filled, prop->relative[0], + prop->relative[1], prop->multi_select, prop->group_item_size[0], prop->group_item_size[1], + prop->select_mode, prop->render_mode, prop->highlight_mode, prop->item_size[0], + prop->item_size[1], prop->multi_select_mode, prop->horizontal, prop->wheel_disabled, + prop->items_count); + + to = pack_float(to, prop->align[0]); + to = pack_float(to, prop->align[1]); + to = pack_int8(to, prop->filled); + to = pack_float(to, prop->relative[0]); + to = pack_float(to, prop->relative[1]); + to = pack_int8(to, prop->multi_select); + to = pack_int32(to, prop->group_item_size[0]); + to = pack_int32(to, prop->group_item_size[1]); + to = pack_int8(to, prop->select_mode); + to = pack_int8(to, prop->render_mode); + to = pack_int8(to, prop->highlight_mode); + to = pack_int32(to, prop->item_size[0]); + to = pack_int32(to, prop->item_size[1]); + to = pack_int8(to, prop->multi_select_mode); + to = pack_int8(to, prop->horizontal); + to = pack_int8(to, prop->wheel_disabled); + to = pack_int32(to, prop->items_count); + + return to; +} + +static char *_pack_genlist_prop(char *to, genlist_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("genlist prop: multi_select : %d, genlist_mode : %d, items_count : %d, homogeneous : %d, " + "block_count : %d, timeout : %f, reorder_mode : %d,\n\t" + "decorate_mode : %d, effect_enabled : %d, select_mode: %d, " + "highlight_mode : %d, realization_mode : %d\n", + prop->multi_select, prop->genlist_mode, prop->items_count, prop->homogeneous, + prop->block_count, prop->timeout, prop->reorder_mode, prop->decorate_mode, + prop->effect_enabled, prop->select_mode, prop->highlight_mode, prop->realization_mode); + + to = pack_int8(to, prop->multi_select); + to = pack_int8(to, prop->genlist_mode); + to = pack_int32(to, prop->items_count); + to = pack_int8(to, prop->homogeneous); + to = pack_int32(to, prop->block_count); + to = pack_float(to, prop->timeout); + to = pack_int8(to, prop->reorder_mode); + to = pack_int8(to, prop->decorate_mode); + to = pack_int8(to, prop->effect_enabled); + to = pack_int8(to, prop->select_mode); + to = pack_int8(to, prop->highlight_mode); + to = pack_int8(to, prop->realization_mode); + + return to; +} + +static char *_pack_glview_prop(char *to, glview_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("glview prop: size : [%d,%d], rotation: %d\n", + prop->size[0], prop->size[1], prop->rotation); + + to = pack_int32(to, prop->size[0]); + to = pack_int32(to, prop->size[1]); + to = pack_int32(to, prop->rotation); + + return to; +} + +static char *_pack_icon_prop(char *to, icon_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("icon prop: lookup : %d, standard : %s\n", + prop->lookup, prop->standard); + + to = pack_int8(to, prop->lookup); + to = pack_string(to, prop->standard); + + return to; +} + +static char *_pack_elm_image_prop(char *to, elm_image_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("elm_image prop: editable : %d, play : %d, smooth : %d, no_scale : %d, " + "animated : %d, aspect_fixed : %d, orient : %d,\n\t" + "fill_outside : %d, resizable : [%d,%d], animated_available: %d, " + "size : [%d,%d]\n", + prop->editable, prop->play, prop->smooth, prop->no_scale, + prop->animated, prop->aspect_fixed, prop->orient, prop->fill_outside, + prop->resizable[0], prop->resizable[1], prop->animated_available, + prop->size[0], prop->size[1]); + + to = pack_int8(to, prop->editable); + to = pack_int8(to, prop->play); + to = pack_int8(to, prop->smooth); + to = pack_int8(to, prop->no_scale); + to = pack_int8(to, prop->animated); + to = pack_int8(to, prop->aspect_fixed); + to = pack_int8(to, prop->orient); + to = pack_int8(to, prop->fill_outside); + to = pack_int8(to, prop->resizable[0]); + to = pack_int8(to, prop->resizable[1]); + to = pack_int8(to, prop->animated_available); + to = pack_int32(to, prop->size[0]); + to = pack_int32(to, prop->size[1]); + + return to; +} + +static char *_pack_index_prop(char *to, index_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("index prop: autohide_disabled : %d, omit_enabled : %d, priority : %d, horizontal : %d, " + "change_time : %f,\n\tindicator_disabled : %d, item_level : %d\n", + prop->autohide_disabled, prop->omit_enabled, prop->priority, prop->horizontal, + prop->change_time, prop->indicator_disabled, prop->item_level); + + to = pack_int8(to, prop->autohide_disabled); + to = pack_int8(to, prop->omit_enabled); + to = pack_int32(to, prop->priority); + to = pack_int8(to, prop->horizontal); + to = pack_float(to, prop->change_time); + to = pack_int8(to, prop->indicator_disabled); + to = pack_int32(to, prop->item_level); + + return to; +} + +static char *_pack_label_prop(char *to, label_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("label prop: wrap_width : %d, speed : %f, mode : %d\n", + prop->wrap_width, prop->speed, prop->mode); + + to = pack_int32(to, prop->wrap_width); + to = pack_float(to, prop->speed); + to = pack_int8(to, prop->mode); + + return to; +} + +static char *_pack_list_prop(char *to, list_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("list prop: horizontal : %d, select_mode : %d, focus_on_selection : %d, multi_select : %d, " + "multi_select_mode : %d, mode : %d\n", + prop->horizontal, prop->select_mode, prop->focus_on_selection, prop->multi_select, + prop->multi_select_mode, prop->mode); + + to = pack_int8(to, prop->horizontal); + to = pack_int8(to, prop->select_mode); + to = pack_int8(to, prop->focus_on_selection); + to = pack_int8(to, prop->multi_select); + to = pack_int8(to, prop->multi_select_mode); + to = pack_int8(to, prop->mode); + + return to; +} + +static char *_pack_map_prop(char *to, map_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("map prop: zoom : %d, paused : %d, wheel_disabled : %d, zoom_min : %d, " + "rotate_degree : %f, rotate : [%d,%d],\n\tagent : %s, zoom_max : %d, " + "zoom_mode : %d, region : [%f,%f]\n", + prop->zoom, prop->paused, prop->wheel_disabled, prop->zoom_min, + prop->rotate_degree, prop->rotate[0], prop->rotate[1], + prop->agent, prop->zoom_max, prop->zoom_mode, prop->region[0], prop->region[1]); + + to = pack_int32(to, prop->zoom); + to = pack_int8(to, prop->paused); + to = pack_int8(to, prop->wheel_disabled); + to = pack_int32(to, prop->zoom_min); + to = pack_float(to, prop->rotate_degree); + to = pack_int32(to, prop->rotate[0]); + to = pack_int32(to, prop->rotate[1]); + to = pack_string(to, prop->agent); + to = pack_int32(to, prop->zoom_max); + to = pack_int8(to, prop->zoom_mode); + to = pack_float(to, prop->region[0]); + to = pack_float(to, prop->region[1]); + + return to; +} + +static char *_pack_notify_prop(char *to, notify_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("notify prop: align : [%f,%f], allow_events: %d, " + "timeout : %f\n", + prop->align[0], prop->align[1], prop->allow_events, + prop->timeout); + + to = pack_float(to, prop->align[0]); + to = pack_float(to, prop->align[1]); + to = pack_int8(to, prop->allow_events); + to = pack_float(to, prop->timeout); + + return to; +} + +static char *_pack_panel_prop(char *to, panel_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("panel prop: orient : %d, hidden : %d, scrollable : %d\n", + prop->orient, prop->hidden, prop->scrollable); + + to = pack_int8(to, prop->orient); + to = pack_int8(to, prop->hidden); + to = pack_int8(to, prop->scrollable); + + return to; +} + +static char *_pack_photo_prop(char *to, photo_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("photo prop: editable : %d, fill_inside : %d, aspect_fixed : %d, size : %d\n", + prop->editable, prop->fill_inside, prop->aspect_fixed, prop->size); + + to = pack_int8(to, prop->editable); + to = pack_int8(to, prop->fill_inside); + to = pack_int8(to, prop->aspect_fixed); + to = pack_int32(to, prop->size); + + return to; +} + +static char *_pack_photocam_prop(char *to, photocam_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("photocam prop: paused : %d, file : %f, gesture_enabled : %d, zoom : %f, " + "zoom_mode : %d, image_size : [%d,%d]\n", + prop->paused, prop->file, prop->gesture_enabled, prop->zoom, + prop->zoom_mode, prop->image_size[0], prop->image_size[1]); + + to = pack_int8(to, prop->paused); + to = pack_string(to, prop->file); + to = pack_int8(to, prop->gesture_enabled); + to = pack_float(to, prop->zoom); + to = pack_int8(to, prop->zoom_mode); + to = pack_int32(to, prop->image_size[0]); + to = pack_int32(to, prop->image_size[1]); + + return to; +} + +static char *_pack_popup_prop(char *to, popup_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("popup prop: align : [%f,%f], allow_events : %d, wrap_type : %d, orient : %d, " + "timeout : %f\n", + prop->align[0], prop->align[1], prop->allow_events, prop->wrap_type, + prop->orient, prop->timeout); + + to = pack_float(to, prop->align[0]); + to = pack_float(to, prop->align[1]); + to = pack_int8(to, prop->allow_events); + to = pack_int8(to, prop->wrap_type); + to = pack_int8(to, prop->orient); + to = pack_float(to, prop->timeout); + + return to; +} + +static char *_pack_progressbar_prop(char *to, progressbar_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("progressbar prop: span_size : %d, pulse : %d, value : %f, inverted : %d, " + "horizontal : %d, unit_format : %s\n", + prop->span_size, prop->pulse, prop->value, prop->inverted, + prop->horizontal, prop->unit_format); + + to = pack_int32(to, prop->span_size); + to = pack_int8(to, prop->pulse); + to = pack_float(to, prop->value); + to = pack_int8(to, prop->inverted); + to = pack_int8(to, prop->horizontal); + to = pack_string(to, prop->unit_format); + + return to; +} + +static char *_pack_radio_prop(char *to, radio_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("radio prop: state_value : %d, value : %d\n", + prop->state_value, prop->value); + + to = pack_int32(to, prop->state_value); + to = pack_int32(to, prop->value); + + return to; +} + +static char *_pack_segmencontrol_prop(char *to, segmencontrol_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("segmencontrol prop: item_count : %d\n", + prop->item_count); + + to = pack_int32(to, prop->item_count); + + return to; +} + +static char *_pack_slider_prop(char *to, slider_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("slider prop: horizontal : %d, value : %f, format : %s\n", + prop->horizontal, prop->value, prop->format); + + to = pack_int8(to, prop->horizontal); + to = pack_float(to, prop->value); + to = pack_string(to, prop->format); + + return to; +} + +static char *_pack_spinner_prop(char *to, spinner_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("spinner prop: min : %f, max : %f, step : %f, wrap : %d, " + "interval : %f, round : %d, editable : %d, " + "base : %f, value : %f, format : %s\n", + prop->min_max[0], prop->min_max[1], prop->step, prop->wrap, + prop->interval, prop->round, prop->editable, prop->base, + prop->value, prop->format); + + to = pack_float(to, prop->min_max[0]); + to = pack_float(to, prop->min_max[1]); + to = pack_float(to, prop->step); + to = pack_int8(to, prop->wrap); + to = pack_float(to, prop->interval); + to = pack_int32(to, prop->round); + to = pack_int8(to, prop->editable); + to = pack_float(to, prop->base); + to = pack_float(to, prop->value); + to = pack_string(to, prop->format); + + return to; +} + +static char *_pack_toolbar_prop(char *to, toolbar_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("toolbar prop: reorder_mode : %d, transverse_expanded : %d, homogeneous : %d, align : %f, " + "select_mode : %d, icon_size : %d, horizontal : %d,\n\tstandard_priority : %d, " + "items_count : %d\n", + prop->reorder_mode, prop->transverse_expanded, prop->homogeneous, prop->align, + prop->select_mode, prop->icon_size, prop->horizontal, prop->standard_priority, + prop->items_count); + + to = pack_int8(to, prop->reorder_mode); + to = pack_int8(to, prop->transverse_expanded); + to = pack_int8(to, prop->homogeneous); + to = pack_float(to, prop->align); + to = pack_int8(to, prop->select_mode); + to = pack_int32(to, prop->icon_size); + to = pack_int8(to, prop->horizontal); + to = pack_int32(to, prop->standard_priority); + to = pack_int32(to, prop->items_count); + + return to; +} + +static char *_pack_tooltip_prop(char *to, tooltip_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("tooltip prop: style : %s, window_mode : %d\n", + prop->style, prop->window_mode); + + to = pack_string(to, prop->style); + to = pack_int8(to, prop->window_mode); + + return to; +} + +static char *_pack_win_prop(char *to, win_prop_t *prop) +{ + if (!prop) + return to; + + ui_viewer_log("win prop: iconfield : %d, maximized : %d, modal : %d, icon_name : %s, " + "withdrawn : %d, role : %s, size_step : [%d,%d], highlight_style : %s,\n\t" + "borderless : %d, highlight_enabled : %d, title : %s, alpha: %d, " + "urgent : %d, rotation : %d, sticky : %d, highlight_animate : %d,\n\t" + "aspect : %f, indicator_opacity : %d, demand_attention : %d, " + "layer : %d, profile : %s, shaped : %d, indicator_mode : %d, conformant : %d,\n\t" + "size_base : [%d,%d], quickpanel : %d, rotation_supported : %d, screen_dpi : [%d,%d], " + "win_type : %d\n", + prop->iconfield, prop->maximized, prop->modal, prop->icon_name, + prop->withdrawn, prop->role, prop->size_step[0], prop->size_step[1], + prop->highlight_style, prop->borderless, prop->highlight_enabled, prop->title, + prop->alpha, prop->urgent, prop->rotation, prop->sticky, + prop->highlight_animate, prop->aspect, prop->indicator_opacity, prop->demand_attention, prop->layer, + prop->profile, prop->shaped, prop->fullscreen, prop->indicator_mode, prop->conformant, + prop->size_base[0], prop->size_base[1], prop->quickpanel, prop->rotation_supported, prop->screen_dpi[0], + prop->screen_dpi[1], prop->win_type); + + to = pack_int8(to, prop->iconfield); + to = pack_int8(to, prop->maximized); + to = pack_int8(to, prop->modal); + to = pack_string(to, prop->icon_name); + to = pack_int8(to, prop->withdrawn); + to = pack_string(to, prop->role); + to = pack_int32(to, prop->size_step[0]); + to = pack_int32(to, prop->size_step[1]); + to = pack_string(to, prop->highlight_style); + to = pack_int8(to, prop->borderless); + to = pack_int8(to, prop->highlight_enabled); + to = pack_string(to, prop->title); + to = pack_int8(to, prop->alpha); + to = pack_int8(to, prop->urgent); + to = pack_int32(to, prop->rotation); + to = pack_int8(to, prop->sticky); + to = pack_int8(to, prop->highlight_animate); + to = pack_float(to, prop->aspect); + to = pack_int8(to, prop->indicator_opacity); + to = pack_int8(to, prop->demand_attention); + to = pack_int32(to, prop->layer); + to = pack_string(to, prop->profile); + to = pack_int8(to, prop->shaped); + to = pack_int8(to, prop->fullscreen); + to = pack_int8(to, prop->indicator_mode); + to = pack_int8(to, prop->conformant); + to = pack_int32(to, prop->size_base[0]); + to = pack_int32(to, prop->size_base[1]); + to = pack_int8(to, prop->quickpanel); + to = pack_int8(to, prop->rotation_supported); + to = pack_int32(to, prop->screen_dpi[0]); + to = pack_int32(to, prop->screen_dpi[1]); + to = pack_int8(to, prop->win_type); + + return to; +} + +static char *pack_ui_obj_prop(char *to, Evas_Object *obj, const char *type_name) +{ + ui_obj_prop_t obj_prop; + enum ui_obj_category_t category; + enum ui_obj_code_t code; + + evas_object_geometry_get(obj, &obj_prop.geometry[0], &obj_prop.geometry[1], + &obj_prop.geometry[2], &obj_prop.geometry[3]); + obj_prop.focus = evas_object_focus_get(obj); + _strncpy(obj_prop.name, evas_object_name_get(obj), MAX_PATH_LENGTH); + obj_prop.visible = evas_object_visible_get(obj); + evas_object_color_get(obj, &obj_prop.color[0], &obj_prop.color[1], + &obj_prop.color[2], &obj_prop.color[3]); + obj_prop.anti_alias = evas_object_anti_alias_get(obj); + obj_prop.scale = evas_object_scale_get(obj); + evas_object_size_hint_min_get(obj, &obj_prop.size_min[0], &obj_prop.size_min[1]); + evas_object_size_hint_max_get(obj, &obj_prop.size_max[0], &obj_prop.size_max[1]); + evas_object_size_hint_request_get(obj, &obj_prop.size_request[0], &obj_prop.size_request[1]); + evas_object_size_hint_align_get(obj, &obj_prop.size_align[0], &obj_prop.size_align[1]); + evas_object_size_hint_weight_get(obj, &obj_prop.size_weight[0], &obj_prop.size_weight[1]); + evas_object_size_hint_padding_get(obj, &obj_prop.size_padding[0], &obj_prop.size_padding[1], + &obj_prop.size_padding[2], &obj_prop.size_padding[3]); + obj_prop.render_op = evas_object_render_op_get(obj); + + to = _pack_ui_obj_evas_prop(to, &obj_prop); + + category = _get_object_category(type_name); + if (category == UI_UNDEFINED) { + return to; + } else if (category == UI_ELM) { + ui_obj_elm_prop_t elm_prop; + + if (!strcmp(type_name, "elm_pan")) { + strcpy(elm_prop.text, ""); + strcpy(elm_prop.style, ""); + elm_prop.disabled = 0; + } else { + _strncpy(elm_prop.text, elm_object_text_get(obj), MAX_TEXT_LENGTH); + _strncpy(elm_prop.style, elm_object_style_get(obj), MAX_PATH_LENGTH); + elm_prop.disabled = elm_object_disabled_get(obj); + } + _strncpy(elm_prop.type, elm_object_widget_type_get(obj), MAX_PATH_LENGTH); + + to = _pack_ui_obj_elm_prop(to, &elm_prop); + + } else if (category == UI_EDJE) { + ui_obj_edje_prop_t edje_prop; + edje_prop.animation = edje_object_animation_get(obj); + edje_prop.play = edje_object_play_get(obj); + edje_prop.scale = edje_object_scale_get(obj); + edje_prop.base_scale = edje_object_base_scale_get(obj); + edje_object_size_min_get(obj, &edje_prop.size_min[0], &edje_prop.size_min[1]); + edje_object_size_max_get(obj, &edje_prop.size_max[0], &edje_prop.size_max[1]); + + to = _pack_ui_obj_edje_prop(to, &edje_prop); + } + + code = _get_object_type_code(type_name); + + if (code == 0) { + return to; + } else if (code == UI_EVAS_IMAGE) { + image_prop_t image_prop; + + image_prop.load_dpi = evas_object_image_load_dpi_get(obj); + image_prop.source_clip = evas_object_image_source_clip_get(obj); + image_prop.filled = evas_object_image_filled_get(obj); + image_prop.content_hint = evas_object_image_content_hint_get(obj); + image_prop.alpha = evas_object_image_alpha_get(obj); + evas_object_image_border_get(obj, &(image_prop.border[0]), + &(image_prop.border[1]), + &(image_prop.border[2]), + &(image_prop.border[3])); + image_prop.border_scale = evas_object_image_border_scale_get(obj); + image_prop.pixels_dirty = evas_object_image_pixels_dirty_get(obj); + image_prop.load_orientation = evas_object_image_load_orientation_get(obj); + image_prop.border_center_fill = evas_object_image_border_center_fill_get(obj); + evas_object_image_size_get(obj, &(image_prop.size[0]), &(image_prop.size[1])); + image_prop.source_visible = evas_object_image_source_visible_get(obj); + evas_object_image_fill_get(obj, &(image_prop.fill[0]), + &(image_prop.fill[1]), + &(image_prop.fill[2]), + &(image_prop.fill[3])); + image_prop.load_scale_down = evas_object_image_load_scale_down_get(obj); + image_prop.scale_hint = evas_object_image_scale_hint_get(obj); + image_prop.source_events = evas_object_image_source_events_get(obj); + //evas_object_image_animated_frame_count_get(obj); - unstable + image_prop.frame_count = 0; + image_prop.evas_image_stride = evas_object_image_stride_get(obj); + + to = _pack_image_prop(to, &image_prop); + } else if (code == UI_EVAS_LINE) { + line_prop_t line_prop; + + evas_object_line_xy_get(obj, &(line_prop.xy[0]), + &(line_prop.xy[1]), + &(line_prop.xy[2]), + &(line_prop.xy[3])); + + to = _pack_line_prop(to, &line_prop); + } else if (code == UI_EVAS_TEXT) { + text_prop_t text_prop; + const char *text_font; + + evas_object_text_font_get(obj, &text_font, &(text_prop.size)); + _strncpy(text_prop.font, text_font, MAX_PATH_LENGTH); + _strncpy(text_prop.text, evas_object_text_text_get(obj), MAX_PATH_LENGTH); + _strncpy(text_prop.delim, evas_object_text_bidi_delimiters_get(obj), MAX_PATH_LENGTH); + text_prop.ellipsis = evas_object_text_ellipsis_get(obj); + text_prop.style = evas_object_text_style_get(obj); + evas_object_text_shadow_color_get(obj, &(text_prop.shadow_color[0]), + &(text_prop.shadow_color[1]), + &(text_prop.shadow_color[2]), + &(text_prop.shadow_color[3])); + evas_object_text_glow_color_get(obj, &(text_prop.glow_color[0]), + &(text_prop.glow_color[1]), + &(text_prop.glow_color[2]), + &(text_prop.glow_color[3])); + evas_object_text_glow2_color_get(obj, &(text_prop.glow2_color[0]), + &(text_prop.glow2_color[1]), + &(text_prop.glow2_color[2]), + &(text_prop.glow2_color[3])); + evas_object_text_outline_color_get(obj, &(text_prop.outline_color[0]), + &(text_prop.outline_color[1]), + &(text_prop.outline_color[2]), + &(text_prop.outline_color[3])); + evas_object_text_style_pad_get(obj, &(text_prop.style_pad[0]), + &(text_prop.style_pad[1]), + &(text_prop.style_pad[2]), + &(text_prop.style_pad[3])); + text_prop.direction = evas_object_text_direction_get(obj); + + to = _pack_text_prop(to, &text_prop); + } else if (code == UI_EVAS_TEXTBLOCK) { + textblock_prop_t textblock_prop; + + _strncpy(textblock_prop.replace_char, evas_object_textblock_replace_char_get(obj), MAX_PATH_LENGTH); + textblock_prop.valign = evas_object_textblock_valign_get(obj); + _strncpy(textblock_prop.delim, evas_object_textblock_bidi_delimiters_get(obj), MAX_PATH_LENGTH); + textblock_prop.newline = evas_object_textblock_legacy_newline_get(obj); + _strncpy(textblock_prop.markup, evas_object_textblock_text_markup_get(obj), MAX_PATH_LENGTH); + + to = _pack_textblock_prop(to, &textblock_prop); + } else if (code == UI_EVAS_TABLE) { + table_prop_t table_prop; + + table_prop.homogeneous = evas_object_table_homogeneous_get(obj); + evas_object_table_align_get(obj, &(table_prop.align[0]), + &(table_prop.align[1])); + evas_object_table_padding_get(obj, &(table_prop.padding[0]), + &(table_prop.padding[1])); + table_prop.mirrored = evas_object_table_mirrored_get(obj); + evas_object_table_col_row_size_get(obj, &(table_prop.col_row_size[0]), + &(table_prop.col_row_size[1])); + + to = _pack_table_prop(to, &table_prop); + } else if (code == UI_EVAS_BOX) { + box_prop_t box_prop; + + evas_object_box_align_get(obj, &(box_prop.align[0]), + &(box_prop.align[1])); + + to = _pack_box_prop(to, &box_prop); + } else if (code == UI_EVAS_GRID) { + grid_prop_t grid_prop; + + grid_prop.mirrored = evas_object_grid_mirrored_get(obj); + + to = _pack_grid_prop(to, &grid_prop); + } else if (code == UI_EVAS_TEXTGRID) { + textgrid_prop_t textgrid_prop; + + evas_object_textgrid_size_get(obj, &(textgrid_prop.size[0]), + &(textgrid_prop.size[1])); + evas_object_textgrid_cell_size_get(obj, &(textgrid_prop.cell_size[0]), + &(textgrid_prop.cell_size[1])); + + to = _pack_textgrid_prop(to, &textgrid_prop); + } else if (code == UI_ELM_BACKGROUND) { + bg_prop_t bg_prop; + + elm_bg_color_get(obj, &(bg_prop.color[0]), + &(bg_prop.color[1]), + &(bg_prop.color[2])); + bg_prop.option = elm_bg_option_get(obj); + + to = _pack_bg_prop(to, &bg_prop); + } else if (code == UI_ELM_BUTTON) { + button_prop_t button_prop; + + button_prop.initial_timeout = elm_button_autorepeat_initial_timeout_get(obj); + button_prop.gap_timeout = elm_button_autorepeat_gap_timeout_get(obj); + button_prop.autorepeat = elm_button_autorepeat_get(obj); + + to = _pack_button_prop(to, &button_prop); + } else if (code == UI_ELM_CHECK) { + check_prop_t check_prop; + + check_prop.state = elm_check_state_get(obj); + + to = _pack_check_prop(to, &check_prop); + } else if (code == UI_ELM_COLORSELECTOR) { + colorselector_prop_t colorselector_prop; + + elm_colorselector_color_get(obj, &(colorselector_prop.color[0]), + &(colorselector_prop.color[1]), + &(colorselector_prop.color[2]), + &(colorselector_prop.color[3])); + _strncpy(colorselector_prop.palette_name, elm_colorselector_palette_name_get(obj), MAX_PATH_LENGTH); + colorselector_prop.mode = elm_colorselector_mode_get(obj); + + to = _pack_colorselector_prop(to, &colorselector_prop); + } else if (code == UI_ELM_CTXPOPUP) { + ctxpopup_prop_t ctxpopup_prop; + + ctxpopup_prop.horizontal = elm_ctxpopup_horizontal_get(obj); + + to = _pack_ctxpopup_prop(to, &ctxpopup_prop); + } else if (code == UI_ELM_DATETIME) { + datetime_prop_t datetime_prop; + struct tm currtime; + + _strncpy(datetime_prop.format, elm_datetime_format_get(obj), MAX_PATH_LENGTH); + elm_datetime_value_get(obj, &currtime); + datetime_prop.value[0] = currtime.tm_sec; + datetime_prop.value[1] = currtime.tm_min; + datetime_prop.value[2] = currtime.tm_hour; + datetime_prop.value[3] = currtime.tm_mday; + datetime_prop.value[4] = currtime.tm_mon; + datetime_prop.value[5] = currtime.tm_year; + datetime_prop.value[6] = currtime.tm_wday; + datetime_prop.value[7] = currtime.tm_yday; + + to = _pack_datetime_prop(to, &datetime_prop); + } else if (code == UI_ELM_ENTRY) { + entry_prop_t entry_prop; + + _strncpy(entry_prop.entry, elm_entry_entry_get(obj), MAX_PATH_LENGTH); + entry_prop.scrollable = elm_entry_scrollable_get(obj); + entry_prop.panel_show_on_demand = elm_entry_input_panel_show_on_demand_get(obj); + entry_prop.menu_disabled = elm_entry_context_menu_disabled_get(obj); + entry_prop.cnp_mode = elm_entry_cnp_mode_get(obj); + entry_prop.editable = elm_entry_editable_get(obj); + _strncpy(entry_prop.hover_style, elm_entry_anchor_hover_style_get(obj), MAX_PATH_LENGTH); + entry_prop.single_line= elm_entry_single_line_get(obj); + entry_prop.password = elm_entry_password_get(obj); + entry_prop.autosave = elm_entry_autosave_get(obj); + entry_prop.prediction_allow = elm_entry_prediction_allow_get(obj); + entry_prop.panel_enabled = elm_entry_input_panel_enabled_get(obj); + entry_prop.cursor_pos = elm_entry_cursor_pos_get(obj); + entry_prop.cursor_is_format = elm_entry_cursor_is_format_get(obj); + entry_prop.cursor_content = elm_entry_cursor_content_get(obj); + _strncpy(entry_prop.selection, elm_entry_selection_get(obj), MAX_PATH_LENGTH); + entry_prop.is_visible_format = elm_entry_cursor_is_visible_format_get(obj); + + to = _pack_entry_prop(to, &entry_prop); + } else if (code == UI_ELM_FLIP) { + flip_prop_t flip_prop; + + flip_prop.interaction = elm_flip_interaction_get(obj); + flip_prop.front_visible = elm_flip_front_visible_get(obj); + + to = _pack_flip_prop(to, &flip_prop); + } else if (code == UI_ELM_GENGRID) { + gengrid_prop_t gengrid_prop; + + elm_gengrid_align_get(obj, &(gengrid_prop.align[0]), + &(gengrid_prop.align[1])); + gengrid_prop.filled = elm_gengrid_filled_get(obj); + elm_gengrid_page_relative_get(obj, &(gengrid_prop.relative[0]), + &(gengrid_prop.relative[1])); + gengrid_prop.multi_select = elm_gengrid_multi_select_get(obj); + elm_gengrid_group_item_size_get(obj, &(gengrid_prop.group_item_size[0]), + &(gengrid_prop.group_item_size[1])); + gengrid_prop.select_mode = elm_gengrid_select_mode_get(obj); + gengrid_prop.render_mode = elm_gengrid_reorder_mode_get(obj); + gengrid_prop.highlight_mode = elm_gengrid_highlight_mode_get(obj); + elm_gengrid_item_size_get(obj, &(gengrid_prop.item_size[0]), + &(gengrid_prop.item_size[1])); + gengrid_prop.multi_select_mode = elm_gengrid_multi_select_mode_get(obj); + gengrid_prop.horizontal = elm_gengrid_horizontal_get(obj); + gengrid_prop.wheel_disabled = elm_gengrid_wheel_disabled_get(obj); + gengrid_prop.items_count = elm_gengrid_items_count(obj); + + to = _pack_gengrid_prop(to, &gengrid_prop); + } else if (code == UI_ELM_GENLIST) { + genlist_prop_t genlist_prop; + + genlist_prop.multi_select = elm_genlist_multi_select_get(obj); + genlist_prop.genlist_mode = elm_genlist_mode_get(obj); + genlist_prop.items_count = elm_genlist_items_count(obj); + genlist_prop.homogeneous = elm_genlist_homogeneous_get(obj); + genlist_prop.block_count = elm_genlist_block_count_get(obj); + genlist_prop.timeout = elm_genlist_longpress_timeout_get(obj); + genlist_prop.reorder_mode = elm_genlist_reorder_mode_get(obj); + genlist_prop.decorate_mode = elm_genlist_decorate_mode_get(obj); + genlist_prop.effect_enabled = elm_genlist_tree_effect_enabled_get(obj); + genlist_prop.select_mode = elm_genlist_select_mode_get(obj); + genlist_prop.highlight_mode = elm_genlist_highlight_mode_get(obj); + genlist_prop.realization_mode = elm_genlist_realization_mode_get(obj); + + to = _pack_genlist_prop(to, &genlist_prop); + } else if (code == UI_ELM_GLVIEW) { + glview_prop_t glview_prop; + + elm_glview_size_get(obj, &(glview_prop.size[0]), + &(glview_prop.size[1])); + glview_prop.rotation = elm_glview_rotation_get(obj); + + to = _pack_glview_prop(to, &glview_prop); + } else if (code == UI_ELM_ICON) { + icon_prop_t icon_prop; + + icon_prop.lookup = elm_icon_order_lookup_get(obj); + _strncpy(icon_prop.standard, elm_icon_standard_get(obj), MAX_PATH_LENGTH); + + to = _pack_icon_prop(to, &icon_prop); + } else if (code == UI_ELM_IMAGE) { + elm_image_prop_t elm_image_prop; + + elm_image_prop.editable = elm_image_editable_get(obj); + // elm_image_animated_available_get(obj); - unstable + elm_image_prop.animated_available = EINA_FALSE; + // elm_image_animated_play_get(obj); - unstable + elm_image_prop.play = EINA_FALSE; + elm_image_prop.smooth = elm_image_smooth_get(obj); + elm_image_prop.no_scale = elm_image_no_scale_get(obj); + elm_image_prop.animated = elm_image_animated_get(obj); + elm_image_prop.aspect_fixed = elm_image_aspect_fixed_get(obj); + elm_image_prop.orient = elm_image_orient_get(obj); + elm_image_prop.fill_outside = elm_image_fill_outside_get(obj); + elm_image_resizable_get(obj, &(elm_image_prop.resizable[0]), + &(elm_image_prop.resizable[1])); + elm_image_object_size_get(obj, &(elm_image_prop.size[0]), + &(elm_image_prop.size[1])); + + to = _pack_elm_image_prop(to, &elm_image_prop); + } else if (code == UI_ELM_INDEX) { + index_prop_t index_prop; + + index_prop.autohide_disabled = elm_index_autohide_disabled_get(obj); + index_prop.omit_enabled = elm_index_omit_enabled_get(obj); + index_prop.priority = elm_index_priority_get(obj); + index_prop.horizontal = elm_index_horizontal_get(obj); + index_prop.change_time = elm_index_delay_change_time_get(obj); + index_prop.indicator_disabled = elm_index_indicator_disabled_get(obj); + index_prop.item_level = elm_index_item_level_get(obj); + + to = _pack_index_prop(to, &index_prop); + } else if (code == UI_ELM_LABEL) { + label_prop_t label_prop; + + label_prop.wrap_width = elm_label_wrap_width_get(obj); + label_prop.speed = elm_label_slide_speed_get(obj); + label_prop.mode = elm_label_slide_mode_get(obj); + + to = _pack_label_prop(to, &label_prop); + } else if (code == UI_ELM_LIST) { + list_prop_t list_prop; + + list_prop.horizontal = elm_list_horizontal_get(obj); + list_prop.select_mode = elm_list_select_mode_get(obj); + list_prop.focus_on_selection = elm_list_focus_on_selection_get(obj); + list_prop.multi_select = elm_list_multi_select_get(obj); + list_prop.multi_select_mode = elm_list_multi_select_mode_get(obj); + list_prop.mode = elm_list_mode_get(obj); + + to = _pack_list_prop(to, &list_prop); + } else if (code == UI_ELM_MAP) { + map_prop_t map_prop; + + map_prop.zoom = elm_map_zoom_get(obj); + map_prop.paused = elm_map_paused_get(obj); + map_prop.wheel_disabled = elm_map_wheel_disabled_get(obj); + map_prop.zoom_min = elm_map_zoom_min_get(obj); + elm_map_rotate_get(obj, &(map_prop.rotate_degree), + &(map_prop.rotate[0]), + &(map_prop.rotate[1])); + _strncpy(map_prop.agent, elm_map_user_agent_get(obj), MAX_PATH_LENGTH); + map_prop.zoom_max = elm_map_zoom_max_get(obj); + map_prop.zoom_mode = elm_map_zoom_mode_get(obj); + elm_map_region_get(obj, &(map_prop.region[0]), + &(map_prop.region[1])); + + to = _pack_map_prop(to, &map_prop); + } else if (code == UI_ELM_NOTIFY) { + notify_prop_t notify_prop; + + elm_notify_align_get(obj, &(notify_prop.align[0]), + &(notify_prop.align[1])); + notify_prop.allow_events = elm_notify_allow_events_get(obj); + notify_prop.timeout = elm_notify_timeout_get(obj); + + to = _pack_notify_prop(to, ¬ify_prop); + } else if (code == UI_ELM_PANEL) { + panel_prop_t panel_prop; + + panel_prop.orient = elm_panel_orient_get(obj); + panel_prop.hidden = elm_panel_hidden_get(obj); + panel_prop.scrollable = elm_panel_scrollable_get(obj); + + to = _pack_panel_prop(to, &panel_prop); + } else if (code == UI_ELM_PHOTO) { + photo_prop_t photo_prop; + + photo_prop.editable = elm_photo_editable_get(obj); + photo_prop.fill_inside = elm_photo_fill_inside_get(obj); + photo_prop.aspect_fixed = elm_photo_aspect_fixed_get(obj); + photo_prop.size = elm_photo_size_get(obj); + + to = _pack_photo_prop(to, &photo_prop); + } else if (code == UI_ELM_PHOTOCAM) { + photocam_prop_t photocam_prop; + + photocam_prop.paused = elm_photocam_paused_get(obj); + _strncpy(photocam_prop.file, elm_photocam_file_get(obj), MAX_PATH_LENGTH); + photocam_prop.gesture_enabled = elm_photocam_gesture_enabled_get(obj); + photocam_prop.zoom = elm_photocam_zoom_get(obj); + photocam_prop.zoom_mode = elm_photocam_zoom_mode_get(obj); + elm_photocam_image_size_get(obj, &(photocam_prop.image_size[0]), + &(photocam_prop.image_size[1])); + + to = _pack_photocam_prop(to, &photocam_prop); + } else if (code == UI_ELM_POPUP) { + popup_prop_t popup_prop; + + elm_popup_align_get(obj, &(popup_prop.align[0]), + &(popup_prop.align[1])); + popup_prop.allow_events = elm_popup_allow_events_get(obj); + popup_prop.wrap_type = elm_popup_content_text_wrap_type_get(obj); + popup_prop.orient = elm_popup_orient_get(obj); + popup_prop.timeout = elm_popup_timeout_get(obj); + + to = _pack_popup_prop(to, &popup_prop); + } else if (code == UI_ELM_PROGRESSBAR) { + progressbar_prop_t progressbar_prop; + + progressbar_prop.span_size = elm_progressbar_span_size_get(obj); + progressbar_prop.pulse = elm_progressbar_pulse_get(obj); + progressbar_prop.value = elm_progressbar_value_get(obj); + progressbar_prop.inverted = elm_progressbar_inverted_get(obj); + progressbar_prop.horizontal = elm_progressbar_horizontal_get(obj); + _strncpy(progressbar_prop.unit_format, elm_progressbar_unit_format_get(obj), MAX_PATH_LENGTH); + + to = _pack_progressbar_prop(to, &progressbar_prop); + } else if (code == UI_ELM_RADIO) { + radio_prop_t radio_prop; + + radio_prop.state_value = elm_radio_state_value_get(obj); + radio_prop.value = elm_radio_value_get(obj); + + to = _pack_radio_prop(to, &radio_prop); + } else if (code == UI_ELM_SEGMENTCONTROL) { + segmencontrol_prop_t segmencontrol_prop; + + segmencontrol_prop.item_count = elm_segment_control_item_count_get(obj); + + to = _pack_segmencontrol_prop(to, &segmencontrol_prop); + } else if (code == UI_ELM_SLIDER) { + slider_prop_t slider_prop; + + slider_prop.horizontal = elm_slider_horizontal_get(obj); + slider_prop.value = elm_slider_value_get(obj); + _strncpy(slider_prop.format, elm_slider_indicator_format_get(obj), MAX_PATH_LENGTH); + + to = _pack_slider_prop(to, &slider_prop); + } else if (code == UI_ELM_SPINNER) { + spinner_prop_t spinner_prop; + + elm_spinner_min_max_get(obj, &(spinner_prop.min_max[0]), + &(spinner_prop.min_max[1])); + spinner_prop.step = elm_spinner_step_get(obj); + spinner_prop.wrap = elm_spinner_wrap_get(obj); + spinner_prop.interval = elm_spinner_interval_get(obj); + spinner_prop.round = elm_spinner_round_get(obj); + spinner_prop.editable = elm_spinner_editable_get(obj); + spinner_prop.base = elm_spinner_base_get(obj); + spinner_prop.value = elm_spinner_value_get(obj); + _strncpy(spinner_prop.format, elm_spinner_label_format_get(obj), MAX_PATH_LENGTH); + + to = _pack_spinner_prop(to, &spinner_prop); + } else if (code == UI_ELM_TOOLBAR) { + toolbar_prop_t toolbar_prop; + + toolbar_prop.reorder_mode = elm_toolbar_reorder_mode_get(obj); + toolbar_prop.transverse_expanded = elm_toolbar_transverse_expanded_get(obj); + toolbar_prop.homogeneous = elm_toolbar_homogeneous_get(obj); + toolbar_prop.align = elm_toolbar_align_get(obj); + toolbar_prop.select_mode = elm_toolbar_select_mode_get(obj); + toolbar_prop.icon_size = elm_toolbar_icon_size_get(obj); + toolbar_prop.horizontal = elm_toolbar_horizontal_get(obj); + toolbar_prop.standard_priority = elm_toolbar_standard_priority_get(obj); + toolbar_prop.items_count = elm_toolbar_items_count(obj); + + to = _pack_toolbar_prop(to, &toolbar_prop); + } else if (code == UI_ELM_TOOLTIP) { + tooltip_prop_t tooltip_prop; + + _strncpy(tooltip_prop.style, elm_object_tooltip_style_get(obj), MAX_PATH_LENGTH); + tooltip_prop.window_mode = elm_object_tooltip_window_mode_get(obj); + + to = _pack_tooltip_prop(to, &tooltip_prop); + } else if (code == UI_ELM_WIN) { + win_prop_t win_prop; + + win_prop.iconfield = elm_win_iconified_get(obj); + win_prop.maximized = elm_win_maximized_get(obj); + win_prop.modal = elm_win_modal_get(obj); + _strncpy(win_prop.icon_name, elm_win_icon_name_get(obj), MAX_PATH_LENGTH); + win_prop.withdrawn = elm_win_withdrawn_get(obj); + _strncpy(win_prop.role, elm_win_role_get(obj), MAX_PATH_LENGTH); + elm_win_size_step_get(obj, &(win_prop.size_step[0]), + &(win_prop.size_step[1])); + _strncpy(win_prop.highlight_style, elm_win_focus_highlight_style_get(obj), MAX_PATH_LENGTH); + win_prop.borderless = elm_win_borderless_get(obj); + win_prop.highlight_enabled = elm_win_focus_highlight_enabled_get(obj); + _strncpy(win_prop.title, elm_win_title_get(obj), MAX_PATH_LENGTH); + win_prop.alpha = elm_win_alpha_get(obj); + win_prop.urgent = elm_win_urgent_get(obj); + win_prop.rotation = elm_win_rotation_get(obj); + win_prop.sticky = elm_win_sticky_get(obj); + win_prop.highlight_animate = elm_win_focus_highlight_animate_get(obj); + win_prop.aspect = elm_win_aspect_get(obj); + win_prop.indicator_opacity = elm_win_indicator_opacity_get(obj); + win_prop.demand_attention = elm_win_demand_attention_get(obj); + win_prop.layer = elm_win_layer_get(obj); + _strncpy(win_prop.profile, elm_win_profile_get(obj), MAX_PATH_LENGTH); + win_prop.shaped = elm_win_shaped_get(obj); + win_prop.fullscreen = elm_win_fullscreen_get(obj); + win_prop.indicator_mode = elm_win_indicator_mode_get(obj); + win_prop.conformant = elm_win_conformant_get(obj); + elm_win_size_base_get(obj, &(win_prop.size_base[0]), + &(win_prop.size_base[1])); + win_prop.quickpanel = elm_win_quickpanel_get(obj); + win_prop.rotation_supported = elm_win_wm_rotation_supported_get(obj); + elm_win_screen_dpi_get(obj, &(win_prop.screen_dpi[0]), + &(win_prop.screen_dpi[1])); + win_prop.win_type = elm_win_type_get(obj); + to = _pack_win_prop(to, &win_prop); + + } + + return to; +} + +Eina_Bool _get_shot_in_bg(Evas_Object *obj) +{ + char type_name[MAX_PATH_LENGTH]; + Eina_Bool can_shot_in_bg = EINA_FALSE; + + _strncpy(type_name, evas_object_type_get(obj), MAX_PATH_LENGTH); + + if (!strcmp(type_name, "rectangle") || + !strcmp(type_name, "image") || + !strcmp(type_name, "elm_image") || + !strcmp(type_name, "elm_icon")) + can_shot_in_bg = EINA_TRUE; + + return can_shot_in_bg; +} + +char *pack_ui_obj_screenshot(char *to, Evas_Object *obj) +{ + char screenshot[MAX_PATH_LENGTH]; + enum ErrorCode err_code = ERR_NO; + Eina_Bool exists; + + screenshot[0] = '\0'; + + pthread_mutex_lock(&request_lock); + + exists = _get_obj_exists(obj); + + if (!exists) { + err_code = ERR_UI_OBJ_NOT_FOUND; + ui_viewer_log("can't take screenshot of not existing obj = %p\n", obj); + } else { + Evas_Object *win_id; + Eina_Bool win_focus; + Evas *evas; + + evas_object_ref(obj); + evas = evas_object_evas_get(obj); + evas_event_freeze(evas); + win_id = _get_win_id(evas); + win_focus = elm_win_focus_get(win_id); + + if (win_focus || _get_shot_in_bg(obj)) + ui_viewer_capture_screen(screenshot, obj); + else + err_code = ERR_UI_OBJ_SCREENSHOT_FAILED; + evas_event_thaw(evas); + evas_object_unref(obj); + } + + ui_viewer_log("screenshot: obj : %p, err_code : %d, path : %s\n", obj, err_code, screenshot); + + to = pack_int32(to, err_code); + to = pack_string(to, screenshot); + + pthread_mutex_unlock(&request_lock); + + return to; +} diff --git a/ui_viewer/ui_viewer_data.h b/ui_viewer/ui_viewer_data.h new file mode 100644 index 0000000..a16ef41 --- /dev/null +++ b/ui_viewer/ui_viewer_data.h @@ -0,0 +1,551 @@ +/* + * DA manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Lyupa Anastasia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + +#ifndef _UI_VIEWER_DATA_ +#define _UI_VIEWER_DATA_ + +#include + +#define MAX_PATH_LENGTH 256 +#define MAX_TEXT_LENGTH 1024 + +enum ErrorCode { + ERR_NO = 0, /* success */ + ERR_ALREADY_RUNNING = -102, /* already running */ + ERR_UI_OBJ_NOT_FOUND = -207, /* requested ui object is not found */ + ERR_UI_OBJ_SCREENSHOT_FAILED = -208, /* requested ui object is in background */ + ERR_UNKNOWN = -999 /* unknown error */ +}; + +enum hierarchy_status_t { + HIERARCHY_NOT_RUNNING, + HIERARCHY_RUNNING, + HIERARCHY_CANCELLED +}; + +enum rendering_option_t { + RENDER_NONE = 0x0, + RENDER_ALL = 0x1, + RENDER_ELM = 0x2, + RENDER_NONE_HOST_OPT = 0x3 /* it's equal to RENDER_NONE for target*/ +}; + +enum ui_obj_category_t { + UI_UNDEFINED = 0x00, + UI_EVAS = 0x01, + UI_ELM = 0x02, + UI_EDJE = 0x03 +}; + +enum ui_obj_code_t { + UI_CODE_UNDEFINED = 0x0000, + /* Evas */ + UI_EVAS_UNDEFINED = 0x0100, + UI_EVAS_IMAGE = 0x0101, + UI_EVAS_LINE = 0x0102, + UI_EVAS_POLYGON = 0X0103, + UI_EVAS_RECTANGLE = 0X0104, + UI_EVAS_TEXT = 0x0105, + UI_EVAS_TEXTBLOCK = 0x0106, + UI_EVAS_VECTORS = 0x0107, + UI_EVAS_TABLE = 0x0108, + UI_EVAS_BOX = 0x0109, + UI_EVAS_GRID = 0x010A, + UI_EVAS_TEXTGRID = 0x010B, + UI_EVAS_SMART = 0x010C, + /* Elementary */ + UI_ELM_UNDEFINED = 0x0200, + UI_ELM_BACKGROUND = 0x0201, + UI_ELM_BUTTON = 0x0202, + UI_ELM_CHECK = 0x0203, + UI_ELM_COLORSELECTOR = 0x0204, + UI_ELM_CTXPOPUP = 0x0205, + UI_ELM_DATETIME = 0x0206, + UI_ELM_ENTRY = 0x0207, + UI_ELM_FLIP = 0x0208, + UI_ELM_GENGRID = 0x0209, + UI_ELM_GENLIST = 0x020A, + UI_ELM_GLVIEW = 0x020B, + UI_ELM_ICON = 0x020C, + UI_ELM_IMAGE = 0x020D, + UI_ELM_INDEX = 0x020E, + UI_ELM_LABEL = 0x020F, + UI_ELM_LIST = 0x0210, + UI_ELM_MAP = 0x0211, + UI_ELM_NOTIFY = 0x0212, + UI_ELM_PANEL = 0x0213, + UI_ELM_PHOTO = 0x0214, + UI_ELM_PHOTOCAM = 0x0215, + UI_ELM_PLUG = 0x0216, + UI_ELM_POPUP = 0x0217, + UI_ELM_PROGRESSBAR = 0x0218, + UI_ELM_RADIO = 0x0219, + UI_ELM_SEGMENTCONTROL = 0x021A, + UI_ELM_SLIDER = 0x021B, + UI_ELM_SPINNER = 0x021C, + UI_ELM_TOOLBAR = 0x021D, + UI_ELM_TOOLTIP = 0x021E, + UI_ELM_WIN = 0x021F, + /* Edje */ + UI_EDJE_UNDEFINED = 0x0300, + UI_EDJE_EDJE = 0x0301, + UI_EDJE_BOX = 0x0302, + UI_EDJE_DRAG = 0x0303, + UI_EDJE_SWALLOW = 0x0304, + UI_EDJE_TABLE = 0x0305, + UI_EDJE_TEXT = 0x0306, + UI_EDJE_TEXTBLOCK = 0x0307, + UI_EDJE_RECTANGLE = 0x0308, + UI_EDJE_VECTORS = 0x0309, + UI_EDJE_BACKGROUND = 0x0309 +}; + +typedef struct _ui_obj_info_t { + Evas_Object *id; + enum ui_obj_category_t category; + enum ui_obj_code_t code; + char name[MAX_PATH_LENGTH]; + struct timeval rendering_tv; + Evas_Object *parent_id; +} ui_obj_info_t; + +typedef struct _ui_obj_elm_prop_t { + char text[MAX_TEXT_LENGTH]; + char style[MAX_PATH_LENGTH]; + Eina_Bool disabled; + char type[MAX_PATH_LENGTH]; +} ui_obj_elm_prop_t; + +typedef struct _ui_obj_edje_prop_t { + Eina_Bool animation; + Eina_Bool play; + double scale; + double base_scale; + Evas_Coord size_min[2]; + Evas_Coord size_max[2]; +} ui_obj_edje_prop_t; + +typedef struct _ui_obj_prop_t { + Evas_Coord geometry[4]; + Eina_Bool focus; + char name[MAX_PATH_LENGTH]; + Eina_Bool visible; + int color[4]; + Eina_Bool anti_alias; + float scale; + Evas_Coord size_min[2]; + Evas_Coord size_max[2]; + Evas_Coord size_request[2]; + double size_align[2]; + double size_weight[2]; + Evas_Coord size_padding[4]; + Evas_Render_Op render_op; +} ui_obj_prop_t; + +typedef struct _image_prop_t { + double load_dpi; + Eina_Bool source_clip; + Eina_Bool filled; + char content_hint; + Eina_Bool alpha; + int border[4]; + double border_scale; + Eina_Bool pixels_dirty; + Eina_Bool load_orientation; + char border_center_fill; + int size[2]; + Eina_Bool source_visible; + Evas_Coord fill[4]; + int load_scale_down; + char scale_hint; + Eina_Bool source_events; + int frame_count; + int evas_image_stride; +} image_prop_t; + +typedef struct _line_prop_t { + Evas_Coord xy[4]; +} line_prop_t; + +typedef struct _text_prop_t { + char font[MAX_PATH_LENGTH]; + int size; + char text[MAX_PATH_LENGTH]; + char delim[MAX_PATH_LENGTH]; + double ellipsis; + char style; + int shadow_color[4]; + int glow_color[4]; + int glow2_color[4]; + int outline_color[4]; + int style_pad[4]; + char direction; +} text_prop_t; + +typedef struct _textblock_prop_t { + char replace_char[MAX_PATH_LENGTH]; + double valign; + char delim[MAX_PATH_LENGTH]; + Eina_Bool newline; + char markup[MAX_PATH_LENGTH]; +} textblock_prop_t; + +typedef struct _table_prop_t { + char homogeneous; + double align[2]; + Evas_Coord padding[2]; + Eina_Bool mirrored; + int col_row_size[2]; +} table_prop_t; + +typedef struct _box_prop_t { + double align[2]; +} box_prop_t; + +typedef struct _grid_prop_t { + Eina_Bool mirrored; +} grid_prop_t; + +typedef struct _textgrid_prop_t { + int size[2]; + int cell_size[2]; +} textgrid_prop_t; + +typedef struct _bg_prop_t { + int color[3]; + char option; +} bg_prop_t; + +typedef struct _button_prop_t { + double initial_timeout; + double gap_timeout; + Eina_Bool autorepeat; +} button_prop_t; + +typedef struct _check_prop_t { + Eina_Bool state; +} check_prop_t; + +typedef struct _colorselector_prop_t { + int color[4]; + char palette_name[MAX_PATH_LENGTH]; + char mode; +} colorselector_prop_t; + +typedef struct _ctxpopup_prop_t { + Eina_Bool horizontal; +} ctxpopup_prop_t; + +typedef struct _datetime_prop_t { + char format[MAX_PATH_LENGTH]; + int value[8]; +} datetime_prop_t; + +typedef struct _entry_prop_t { + char entry[MAX_PATH_LENGTH]; + Eina_Bool scrollable; + Eina_Bool panel_show_on_demand; + Eina_Bool menu_disabled; + char cnp_mode; + Eina_Bool editable; + char hover_style[MAX_PATH_LENGTH]; + Eina_Bool single_line; + Eina_Bool password; + Eina_Bool autosave; + Eina_Bool prediction_allow; + Eina_Bool panel_enabled; + int cursor_pos; + Eina_Bool cursor_is_format; + char *cursor_content; + char selection[MAX_PATH_LENGTH]; + Eina_Bool is_visible_format; +} entry_prop_t; + +typedef struct _flip_prop_t { + char interaction; + Eina_Bool front_visible; +} flip_prop_t; + +typedef struct _gengrid_prop_t { + double align[2]; + Eina_Bool filled; + double relative[2]; + Eina_Bool multi_select; + Evas_Coord group_item_size[2]; + char select_mode; + Eina_Bool render_mode; + Eina_Bool highlight_mode; + Evas_Coord item_size[2]; + char multi_select_mode; + Eina_Bool horizontal; + Eina_Bool wheel_disabled; + int items_count; +} gengrid_prop_t; + +typedef struct _genlist_prop_t { + Eina_Bool multi_select; + char genlist_mode; + int items_count; + Eina_Bool homogeneous; + int block_count; + double timeout; + Eina_Bool reorder_mode; + Eina_Bool decorate_mode; + Eina_Bool effect_enabled; + char select_mode; + Eina_Bool highlight_mode; + Eina_Bool realization_mode; +} genlist_prop_t; + +typedef struct _glview_prop_t { + int size[2]; + int rotation; +} glview_prop_t; + +typedef struct _icon_prop_t { + char lookup; + char standard[MAX_PATH_LENGTH]; +} icon_prop_t; + +typedef struct _elm_image_prop_t { + Eina_Bool editable; + Eina_Bool play; + Eina_Bool smooth; + Eina_Bool no_scale; + Eina_Bool animated; + Eina_Bool aspect_fixed; + char orient; + Eina_Bool fill_outside; + Eina_Bool resizable[2]; + Eina_Bool animated_available; + int size[2]; +} elm_image_prop_t; + +typedef struct _index_prop_t { + Eina_Bool autohide_disabled; + Eina_Bool omit_enabled; + int priority; + Eina_Bool horizontal; + double change_time; + Eina_Bool indicator_disabled; + int item_level; +} index_prop_t; + +typedef struct _label_prop_t { + int wrap_width; + double speed; + char mode; +} label_prop_t; + +typedef struct _list_prop_t { + Eina_Bool horizontal; + char select_mode; + Eina_Bool focus_on_selection; + Eina_Bool multi_select; + char multi_select_mode; + char mode; +} list_prop_t; + +typedef struct _map_prop_t { + int zoom; + Eina_Bool paused; + Eina_Bool wheel_disabled; + int zoom_min; + double rotate_degree; + Evas_Coord rotate[2]; + char agent[MAX_PATH_LENGTH]; + int zoom_max; + char zoom_mode; + double region[2]; +} map_prop_t; + +typedef struct _notify_prop_t { + double align[2]; + Eina_Bool allow_events; + double timeout; +} notify_prop_t; + +typedef struct _panel_prop_t { + char orient; + Eina_Bool hidden; + Eina_Bool scrollable; +} panel_prop_t; + +typedef struct _photo_prop_t { + Eina_Bool editable; + Eina_Bool fill_inside; + Eina_Bool aspect_fixed; + int size; +} photo_prop_t; + +typedef struct _photocam_prop_t { + Eina_Bool paused; + char file[MAX_PATH_LENGTH]; + Eina_Bool gesture_enabled; + double zoom; + char zoom_mode; + int image_size[2]; +} photocam_prop_t; + +typedef struct _popup_prop_t { + double align[2]; + Eina_Bool allow_events; + char wrap_type; + char orient; + double timeout; +} popup_prop_t; + +typedef struct _progressbar_prop_t { + Evas_Coord span_size; + Eina_Bool pulse; + double value; + Eina_Bool inverted; + Eina_Bool horizontal; + char unit_format[MAX_PATH_LENGTH]; +} progressbar_prop_t; + +typedef struct _radio_prop_t { + int state_value; + int value; +} radio_prop_t; + +typedef struct _segmencontrol_prop_t { + int item_count; +} segmencontrol_prop_t; + +typedef struct _slider_prop_t { + Eina_Bool horizontal; + double value; + char format[MAX_PATH_LENGTH]; +} slider_prop_t; + +typedef struct _spinner_prop_t { + double min_max[2]; + double step; + Eina_Bool wrap; + double interval; + int round; + Eina_Bool editable; + double base; + double value; + char format[MAX_PATH_LENGTH]; +} spinner_prop_t; + +typedef struct _toolbar_prop_t { + Eina_Bool reorder_mode; + Eina_Bool transverse_expanded; + Eina_Bool homogeneous; + double align; + char select_mode; + int icon_size; + Eina_Bool horizontal; + int standard_priority; + int items_count; +} toolbar_prop_t; + +typedef struct _tooltip_prop_t { + char style[MAX_PATH_LENGTH]; + Eina_Bool window_mode; +} tooltip_prop_t; + +typedef struct _win_prop_t { + Eina_Bool iconfield; + Eina_Bool maximized; + Eina_Bool modal; + char icon_name[MAX_PATH_LENGTH]; + Eina_Bool withdrawn; + char role[MAX_PATH_LENGTH]; + int size_step[2]; + char highlight_style[MAX_PATH_LENGTH]; + Eina_Bool borderless; + Eina_Bool highlight_enabled; + char title[MAX_PATH_LENGTH]; + Eina_Bool alpha; + Eina_Bool urgent; + int rotation; + Eina_Bool sticky; + Eina_Bool highlight_animate; + double aspect; + char indicator_opacity; + Eina_Bool demand_attention; + int layer; + char profile[MAX_PATH_LENGTH]; + Eina_Bool shaped; + Eina_Bool fullscreen; + char indicator_mode; + Eina_Bool conformant; + int size_base[2]; + Eina_Bool quickpanel; + Eina_Bool rotation_supported; + int screen_dpi[2]; + char win_type; +} win_prop_t; + +char *pack_string(char *to, const char *str); +char *pack_ui_obj_info_list(char *to, enum rendering_option_t rendering, + Eina_Bool *cancelled); +char *pack_ui_obj_screenshot(char *to, Evas_Object *obj); +enum hierarchy_status_t get_hierarchy_status(void); +void set_hierarchy_status(enum hierarchy_status_t status); + +static inline char *pack_int8(char *to, uint8_t val) +{ + *(uint8_t *)to = val; + return to + sizeof(uint8_t); +} + +static inline char *pack_int32(char *to, uint32_t val) +{ + *(uint32_t *)to = val; + return to + sizeof(uint32_t); +} + +static inline char *pack_int64(char *to, uint64_t val) +{ + *(uint64_t *)to = val; + return to + sizeof(uint64_t); +} + +static inline char *pack_float(char *to, float val) +{ + *(float *)to = val; + return to + sizeof(float); +} +static inline char *pack_ptr(char *to, const void *val) +{ + *(uint64_t *)to = (uint64_t)(uintptr_t)val; + return to + sizeof(uint64_t); +} + +static inline char *pack_timeval(char *to, struct timeval tv) +{ + to = pack_int32(to, tv.tv_sec); + to = pack_int32(to, tv.tv_usec * 1000); + + return to; +} + +#endif /* _UI_VIEWER_DATA_ */ diff --git a/ui_viewer/ui_viewer_lib.c b/ui_viewer/ui_viewer_lib.c new file mode 100644 index 0000000..ecd05a1 --- /dev/null +++ b/ui_viewer/ui_viewer_lib.c @@ -0,0 +1,401 @@ +/* + * DA manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Lyupa Anastasia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ui_viewer_lib.h" +#include "ui_viewer_utils.h" +#include "ui_viewer_data.h" + +static const char socket_name[] = "/tmp/da_ui.socket"; + +int g_timerfd = 0; +long g_total_alloc_size = 0; +pthread_t g_recvthread_id; + +__traceInfo gTraceInfo; + +static int createSocket(void); +static int create_recv_thread(void); +static void *recvThread(void __unused *data); + +__attribute__((constructor)) void init_ui_viewer(void) +{ + ui_viewer_clean_log(); + ui_viewer_log("constructor started\n"); + + if (createSocket() == 0) { + create_recv_thread(); + } +} + +__attribute__((destructor)) void finite_ui_viewer (void) +{ + ui_viewer_log("destructor started\n"); + + if (gTraceInfo.socket.daemonSock != -1) + close(gTraceInfo.socket.daemonSock); +} + +static int create_recv_thread(void) +{ + int err = pthread_create(&g_recvthread_id, NULL, recvThread, NULL); + + if (err) + PRINTMSG("failed to crate recv thread\n"); + + return err; +} + +// runtime configure the probe option +static void _configure(char* configstr) +{ + gTraceInfo.optionflag = atoll(configstr); +} + +void application_exit() +{ + pid_t gpid; + FILE *f = NULL; + char buf[MAX_PATH_LENGTH]; + const char manager_name[] = "da_manager"; + + gpid = getpgrp(); + snprintf(buf, sizeof(buf), "/proc/%d/cmdline", gpid); + f = fopen(buf, "r"); + if (f != NULL) { + fscanf(f, "%s", buf); + fclose(f); + if (strlen(buf) == strlen(manager_name) && + strncmp(buf, manager_name, sizeof(manager_name)) == 0) { + PRINTMSG("App termination: EXIT(0)"); + exit(0); + } + } + + PRINTMSG("App termination: kill all process group"); + killpg(gpid, SIGKILL); +} + +// create socket to daemon and connect +#define MSG_CONFIG_RECV 0x01 +#define MSG_MAPS_INST_LIST_RECV 0x02 +static int createSocket(void) +{ + char strerr_buf[MAX_PATH_LENGTH]; + ssize_t recvlen; + int clientLen, ret = 0; + struct sockaddr_un clientAddr; + log_t log; + + gTraceInfo.socket.daemonSock = + socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (gTraceInfo.socket.daemonSock != -1) { + memset(&clientAddr, '\0', sizeof(clientAddr)); + clientAddr.sun_family = AF_UNIX; + snprintf(clientAddr.sun_path, sizeof(socket_name), "%s", socket_name); + + clientLen = sizeof(clientAddr); + if (connect(gTraceInfo.socket.daemonSock, + (struct sockaddr *)&clientAddr, clientLen) >= 0) + { + char buf[64]; + int recved = 0; + + snprintf(buf, sizeof(buf), "%d %d", getpid(), getppid()); + print_log_str(APP_MSG_PID, buf); + + while (((recved & MSG_CONFIG_RECV) == 0) || + ((recved & MSG_MAPS_INST_LIST_RECV) == 0)) + { + PRINTMSG("wait incoming message %d\n", + gTraceInfo.socket.daemonSock); + recvlen = recv(gTraceInfo.socket.daemonSock, &log, + sizeof(log.type) + sizeof(log.length), + MSG_WAITALL); + + ui_viewer_log("recv %d\n", recvlen); + if (recvlen > 0) { + char *data_buf = NULL; + + data_buf = malloc(log.length); + + if (data_buf == NULL) { + PRINTERR("cannot allocate buf to recv msg"); + break; + } + + recvlen = recv(gTraceInfo.socket.daemonSock, data_buf, + log.length, MSG_WAITALL); + + if (recvlen != log.length) { + PRINTERR("Can not get data from daemon sock\n"); + goto free_data_buf; + } + + if (log.type == APP_MSG_CONFIG) { + PRINTMSG("APP_MSG_CONFIG"); + _configure(data_buf); + recved |= MSG_CONFIG_RECV; + } else if(log.type == APP_MSG_MAPS_INST_LIST) { + PRINTMSG("APP_MSG_MAPS_INST_LIST <%u>", *((uint32_t *)data_buf)); + // do nothing + recved |= MSG_MAPS_INST_LIST_RECV; + } else { + // unexpected case + PRINTERR("unknown message! %d", log.type); + } + +free_data_buf: + if (data_buf != NULL) + free(data_buf); + + } else if (recvlen < 0) { + close(gTraceInfo.socket.daemonSock); + gTraceInfo.socket.daemonSock = -1; + PRINTERR("recv failed with error(%d)\n", + recvlen); + ret = -1; + application_exit(); + break; + } else { + close(gTraceInfo.socket.daemonSock); + gTraceInfo.socket.daemonSock = -1; + PRINTERR("closed by other peer\n"); + ret = -1; + application_exit(); + break; + } + + } + + PRINTMSG("createSocket connect() success\n"); + } else { + close(gTraceInfo.socket.daemonSock); + gTraceInfo.socket.daemonSock = -1; + strerror_r(errno, strerr_buf, sizeof(strerr_buf)); + PRINTERR("cannot connect to da_manager. err <%s>\n", + strerr_buf); + ret = -1; + } + } else { + strerror_r(errno, strerr_buf, sizeof(strerr_buf)); + PRINTERR("cannot create socket. err <%s>\n", strerr_buf); + ret = -1; + } + + PRINTMSG("socket create done with result = %d", ret); + return ret; +} + +static void *recvThread(void __unused *data) +{ + fd_set readfds, workfds; + int maxfd = 0, rc; + uint64_t xtime; + uint32_t tmp; + ssize_t recvlen; + log_t log; + char *data_buf = NULL; + sigset_t profsigmask; + pthread_t hierarchy_thread_id; + bool hierarchy_thread_running = false; + + if(gTraceInfo.socket.daemonSock == -1) + return NULL; + + sigemptyset(&profsigmask); + sigaddset(&profsigmask, SIGPROF); + pthread_sigmask(SIG_BLOCK, &profsigmask, NULL); + + FD_ZERO(&readfds); + if(g_timerfd > 0) + { + maxfd = g_timerfd; + FD_SET(g_timerfd, &readfds); + } + if(maxfd < gTraceInfo.socket.daemonSock) + maxfd = gTraceInfo.socket.daemonSock; + FD_SET(gTraceInfo.socket.daemonSock, &readfds); + + while(1) + { + workfds = readfds; + rc = select(maxfd + 1, &workfds, NULL, NULL, NULL); + if(rc < 0) + { + continue; + } + + if(g_timerfd > 0 && FD_ISSET(g_timerfd, &workfds)) + { + recvlen = read(g_timerfd, &xtime, sizeof(xtime)); + if(recvlen > 0) + { + log.length = snprintf(log.data, sizeof(log.data), "%ld", g_total_alloc_size) + 1; + printLog(&log, APP_MSG_ALLOC); + } + else + { + // read failed + } + continue; + } + else if(FD_ISSET(gTraceInfo.socket.daemonSock, &workfds)) + { + recvlen = recv(gTraceInfo.socket.daemonSock, &log, + sizeof(log.type) + sizeof(log.length), MSG_WAITALL); + + if(recvlen > 0) // recv succeed + { + + if(log.length > 0) { + data_buf = malloc(log.length); + if (data_buf == NULL) { + PRINTERR("cannot allocate buf to recv msg"); + break; + } + recvlen = recv(gTraceInfo.socket.daemonSock, data_buf, + log.length, MSG_WAITALL); + if (recvlen != log.length) { + PRINTERR("Can not recv data from\n"); + goto free_data_buf; + } + } + + if (log.type == APP_MSG_CONFIG) { + _configure(data_buf); + } else if(log.type == APP_MSG_STOP) { + PRINTMSG("APP_MSG_STOP"); + if (data_buf) { + free(data_buf); + data_buf = NULL; + } + application_exit(); + break; + } else if(log.type == APP_MSG_MAPS_INST_LIST) { + if(log.length > 0) { + tmp = *((uint32_t *)data_buf); + PRINTMSG("APP_MSG_MAPS_INST_LIST <%u>", tmp); + continue; + } else { + PRINTERR("WRONG APP_MSG_MAPS_INST_LIST"); + } + } else if(log.type == APP_MSG_GET_UI_HIERARCHY) { + enum ErrorCode err_code = ERR_UNKNOWN; + + print_log_ui_viewer_hierarchy_status(&err_code); + + if (err_code != ERR_NO) { + PRINTERR("APP_MSG_GET_UI_HIERARCHY error <%d>", err_code); + continue; + } + + if(log.length > 0) { + Eina_Bool rendering; + + hierarchy_thread_running = false; + rendering = (enum rendering_option_t)*((uint8_t *)data_buf); + PRINTMSG("APP_MSG_GET_UI_HIERARCHY, rendering option <%d>", rendering); + raise_app_window(); + if (pthread_create(&hierarchy_thread_id, NULL, print_log_ui_viewer_info_list, + (void*)&rendering)) { + PRINTERR("failed to crate hierarchy thread"); + } else { + hierarchy_thread_running = true; + } + } else { + PRINTERR("WRONG APP_MSG_GET_UI_PROPERTIES"); + } + + continue; + } else if(log.type == APP_MSG_GET_UI_HIERARCHY_CANCEL) { + PRINTMSG("APP_MSG_GET_UI_HIERARCHY_CANCEL"); + set_hierarchy_status(HIERARCHY_CANCELLED); + if (hierarchy_thread_running) { + pthread_join(hierarchy_thread_id, NULL); + hierarchy_thread_running = false; + } + + continue; + } else if(log.type == APP_MSG_GET_UI_SCREENSHOT) { + if(log.length > 0) { + Evas_Object *obj; + + obj = (Evas_Object*)(unsigned long)*((uint64_t *)data_buf); + PRINTMSG("APP_MSG_GET_UI_SCREENSHOT <0x%lx>", obj); + raise_app_window(); + print_log_ui_obj_screenshot(obj); + } else { + PRINTERR("WRONG APP_MSG_GET_UI_SCREENSHOT"); + } + + continue; + } else { + PRINTERR("recv unknown message. id = (%d)", log.type); + } + +free_data_buf: + if (data_buf) { + free(data_buf); + data_buf = NULL; + } + + } + else if(recvlen == 0) // closed by other peer + { + close(gTraceInfo.socket.daemonSock); + gTraceInfo.socket.daemonSock = -1; + break; + } + else // recv error + { + PRINTERR("recv failed in recv thread with error(%d)", recvlen); + continue; + } + } + else // unknown case + { + continue; + } + } + + if (data_buf) + free(data_buf); + + return NULL; +} diff --git a/ui_viewer/ui_viewer_lib.h b/ui_viewer/ui_viewer_lib.h new file mode 100644 index 0000000..0f3d1fe --- /dev/null +++ b/ui_viewer/ui_viewer_lib.h @@ -0,0 +1,46 @@ +/* + * DA manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Lyupa Anastasia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + +#ifndef _UI_VIEWER_LIB_ +#define _UI_VIEWER_LIB_ + +#include +#include + +typedef struct +{ + int daemonSock; + pthread_mutex_t sockMutex; +} __socketInfo; + +typedef struct +{ + __socketInfo socket; + uint64_t optionflag; +} __traceInfo; + + +#endif /* _UI_VIEWER_LIB_ */ diff --git a/ui_viewer/ui_viewer_screenshot.c b/ui_viewer/ui_viewer_screenshot.c new file mode 100644 index 0000000..610bf08 --- /dev/null +++ b/ui_viewer/ui_viewer_screenshot.c @@ -0,0 +1,311 @@ +/* + * DA manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Lyupa Anastasia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "ui_viewer_utils.h" + +typedef struct _screenshot_data +{ + XImage* ximage; + Display* dpy; + XShmSegmentInfo x_shm_info; +} screenshot_data; + +static int screenshotIndex = 0; +static pthread_mutex_t captureScreenLock = PTHREAD_MUTEX_INITIALIZER; + +static char* captureScreenShotX(screenshot_data* sdata) +{ + Window root; + int width, height; + + sdata->dpy = XOpenDisplay(NULL); + if(sdata->dpy == NULL) + { + ui_viewer_log("ERROR: XOpenDisplay failed\n"); + return NULL; + } + + width = DisplayWidth(sdata->dpy, DefaultScreen(sdata->dpy)); + height = DisplayHeight(sdata->dpy, DefaultScreen(sdata->dpy)); + + root = RootWindow(sdata->dpy, DefaultScreen(sdata->dpy)); + + sdata->ximage = XShmCreateImage(sdata->dpy, DefaultVisualOfScreen (DefaultScreenOfDisplay (sdata->dpy)), 24, + ZPixmap, NULL, &sdata->x_shm_info, (unsigned int)width, (unsigned int)height); + + if (sdata->ximage != NULL) + { + sdata->x_shm_info.shmid = shmget(IPC_PRIVATE, sdata->ximage->bytes_per_line * sdata->ximage->height, IPC_CREAT | 0777); + sdata->x_shm_info.shmaddr = sdata->ximage->data = shmat(sdata->x_shm_info.shmid, 0, 0); + sdata->x_shm_info.readOnly = False; + + if (XShmAttach(sdata->dpy, &sdata->x_shm_info)) + { + if (XShmGetImage(sdata->dpy, root, sdata->ximage, 0, 0, AllPlanes)) + { + XSync(sdata->dpy, False); + return sdata->ximage->data; + } + else + { + ui_viewer_log("ERROR: XShmGetImage failed\n"); + } + + XShmDetach(sdata->dpy, &sdata->x_shm_info); + } + else + { + ui_viewer_log("ERROR: XShmAttach failed\n"); + } + + shmdt (sdata->x_shm_info.shmaddr); + shmctl (sdata->x_shm_info.shmid, IPC_RMID, NULL); + XDestroyImage(sdata->ximage); + sdata->ximage = NULL; + } + else + { + ui_viewer_log("ERROR: XShmCreateImage failed\n"); + } + + return NULL; +} + +static void releaseScreenShotX(screenshot_data* sdata) +{ + if(sdata->ximage) + { + XShmDetach(sdata->dpy, &sdata->x_shm_info); + shmdt (sdata->x_shm_info.shmaddr); + shmctl (sdata->x_shm_info.shmid, IPC_RMID, NULL); + XDestroyImage(sdata->ximage); + } + else { } + + if(sdata->dpy) + { + XCloseDisplay(sdata->dpy); + } +} + +static int capture_object(char *screenshot_path, int width, int height, + Evas_Object *obj, const char *type_name) { + char dstpath[MAX_PATH_LENGTH]; + Evas_Object *img; + Evas *canvas, *sub_canvas; + Ecore_Evas *ee, *sub_ee; + int ret = 0; + char *image_data = NULL; + + screenshotIndex++; + + canvas = evas_object_evas_get(obj); + ee = ecore_evas_ecore_evas_get(canvas); + img = ecore_evas_object_image_new(ee); + evas_object_image_filled_set(img, EINA_TRUE); + evas_object_image_size_set(img, width, height); + sub_ee = ecore_evas_object_ecore_evas_get(img); + sub_canvas = ecore_evas_object_evas_get(img); + evas_object_resize(img, width, height); + ecore_evas_resize(sub_ee, width, height); + + if (!strcmp(type_name, "rectangle")) { + Evas_Object* rect; + int r, g, b, a; + + rect = evas_object_rectangle_add(sub_canvas); + evas_object_color_get(obj, &r, &g, &b, &a); + evas_object_color_set(rect, r, g, b, a); + evas_object_resize(rect, width, height); + evas_object_show(rect); + } else if (!strcmp(type_name, "image")) { + Evas_Object *image; + void *img_data; + int w, h; + + img_data = evas_object_image_data_get(obj, EINA_FALSE); + evas_object_image_size_get(obj, &w, &h); + image = evas_object_image_filled_add(sub_canvas); + evas_object_image_size_set(image, w, h); + evas_object_image_data_set(image, img_data); + evas_object_image_data_update_add(image, 0, 0, w, h); + evas_object_resize(image, width, height); + + evas_object_show(image); + } else { + char* scrimage; + screenshot_data sdata; + int x, y; + int screen_w; + Evas_Object *image; + int i, j; + int bytes_per_pixel; + + evas_object_geometry_get(obj, &x, &y, NULL, NULL); + + sdata.ximage = NULL; + scrimage = captureScreenShotX(&sdata); + if (!scrimage) { + ui_viewer_log("ERROR: capture_object : no scrimage\n"); + ret = -1; + goto finish; + } + bytes_per_pixel = sdata.ximage->bits_per_pixel / 8; + screen_w = sdata.ximage->width; + + image_data = malloc(width * height * bytes_per_pixel); + if (!image_data) { + ui_viewer_log("ERROR: capture_object : can't allocate %d bytes\n", + width * height * bytes_per_pixel); + ret = -1; + goto finish; + } + + // crop image + for (j = 0; j < height; j++) { + for (i = 0; i < width * bytes_per_pixel; i++) { + image_data[i + j * width * bytes_per_pixel] = + scrimage[(i + x * bytes_per_pixel) + (j + y) * screen_w * bytes_per_pixel]; + } + } + + image = evas_object_image_filled_add(sub_canvas); + evas_object_image_size_set(image, width, height); + evas_object_image_data_set(image, image_data); + evas_object_image_data_update_add(image, 0, 0, width, height); + evas_object_resize(image, width, height); + evas_object_show(image); +finish: + releaseScreenShotX(&sdata); + } + + ecore_evas_manual_render(sub_ee); + + snprintf(dstpath, sizeof(dstpath), TMP_DIR"/%d_%d.png", _getpid(), + screenshotIndex); + + if (evas_object_image_save(img, dstpath, NULL, "compress=5") != 0) { + strcpy(screenshot_path, dstpath); + } else { + ui_viewer_log("ERROR: capture_object : can't save image\n"); + ret = -1; + } + + evas_object_del(img); + free(image_data); + + return ret; +} + +int ui_viewer_capture_screen(char *screenshot_path, Evas_Object *obj) +{ + int view_w, view_h; + int obj_x, obj_y, obj_w, obj_h; + int ret = 0; + Evas *evas; + char type_name[MAX_PATH_LENGTH]; + + if (!screenshot_path) { + ui_viewer_log("ui_viewer_capture_screen : no screenshot path\n"); + ret = -1; + return ret; + } + + pthread_mutex_lock(&captureScreenLock); + + _strncpy(type_name, evas_object_type_get(obj), MAX_PATH_LENGTH); + + evas = evas_object_evas_get(obj); + evas_output_viewport_get(evas, NULL, NULL, &view_w, &view_h); + evas_object_geometry_get(obj, &obj_x, &obj_y, &obj_w, &obj_h); + + if (obj_w == 0 || obj_h == 0) { + ui_viewer_log("ui_viewer_capture_screen : object %p[%d,%d] has zero width or height\n", + obj, obj_w, obj_h); + ret = -1; + } else if (!strcmp(type_name, "rectangle")) { + int width, height; + + // restrict rectangle area + width = (obj_w <= view_w) ? obj_w : view_w; + height = (obj_h <= view_h) ? obj_h : view_h; + + ret = capture_object(screenshot_path, width, height, obj, type_name); + } else if (!strcmp(type_name, "image")) { + ret = capture_object(screenshot_path, obj_w, obj_h, obj, type_name); + } else if (!strcmp(type_name, "vectors")) { + ret = -1; + } else if (!strcmp(type_name, "elm_image") || + !strcmp(type_name, "elm_icon")) { + Evas_Object *internal_img; + int img_w, img_h; + + internal_img = elm_image_object_get(obj); + evas_object_geometry_get(internal_img, NULL, NULL, &img_w, &img_h); + + ret = capture_object(screenshot_path, img_w, img_h, internal_img, type_name); + } else if (obj_x > view_w || obj_y > view_h) { + ui_viewer_log("ui_viewer_capture_screen : object %p lies beside view area\n", + obj); + ret = -1; + } else if (!evas_object_visible_get(obj)) { + ui_viewer_log("ui_viewer_capture_screen : object %p is unvisible\n", + obj); + ret = -1; + } else { + int width, height; + + // take visible on screen part of object + width = (view_w < obj_w + obj_x) ? (view_w - obj_x) : obj_w; + height = (view_h < obj_h + obj_y) ? (view_h - obj_y) : obj_h; + + ret = capture_object(screenshot_path, width, height, obj, type_name); + } + + if (ret) + screenshot_path[0] = '\0'; + + pthread_mutex_unlock(&captureScreenLock); + return ret; +} diff --git a/ui_viewer/ui_viewer_utils.c b/ui_viewer/ui_viewer_utils.c new file mode 100644 index 0000000..c3da116 --- /dev/null +++ b/ui_viewer/ui_viewer_utils.c @@ -0,0 +1,346 @@ +/* + * DA manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Lyupa Anastasia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ui_viewer_lib.h" +#include "ui_viewer_utils.h" +#include "ui_viewer_data.h" + +static const ssize_t TMP_BUF_SIZE = 262144; +static const char log_filename[] = "/tmp/uilib.log"; +static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER; +static pid_t gPid = -1; +static __thread pid_t gTid = -1; + +extern __traceInfo gTraceInfo; + +void reset_pid_tid() +{ + gPid = -1; + gTid = -1; +} + +// return current process id +pid_t _getpid() +{ + if (gPid == -1) + gPid = getpid(); + return gPid; +} + +// return current thread id +pid_t _gettid() +{ + if(gTid == -1) + gTid = syscall(__NR_gettid); // syscall is very expensive + return gTid; +} + +char * _strncpy(char *dest, const char *src, size_t n) +{ + if (!src) { + if (dest) + dest[0] = '\0'; + } else { + strncpy(dest, src, n); + if (n > 0) + dest[n - 1] = '\0'; + } + + return dest; +} + +bool printLog(log_t *log, int msgType) +{ + ssize_t res, len; + if (gTraceInfo.socket.daemonSock == -1) + return false; + + if (log == NULL) + return false; + + log->type = msgType; + len = sizeof(log->type) + sizeof(log->length) + log->length; + + pthread_mutex_lock(&(gTraceInfo.socket.sockMutex)); + res = send(gTraceInfo.socket.daemonSock, log, len, 0); + pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex)); + + return (res == len); +} + +bool print_log_str(int msgType, char *str) +{ + log_t log; + ssize_t res, len; + + if (gTraceInfo.socket.daemonSock == -1) + return false; + + log.type = msgType; + if (str != NULL) + log.length = snprintf(log.data, sizeof(log.data), str); + else + log.length = 0; + + len = sizeof(log.type) + sizeof(log.length) + log.length; + + pthread_mutex_lock(&(gTraceInfo.socket.sockMutex)); + res = send(gTraceInfo.socket.daemonSock, &log, len, 0); + pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex)); + + return (res == len); +} + +bool print_log_fmt(int msgType, const char *func_name, int line, ...) +{ + ssize_t res = 0, len = 0; + char *fmt, *p; + int n; + log_t log; + va_list ap; + + log.type = msgType; + + p = log.data; + n = snprintf(p, sizeof(log.data), "[%05d:%05d]%s:%d)", _getpid(), + _gettid(), func_name, line); + p += n; + + va_start(ap, line); + fmt = va_arg(ap, char *); + if (fmt != NULL) { + if (strchr(fmt, '%') == NULL) + n += snprintf(p, sizeof(log.data) - n, "%s", fmt); + else + n += vsnprintf(p, sizeof(log.data) - n, fmt, ap); + } + va_end(ap); + + if (n > -1 && n < (int)sizeof(log.data)) { + log.length = n; + } else { + ui_viewer_log("Log pack error\n"); + log.length = 0; + } + + len = sizeof(log.type) + sizeof(log.length) + log.length; + + pthread_mutex_lock(&(gTraceInfo.socket.sockMutex)); + + if (gTraceInfo.socket.daemonSock != -1) { + res = send(gTraceInfo.socket.daemonSock, &log, len, MSG_DONTWAIT); + } else { + ui_viewer_log("%d %s\n", msgType, log.data); + fflush(stderr); + } + + pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex)); + + return (res == len); +} + +static char *pack_string_to_file(char *to, char *st, ssize_t data_len) +{ + char template_name[] = TMP_DIR"/swap_ui_viewer_XXXXXX"; + FILE *file; + mktemp(template_name); + file = fopen(template_name, "w"); + if (file != NULL) { + fwrite(st, data_len, 1, file); + fclose(file); + } + to = pack_string(to, template_name); + + return to; +} + +bool print_log_ui_viewer_hierarchy_status(enum ErrorCode *err_code) +{ + log_t log; + ssize_t res, len; + char *log_ptr; + + *err_code = ERR_NO; + + if (gTraceInfo.socket.daemonSock == -1) + return false; + + // check if hierarchy request is proceeding now + if (get_hierarchy_status() == HIERARCHY_RUNNING) + *err_code = ERR_ALREADY_RUNNING; + + log.type = APP_MSG_GET_UI_HIERARCHY; + log_ptr = pack_int32(log.data, (uint32_t)*err_code); + log.length = log_ptr - log.data; + len = sizeof(log.type) + sizeof(log.length) + log.length; + + pthread_mutex_lock(&(gTraceInfo.socket.sockMutex)); + res = send(gTraceInfo.socket.daemonSock, &log, len, 0); + pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex)); + + return (res == len); +} + +bool print_log_ui_viewer_hierarchy_error(void) +{ + log_t log; + ssize_t res, len; + char *log_ptr; + enum ErrorCode err_code; + + // TODO: system error + err_code = ERR_UNKNOWN; + + if (gTraceInfo.socket.daemonSock == -1) + return false; + + log.type = APP_MSG_GET_UI_HIERARCHY_DATA; + log_ptr = pack_int32(log.data, (uint32_t)err_code); + log.length = log_ptr - log.data; + len = sizeof(log.type) + sizeof(log.length) + log.length; + + pthread_mutex_lock(&(gTraceInfo.socket.sockMutex)); + res = send(gTraceInfo.socket.daemonSock, &log, len, 0); + pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex)); + + return (res == len); +} + +void* print_log_ui_viewer_info_list(void *prendering) +{ + log_t log; + ssize_t res, len; + char *log_ptr, *tmp_ptr; + char *tmp_buf; + struct timeval start_tv, finish_tv, tv; + Eina_Bool rendering, cancelled = EINA_FALSE; + + if (gTraceInfo.socket.daemonSock == -1) + return NULL; + + if (get_hierarchy_status() == HIERARCHY_RUNNING) + return NULL; + + set_hierarchy_status(HIERARCHY_RUNNING); + + rendering = *(Eina_Bool*)prendering; + + tmp_buf = malloc(TMP_BUF_SIZE); + if (!tmp_buf) { + ui_viewer_log("Cannot alloc buffer: %d bytes\n", TMP_BUF_SIZE); + return NULL; + } + + gettimeofday(&start_tv, NULL); + tmp_ptr = pack_ui_obj_info_list(tmp_buf, rendering, &cancelled); + gettimeofday(&finish_tv, NULL); + timersub(&finish_tv, &start_tv, &tv); + ui_viewer_log("getting hierarchy time : %d sec, %d usec\n", + tv.tv_sec, tv.tv_usec); + + if (!cancelled) { + log.type = APP_MSG_GET_UI_HIERARCHY_DATA; + log_ptr = pack_string_to_file(log.data, tmp_buf, tmp_ptr - tmp_buf); + log.length = log_ptr - log.data; + len = sizeof(log.type) + sizeof(log.length) + log.length; + + pthread_mutex_lock(&(gTraceInfo.socket.sockMutex)); + res = send(gTraceInfo.socket.daemonSock, &log, len, 0); + pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex)); + + ui_viewer_log("getting hierarchy filename: %s filesize: %d\n", + log.data, tmp_ptr - tmp_buf); + + if (res != len) + ui_viewer_log("can't send hierarchy info\n"); + set_hierarchy_status(HIERARCHY_NOT_RUNNING); + } + free(tmp_buf); + + return NULL; +} + +bool print_log_ui_obj_screenshot(Evas_Object *obj) +{ + log_t log; + ssize_t res, len; + char *log_ptr; + + if (gTraceInfo.socket.daemonSock == -1) + return false; + + log.type = APP_MSG_GET_UI_SCREENSHOT; + log_ptr = pack_ui_obj_screenshot(log.data, obj); + log.length = log_ptr - log.data; + len = sizeof(log.type) + sizeof(log.length) + log.length; + + pthread_mutex_lock(&(gTraceInfo.socket.sockMutex)); + res = send(gTraceInfo.socket.daemonSock, &log, len, 0); + pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex)); + + return (res == len); +} + +void raise_app_window(void) +{ + x_raise_win(gPid); +} + +void ui_viewer_clean_log(void) +{ + remove(log_filename); +} + +void ui_viewer_log(const char *format, ...) +{ + FILE *fp; + va_list args; + + pthread_mutex_lock(&log_lock); + fp = fopen(log_filename, "a"); + if (fp == NULL) + return; + va_start (args, format); + vfprintf (fp, format, args); + va_end (args); + fclose(fp); + pthread_mutex_unlock(&log_lock); +} diff --git a/ui_viewer/ui_viewer_utils.h b/ui_viewer/ui_viewer_utils.h new file mode 100644 index 0000000..3a4fe0f --- /dev/null +++ b/ui_viewer/ui_viewer_utils.h @@ -0,0 +1,91 @@ +/* + * DA manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Lyupa Anastasia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + +#ifndef _UI_VIEWER_UTILS_ +#define _UI_VIEWER_UTILS_ + +#include +#include + +#include "app_protocol.h" /* from swap-probe-devel package */ + +#include "ui_viewer_data.h" + +#define DA_LOG_MAX (MAX_PATH_LENGTH + 4) +#define TMP_DIR "/tmp/da" + +#define __unused __attribute__((unused)) + +typedef struct +{ + int type; + int length; + char data[DA_LOG_MAX]; +} log_t; + +// ========================= print log ===================================== +#define PRINTMSG(...) print_log_fmt(APP_MSG_MSG, __FUNCTION__, __LINE__, __VA_ARGS__) +#define PRINTWRN(...) print_log_fmt(APP_MSG_WARNING, __FUNCTION__, __LINE__, __VA_ARGS__) +#define PRINTERR(...) print_log_fmt(APP_MSG_ERROR, __FUNCTION__, __LINE__, __VA_ARGS__) + +#define INIT_INFO \ + info.host_ip = 0; \ + info.host_port = 0; \ + info.msg_total_size = 0; \ + info.msg_pack_size = 0; \ + info.sock = NULL; \ + info.msg_buf = (char *)"" + +typedef struct { + uint32_t host_port; + uint32_t host_ip; + struct sockaddr *sock; + + uint64_t msg_total_size; + uint32_t msg_pack_size; + char *msg_buf; + +} info_t; + +void reset_pid_tid(); +pid_t _getpid(); +pid_t _gettid(); +char * _strncpy(char *dest, const char *src, size_t n); +bool print_log_fmt(int msgType, const char *func_name, int line, ...); +bool print_log_str(int msgType, char *st); +bool print_log_ui_viewer_hierarchy_status(enum ErrorCode *err_code); +void* print_log_ui_viewer_info_list(void *prendering); +bool print_log_ui_viewer_hierarchy_error(void); +bool print_log_ui_obj_screenshot(Evas_Object *obj); +bool printLog(log_t* log, int msgType); +void raise_app_window(void); + +int ui_viewer_capture_screen(char *screenshot_path, Evas_Object *obj); + +void ui_viewer_clean_log(void); +void ui_viewer_log(const char *format, ...); + +#endif /* _UI_VIEWER_UTILS_ */