San Mehat | a430b2b | 2014-09-23 08:30:51 -0700 | [diff] [blame] | 1 | #include <assert.h> |
| 2 | #include <string.h> |
| 3 | #include <rfb/rfb.h> |
| 4 | #include <rfb/rfbclient.h> |
| 5 | |
| 6 | #include "nacro.h" |
| 7 | |
| 8 | /* for visual grepping */ |
| 9 | typedef struct image_t { |
| 10 | int width,height; |
| 11 | char* buffer; |
| 12 | } image_t; |
| 13 | |
| 14 | /* this is a VNC connection */ |
| 15 | typedef struct private_resource_t { |
| 16 | int listen_port; |
| 17 | rfbScreenInfo* server; |
| 18 | rfbClient* client; |
| 19 | |
| 20 | uint32_t keysym; |
| 21 | rfbBool keydown; |
| 22 | |
| 23 | int x,y; |
| 24 | int buttons; |
| 25 | |
| 26 | char* text_client; |
| 27 | char* text_server; |
| 28 | |
| 29 | image_t* grep_image; |
| 30 | int x_origin,y_origin; |
| 31 | |
| 32 | enum { SLEEP,VISUALGREP,WAITFORUPDATE } state; |
| 33 | result_t result; |
| 34 | } private_resource_t; |
| 35 | |
| 36 | /* resource management */ |
| 37 | |
| 38 | #define MAX_RESOURCE_COUNT 20 |
| 39 | |
| 40 | static private_resource_t resource_pool[MAX_RESOURCE_COUNT]; |
| 41 | static int resource_count=0; |
| 42 | |
| 43 | static private_resource_t* get_resource(int resource) |
| 44 | { |
| 45 | if(resource>=MAX_RESOURCE_COUNT || resource<0 || resource_pool[resource].client==0) |
| 46 | return NULL; |
| 47 | return resource_pool+resource; |
| 48 | } |
| 49 | |
| 50 | static private_resource_t* get_next_resource(void) |
| 51 | { |
| 52 | if(resource_count<MAX_RESOURCE_COUNT) { |
| 53 | memset(resource_pool+resource_count,0,sizeof(private_resource_t)); |
| 54 | resource_count++; |
| 55 | return resource_pool+resource_count-1; |
| 56 | } else { |
| 57 | int i; |
| 58 | |
| 59 | for(i=0;i<MAX_RESOURCE_COUNT && resource_pool[i].client;i++); |
| 60 | if(i<MAX_RESOURCE_COUNT) |
| 61 | return resource_pool+i; |
| 62 | } |
| 63 | return NULL; |
| 64 | } |
| 65 | |
| 66 | static void free_resource(int resource) |
| 67 | { |
| 68 | private_resource_t* res=get_resource(resource); |
| 69 | if(res) |
| 70 | res->client=NULL; |
| 71 | } |
| 72 | |
| 73 | /* hooks */ |
| 74 | |
| 75 | static void got_key(rfbBool down,rfbKeySym keysym,rfbClientRec* cl) |
| 76 | { |
| 77 | private_resource_t* res=(private_resource_t*)cl->screen->screenData; |
| 78 | |
| 79 | res->keydown=down; |
| 80 | res->keysym=keysym; |
| 81 | res->result|=RESULT_KEY; |
| 82 | } |
| 83 | |
| 84 | static void got_mouse(int buttons,int x,int y,rfbClientRec* cl) |
| 85 | { |
| 86 | private_resource_t* res=(private_resource_t*)cl->screen->screenData; |
| 87 | |
| 88 | res->buttons=buttons; |
| 89 | res->x=x; |
| 90 | res->y=y; |
| 91 | res->result|=RESULT_MOUSE; |
| 92 | } |
| 93 | |
| 94 | static void got_text(char* str,int len,rfbClientRec* cl) |
| 95 | { |
| 96 | private_resource_t* res=(private_resource_t*)cl->screen->screenData; |
| 97 | |
| 98 | if (res->text_client) |
| 99 | free(res->text_client); |
| 100 | res->text_client=strdup(str); |
| 101 | res->result|=RESULT_TEXT_CLIENT; |
| 102 | } |
| 103 | |
| 104 | static void got_text_from_server(rfbClient* cl, const char *str, int textlen) |
| 105 | { |
| 106 | private_resource_t* res=(private_resource_t*)cl->clientData; |
| 107 | |
| 108 | if (res->text_server) |
| 109 | free(res->text_server); |
| 110 | res->text_server=strdup(str); |
| 111 | res->result|=RESULT_TEXT_SERVER; |
| 112 | } |
| 113 | |
| 114 | static rfbBool malloc_frame_buffer(rfbClient* cl) |
| 115 | { |
| 116 | private_resource_t* res=(private_resource_t*)cl->clientData; |
| 117 | |
| 118 | if(!res->server) { |
| 119 | int w=cl->width,h=cl->height; |
| 120 | |
| 121 | res->client->frameBuffer=malloc(w*4*h); |
| 122 | |
| 123 | res->server=rfbGetScreen(NULL,NULL,w,h,8,3,4); |
| 124 | if(!res->server) |
| 125 | return FALSE; |
| 126 | res->server->screenData=res; |
| 127 | res->server->port=res->listen_port; |
| 128 | res->server->frameBuffer=res->client->frameBuffer; |
| 129 | res->server->kbdAddEvent=got_key; |
| 130 | res->server->ptrAddEvent=got_mouse; |
| 131 | res->server->setXCutText=got_text; |
| 132 | rfbInitServer(res->server); |
| 133 | } else { |
| 134 | /* TODO: realloc if necessary */ |
| 135 | /* TODO: resolution change: send NewFBSize */ |
| 136 | /* TODO: if the origin is out of bounds, reset to 0 */ |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | static bool_t do_visual_grep(private_resource_t* res,int x,int y,int w,int h) |
| 141 | { |
| 142 | rfbClient* cl; |
| 143 | image_t* image; |
| 144 | int x_start,y_start,x_end=x+w-1,y_end=y+h-1; |
| 145 | bool_t found=0; |
| 146 | |
| 147 | if(res==0 || (cl=res->client)==0 || (image=res->grep_image)==0) |
| 148 | return 0; |
| 149 | |
| 150 | x_start=x-image->width; |
| 151 | y_start=y-image->height; |
| 152 | if(x_start<0) x_start=0; |
| 153 | if(y_start<0) y_start=0; |
| 154 | if(x_end+image->width>cl->width) x_end=cl->width-image->width; |
| 155 | if(y_end+image->height>cl->height) y_end=cl->height-image->height; |
| 156 | |
| 157 | /* find image and set x_origin,y_origin if found */ |
| 158 | for(y=y_start;y<y_end;y++) |
| 159 | for(x=x_start;x<x_end;x++) { |
| 160 | bool_t matching=1; |
| 161 | int i,j; |
| 162 | for(j=0;matching && j<image->height;j++) |
| 163 | for(i=0;matching && i<image->width;i++) |
| 164 | if(memcmp(cl->frameBuffer+4*(x+i+cl->width*(y+j)),image->buffer+4*(i+image->width*j),3)) |
| 165 | matching=0; |
| 166 | if(matching) { |
| 167 | private_resource_t* res=(private_resource_t*)cl->clientData; |
| 168 | res->x_origin=x; |
| 169 | res->y_origin=y; |
| 170 | return -1; |
| 171 | } |
| 172 | } |
| 173 | return 0; |
| 174 | } |
| 175 | |
| 176 | static void got_frame_buffer(rfbClient* cl,int x,int y,int w,int h) |
| 177 | { |
| 178 | private_resource_t* res=(private_resource_t*)cl->clientData; |
| 179 | |
| 180 | assert(res->server); |
| 181 | |
| 182 | if(res->grep_image && do_visual_grep(res,x,y,w,h)) { |
| 183 | res->result|=RESULT_FOUNDIMAGE; |
| 184 | } |
| 185 | if(res->server) { |
| 186 | rfbMarkRectAsModified(res->server,x,y,x+w,y+h); |
| 187 | } |
| 188 | |
| 189 | res->result|=RESULT_SCREEN; |
| 190 | } |
| 191 | |
| 192 | /* init/shutdown functions */ |
| 193 | |
| 194 | resource_t initvnc(const char* server,int server_port,int listen_port) |
| 195 | { |
| 196 | private_resource_t* res=get_next_resource(); |
| 197 | int dummy=0; |
| 198 | |
| 199 | if(res==0) |
| 200 | return -1; |
| 201 | |
| 202 | /* remember for later */ |
| 203 | res->listen_port=listen_port; |
| 204 | |
| 205 | res->text_client = NULL; |
| 206 | res->text_server = NULL; |
| 207 | |
| 208 | res->client=rfbGetClient(8,3,4); |
| 209 | res->client->clientData=(void*)res; |
| 210 | res->client->GotFrameBufferUpdate=got_frame_buffer; |
| 211 | res->client->MallocFrameBuffer=malloc_frame_buffer; |
| 212 | res->client->GotXCutText=got_text_from_server; |
| 213 | res->client->serverHost=strdup(server); |
| 214 | res->client->serverPort=server_port; |
| 215 | res->client->appData.encodingsString="raw"; |
| 216 | if(!rfbInitClient(res->client,&dummy,NULL)) { |
| 217 | res->client=NULL; |
| 218 | return -1; |
| 219 | } |
| 220 | return res-resource_pool; |
| 221 | } |
| 222 | |
| 223 | void closevnc(resource_t resource) |
| 224 | { |
| 225 | private_resource_t* res=get_resource(resource); |
| 226 | if(res==0) |
| 227 | return; |
| 228 | |
| 229 | if(res->server) |
| 230 | rfbScreenCleanup(res->server); |
| 231 | |
| 232 | assert(res->client); |
| 233 | |
| 234 | rfbClientCleanup(res->client); |
| 235 | |
| 236 | res->client=NULL; |
| 237 | } |
| 238 | |
| 239 | /* PNM (image) helpers */ |
| 240 | |
| 241 | bool_t savepnm(resource_t resource,const char* filename,int x1,int y1,int x2,int y2) |
| 242 | { |
| 243 | private_resource_t* res=get_resource(resource); |
| 244 | int i,j,w,h; |
| 245 | uint32_t* buffer; |
| 246 | FILE* f; |
| 247 | |
| 248 | if(res==0 || res->client==0) |
| 249 | return 0; |
| 250 | assert(res->client->format.depth==24); |
| 251 | |
| 252 | w=res->client->width; |
| 253 | h=res->client->height; |
| 254 | buffer=(uint32_t*)res->client->frameBuffer; |
| 255 | |
| 256 | if(res==0 || x1>x2 || y1>y2 || x1<0 || x2>=w || y1<0 || y2>=h) |
| 257 | return FALSE; |
| 258 | |
| 259 | f=fopen(filename,"wb"); |
| 260 | |
| 261 | if(f==0) |
| 262 | return FALSE; |
| 263 | |
| 264 | fprintf(f,"P6\n%d %d\n255\n",1+x2-x1,1+y2-y1); |
| 265 | for(j=y1;j<=y2;j++) |
| 266 | for(i=x1;i<=x2;i++) { |
| 267 | fwrite(buffer+i+j*w,3,1,f); |
| 268 | } |
| 269 | if(fclose(f)) |
| 270 | return FALSE; |
| 271 | return TRUE; |
| 272 | } |
| 273 | |
| 274 | static image_t* loadpnm(const char* filename) |
| 275 | { |
| 276 | FILE* f=fopen(filename,"rb"); |
| 277 | char buffer[1024]; |
| 278 | int i,j,w,h; |
| 279 | image_t* image; |
| 280 | |
| 281 | if(f==0) |
| 282 | return NULL; |
| 283 | |
| 284 | if(!fgets(buffer,1024,f) || strcmp("P6\n",buffer)) { |
| 285 | fclose(f); |
| 286 | return NULL; |
| 287 | } |
| 288 | |
| 289 | do { |
| 290 | fgets(buffer,1024,f); |
| 291 | if(feof(f)) { |
| 292 | fclose(f); |
| 293 | return NULL; |
| 294 | } |
| 295 | } while(buffer[0]=='#'); |
| 296 | |
| 297 | if( sscanf(buffer,"%d %d",&w,&h)!=2 |
| 298 | || !fgets(buffer,1024,f) || strcmp("255\n",buffer)) { |
| 299 | fclose(f); |
| 300 | return NULL; |
| 301 | } |
| 302 | |
| 303 | image=(image_t*)malloc(sizeof(image_t)); |
| 304 | image->width=w; |
| 305 | image->height=h; |
| 306 | image->buffer=malloc(w*4*h); |
| 307 | if(!image->buffer) { |
| 308 | fclose(f); |
| 309 | free(image); |
| 310 | return NULL; |
| 311 | } |
| 312 | |
| 313 | for(j=0;j<h;j++) |
| 314 | for(i=0;i<w;i++) |
| 315 | if(fread(image->buffer+4*(i+w*j),3,1,f)!=1) { |
| 316 | fprintf(stderr,"Could not read 3 bytes at %d,%d\n",i,j); |
| 317 | fclose(f); |
| 318 | free(image->buffer); |
| 319 | free(image); |
| 320 | return NULL; |
| 321 | } |
| 322 | |
| 323 | fclose(f); |
| 324 | |
| 325 | return image; |
| 326 | } |
| 327 | |
| 328 | static void free_image(image_t* image) |
| 329 | { |
| 330 | if(image->buffer) |
| 331 | free(image->buffer); |
| 332 | free(image); |
| 333 | } |
| 334 | |
| 335 | static void copy_line(rfbScreenInfo *dest, char *backup, |
| 336 | int x0, int y0, int x1, int y1, int color_offset) |
| 337 | { |
| 338 | uint8_t *d = (uint8_t *)dest->frameBuffer, *s = (uint8_t *)backup; |
| 339 | int i; |
| 340 | int steps0 = x1 > x0 ? x1 - x0 : x0 - x1; |
| 341 | int steps1 = y1 > y0 ? y1 - y0 : y0 - y1; |
| 342 | |
| 343 | if (steps1 > steps0) |
| 344 | steps0 = steps1; |
| 345 | else if (steps0 == 0) |
| 346 | steps0 = 1; |
| 347 | |
| 348 | for (i = 0; i <= steps0; i++) { |
| 349 | int j, index = 4 * (x0 + i * (x1 - x0) / steps0 |
| 350 | + dest->width * (y0 + i * (y1 - y0) / steps0)); |
| 351 | for (j = 0; j < 4; j++) |
| 352 | d[index + j] = s[index + j] + color_offset; |
| 353 | } |
| 354 | |
| 355 | rfbMarkRectAsModified(dest, x0 - 5, y0 - 5, x1 + 1, y1 + 2); |
| 356 | } |
| 357 | |
| 358 | result_t displaypnm(resource_t resource, const char *filename, |
| 359 | coordinate_t x, coordinate_t y, bool_t border, |
| 360 | timeout_t timeout_in_seconds) |
| 361 | { |
| 362 | private_resource_t* res = get_resource(resource); |
| 363 | image_t *image; |
| 364 | char* fake_frame_buffer; |
| 365 | char* backup; |
| 366 | int w, h, i, j, w2, h2; |
| 367 | result_t result; |
| 368 | |
| 369 | if (res == NULL || res->server == NULL || |
| 370 | (image = loadpnm(filename)) == NULL) |
| 371 | return 0; |
| 372 | |
| 373 | w = res->server->width; |
| 374 | h = res->server->height; |
| 375 | fake_frame_buffer = malloc(w * 4 * h); |
| 376 | if(!fake_frame_buffer) |
| 377 | return 0; |
| 378 | memcpy(fake_frame_buffer, res->server->frameBuffer, w * 4 * h); |
| 379 | |
| 380 | backup = res->server->frameBuffer; |
| 381 | res->server->frameBuffer = fake_frame_buffer; |
| 382 | |
| 383 | w2 = image->width; |
| 384 | if (x + w2 > w) |
| 385 | w2 = w - x; |
| 386 | h2 = image->height; |
| 387 | if (y + h2 > h) |
| 388 | h2 = h - y; |
| 389 | for (j = 0; j < h2; j++) |
| 390 | memcpy(fake_frame_buffer + 4 * (x + (y + j) * w), |
| 391 | image->buffer + j * 4 * image->width, 4 * w2); |
| 392 | free(image); |
| 393 | if (border) { |
| 394 | copy_line(res->server, backup, x, y, x + w2, y, 0x80); |
| 395 | copy_line(res->server, backup, x, y, x, y + h2, 0x80); |
| 396 | copy_line(res->server, backup, x + w2, y, x + w2, y + h2, 0x80); |
| 397 | copy_line(res->server, backup, x, y + h2, x + w2, y + h2, 0x80); |
| 398 | } |
| 399 | rfbMarkRectAsModified(res->server, |
| 400 | x - 1, y - 1, x + w2 + 1, y + h2 + 1); |
| 401 | |
| 402 | result = waitforinput(resource, timeout_in_seconds); |
| 403 | |
| 404 | res->server->frameBuffer=backup; |
| 405 | free(fake_frame_buffer); |
| 406 | rfbMarkRectAsModified(res->server, |
| 407 | x - 1, y - 1, x + w2 + 1, y + h2 + 1); |
| 408 | |
| 409 | return result; |
| 410 | } |
| 411 | |
| 412 | /* process() and friends */ |
| 413 | |
| 414 | /* this function returns only if res->result in return_mask */ |
| 415 | static result_t private_process(resource_t resource,timeout_t timeout_in_seconds,result_t return_mask) |
| 416 | { |
| 417 | private_resource_t* res=get_resource(resource); |
| 418 | fd_set fds; |
| 419 | struct timeval tv,tv_start,tv_end; |
| 420 | unsigned long timeout=(unsigned long)(timeout_in_seconds*1000000UL); |
| 421 | int count,max_fd; |
| 422 | |
| 423 | if(res==0) |
| 424 | return 0; |
| 425 | |
| 426 | assert(res->client); |
| 427 | |
| 428 | gettimeofday(&tv_start,NULL); |
| 429 | res->result=0; |
| 430 | |
| 431 | do { |
| 432 | unsigned long timeout_done; |
| 433 | |
| 434 | if(res->server) { |
| 435 | rfbBool loop; |
| 436 | do { |
| 437 | loop=rfbProcessEvents(res->server,res->server->deferUpdateTime); |
| 438 | } while(loop && (res->result&return_mask)==0 |
| 439 | && rfbIsActive(res->server)); |
| 440 | |
| 441 | if(!rfbIsActive(res->server)) |
| 442 | return RESULT_SHUTDOWN; |
| 443 | |
| 444 | if((res->result&return_mask)!=0) |
| 445 | return res->result; |
| 446 | |
| 447 | memcpy((char*)&fds,(const char*)&(res->server->allFds),sizeof(fd_set)); |
| 448 | max_fd=res->server->maxFd; |
| 449 | } else { |
| 450 | FD_ZERO(&fds); |
| 451 | max_fd=0; |
| 452 | } |
| 453 | FD_SET(res->client->sock,&fds); |
| 454 | if(res->client->sock>max_fd) |
| 455 | max_fd=res->client->sock; |
| 456 | |
| 457 | gettimeofday(&tv_end,NULL); |
| 458 | timeout_done=tv_end.tv_usec-tv_start.tv_usec+ |
| 459 | 1000000L*(tv_end.tv_sec-tv_start.tv_sec); |
| 460 | if(timeout_done>=timeout) |
| 461 | return RESULT_TIMEOUT; |
| 462 | |
| 463 | tv.tv_usec=((timeout-timeout_done)%1000000); |
| 464 | tv.tv_sec=(timeout-timeout_done)/1000000; |
| 465 | |
| 466 | count=select(max_fd+1,&fds,NULL,NULL,&tv); |
| 467 | if(count<0) |
| 468 | return 0; |
| 469 | |
| 470 | if(count>0) { |
| 471 | if(FD_ISSET(res->client->sock,&fds)) { |
| 472 | if(!HandleRFBServerMessage(res->client)) { |
| 473 | closevnc(resource); |
| 474 | return 0; |
| 475 | } |
| 476 | if((res->result&return_mask)!=0) |
| 477 | return res->result; |
| 478 | } |
| 479 | } else { |
| 480 | res->result|=RESULT_TIMEOUT; |
| 481 | return res->result; |
| 482 | } |
| 483 | } while(1); |
| 484 | |
| 485 | return RESULT_TIMEOUT; |
| 486 | } |
| 487 | |
| 488 | result_t process(resource_t res,timeout_t timeout) |
| 489 | { |
| 490 | return private_process(res,timeout,RESULT_TIMEOUT); |
| 491 | } |
| 492 | |
| 493 | result_t waitforanything(resource_t res,timeout_t timeout) |
| 494 | { |
| 495 | return private_process(res,timeout,-1); |
| 496 | } |
| 497 | |
| 498 | result_t waitforinput(resource_t res,timeout_t timeout) |
| 499 | { |
| 500 | return private_process(res,timeout,RESULT_KEY|RESULT_MOUSE|RESULT_TIMEOUT); |
| 501 | } |
| 502 | |
| 503 | result_t waitforupdate(resource_t res,timeout_t timeout) |
| 504 | { |
| 505 | return private_process(res,timeout,RESULT_SCREEN|RESULT_TIMEOUT); |
| 506 | } |
| 507 | |
| 508 | result_t visualgrep(resource_t resource,const char* filename,timeout_t timeout) |
| 509 | { |
| 510 | private_resource_t* res=get_resource(resource); |
| 511 | image_t* image; |
| 512 | result_t result; |
| 513 | |
| 514 | if(res==0 || res->client==0) |
| 515 | return 0; |
| 516 | |
| 517 | /* load filename and set res->grep_image to this image */ |
| 518 | image=loadpnm(filename); |
| 519 | if(image==0) |
| 520 | return 0; |
| 521 | if(res->grep_image) |
| 522 | free_image(res->grep_image); |
| 523 | res->grep_image=image; |
| 524 | |
| 525 | if(do_visual_grep(res,0,0,res->client->width,res->client->height)) |
| 526 | return RESULT_FOUNDIMAGE; |
| 527 | |
| 528 | result=private_process(resource,timeout,RESULT_FOUNDIMAGE|RESULT_TIMEOUT); |
| 529 | |
| 530 | /* free image */ |
| 531 | if(res->grep_image) { |
| 532 | free_image(res->grep_image); |
| 533 | res->grep_image=NULL; |
| 534 | } |
| 535 | |
| 536 | return result; |
| 537 | } |
| 538 | |
| 539 | /* auxiliary function for alert */ |
| 540 | |
| 541 | #include "default8x16.h" |
| 542 | |
| 543 | static void center_text(rfbScreenInfo* screen,const char* message,int* x,int* y,int* w,int* h) |
| 544 | { |
| 545 | rfbFontData* font=&default8x16Font; |
| 546 | const char* pointer; |
| 547 | int j,x1,y1,x2,y2,line_count=0; |
| 548 | if(message==0 || screen==0) |
| 549 | return; |
| 550 | rfbWholeFontBBox(font,&x1,&y1,&x2,&y2); |
| 551 | for(line_count=1,pointer=message;*pointer;pointer++) |
| 552 | if(*pointer=='\n') |
| 553 | line_count++; |
| 554 | |
| 555 | *h=(y2-y1)*line_count; |
| 556 | assert(*h>0); |
| 557 | |
| 558 | if(*h>screen->height) |
| 559 | *h=screen->height; |
| 560 | |
| 561 | *x=0; *w=screen->width; *y=(screen->height-*h)/2; |
| 562 | |
| 563 | rfbFillRect(screen,*x,*y,*x+*w,*y+*h,0xff0000); |
| 564 | |
| 565 | for(pointer=message,j=0;j<line_count;j++) { |
| 566 | const char* eol; |
| 567 | int x_cur,y_cur=*y-y1+j*(y2-y1),width; |
| 568 | |
| 569 | for(width=0,eol=pointer;*eol && *eol!='\n';eol++) |
| 570 | width+=rfbWidthOfChar(font,*eol); |
| 571 | if(width>screen->width) |
| 572 | width=screen->width; |
| 573 | |
| 574 | x_cur=(screen->width-width)/2; |
| 575 | for(;pointer!=eol;pointer++) |
| 576 | x_cur+=rfbDrawCharWithClip(screen,font, |
| 577 | x_cur,y_cur,*pointer, |
| 578 | 0,0,screen->width,screen->height, |
| 579 | 0xffffffff,0xffffffff); |
| 580 | pointer++; |
| 581 | } |
| 582 | rfbMarkRectAsModified(screen,*x,*y,*x+*w,*y+*h); |
| 583 | } |
| 584 | |
| 585 | /* this is an overlay which is shown for a certain time */ |
| 586 | |
| 587 | result_t alert(resource_t resource,const char* message,timeout_t timeout) |
| 588 | { |
| 589 | private_resource_t* res=get_resource(resource); |
| 590 | char* fake_frame_buffer; |
| 591 | char* backup; |
| 592 | int x,y,w,h; |
| 593 | result_t result; |
| 594 | |
| 595 | if(res == NULL || res->server==NULL) |
| 596 | return -1; |
| 597 | |
| 598 | w=res->server->width; |
| 599 | h=res->server->height; |
| 600 | |
| 601 | fake_frame_buffer=malloc(w*4*h); |
| 602 | if(!fake_frame_buffer) |
| 603 | return -1; |
| 604 | memcpy(fake_frame_buffer,res->server->frameBuffer,w*4*h); |
| 605 | |
| 606 | backup=res->server->frameBuffer; |
| 607 | res->server->frameBuffer=fake_frame_buffer; |
| 608 | center_text(res->server,message,&x,&y,&w,&h); |
| 609 | fprintf(stderr,"%s\n",message); |
| 610 | |
| 611 | result=waitforinput(resource,timeout); |
| 612 | |
| 613 | res->server->frameBuffer=backup; |
| 614 | free(fake_frame_buffer); |
| 615 | rfbMarkRectAsModified(res->server,x,y,x+w,y+h); |
| 616 | |
| 617 | return result; |
| 618 | } |
| 619 | /* inspect last events */ |
| 620 | |
| 621 | keysym_t getkeysym(resource_t res) |
| 622 | { |
| 623 | private_resource_t* r=get_resource(res); |
| 624 | return r->keysym; |
| 625 | } |
| 626 | |
| 627 | bool_t getkeydown(resource_t res) |
| 628 | { |
| 629 | private_resource_t* r=get_resource(res); |
| 630 | return r->keydown; |
| 631 | } |
| 632 | |
| 633 | coordinate_t getx(resource_t res) |
| 634 | { |
| 635 | private_resource_t* r=get_resource(res); |
| 636 | return r->x; |
| 637 | } |
| 638 | |
| 639 | coordinate_t gety(resource_t res) |
| 640 | { |
| 641 | private_resource_t* r=get_resource(res); |
| 642 | return r->y; |
| 643 | } |
| 644 | |
| 645 | buttons_t getbuttons(resource_t res) |
| 646 | { |
| 647 | private_resource_t* r=get_resource(res); |
| 648 | return r->buttons; |
| 649 | } |
| 650 | |
| 651 | const char *gettext_client(resource_t res) |
| 652 | { |
| 653 | private_resource_t* r=get_resource(res); |
| 654 | return r->text_client; |
| 655 | } |
| 656 | |
| 657 | result_t rubberband(resource_t resource, coordinate_t x0, coordinate_t y0) |
| 658 | { |
| 659 | private_resource_t* res=get_resource(resource); |
| 660 | char* fake_frame_buffer; |
| 661 | char* backup; |
| 662 | int w, h, x, y; |
| 663 | |
| 664 | if(res == NULL || res->server==NULL) |
| 665 | return -1; |
| 666 | |
| 667 | x = res->x; |
| 668 | y = res->y; |
| 669 | w = res->server->width; |
| 670 | h = res->server->height; |
| 671 | fake_frame_buffer = malloc(w * 4 * h); |
| 672 | if(!fake_frame_buffer) |
| 673 | return 0; |
| 674 | memcpy(fake_frame_buffer, res->server->frameBuffer, w * 4 * h); |
| 675 | |
| 676 | backup = res->server->frameBuffer; |
| 677 | res->server->frameBuffer = fake_frame_buffer; |
| 678 | |
| 679 | while (res->buttons) { |
| 680 | result_t r = waitforinput(resource, 1000000L); |
| 681 | if (x == res->x && y == res->y) |
| 682 | continue; |
| 683 | copy_line(res->server, backup, x0, y0, x, y0, 0); |
| 684 | copy_line(res->server, backup, x0, y0, x0, y, 0); |
| 685 | copy_line(res->server, backup, x, y0, x, y, 0); |
| 686 | copy_line(res->server, backup, x0, y, x, y, 0); |
| 687 | x = res->x; |
| 688 | y = res->y; |
| 689 | copy_line(res->server, backup, x0, y0, x, y0, 0x80); |
| 690 | copy_line(res->server, backup, x0, y0, x0, y, 0x80); |
| 691 | copy_line(res->server, backup, x, y0, x, y, 0x80); |
| 692 | copy_line(res->server, backup, x0, y, x, y, 0x80); |
| 693 | } |
| 694 | |
| 695 | copy_line(res->server, backup, x0, y0, x, y0, 0); |
| 696 | copy_line(res->server, backup, x0, y0, x0, y, 0); |
| 697 | copy_line(res->server, backup, x, y0, x, y, 0); |
| 698 | copy_line(res->server, backup, x0, y, x, y, 0); |
| 699 | |
| 700 | res->server->frameBuffer=backup; |
| 701 | free(fake_frame_buffer); |
| 702 | |
| 703 | return RESULT_MOUSE; |
| 704 | } |
| 705 | |
| 706 | const char *gettext_server(resource_t res) |
| 707 | { |
| 708 | private_resource_t* r=get_resource(res); |
| 709 | return r->text_server; |
| 710 | } |
| 711 | |
| 712 | /* send events to the server */ |
| 713 | |
| 714 | bool_t sendkey(resource_t res,keysym_t keysym,bool_t keydown) |
| 715 | { |
| 716 | private_resource_t* r=get_resource(res); |
| 717 | if(r==NULL) |
| 718 | return 0; |
| 719 | return SendKeyEvent(r->client,keysym,keydown); |
| 720 | } |
| 721 | |
| 722 | bool_t sendascii(resource_t res,const char *string) |
| 723 | { |
| 724 | timeout_t delay = 0.1; |
| 725 | private_resource_t* r=get_resource(res); |
| 726 | int i; |
| 727 | if(r==NULL) |
| 728 | return 0; |
| 729 | while (*string) { |
| 730 | int keysym = *string; |
| 731 | int need_shift = 0; |
| 732 | |
| 733 | if (keysym >= 8 && keysym < ' ') |
| 734 | keysym += 0xff00; |
| 735 | else if (keysym >= 'A' && keysym <= 'Z') |
| 736 | need_shift = 1; |
| 737 | else if (keysym > '~') { |
| 738 | fprintf(stderr, "String contains non-ASCII " |
| 739 | "character 0x%02x\n", *string); |
| 740 | return FALSE; |
| 741 | } |
| 742 | |
| 743 | if (need_shift) { |
| 744 | if (!SendKeyEvent(r->client,0xffe1,1)) |
| 745 | return FALSE; |
| 746 | waitforinput(r,delay); |
| 747 | } |
| 748 | for (i = 1; i >= 0; i--) { |
| 749 | if (!SendKeyEvent(r->client,keysym,i)) |
| 750 | return FALSE; |
| 751 | waitforinput(r,delay); |
| 752 | } |
| 753 | if (need_shift) { |
| 754 | if (!SendKeyEvent(r->client,0xffe1,0)) |
| 755 | return FALSE; |
| 756 | waitforinput(r,delay); |
| 757 | } |
| 758 | string++; |
| 759 | } |
| 760 | return TRUE; |
| 761 | } |
| 762 | |
| 763 | bool_t sendmouse(resource_t res,coordinate_t x,coordinate_t y,buttons_t buttons) |
| 764 | { |
| 765 | private_resource_t* r=get_resource(res); |
| 766 | if(r==NULL) |
| 767 | return 0; |
| 768 | return SendPointerEvent(r->client,x,y,buttons); |
| 769 | } |
| 770 | |
| 771 | bool_t sendtext(resource_t res, const char *string) |
| 772 | { |
| 773 | private_resource_t* r=get_resource(res); |
| 774 | if(r==NULL) |
| 775 | return 0; |
| 776 | return SendClientCutText(r->client, (char *)string, (int)strlen(string)); |
| 777 | } |
| 778 | |
| 779 | bool_t sendtext_to_server(resource_t res, const char *string) |
| 780 | { |
| 781 | private_resource_t* r=get_resource(res); |
| 782 | if(r==NULL) |
| 783 | return 0; |
| 784 | rfbSendServerCutText(r->server, (char *)string, (int)strlen(string)); |
| 785 | return 1; |
| 786 | } |
| 787 | |
| 788 | /* for visual grepping */ |
| 789 | |
| 790 | coordinate_t getxorigin(resource_t res) |
| 791 | { |
| 792 | private_resource_t* r=get_resource(res); |
| 793 | return r->x_origin; |
| 794 | } |
| 795 | |
| 796 | coordinate_t getyorigin(resource_t res) |
| 797 | { |
| 798 | private_resource_t* r=get_resource(res); |
| 799 | return r->y_origin; |
| 800 | } |
| 801 | |