#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "ecore_private.h" #include "ecore_evas_private.h" #include "ecore_evas_vnc_server_fb_keymap.h" static int _ecore_evas_vnc_server_log_dom; static unsigned int _available_seat = 1; #ifdef EAPI # undef EAPI #endif #ifdef _WIN32 # ifdef DLL_EXPORT # define EAPI __declspec(dllexport) # else # define EAPI # endif /* ! DLL_EXPORT */ #else # ifdef __GNUC__ # if __GNUC__ >= 4 # define EAPI __attribute__ ((visibility("default"))) # else # define EAPI # endif # else # define EAPI # endif #endif /* ! _WIN32 */ #ifdef WRN #undef WRN #endif #define WRN(...) EINA_LOG_DOM_WARN(_ecore_evas_vnc_server_log_dom, __VA_ARGS__) #ifdef DBG #undef DBG #endif #define DBG(...) EINA_LOG_DOM_DBG(_ecore_evas_vnc_server_log_dom, __VA_ARGS__) typedef Eina_Bool (*Ecore_Evas_Vnc_Key_Info_Get)(rfbKeySym key, const char **key_name, const char **key_str, const char **compose, int *keycode); typedef struct _Ecore_Evas_Vnc_Server { char *frame_buffer; rfbScreenInfoPtr vnc_screen; Ecore_Fd_Handler *vnc_listen_handler; Ecore_Fd_Handler *vnc_listen6_handler; Ecore_Evas_Vnc_Client_Accept_Cb accept_cb; Ecore_Evas_Vnc_Client_Disconnected_Cb disc_cb; void *cb_data; Evas_Object *snapshot; Ecore_Evas *ee; Eina_Tiler *t; Ecore_Evas_Vnc_Key_Info_Get key_info_get_func; double double_click_time; int last_w; int last_h; } Ecore_Evas_Vnc_Server; typedef struct _Ecore_Evas_Vnc_Server_Client_Data { Ecore_Fd_Handler *handler; Evas_Device *keyboard; Evas_Device *mouse; Evas_Device *seat; unsigned int key_modifiers; time_t last_mouse_button_down; Eina_Bool double_click; Eina_Bool triple_click; } Ecore_Evas_Vnc_Server_Client_Data; #define VNC_BITS_PER_SAMPLE (8) #define VNC_SAMPLES_PER_PIXEL (3) #define VNC_BYTES_PER_PIXEL (4) static void _ecore_evas_vnc_server_ecore_event_generic_free(void *user_data, void *func_data); static void _ecore_evas_vnc_server_update_clients(rfbScreenInfoPtr vnc_screen) { rfbClientIteratorPtr itr; rfbClientRec *client; itr = rfbGetClientIterator(vnc_screen); //No clients. if (!itr) return; while ((client = rfbClientIteratorNext(itr))) { rfbBool r; r = rfbUpdateClient(client); if (!r) { Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData; WRN("Could not update the VNC client on seat '%s'\n", evas_device_name_get(cdata->seat)); } //Client disconnected if (client->sock == -1) rfbClientConnectionGone(client); } rfbReleaseClientIterator(itr); } static void _ecore_evas_vnc_server_format_setup(rfbScreenInfoPtr vnc_screen) { int aux; //FIXME: Using BGR - Is there a better way to do this? aux = vnc_screen->serverFormat.redShift; vnc_screen->serverFormat.redShift = vnc_screen->serverFormat.blueShift; vnc_screen->serverFormat.blueShift = aux; } static Eina_Bool _ecore_evas_vnc_server_socket_listen_activity(void *data, Ecore_Fd_Handler *fd_handler EINA_UNUSED) { rfbProcessNewConnection(data); return ECORE_CALLBACK_RENEW; } static void _ecore_evas_vnc_server_mouse_inout_emit(Ecore_Evas_Vnc_Server *server, Evas_Device *dev, int event_type) { Ecore_Event_Mouse_IO *io = calloc(1, sizeof(Ecore_Event_Mouse_IO)); EINA_SAFETY_ON_NULL_RETURN(io); io->timestamp = time(NULL); io->dev = efl_ref(dev); io->event_window = io->window = server->ee->prop.window; ecore_event_add(event_type, io, _ecore_evas_vnc_server_ecore_event_generic_free, dev); } static void _ecore_evas_vnc_server_client_gone(rfbClientRec *client) { Ecore_Evas_Vnc_Server *server = client->screen->screenData; Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData; DBG("VNC client on seat '%s' gone", evas_device_name_get(cdata->seat)); if (server->disc_cb) server->disc_cb(server->cb_data, server->ee, client->host); _ecore_evas_vnc_server_mouse_inout_emit(server, cdata->mouse, ECORE_EVENT_MOUSE_OUT); _ecore_evas_mouse_inout_set(server->ee, cdata->mouse, EINA_FALSE, EINA_FALSE); ecore_evas_focus_device_set(server->ee, cdata->seat, EINA_FALSE); ecore_main_fd_handler_del(cdata->handler); evas_device_del(cdata->keyboard); evas_device_del(cdata->mouse); evas_device_del(cdata->seat); free(cdata); _available_seat--; } static Eina_Bool _ecore_evas_vnc_server_client_activity(void *data, Ecore_Fd_Handler *fd_handler EINA_UNUSED) { rfbClientRec *client = data; rfbScreenInfoPtr screen = client->screen; rfbProcessClientMessage(client); //macro from rfb.h if (screen->frameBuffer && FB_UPDATE_PENDING(client)) rfbSendFramebufferUpdate(client, client->modifiedRegion); //Client disconnected. if (client->sock == -1) { rfbClientConnectionGone(client); return ECORE_CALLBACK_DONE; } return ECORE_CALLBACK_RENEW; } static enum rfbNewClientAction _ecore_evas_vnc_server_client_connection_new(rfbClientRec *client) { Ecore_Evas_Vnc_Server *server; Ecore_Evas_Vnc_Server_Client_Data *cdata; char buf[32]; EINA_SAFETY_ON_TRUE_RETURN_VAL(_available_seat == UINT_MAX, RFB_CLIENT_REFUSE); server = client->screen->screenData; if (server->accept_cb && !server->accept_cb(server->cb_data, server->ee, client->host)) return RFB_CLIENT_REFUSE; cdata = calloc(1, sizeof(Ecore_Evas_Vnc_Server_Client_Data)); EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, RFB_CLIENT_REFUSE); cdata->handler = ecore_main_fd_handler_add(client->sock, ECORE_FD_READ, _ecore_evas_vnc_server_client_activity, client, NULL, NULL); EINA_SAFETY_ON_NULL_GOTO(cdata->handler, err_handler); snprintf(buf, sizeof(buf), "seat-%u", _available_seat); cdata->seat = evas_device_add_full(server->ee->evas, buf, "A remote VNC seat", NULL, NULL, EVAS_DEVICE_CLASS_SEAT, EVAS_DEVICE_SUBCLASS_NONE); EINA_SAFETY_ON_NULL_GOTO(cdata->seat, err_handler); evas_device_seat_id_set(cdata->seat, 2); cdata->keyboard = evas_device_add_full(server->ee->evas, "Keyboard", "A remote VNC keyboard", cdata->seat, NULL, EVAS_DEVICE_CLASS_KEYBOARD, EVAS_DEVICE_SUBCLASS_NONE); EINA_SAFETY_ON_NULL_GOTO(cdata->keyboard, err_dev); cdata->mouse = evas_device_add_full(server->ee->evas, "Mouse", "A remote VNC mouse", cdata->seat, NULL, EVAS_DEVICE_CLASS_MOUSE, EVAS_DEVICE_SUBCLASS_NONE); EINA_SAFETY_ON_NULL_GOTO(cdata->mouse, err_mouse); client->clientGoneHook = _ecore_evas_vnc_server_client_gone; client->clientData = cdata; DBG("New VNC client on seat '%u'", _available_seat); _available_seat++; _ecore_evas_vnc_server_mouse_inout_emit(server, cdata->mouse, ECORE_EVENT_MOUSE_IN); _ecore_evas_mouse_inout_set(server->ee, cdata->mouse, EINA_TRUE, EINA_FALSE); ecore_evas_focus_device_set(server->ee, cdata->seat, EINA_TRUE); return RFB_CLIENT_ACCEPT; err_mouse: evas_device_del(cdata->keyboard); err_dev: evas_device_del(cdata->seat); err_handler: free(cdata); return RFB_CLIENT_REFUSE; } static unsigned int _ecore_evas_vnc_server_modifier_to_ecore_modifier(int mod, Eina_Bool *is_lock) { *is_lock = EINA_FALSE; if (mod == XK_Shift_L || mod == XK_Shift_R) return ECORE_EVENT_MODIFIER_SHIFT; if (mod == XK_Control_L || mod == XK_Control_R) return ECORE_EVENT_MODIFIER_CTRL; if (mod == XK_Alt_L || mod == XK_Alt_R) return ECORE_EVENT_MODIFIER_ALT; if (mod == XK_Super_L || mod == XK_Super_R) return ECORE_EVENT_MODIFIER_WIN; if (mod == XK_Scroll_Lock) { *is_lock = EINA_TRUE; return ECORE_EVENT_LOCK_SCROLL; } if (mod == XK_Num_Lock) { *is_lock = EINA_TRUE; return ECORE_EVENT_LOCK_NUM; } if (mod == XK_Caps_Lock) { *is_lock = EINA_TRUE; return ECORE_EVENT_LOCK_CAPS; } if (mod == XK_Shift_Lock) { *is_lock = EINA_TRUE; return ECORE_EVENT_LOCK_SHIFT; } return 0; } static void _ecore_evas_vnc_server_ecore_event_generic_free(void *user_data, void *func_data) { efl_unref(user_data); free(func_data); } static Eina_Bool _ecore_evas_vnc_server_fb_key_info_get(rfbKeySym key, const char **key_name, const char **key_str, const char **compose, int *keycode EINA_UNUSED) { return ecore_evas_vnc_server_keysym_to_fb_translate(key, key_name, key_str, compose); } static void _ecore_evas_vnc_server_client_keyboard_event(rfbBool down, rfbKeySym key, rfbClientRec *client) { Ecore_Event_Key *e; Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData; rfbScreenInfoPtr screen = client->screen; Ecore_Evas_Vnc_Server *server = screen->screenData; const char *key_str, *compose, *key_name; int keycode = 0; Eina_Bool r; char buf[10]; if (key >= XK_Shift_L && key <= XK_Hyper_R) { Eina_Bool is_lock; int mod = _ecore_evas_vnc_server_modifier_to_ecore_modifier(key, &is_lock); if (down) { if (!is_lock || !(cdata->key_modifiers & mod)) cdata->key_modifiers |= mod; else cdata->key_modifiers &= ~mod; } else if (!is_lock) cdata->key_modifiers &= ~mod; } if (server->ee->ignore_events) return; r = server->key_info_get_func(key, &key_str, &key_name, &compose, &keycode); EINA_SAFETY_ON_FALSE_RETURN(r); snprintf(buf, sizeof(buf), "%lc", key); e = calloc(1, sizeof(Ecore_Event_Key) + (compose ? 0 : strlen(buf) + 1)); EINA_SAFETY_ON_NULL_RETURN(e); e->timestamp = (unsigned int)time(NULL); e->modifiers = cdata->key_modifiers; e->same_screen = 1; e->window = e->root_window = e->event_window = server->ee->prop.window; e->dev = cdata->keyboard; efl_ref(cdata->keyboard); e->keyname = key_name; e->key = key_str; e->keycode = keycode; e->compose = (char *)(e + 1); if (compose) e->compose = compose; else strcpy((char *)e->compose, buf); e->string = e->compose; ecore_event_add(down ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP, e, _ecore_evas_vnc_server_ecore_event_generic_free, cdata->keyboard); } static int _ecore_evas_vnc_server_pointer_button_get(int mask) { int i; for (i = 0; i < 32; i++) if (mask >> i & 1) return i + 1; return 0; } static void _ecore_evas_vnc_server_client_pointer_event(int button_mask, int x, int y, rfbClientPtr client) { Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData; rfbScreenInfoPtr screen = client->screen; Ecore_Evas_Vnc_Server *server = screen->screenData; Ecore_Event_Mouse_Move *move_event; Ecore_Event_Mouse_Button *button_event; Ecore_Event_Mouse_Wheel *wheel_event; int button_changed, button, event, z = 0, direction = 0; time_t now = time(NULL); if (server->ee->ignore_events) return; if (client->lastPtrX != x || client->lastPtrY != y) { move_event = calloc(1, sizeof(Ecore_Event_Mouse_Move)); EINA_SAFETY_ON_NULL_RETURN(move_event); move_event->x = move_event->multi.x = x; move_event->y = move_event->multi.y = y; move_event->same_screen = 1; move_event->timestamp = (unsigned int)now; move_event->window = move_event->event_window = move_event->root_window = server->ee->prop.window; move_event->multi.pressure = 1.0; move_event->modifiers = cdata->key_modifiers; move_event->dev = cdata->mouse; efl_ref(cdata->mouse); ecore_event_add(ECORE_EVENT_MOUSE_MOVE, move_event, _ecore_evas_vnc_server_ecore_event_generic_free, cdata->mouse); client->lastPtrX = x; client->lastPtrY = y; } button_changed = button_mask - client->lastPtrButtons; if (button_changed > 0) { button = _ecore_evas_vnc_server_pointer_button_get(button_changed); switch (button) { case 4: event = ECORE_EVENT_MOUSE_WHEEL; direction = 0; //Vertical z = -1; //Up break; case 5: event = ECORE_EVENT_MOUSE_WHEEL; direction = 0; z = 1; //Down break; case 6: event = ECORE_EVENT_MOUSE_WHEEL; direction = 1; //Horizontal z = -1; break; case 7: event = ECORE_EVENT_MOUSE_WHEEL; direction = 1; z = 1; break; default: event = ECORE_EVENT_MOUSE_BUTTON_DOWN; } if (now - cdata->last_mouse_button_down <= 1000 * server->double_click_time) cdata->double_click = EINA_TRUE; else cdata->double_click = cdata->triple_click = EINA_FALSE; if (now - cdata->last_mouse_button_down <= 2000 * server->double_click_time) cdata->triple_click = EINA_TRUE; else cdata->triple_click = EINA_FALSE; cdata->last_mouse_button_down = now; } else if (button_changed < 0) { button = _ecore_evas_vnc_server_pointer_button_get(-button_changed); //Ignore, it was already report. if (button > 3 && button < 8) return; event = ECORE_EVENT_MOUSE_BUTTON_UP; } else return; if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN || event == ECORE_EVENT_MOUSE_BUTTON_UP) { button_event = calloc(1, sizeof(Ecore_Event_Mouse_Button)); EINA_SAFETY_ON_NULL_RETURN(button_event); button_event->timestamp = (unsigned int)now; button_event->window = button_event->event_window = button_event->root_window = server->ee->prop.window; button_event->x = button_event->multi.x = x; button_event->y = button_event->multi.y = y; button_event->multi.pressure = 1.0; button_event->same_screen = 1; button_event->buttons = button; button_event->modifiers = cdata->key_modifiers; button_event->double_click = cdata->double_click ? 1 : 0; button_event->triple_click = cdata->triple_click ? 1 : 0; button_event->dev = cdata->mouse; efl_ref(cdata->mouse); ecore_event_add(event, button_event, _ecore_evas_vnc_server_ecore_event_generic_free, cdata->mouse); return; } //Mouse wheel wheel_event = calloc(1, sizeof(Ecore_Event_Mouse_Wheel)); EINA_SAFETY_ON_NULL_RETURN(wheel_event); wheel_event->dev = cdata->mouse; efl_ref(cdata->mouse); wheel_event->window = wheel_event->event_window = wheel_event->root_window = server->ee->prop.window; wheel_event->same_screen = 1; wheel_event->modifiers = cdata->key_modifiers; wheel_event->x = x; wheel_event->y = y; wheel_event->direction = direction; wheel_event->z = z; ecore_event_add(event, wheel_event, _ecore_evas_vnc_server_ecore_event_generic_free, cdata->mouse); } static Eina_Bool _ecore_evas_vnc_server_init(void) { if (!eina_init()) { EINA_LOG_ERR("Could not init Eina"); return EINA_FALSE; } if (!ecore_init()) { EINA_LOG_ERR("Could not init Ecore"); goto err_ecore; } if (!ecore_evas_init()) { EINA_LOG_ERR("Could not init Ecore_Evas"); goto err_ecore_evas; } if (!ecore_event_init()) { EINA_LOG_ERR("Could not init Ecore_Event"); goto err_ecore_event; } _ecore_evas_vnc_server_log_dom = eina_log_domain_register("Ecore_Evas_Vnc_Server", EINA_COLOR_LIGHTBLUE); if (_ecore_evas_vnc_server_log_dom < 0) { EINA_LOG_ERR("Could not register log domain: Ecore_Evas_Vnc_Server"); goto err_domain; } return EINA_TRUE; err_domain: ecore_event_shutdown(); err_ecore_event: ecore_evas_shutdown(); err_ecore_evas: ecore_shutdown(); err_ecore: eina_shutdown(); return EINA_FALSE; } static void _ecore_evas_vnc_server_shutdown(void) { eina_log_domain_unregister(_ecore_evas_vnc_server_log_dom); _ecore_evas_vnc_server_log_dom = -1; ecore_event_shutdown(); ecore_evas_shutdown(); ecore_shutdown(); eina_shutdown(); } static inline int align4(int v) { return ((v / 4) + (v % 4 ? 1 : 0)) * 4; } static void _ecore_evas_vnc_server_draw(void *data, Evas *e EINA_UNUSED, void *event_info) { Evas_Event_Render_Post *post = event_info; Evas_Object *snapshot = data; Ecore_Evas_Vnc_Server *server; const void *pixels; Eina_List *l; Eina_Rectangle *r; size_t size; Eina_Bool new_buf = EINA_FALSE; Eina_Rectangle snapshot_pos; // Nothing was updated, so let's not bother sending nothingness if (!post->updated_area) return ; server = evas_object_data_get(snapshot, "_ecore_evas.vnc"); EINA_SAFETY_ON_NULL_RETURN(server); pixels = evas_object_image_data_get(snapshot, EINA_FALSE); evas_object_geometry_get(snapshot, &snapshot_pos.x, &snapshot_pos.y, &snapshot_pos.w, &snapshot_pos.h); // Align size on 4 pixels for vnc library stability snapshot_pos.w = align4(snapshot_pos.w); snapshot_pos.h = align4(snapshot_pos.h); DBG("Preparing sending of buffer {%i, %i} with %i updates.", snapshot_pos.w, snapshot_pos.h, eina_list_count(post->updated_area)); if (!server->frame_buffer || server->last_w != snapshot_pos.w || server->last_h != snapshot_pos.h) { Eina_Rectangle tmp = { 0, 0, snapshot_pos.w, snapshot_pos.h }; char *new_fb; size = snapshot_pos.w * snapshot_pos.h * VNC_BYTES_PER_PIXEL; new_fb = malloc(size); EINA_SAFETY_ON_NULL_RETURN(new_fb); free(server->frame_buffer); server->frame_buffer = new_fb; server->last_w = snapshot_pos.w; server->last_h = snapshot_pos.h; new_buf = EINA_TRUE; eina_tiler_area_size_set(server->t, snapshot_pos.w, snapshot_pos.h); eina_tiler_rect_add(server->t, &tmp); rfbNewFramebuffer(server->vnc_screen, server->frame_buffer, snapshot_pos.w, snapshot_pos.h, VNC_BITS_PER_SAMPLE, VNC_SAMPLES_PER_PIXEL, VNC_BYTES_PER_PIXEL); _ecore_evas_vnc_server_format_setup(server->vnc_screen); } EINA_LIST_FOREACH(post->updated_area, l, r) { Eina_Rectangle tmp = *r; size_t src_stride; int dy; if (tmp.x > snapshot_pos.w || tmp.y > snapshot_pos.h) continue ; if (!eina_rectangle_intersection(&tmp, &snapshot_pos)) continue ; src_stride = tmp.w * VNC_BYTES_PER_PIXEL; for (dy = 0; dy < tmp.h; dy++) { memcpy(server->frame_buffer + (tmp.x * VNC_BYTES_PER_PIXEL) + ((dy + tmp.y) * (snapshot_pos.w * VNC_BYTES_PER_PIXEL)), (char *)pixels + (dy * src_stride), src_stride); } rfbMarkRectAsModified(server->vnc_screen, tmp.x, tmp.y, tmp.x + tmp.w, tmp.y + tmp.h); if (new_buf) eina_tiler_rect_del(server->t, &tmp); } //We did not receive the whole buffer yet, zero the missing bytes for now. if (new_buf) { Eina_Iterator *it; it = eina_tiler_iterator_new(server->t); EINA_ITERATOR_FOREACH(it, r) { Eina_Rectangle tmp = *r; size_t src_stride; int dy; src_stride = tmp.w * VNC_BYTES_PER_PIXEL; for (dy = 0; dy < tmp.h; dy++) { memset(server->frame_buffer + (tmp.x * VNC_BYTES_PER_PIXEL) + ((dy + tmp.y) * (snapshot_pos.w * VNC_BYTES_PER_PIXEL)), 0, src_stride); } } eina_iterator_free(it); eina_tiler_clear(server->t); } _ecore_evas_vnc_server_update_clients(server->vnc_screen); } static void _ecore_evas_vnc_server_del(void *data, const Efl_Event *ev EINA_UNUSED) { Ecore_Evas_Vnc_Server *server = data; ecore_main_fd_handler_del(server->vnc_listen6_handler); ecore_main_fd_handler_del(server->vnc_listen_handler); evas_object_del(server->snapshot); rfbShutdownServer(server->vnc_screen, TRUE); free(server->frame_buffer); rfbScreenCleanup(server->vnc_screen); free(server); } EAPI Evas_Object * ecore_evas_vnc_server_new(Ecore_Evas *ee, int port, const char *addr, Ecore_Evas_Vnc_Client_Accept_Cb accept_cb, Ecore_Evas_Vnc_Client_Disconnected_Cb disc_cb, void *data) { Ecore_Evas_Vnc_Server *server; Evas_Object *snapshot; Eina_Bool can_listen = EINA_FALSE; EINA_SAFETY_ON_NULL_RETURN_VAL(ee, NULL); server = calloc(1, sizeof(Ecore_Evas_Vnc_Server)); EINA_SAFETY_ON_NULL_RETURN_VAL(server, NULL); snapshot = evas_object_image_filled_add(ee->evas); EINA_SAFETY_ON_NULL_RETURN_VAL(snapshot, NULL); evas_object_image_snapshot_set(snapshot, EINA_TRUE); efl_event_callback_del(snapshot, EFL_EVENT_DEL, _ecore_evas_vnc_server_del, server); server->key_info_get_func = _ecore_evas_vnc_server_fb_key_info_get; server->vnc_screen = rfbGetScreen(0, NULL, 4, 4, VNC_BITS_PER_SAMPLE, VNC_SAMPLES_PER_PIXEL, VNC_BYTES_PER_PIXEL); EINA_SAFETY_ON_NULL_GOTO(server->vnc_screen, err_screen); server->vnc_screen->newClientHook = _ecore_evas_vnc_server_client_connection_new; server->vnc_screen->kbdAddEvent = _ecore_evas_vnc_server_client_keyboard_event; server->vnc_screen->ptrAddEvent = _ecore_evas_vnc_server_client_pointer_event; //This enables multiple client connections at the same time. server->vnc_screen->alwaysShared = TRUE; server->vnc_screen->frameBuffer = server->frame_buffer; _ecore_evas_vnc_server_format_setup(server->vnc_screen); if (port > 0) server->vnc_screen->port = server->vnc_screen->ipv6port= port; if (addr) { int err; //rfbStringToAddr() does not change the addr contents. err = rfbStringToAddr((char *)addr, &server->vnc_screen->listenInterface); EINA_SAFETY_ON_TRUE_GOTO(err == 0, err_addr); } rfbInitServer(server->vnc_screen); if (server->vnc_screen->listenSock >= 0) { server->vnc_listen_handler = ecore_main_fd_handler_add(server->vnc_screen->listenSock, ECORE_FD_READ, _ecore_evas_vnc_server_socket_listen_activity, server->vnc_screen, NULL, NULL); EINA_SAFETY_ON_NULL_GOTO(server->vnc_listen_handler, err_listen); can_listen = EINA_TRUE; } if (server->vnc_screen->listen6Sock >= 0) { server->vnc_listen6_handler = ecore_main_fd_handler_add(server->vnc_screen->listen6Sock, ECORE_FD_READ, _ecore_evas_vnc_server_socket_listen_activity, server->vnc_screen, NULL, NULL); EINA_SAFETY_ON_NULL_GOTO(server->vnc_listen6_handler, err_listen6); can_listen = EINA_TRUE; } //rfbInitServer() failed and could not setup the sockets. EINA_SAFETY_ON_FALSE_GOTO(can_listen, err_engine); server->ee = ee; server->vnc_screen->screenData = server; server->cb_data = data; server->accept_cb = accept_cb; server->disc_cb = disc_cb; server->snapshot = snapshot; server->t = eina_tiler_new(1, 1); eina_tiler_tile_size_set(server->t, 1, 1); eina_tiler_strict_set(server->t, EINA_TRUE); evas_object_data_set(snapshot, "_ecore_evas.vnc", server); evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST, _ecore_evas_vnc_server_draw, snapshot); return snapshot; err_engine: ecore_main_fd_handler_del(server->vnc_listen6_handler); err_listen6: ecore_main_fd_handler_del(server->vnc_listen_handler); err_listen: rfbShutdownServer(server->vnc_screen, TRUE); err_addr: rfbScreenCleanup(server->vnc_screen); err_screen: free(server); return NULL; } EAPI Eina_Bool ecore_evas_vnc_server_pointer_xy_get(const Evas_Object *snapshot, const Evas_Device *pointer, Evas_Coord *x, Evas_Coord *y) { Ecore_Evas_Vnc_Server *server; rfbClientRec *client; Ecore_Evas_Vnc_Server_Client_Data *cdata; rfbClientIteratorPtr itr; EINA_SAFETY_ON_NULL_RETURN_VAL(snapshot, EINA_FALSE); server = evas_object_data_get(snapshot, "_ecore_evas.vnc"); EINA_SAFETY_ON_NULL_RETURN_VAL(server, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(pointer, EINA_FALSE); itr = rfbGetClientIterator(server->vnc_screen); while ((client = rfbClientIteratorNext(itr))) { cdata = client->clientData; if (cdata->mouse == pointer) { if (x) *x = client->lastPtrX; if (y) *y = client->lastPtrY; return EINA_TRUE; } } rfbReleaseClientIterator(itr); return EINA_FALSE; } EINA_MODULE_INIT(_ecore_evas_vnc_server_init); EINA_MODULE_SHUTDOWN(_ecore_evas_vnc_server_shutdown);