diff options
Diffstat (limited to 'VisualNaCro/nacro.c')
-rw-r--r-- | VisualNaCro/nacro.c | 455 |
1 files changed, 455 insertions, 0 deletions
diff --git a/VisualNaCro/nacro.c b/VisualNaCro/nacro.c new file mode 100644 index 0000000..7f1a874 --- /dev/null +++ b/VisualNaCro/nacro.c @@ -0,0 +1,455 @@ +#include <assert.h> +#include <rfb/rfb.h> +#include <rfb/rfbclient.h> + +#include "nacro.h" + +/* for visual grepping */ +typedef struct image_t { + int width,height; + char* buffer; +} image_t; + +/* this is a VNC connection */ +typedef struct private_resource_t { + int listen_port; + rfbScreenInfo* server; + rfbClient* client; + + uint32_t keysym; + rfbBool keydown; + + int x,y; + int buttons; + + image_t* grep_image; + int x_origin,y_origin; + + enum { SLEEP,VISUALGREP,WAITFORUPDATE } state; + result_t result; +} private_resource_t; + +/* resource management */ + +#define MAX_RESOURCE_COUNT 20 + +static private_resource_t resource_pool[MAX_RESOURCE_COUNT]; +static int resource_count=0; + +private_resource_t* get_resource(int resource) +{ + if(resource>=MAX_RESOURCE_COUNT || resource<0 || resource_pool[resource].client==0) + return 0; + return resource_pool+resource; +} + +private_resource_t* get_next_resource() +{ + if(resource_count<MAX_RESOURCE_COUNT) { + memset(resource_pool+resource_count,0,sizeof(private_resource_t)); + resource_count++; + return resource_pool+resource_count-1; + } else { + int i; + + for(i=0;i<MAX_RESOURCE_COUNT && resource_pool[i].client;i++); + if(i<MAX_RESOURCE_COUNT) + return resource_pool+i; + } + return 0; +} + +void free_resource(int resource) +{ + private_resource_t* res=get_resource(resource); + if(res) + res->client=0; +} + +/* hooks */ + +void got_key(rfbBool down,rfbKeySym keysym,rfbClientRec* cl) +{ + private_resource_t* res=(private_resource_t*)cl->screen->screenData; + + res->keydown=down; + res->keysym=keysym; + res->result|=RESULT_KEY; +} + +void got_mouse(int buttons,int x,int y,rfbClientRec* cl) +{ + private_resource_t* res=(private_resource_t*)cl->screen->screenData; + + res->buttons=buttons; + res->x=x; + res->y=y; + res->result|=RESULT_MOUSE; +} + +rfbBool malloc_frame_buffer(rfbClient* cl) +{ + private_resource_t* res=(private_resource_t*)cl->clientData; + + if(!res->server) { + int w=cl->width,h=cl->height; + + res->client->frameBuffer=malloc(w*4*h); + + res->server=rfbGetScreen(0,0,w,h,8,3,4); + res->server->screenData=res; + res->server->port=res->listen_port; + res->server->frameBuffer=res->client->frameBuffer; + res->server->kbdAddEvent=got_key; + res->server->ptrAddEvent=got_mouse; + rfbInitServer(res->server); + } else { + /* TODO: realloc if necessary */ + /* TODO: resolution change: send NewFBSize */ + /* TODO: if the origin is out of bounds, reset to 0 */ + } +} + +void got_frame_buffer(rfbClient* cl,int x,int y,int w,int h) +{ + private_resource_t* res=(private_resource_t*)cl->clientData; + + assert(res->server); + + if(res->grep_image) { + /* TODO: find image and set x_origin,y_origin if found */ + } else { + res->state=RESULT_SCREEN; + } + if(res->server) { + rfbMarkRectAsModified(res->server,x,y,x+w,y+h); + } + + res->result|=RESULT_SCREEN; +} + +/* init/shutdown functions */ + +resource_t initvnc(const char* server,int server_port,int listen_port) +{ + private_resource_t* res=get_next_resource(); + int dummy=0; + + if(res==0) + return -1; + + /* remember for later */ + res->listen_port=listen_port; + + res->client=rfbGetClient(8,3,4); + res->client->clientData=res; + res->client->GotFrameBufferUpdate=got_frame_buffer; + res->client->MallocFrameBuffer=malloc_frame_buffer; + res->client->serverHost=strdup(server); + res->client->serverPort=server_port; + res->client->appData.encodingsString="raw"; + if(!rfbInitClient(res->client,&dummy,0)) { + res->client=0; + return -1; + } + return res-resource_pool; +} + +void closevnc(resource_t resource) +{ + private_resource_t* res=get_resource(resource); + if(res==0) + return; + + if(res->server) + rfbScreenCleanup(res->server); + + assert(res->client); + + rfbClientCleanup(res->client); + + res->client=0; +} + +/* PNM (image) helpers */ + +bool_t savepnm(resource_t resource,const char* filename,int x1,int y1,int x2,int y2) +{ + private_resource_t* res=get_resource(resource); + int i,j,w,h; + uint32_t* buffer; + FILE* f; + + assert(res->client); + assert(res->client->format.depth==24); + + w=res->client->width; + h=res->client->height; + buffer=(uint32_t*)res->client->frameBuffer; + + if(res==0 || x1>x2 || y1>y2 || x1<0 || x2>=w || y1<0 || y2>=h) + return FALSE; + + f=fopen(filename,"wb"); + + if(f==0) + return FALSE; + + fprintf(f,"P6\n%d %d\n255\n",1+x2-x1,1+y2-y1); + for(j=y1;j<=y2;j++) + for(i=x1;i<=x2;i++) { + fwrite(buffer+i+j*w,3,1,f); + } + if(fclose(f)) + return FALSE; + return TRUE; +} + +image_t* loadpnm(const char* filename) +{ + FILE* f=fopen(filename,"rb"); + char buffer[1024]; + int i,j,w,h; + image_t* image; + + if(f==0) + return 0; + + if(!fgets(buffer,1024,f) || strcmp("P6\n",buffer)) { + fclose(f); + return 0; + } + + do { + fgets(buffer,1024,f); + if(feof(f)) { + fclose(f); + return 0; + } + } while(buffer[0]=='#'); + + if(!fgets(buffer,1024,f) || sscanf(buffer,"%d %d",&w,&h)!=2 + || !fgets(buffer,1024,f) || strcmp("255\n",buffer)) { + fclose(f); + return 0; + } + + image=(image_t*)malloc(sizeof(image_t)); + image->width=w; + image->height=h; + image->buffer=malloc(w*4*h); + if(!image->buffer) { + fclose(f); + free(image); + return 0; + } + + for(j=0;j<h;j++) + for(i=0;i<w;i++) + if(fread(image->buffer+4*(i+w*j),3,1,f)!=3) { + fclose(f); + free(image->buffer); + free(image); + return 0; + } + + fclose(f); + + return image; +} + +void free_image(image_t* image) +{ + if(image->buffer) + free(image->buffer); + free(image); +} + +/* process() and friends */ + +/* this function returns only if res->result in return_mask */ +result_t private_process(resource_t resource,timeout_t timeout_in_seconds,result_t return_mask) +{ + private_resource_t* res=get_resource(resource); + fd_set fds; + struct timeval tv,tv_start,tv_end; + unsigned long timeout=(unsigned long)(timeout_in_seconds*1000000UL); + int count,max_fd; + + if(res==0) + return 0; + + assert(res->client); + + gettimeofday(&tv_start,0); + res->result=0; + + do { + unsigned long timeout_done; + + if(res->server) { + rfbBool loop; + do { + loop=rfbProcessEvents(res->server,res->server->deferUpdateTime); + } while(loop && res->result&return_mask==0); + + if(res->result&return_mask!=0) + return res->result; + + memcpy((char*)&fds,(const char*)&(res->server->allFds),sizeof(fd_set)); + max_fd=res->server->maxFd; + } else { + FD_ZERO(&fds); + max_fd=0; + } + FD_SET(res->client->sock,&fds); + if(res->client->sock>max_fd) + max_fd=res->client->sock; + + gettimeofday(&tv_end,0); + timeout_done=tv_end.tv_usec-tv_start.tv_usec+ + 1000000L*(tv_end.tv_sec-tv_start.tv_sec); + if(timeout_done>=timeout) + return RESULT_TIMEOUT; + + tv.tv_usec=((timeout-timeout_done)%1000000); + tv.tv_sec=(timeout-timeout_done)/1000000; + + count=select(max_fd+1,&fds,0,0,&tv); + if(count<0) + return 0; + + if(count>0) { + if(FD_ISSET(res->client->sock,&fds)) { + if(!HandleRFBServerMessage(res->client)) + return 0; + if(res->result&return_mask!=0) + return res->result; + } + } else { + res->result|=RESULT_TIMEOUT; + return RESULT_TIMEOUT; + } + } while(1); + + return RESULT_TIMEOUT; +} + +result_t process(resource_t res,timeout_t timeout) +{ + return private_process(res,timeout,RESULT_TIMEOUT); +} + +result_t waitforanything(resource_t res,timeout_t timeout) +{ + return private_process(res,timeout,-1); +} + +result_t waitforinput(resource_t res,timeout_t timeout) +{ + return private_process(res,timeout,RESULT_KEY|RESULT_MOUSE|RESULT_TIMEOUT); +} + +result_t waitforupdate(resource_t res,timeout_t timeout) +{ + return private_process(res,timeout,RESULT_SCREEN|RESULT_TIMEOUT); +} + +result_t visualgrep(resource_t res,const char* filename,timeout_t timeout) +{ + /* TODO: load filename and set res->grep_image to this image */ + return private_process(res,timeout,RESULT_FOUNDIMAGE|RESULT_TIMEOUT); +} + +/* this is an overlay which is shown for a certain time */ + +result_t alert(resource_t resource,const char* message,timeout_t timeout) +{ + private_resource_t* res=get_resource(resource); + char* fake_frame_buffer; + char* backup; + int w,h; + result_t result; + + if(res->server==0) + return -1; + + w=res->server->width; + h=res->server->height; + + fake_frame_buffer=malloc(w*4*h); + if(!fake_frame_buffer) + return -1; + memcpy(fake_frame_buffer,res->server->frameBuffer,w*4*h); + /* TODO: draw message */ + + backup=res->server->frameBuffer; + res->server->frameBuffer=fake_frame_buffer; + + result=private_process(resource,timeout,-1); + + res->server->frameBuffer=backup; + /* TODO: rfbMarkRectAsModified() */ + + return result; +} +/* inspect last events */ + +keysym_t getkeysym(resource_t res) +{ + private_resource_t* r=get_resource(res); + return r->keysym; +} + +bool_t getkeydown(resource_t res) +{ + private_resource_t* r=get_resource(res); + return r->keydown; +} + +coordinate_t getx(resource_t res) +{ + private_resource_t* r=get_resource(res); + return r->x; +} + +coordinate_t gety(resource_t res) +{ + private_resource_t* r=get_resource(res); + return r->y; +} + +buttons_t getbuttons(resource_t res) +{ + private_resource_t* r=get_resource(res); + return r->buttons; +} + +/* send events to the server */ + +bool_t sendkey(resource_t res,keysym_t keysym,bool_t keydown) +{ + private_resource_t* r=get_resource(res); + return SendKeyEvent(r->client,keysym,keydown); +} + +bool_t sendmouse(resource_t res,coordinate_t x,coordinate_t y,buttons_t buttons) +{ + private_resource_t* r=get_resource(res); + return SendPointerEvent(r->client,x,y,buttons); +} + +/* for visual grepping */ + +coordinate_t getoriginx(resource_t res) +{ + private_resource_t* r=get_resource(res); + return r->x_origin; +} + +coordinate_t getoriginy(resource_t res) +{ + private_resource_t* r=get_resource(res); + return r->y_origin; +} + |