1 /* Copyright (C) 2007-2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 #include "android/skin/window.h" 13 #include "android/skin/image.h" 14 #include "android/skin/scaler.h" 15 #include "android/charmap.h" 16 #include "android/utils/debug.h" 17 #include "android/utils/system.h" 18 #include "android/utils/duff.h" 19 #include "android/protocol/core-commands-api.h" 20 #include <SDL_syswm.h> 21 #include "user-events.h" 22 #include <math.h> 23 24 #include "android/framebuffer.h" 25 #include "android/opengles.h" 26 27 /* when shrinking, we reduce the pixel ratio by this fixed amount */ 28 #define SHRINK_SCALE 0.6 29 30 /* maximum value of LCD brighness */ 31 #define LCD_BRIGHTNESS_MIN 0 32 #define LCD_BRIGHTNESS_DEFAULT 128 33 #define LCD_BRIGHTNESS_MAX 255 34 35 typedef struct Background { 36 SkinImage* image; 37 SkinRect rect; 38 SkinPos origin; 39 } Background; 40 41 static void 42 background_done( Background* back ) 43 { 44 skin_image_unref( &back->image ); 45 } 46 47 static void 48 background_init( Background* back, SkinBackground* sback, SkinLocation* loc, SkinRect* frame ) 49 { 50 SkinRect r; 51 52 back->image = skin_image_rotate( sback->image, loc->rotation ); 53 skin_rect_rotate( &r, &sback->rect, loc->rotation ); 54 r.pos.x += loc->anchor.x; 55 r.pos.y += loc->anchor.y; 56 57 back->origin = r.pos; 58 skin_rect_intersect( &back->rect, &r, frame ); 59 } 60 61 static void 62 background_redraw( Background* back, SkinRect* rect, SDL_Surface* surface ) 63 { 64 SkinRect r; 65 66 if (skin_rect_intersect( &r, rect, &back->rect ) ) 67 { 68 SDL_Rect rd, rs; 69 70 rd.x = r.pos.x; 71 rd.y = r.pos.y; 72 rd.w = r.size.w; 73 rd.h = r.size.h; 74 75 rs.x = r.pos.x - back->origin.x; 76 rs.y = r.pos.y - back->origin.y; 77 rs.w = r.size.w; 78 rs.h = r.size.h; 79 80 SDL_BlitSurface( skin_image_surface(back->image), &rs, surface, &rd ); 81 //SDL_UpdateRects( surface, 1, &rd ); 82 } 83 } 84 85 86 typedef struct ADisplay { 87 SkinRect rect; 88 SkinPos origin; 89 SkinRotation rotation; 90 SkinSize datasize; /* framebuffer size */ 91 void* data; /* framebuffer pixels */ 92 QFrameBuffer* qfbuff; 93 SkinImage* onion; /* onion image */ 94 SkinRect onion_rect; /* onion rect, if any */ 95 int brightness; 96 } ADisplay; 97 98 static void 99 display_done( ADisplay* disp ) 100 { 101 disp->data = NULL; 102 disp->qfbuff = NULL; 103 skin_image_unref( &disp->onion ); 104 } 105 106 static int 107 display_init( ADisplay* disp, SkinDisplay* sdisp, SkinLocation* loc, SkinRect* frame ) 108 { 109 skin_rect_rotate( &disp->rect, &sdisp->rect, loc->rotation ); 110 disp->rect.pos.x += loc->anchor.x; 111 disp->rect.pos.y += loc->anchor.y; 112 113 disp->rotation = (loc->rotation + sdisp->rotation) & 3; 114 switch (disp->rotation) { 115 case SKIN_ROTATION_0: 116 disp->origin = disp->rect.pos; 117 break; 118 119 case SKIN_ROTATION_90: 120 disp->origin.x = disp->rect.pos.x + disp->rect.size.w; 121 disp->origin.y = disp->rect.pos.y; 122 break; 123 124 case SKIN_ROTATION_180: 125 disp->origin.x = disp->rect.pos.x + disp->rect.size.w; 126 disp->origin.y = disp->rect.pos.y + disp->rect.size.h; 127 break; 128 129 default: 130 disp->origin.x = disp->rect.pos.x; 131 disp->origin.y = disp->rect.pos.y + disp->rect.size.h; 132 break; 133 } 134 skin_size_rotate( &disp->datasize, &sdisp->rect.size, sdisp->rotation ); 135 skin_rect_intersect( &disp->rect, &disp->rect, frame ); 136 #if 0 137 fprintf(stderr, "... display_init rect.pos(%d,%d) rect.size(%d,%d) datasize(%d,%d)\n", 138 disp->rect.pos.x, disp->rect.pos.y, 139 disp->rect.size.w, disp->rect.size.h, 140 disp->datasize.w, disp->datasize.h); 141 #endif 142 disp->qfbuff = sdisp->qfbuff; 143 disp->data = sdisp->qfbuff->pixels; 144 disp->onion = NULL; 145 146 disp->brightness = LCD_BRIGHTNESS_DEFAULT; 147 148 return (disp->data == NULL) ? -1 : 0; 149 } 150 151 static __inline__ uint32_t rgb565_to_argb32( uint32_t pix ) 152 { 153 uint32_t r = ((pix & 0xf800) << 8) | ((pix & 0xe000) << 3); 154 uint32_t g = ((pix & 0x07e0) << 5) | ((pix & 0x0600) >> 1); 155 uint32_t b = ((pix & 0x001f) << 3) | ((pix & 0x001c) >> 2); 156 return 0xff000000 | r | g | b; 157 } 158 159 /* The framebuffer format is R,G,B,X in framebuffer memory, on a 160 * little-endian system, this translates to XBGR after a load. 161 */ 162 static __inline__ uint32_t xbgr_to_argb32( uint32_t pix ) 163 { 164 uint32_t g = (pix & 0x0000ff00); 165 uint32_t rb = (pix & 0xff00ff); 166 return 0xff000000 | (rb << 16) | g | (rb >> 16); 167 } 168 169 static void 170 display_set_onion( ADisplay* disp, SkinImage* onion, SkinRotation rotation, int blend ) 171 { 172 int onion_w, onion_h; 173 SkinRect* rect = &disp->rect; 174 SkinRect* orect = &disp->onion_rect; 175 176 rotation = (rotation + disp->rotation) & 3; 177 178 skin_image_unref( &disp->onion ); 179 disp->onion = skin_image_clone_full( onion, rotation, blend ); 180 181 onion_w = skin_image_w(disp->onion); 182 onion_h = skin_image_h(disp->onion); 183 184 switch (rotation) { 185 case SKIN_ROTATION_0: 186 orect->pos = rect->pos; 187 break; 188 189 case SKIN_ROTATION_90: 190 orect->pos.x = rect->pos.x + rect->size.w - onion_w; 191 orect->pos.y = rect->pos.y; 192 break; 193 194 case SKIN_ROTATION_180: 195 orect->pos.x = rect->pos.x + rect->size.w - onion_w; 196 orect->pos.y = rect->pos.y + rect->size.h - onion_h; 197 break; 198 199 default: 200 orect->pos.x = rect->pos.x; 201 orect->pos.y = rect->pos.y + rect->size.h - onion_h; 202 } 203 orect->size.w = onion_w; 204 orect->size.h = onion_h; 205 } 206 207 #define DOT_MATRIX 0 208 209 #if DOT_MATRIX 210 211 static void 212 dotmatrix_dither_argb32( unsigned char* pixels, int x, int y, int w, int h, int pitch ) 213 { 214 static const unsigned dotmatrix_argb32[16] = { 215 0x003f00, 0x00003f, 0x3f0000, 0x000000, 216 0x3f3f3f, 0x000000, 0x3f3f3f, 0x000000, 217 0x3f0000, 0x000000, 0x003f00, 0x00003f, 218 0x3f3f3f, 0x000000, 0x3f3f3f, 0x000000 219 }; 220 221 int yy = y & 3; 222 223 pixels += 4*x + y*pitch; 224 225 for ( ; h > 0; h-- ) { 226 unsigned* line = (unsigned*) pixels; 227 int nn, xx = x & 3; 228 229 for (nn = 0; nn < w; nn++) { 230 unsigned c = line[nn]; 231 232 c = c - ((c >> 2) & dotmatrix_argb32[(yy << 2)|xx]); 233 234 xx = (xx + 1) & 3; 235 line[nn] = c; 236 } 237 238 yy = (yy + 1) & 3; 239 pixels += pitch; 240 } 241 } 242 243 #endif /* DOT_MATRIX */ 244 245 /* technical note about the lightness emulation 246 * 247 * we try to emulate something that looks like the Dream's 248 * non-linear LCD lightness, without going too dark or bright. 249 * 250 * the default lightness is around 105 (about 40%) and we prefer 251 * to keep full RGB colors at that setting, to not alleviate 252 * developers who will not understand why the emulator's colors 253 * look slightly too dark. 254 * 255 * we also want to implement a 'bright' mode by de-saturating 256 * colors towards bright white. 257 * 258 * All of this leads to the implementation below that looks like 259 * the following: 260 * 261 * if (level == MIN) 262 * screen is off 263 * 264 * if (level > MIN && level < LOW) 265 * interpolate towards black, with 266 * MINALPHA = 0.2 267 * alpha = MINALPHA + (1-MINALPHA)*(level-MIN)/(LOW-MIN) 268 * 269 * if (level >= LOW && level <= HIGH) 270 * keep full RGB colors 271 * 272 * if (level > HIGH) 273 * interpolate towards bright white, with 274 * MAXALPHA = 0.6 275 * alpha = MAXALPHA*(level-HIGH)/(MAX-HIGH) 276 * 277 * we probably want some sort of power law instead of interpolating 278 * linearly, but frankly, this is sufficient for most uses. 279 */ 280 281 #define LCD_BRIGHTNESS_LOW 80 282 #define LCD_BRIGHTNESS_HIGH 180 283 284 #define LCD_ALPHA_LOW_MIN 0.2 285 #define LCD_ALPHA_HIGH_MAX 0.6 286 287 /* treat as special value to turn screen off */ 288 #define LCD_BRIGHTNESS_OFF LCD_BRIGHTNESS_MIN 289 290 static void 291 lcd_brightness_argb32( unsigned char* pixels, SkinRect* r, int pitch, int brightness ) 292 { 293 const unsigned b_min = LCD_BRIGHTNESS_MIN; 294 const unsigned b_max = LCD_BRIGHTNESS_MAX; 295 const unsigned b_low = LCD_BRIGHTNESS_LOW; 296 const unsigned b_high = LCD_BRIGHTNESS_HIGH; 297 298 unsigned alpha = brightness; 299 int w = r->size.w; 300 int h = r->size.h; 301 302 if (alpha <= b_min) 303 alpha = b_min; 304 else if (alpha > b_max) 305 alpha = b_max; 306 307 pixels += 4*r->pos.x + r->pos.y*pitch; 308 309 if (alpha < b_low) 310 { 311 const unsigned alpha_min = (255*LCD_ALPHA_LOW_MIN); 312 const unsigned alpha_range = (255 - alpha_min); 313 314 alpha = alpha_min + ((alpha - b_min)*alpha_range) / (b_low - b_min); 315 316 for ( ; h > 0; h-- ) { 317 unsigned* line = (unsigned*) pixels; 318 int nn = 0; 319 320 DUFF4(w, { 321 unsigned c = line[nn]; 322 unsigned ag = (c >> 8) & 0x00ff00ff; 323 unsigned rb = (c) & 0x00ff00ff; 324 325 ag = (ag*alpha) & 0xff00ff00; 326 rb = ((rb*alpha) >> 8) & 0x00ff00ff; 327 328 line[nn] = (unsigned)(ag | rb); 329 nn++; 330 }); 331 pixels += pitch; 332 } 333 } 334 else if (alpha > LCD_BRIGHTNESS_HIGH) /* 'superluminous' mode */ 335 { 336 const unsigned alpha_max = (255*LCD_ALPHA_HIGH_MAX); 337 const unsigned alpha_range = (255-alpha_max); 338 unsigned ialpha; 339 340 alpha = ((alpha - b_high)*alpha_range) / (b_max - b_high); 341 ialpha = 255-alpha; 342 343 for ( ; h > 0; h-- ) { 344 unsigned* line = (unsigned*) pixels; 345 int nn = 0; 346 347 DUFF4(w, { 348 unsigned c = line[nn]; 349 unsigned ag = (c >> 8) & 0x00ff00ff; 350 unsigned rb = (c) & 0x00ff00ff; 351 352 /* interpolate towards bright white, i.e. 0x00ffffff */ 353 ag = ((ag*ialpha + 0x00ff00ff*alpha)) & 0xff00ff00; 354 rb = ((rb*ialpha + 0x00ff00ff*alpha) >> 8) & 0x00ff00ff; 355 356 line[nn] = (unsigned)(ag | rb); 357 nn++; 358 }); 359 pixels += pitch; 360 } 361 } 362 } 363 364 365 /* this is called when the LCD framebuffer is off */ 366 static void 367 lcd_off_argb32( unsigned char* pixels, SkinRect* r, int pitch ) 368 { 369 int x = r->pos.x; 370 int y = r->pos.y; 371 int w = r->size.w; 372 int h = r->size.h; 373 374 pixels += 4*x + y*pitch; 375 for ( ; h > 0; h-- ) { 376 memset( pixels, 0, w*4 ); 377 pixels += pitch; 378 } 379 } 380 381 static void 382 display_redraw_rect16( ADisplay* disp, SkinRect* rect, SDL_Surface* surface) 383 { 384 int x = rect->pos.x - disp->rect.pos.x; 385 int y = rect->pos.y - disp->rect.pos.y; 386 int w = rect->size.w; 387 int h = rect->size.h; 388 int disp_w = disp->rect.size.w; 389 int disp_h = disp->rect.size.h; 390 int dst_pitch = surface->pitch; 391 uint8_t* dst_line = (uint8_t*)surface->pixels + rect->pos.x*4 + rect->pos.y*dst_pitch; 392 int src_pitch = disp->datasize.w*2; 393 uint8_t* src_line = (uint8_t*)disp->data; 394 int yy, xx; 395 396 switch ( disp->rotation & 3 ) 397 { 398 case ANDROID_ROTATION_0: 399 src_line += x*2 + y*src_pitch; 400 401 for (yy = h; yy > 0; yy--) 402 { 403 uint32_t* dst = (uint32_t*)dst_line; 404 uint16_t* src = (uint16_t*)src_line; 405 406 xx = 0; 407 DUFF4(w, { 408 dst[xx] = rgb565_to_argb32(src[xx]); 409 xx++; 410 }); 411 src_line += src_pitch; 412 dst_line += dst_pitch; 413 } 414 break; 415 416 case ANDROID_ROTATION_90: 417 src_line += y*2 + (disp_w - x - 1)*src_pitch; 418 419 for (yy = h; yy > 0; yy--) 420 { 421 uint32_t* dst = (uint32_t*)dst_line; 422 uint8_t* src = src_line; 423 424 DUFF4(w, { 425 dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]); 426 src -= src_pitch; 427 dst += 1; 428 }); 429 src_line += 2; 430 dst_line += dst_pitch; 431 } 432 break; 433 434 case ANDROID_ROTATION_180: 435 src_line += (disp_w -1 - x)*2 + (disp_h-1-y)*src_pitch; 436 437 for (yy = h; yy > 0; yy--) 438 { 439 uint16_t* src = (uint16_t*)src_line; 440 uint32_t* dst = (uint32_t*)dst_line; 441 442 DUFF4(w, { 443 dst[0] = rgb565_to_argb32(src[0]); 444 src -= 1; 445 dst += 1; 446 }); 447 src_line -= src_pitch; 448 dst_line += dst_pitch; 449 } 450 break; 451 452 default: /* ANDROID_ROTATION_270 */ 453 src_line += (disp_h-1-y)*2 + x*src_pitch; 454 455 for (yy = h; yy > 0; yy--) 456 { 457 uint32_t* dst = (uint32_t*)dst_line; 458 uint8_t* src = src_line; 459 460 DUFF4(w, { 461 dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]); 462 dst += 1; 463 src += src_pitch; 464 }); 465 src_line -= 2; 466 dst_line += dst_pitch; 467 } 468 } 469 } 470 471 static void 472 display_redraw_rect32( ADisplay* disp, SkinRect* rect,SDL_Surface* surface) 473 { 474 int x = rect->pos.x - disp->rect.pos.x; 475 int y = rect->pos.y - disp->rect.pos.y; 476 int w = rect->size.w; 477 int h = rect->size.h; 478 int disp_w = disp->rect.size.w; 479 int disp_h = disp->rect.size.h; 480 int dst_pitch = surface->pitch; 481 uint8_t* dst_line = (uint8_t*)surface->pixels + rect->pos.x*4 + rect->pos.y*dst_pitch; 482 int src_pitch = disp->datasize.w*4; 483 uint8_t* src_line = (uint8_t*)disp->data; 484 int yy; 485 486 switch ( disp->rotation & 3 ) 487 { 488 case ANDROID_ROTATION_0: 489 src_line += x*4 + y*src_pitch; 490 491 for (yy = h; yy > 0; yy--) { 492 uint32_t* src = (uint32_t*)src_line; 493 uint32_t* dst = (uint32_t*)dst_line; 494 495 DUFF4(w, { 496 dst[0] = xbgr_to_argb32(src[0]); 497 dst++; 498 src++; 499 }); 500 src_line += src_pitch; 501 dst_line += dst_pitch; 502 } 503 break; 504 505 case ANDROID_ROTATION_90: 506 src_line += y*4 + (disp_w - x - 1)*src_pitch; 507 508 for (yy = h; yy > 0; yy--) 509 { 510 uint32_t* dst = (uint32_t*)dst_line; 511 uint8_t* src = src_line; 512 513 DUFF4(w, { 514 dst[0] = xbgr_to_argb32(*(uint32_t*)src); 515 src -= src_pitch; 516 dst += 1; 517 }); 518 src_line += 4; 519 dst_line += dst_pitch; 520 } 521 break; 522 523 case ANDROID_ROTATION_180: 524 src_line += (disp_w -1 - x)*4 + (disp_h-1-y)*src_pitch; 525 526 for (yy = h; yy > 0; yy--) 527 { 528 uint32_t* src = (uint32_t*)src_line; 529 uint32_t* dst = (uint32_t*)dst_line; 530 531 DUFF4(w, { 532 dst[0] = xbgr_to_argb32(src[0]); 533 src -= 1; 534 dst += 1; 535 }); 536 src_line -= src_pitch; 537 dst_line += dst_pitch; 538 } 539 break; 540 541 default: /* ANDROID_ROTATION_270 */ 542 src_line += (disp_h-1-y)*4 + x*src_pitch; 543 544 for (yy = h; yy > 0; yy--) 545 { 546 uint32_t* dst = (uint32_t*)dst_line; 547 uint8_t* src = src_line; 548 549 DUFF4(w, { 550 dst[0] = xbgr_to_argb32(*(uint32_t*)src); 551 dst += 1; 552 src += src_pitch; 553 }); 554 src_line -= 4; 555 dst_line += dst_pitch; 556 } 557 } 558 } 559 560 static void 561 display_redraw( ADisplay* disp, SkinRect* rect, SDL_Surface* surface ) 562 { 563 SkinRect r; 564 565 if (skin_rect_intersect( &r, rect, &disp->rect )) 566 { 567 #if 0 568 fprintf(stderr, "--- display redraw r.pos(%d,%d) r.size(%d,%d) " 569 "disp.pos(%d,%d) disp.size(%d,%d) datasize(%d,%d) rect.pos(%d,%d) rect.size(%d,%d)\n", 570 r.pos.x - disp->rect.pos.x, r.pos.y - disp->rect.pos.y, 571 r.size.w, r.size.h, disp->rect.pos.x, disp->rect.pos.y, 572 disp->rect.size.w, disp->rect.size.h, disp->datasize.w, disp->datasize.h, 573 rect->pos.x, rect->pos.y, rect->size.w, rect->size.h ); 574 #endif 575 SDL_LockSurface( surface ); 576 577 if (disp->brightness == LCD_BRIGHTNESS_OFF) 578 { 579 lcd_off_argb32( surface->pixels, &r, surface->pitch ); 580 } 581 else 582 { 583 if (disp->qfbuff->bits_per_pixel == 32) 584 display_redraw_rect32(disp, &r, surface); 585 else 586 display_redraw_rect16(disp, &r, surface); 587 #if DOT_MATRIX 588 dotmatrix_dither_argb32( surface->pixels, r.pos.x, r.pos.y, r.size.w, r.size.h, surface->pitch ); 589 #endif 590 /* apply lightness */ 591 lcd_brightness_argb32( surface->pixels, &r, surface->pitch, disp->brightness ); 592 } 593 SDL_UnlockSurface( surface ); 594 595 /* Apply onion skin */ 596 if (disp->onion != NULL) { 597 SkinRect r2; 598 599 if ( skin_rect_intersect( &r2, &r, &disp->onion_rect ) ) { 600 SDL_Rect rs, rd; 601 602 rd.x = r2.pos.x; 603 rd.y = r2.pos.y; 604 rd.w = r2.size.w; 605 rd.h = r2.size.h; 606 607 rs.x = rd.x - disp->onion_rect.pos.x; 608 rs.y = rd.y - disp->onion_rect.pos.y; 609 rs.w = rd.w; 610 rs.h = rd.h; 611 612 SDL_BlitSurface( skin_image_surface(disp->onion), &rs, surface, &rd ); 613 } 614 } 615 616 SDL_UpdateRect( surface, r.pos.x, r.pos.y, r.size.w, r.size.h ); 617 } 618 } 619 620 621 typedef struct Button { 622 SkinImage* image; 623 SkinRect rect; 624 SkinPos origin; 625 Background* background; 626 unsigned keycode; 627 int down; 628 } Button; 629 630 static void 631 button_done( Button* button ) 632 { 633 skin_image_unref( &button->image ); 634 button->background = NULL; 635 } 636 637 static void 638 button_init( Button* button, SkinButton* sbutton, SkinLocation* loc, Background* back, SkinRect* frame, SkinLayout* slayout ) 639 { 640 SkinRect r; 641 642 button->image = skin_image_rotate( sbutton->image, loc->rotation ); 643 button->background = back; 644 button->keycode = sbutton->keycode; 645 button->down = 0; 646 647 if (slayout->has_dpad_rotation) { 648 /* Dpad keys must be rotated if the skin provides a 'dpad-rotation' field. 649 * this is used as a counter-measure to the fact that the framework always assumes 650 * that the physical D-Pad has been rotated when in landscape mode. 651 */ 652 button->keycode = android_keycode_rotate( button->keycode, -slayout->dpad_rotation ); 653 } 654 655 skin_rect_rotate( &r, &sbutton->rect, loc->rotation ); 656 r.pos.x += loc->anchor.x; 657 r.pos.y += loc->anchor.y; 658 button->origin = r.pos; 659 skin_rect_intersect( &button->rect, &r, frame ); 660 } 661 662 static void 663 button_redraw( Button* button, SkinRect* rect, SDL_Surface* surface ) 664 { 665 SkinRect r; 666 667 if (skin_rect_intersect( &r, rect, &button->rect )) 668 { 669 if ( button->down && button->image != SKIN_IMAGE_NONE ) 670 { 671 SDL_Rect rs, rd; 672 673 rs.x = r.pos.x - button->origin.x; 674 rs.y = r.pos.y - button->origin.y; 675 rs.w = r.size.w; 676 rs.h = r.size.h; 677 678 rd.x = r.pos.x; 679 rd.y = r.pos.y; 680 rd.w = r.size.w; 681 rd.h = r.size.h; 682 683 if (button->image != SKIN_IMAGE_NONE) { 684 SDL_BlitSurface( skin_image_surface(button->image), &rs, surface, &rd ); 685 if (button->down > 1) 686 SDL_BlitSurface( skin_image_surface(button->image), &rs, surface, &rd ); 687 } 688 } 689 } 690 } 691 692 693 typedef struct { 694 char tracking; 695 char inside; 696 SkinPos pos; 697 ADisplay* display; 698 } FingerState; 699 700 static void 701 finger_state_reset( FingerState* finger ) 702 { 703 finger->tracking = 0; 704 finger->inside = 0; 705 } 706 707 typedef struct { 708 Button* pressed; 709 Button* hover; 710 } ButtonState; 711 712 static void 713 button_state_reset( ButtonState* button ) 714 { 715 button->pressed = NULL; 716 button->hover = NULL; 717 } 718 719 typedef struct { 720 char tracking; 721 SkinTrackBall* ball; 722 SkinRect rect; 723 SkinWindow* window; 724 } BallState; 725 726 static void 727 ball_state_reset( BallState* state, SkinWindow* window ) 728 { 729 state->tracking = 0; 730 state->ball = NULL; 731 732 state->rect.pos.x = 0; 733 state->rect.pos.y = 0; 734 state->rect.size.w = 0; 735 state->rect.size.h = 0; 736 state->window = window; 737 } 738 739 static void 740 ball_state_redraw( BallState* state, SkinRect* rect, SDL_Surface* surface ) 741 { 742 SkinRect r; 743 744 if (skin_rect_intersect( &r, rect, &state->rect )) 745 skin_trackball_draw( state->ball, 0, 0, surface ); 746 } 747 748 static void 749 ball_state_show( BallState* state, int enable ) 750 { 751 if (enable) { 752 if ( !state->tracking ) { 753 state->tracking = 1; 754 SDL_ShowCursor(0); 755 SDL_WM_GrabInput( SDL_GRAB_ON ); 756 skin_trackball_refresh( state->ball ); 757 skin_window_redraw( state->window, &state->rect ); 758 } 759 } else { 760 if ( state->tracking ) { 761 state->tracking = 0; 762 SDL_WM_GrabInput( SDL_GRAB_OFF ); 763 SDL_ShowCursor(1); 764 skin_window_redraw( state->window, &state->rect ); 765 } 766 } 767 } 768 769 770 static void 771 ball_state_set( BallState* state, SkinTrackBall* ball ) 772 { 773 ball_state_show( state, 0 ); 774 775 state->ball = ball; 776 if (ball != NULL) { 777 SDL_Rect sr; 778 779 skin_trackball_rect( ball, &sr ); 780 state->rect.pos.x = sr.x; 781 state->rect.pos.y = sr.y; 782 state->rect.size.w = sr.w; 783 state->rect.size.h = sr.h; 784 } 785 } 786 787 typedef struct Layout { 788 int num_buttons; 789 int num_backgrounds; 790 int num_displays; 791 unsigned color; 792 Button* buttons; 793 Background* backgrounds; 794 ADisplay* displays; 795 SkinRect rect; 796 SkinLayout* slayout; 797 } Layout; 798 799 #define LAYOUT_LOOP_BUTTONS(layout,button) \ 800 do { \ 801 Button* __button = (layout)->buttons; \ 802 Button* __button_end = __button + (layout)->num_buttons; \ 803 for ( ; __button < __button_end; __button ++ ) { \ 804 Button* button = __button; 805 806 #define LAYOUT_LOOP_END_BUTTONS \ 807 } \ 808 } while (0); 809 810 #define LAYOUT_LOOP_DISPLAYS(layout,display) \ 811 do { \ 812 ADisplay* __display = (layout)->displays; \ 813 ADisplay* __display_end = __display + (layout)->num_displays; \ 814 for ( ; __display < __display_end; __display ++ ) { \ 815 ADisplay* display = __display; 816 817 #define LAYOUT_LOOP_END_DISPLAYS \ 818 } \ 819 } while (0); 820 821 822 static void 823 layout_done( Layout* layout ) 824 { 825 int nn; 826 827 for (nn = 0; nn < layout->num_buttons; nn++) 828 button_done( &layout->buttons[nn] ); 829 830 for (nn = 0; nn < layout->num_backgrounds; nn++) 831 background_done( &layout->backgrounds[nn] ); 832 833 for (nn = 0; nn < layout->num_displays; nn++) 834 display_done( &layout->displays[nn] ); 835 836 AFREE( layout->buttons ); 837 layout->buttons = NULL; 838 839 AFREE( layout->backgrounds ); 840 layout->backgrounds = NULL; 841 842 AFREE( layout->displays ); 843 layout->displays = NULL; 844 845 layout->num_buttons = 0; 846 layout->num_backgrounds = 0; 847 layout->num_displays = 0; 848 } 849 850 static int 851 layout_init( Layout* layout, SkinLayout* slayout ) 852 { 853 int n_buttons, n_backgrounds, n_displays; 854 855 /* first, count the number of elements of each kind */ 856 n_buttons = 0; 857 n_backgrounds = 0; 858 n_displays = 0; 859 860 layout->color = slayout->color; 861 layout->slayout = slayout; 862 863 SKIN_LAYOUT_LOOP_LOCS(slayout,loc) 864 SkinPart* part = loc->part; 865 866 if ( part->background->valid ) 867 n_backgrounds += 1; 868 if ( part->display->valid ) 869 n_displays += 1; 870 871 SKIN_PART_LOOP_BUTTONS(part, sbutton) 872 n_buttons += 1; 873 sbutton=sbutton; 874 SKIN_PART_LOOP_END 875 SKIN_LAYOUT_LOOP_END 876 877 layout->num_buttons = n_buttons; 878 layout->num_backgrounds = n_backgrounds; 879 layout->num_displays = n_displays; 880 881 /* now allocate arrays, then populate them */ 882 AARRAY_NEW0(layout->buttons, n_buttons); 883 AARRAY_NEW0(layout->backgrounds, n_backgrounds); 884 AARRAY_NEW0(layout->displays, n_displays); 885 886 if (layout->buttons == NULL && n_buttons > 0) goto Fail; 887 if (layout->backgrounds == NULL && n_backgrounds > 0) goto Fail; 888 if (layout->displays == NULL && n_displays > 0) goto Fail; 889 890 n_buttons = 0; 891 n_backgrounds = 0; 892 n_displays = 0; 893 894 layout->rect.pos.x = 0; 895 layout->rect.pos.y = 0; 896 layout->rect.size = slayout->size; 897 898 SKIN_LAYOUT_LOOP_LOCS(slayout,loc) 899 SkinPart* part = loc->part; 900 Background* back = NULL; 901 902 if ( part->background->valid ) { 903 back = layout->backgrounds + n_backgrounds; 904 background_init( back, part->background, loc, &layout->rect ); 905 n_backgrounds += 1; 906 } 907 if ( part->display->valid ) { 908 ADisplay* disp = layout->displays + n_displays; 909 display_init( disp, part->display, loc, &layout->rect ); 910 n_displays += 1; 911 } 912 913 SKIN_PART_LOOP_BUTTONS(part, sbutton) 914 Button* button = layout->buttons + n_buttons; 915 button_init( button, sbutton, loc, back, &layout->rect, slayout ); 916 n_buttons += 1; 917 SKIN_PART_LOOP_END 918 SKIN_LAYOUT_LOOP_END 919 920 return 0; 921 922 Fail: 923 layout_done(layout); 924 return -1; 925 } 926 927 struct SkinWindow { 928 SDL_Surface* surface; 929 Layout layout; 930 SkinPos pos; 931 FingerState finger; 932 ButtonState button; 933 BallState ball; 934 char enabled; 935 char fullscreen; 936 char no_display; 937 938 char enable_touch; 939 char enable_trackball; 940 char enable_dpad; 941 char enable_qwerty; 942 943 SkinImage* onion; 944 SkinRotation onion_rotation; 945 int onion_alpha; 946 947 int x_pos; 948 int y_pos; 949 950 SkinScaler* scaler; 951 int shrink; 952 double shrink_scale; 953 unsigned* shrink_pixels; 954 SDL_Surface* shrink_surface; 955 956 double effective_scale; 957 double effective_x; 958 double effective_y; 959 }; 960 961 static void 962 add_finger_event(unsigned x, unsigned y, unsigned state) 963 { 964 //fprintf(stderr, "::: finger %d,%d %d\n", x, y, state); 965 966 /* NOTE: the 0 is used in hw/goldfish_events.c to differentiate 967 * between a touch-screen and a trackball event 968 */ 969 user_event_mouse(x, y, 0, state); 970 } 971 972 static void 973 skin_window_find_finger( SkinWindow* window, 974 int x, 975 int y ) 976 { 977 FingerState* finger = &window->finger; 978 979 /* find the display that contains this movement */ 980 finger->display = NULL; 981 finger->inside = 0; 982 983 if (!window->enable_touch) 984 return; 985 986 LAYOUT_LOOP_DISPLAYS(&window->layout,disp) 987 if ( skin_rect_contains( &disp->rect, x, y ) ) { 988 finger->inside = 1; 989 finger->display = disp; 990 finger->pos.x = x - disp->origin.x; 991 finger->pos.y = y - disp->origin.y; 992 993 skin_pos_rotate( &finger->pos, &finger->pos, -disp->rotation ); 994 break; 995 } 996 LAYOUT_LOOP_END_DISPLAYS 997 } 998 999 static void 1000 skin_window_move_mouse( SkinWindow* window, 1001 int x, 1002 int y ) 1003 { 1004 FingerState* finger = &window->finger; 1005 ButtonState* button = &window->button; 1006 1007 if (finger->tracking) { 1008 ADisplay* disp = finger->display; 1009 char inside = 1; 1010 int dx = x - disp->rect.pos.x; 1011 int dy = y - disp->rect.pos.y; 1012 1013 if (dx < 0) { 1014 dx = 0; 1015 inside = 0; 1016 } 1017 else if (dx >= disp->rect.size.w) { 1018 dx = disp->rect.size.w - 1; 1019 inside = 0; 1020 } 1021 if (dy < 0) { 1022 dy = 0; 1023 inside = 0; 1024 } else if (dy >= disp->rect.size.h) { 1025 dy = disp->rect.size.h-1; 1026 inside = 0; 1027 } 1028 finger->inside = inside; 1029 finger->pos.x = dx + (disp->rect.pos.x - disp->origin.x); 1030 finger->pos.y = dy + (disp->rect.pos.y - disp->origin.y); 1031 1032 skin_pos_rotate( &finger->pos, &finger->pos, -disp->rotation ); 1033 } 1034 1035 { 1036 Button* hover = button->hover; 1037 1038 if (hover) { 1039 if ( skin_rect_contains( &hover->rect, x, y ) ) 1040 return; 1041 1042 hover->down = 0; 1043 skin_window_redraw( window, &hover->rect ); 1044 button->hover = NULL; 1045 } 1046 1047 hover = NULL; 1048 LAYOUT_LOOP_BUTTONS( &window->layout, butt ) 1049 if ( skin_rect_contains( &butt->rect, x, y ) ) { 1050 hover = butt; 1051 break; 1052 } 1053 LAYOUT_LOOP_END_BUTTONS 1054 1055 /* filter DPAD and QWERTY buttons right here */ 1056 if (hover != NULL) { 1057 switch (hover->keycode) { 1058 /* these correspond to the DPad */ 1059 case kKeyCodeDpadUp: 1060 case kKeyCodeDpadDown: 1061 case kKeyCodeDpadLeft: 1062 case kKeyCodeDpadRight: 1063 case kKeyCodeDpadCenter: 1064 if (!window->enable_dpad) 1065 hover = NULL; 1066 break; 1067 1068 /* these correspond to non-qwerty buttons */ 1069 case kKeyCodeSoftLeft: 1070 case kKeyCodeSoftRight: 1071 case kKeyCodeVolumeUp: 1072 case kKeyCodeVolumeDown: 1073 case kKeyCodePower: 1074 case kKeyCodeHome: 1075 case kKeyCodeBack: 1076 case kKeyCodeCall: 1077 case kKeyCodeEndCall: 1078 case kKeyCodeTV: 1079 case kKeyCodeEPG: 1080 case kKeyCodeDVR: 1081 case kKeyCodePrevious: 1082 case kKeyCodeNext: 1083 case kKeyCodePlay: 1084 case kKeyCodePause: 1085 case kKeyCodeStop: 1086 case kKeyCodeRewind: 1087 case kKeyCodeFastForward: 1088 case kKeyCodeBookmarks: 1089 case kKeyCodeCycleWindows: 1090 case kKeyCodeChannelUp: 1091 case kKeyCodeChannelDown: 1092 break; 1093 1094 /* all the rest is assumed to be qwerty */ 1095 default: 1096 if (!window->enable_qwerty) 1097 hover = NULL; 1098 } 1099 } 1100 1101 if (hover != NULL) { 1102 hover->down = 1; 1103 skin_window_redraw( window, &hover->rect ); 1104 button->hover = hover; 1105 } 1106 } 1107 } 1108 1109 static void 1110 skin_window_trackball_press( SkinWindow* window, int down ) 1111 { 1112 user_event_key( BTN_MOUSE, down ); 1113 } 1114 1115 static void 1116 skin_window_trackball_move( SkinWindow* window, int xrel, int yrel ) 1117 { 1118 BallState* state = &window->ball; 1119 1120 if ( skin_trackball_move( state->ball, xrel, yrel ) ) { 1121 skin_trackball_refresh( state->ball ); 1122 skin_window_redraw( window, &state->rect ); 1123 } 1124 } 1125 1126 void 1127 skin_window_set_trackball( SkinWindow* window, SkinTrackBall* ball ) 1128 { 1129 BallState* state = &window->ball; 1130 1131 ball_state_set( state, ball ); 1132 } 1133 1134 void 1135 skin_window_show_trackball( SkinWindow* window, int enable ) 1136 { 1137 BallState* state = &window->ball; 1138 1139 if (state->ball != NULL && window->enable_trackball) { 1140 ball_state_show(state, enable); 1141 } 1142 } 1143 1144 /* Hide the OpenGL ES framebuffer */ 1145 static void 1146 skin_window_hide_opengles( SkinWindow* window ) 1147 { 1148 android_hideOpenglesWindow(); 1149 } 1150 1151 /* Show the OpenGL ES framebuffer window */ 1152 static void 1153 skin_window_show_opengles( SkinWindow* window ) 1154 { 1155 { 1156 SDL_SysWMinfo wminfo; 1157 void* winhandle; 1158 ADisplay* disp = window->layout.displays; 1159 SkinRect drect = disp->rect; 1160 1161 memset(&wminfo, 0, sizeof(wminfo)); 1162 SDL_GetWMInfo(&wminfo); 1163 #ifdef _WIN32 1164 winhandle = (void*)wminfo.window; 1165 #elif defined(CONFIG_DARWIN) 1166 winhandle = (void*)wminfo.nsWindowPtr; 1167 #else 1168 winhandle = (void*)wminfo.info.x11.window; 1169 #endif 1170 skin_scaler_get_scaled_rect(window->scaler, &drect, &drect); 1171 1172 android_showOpenglesWindow(winhandle, drect.pos.x, drect.pos.y, 1173 drect.size.w, drect.size.h, disp->rotation * -90.); 1174 } 1175 } 1176 1177 static void 1178 skin_window_redraw_opengles( SkinWindow* window ) 1179 { 1180 android_redrawOpenglesWindow(); 1181 } 1182 1183 static int skin_window_reset_internal (SkinWindow*, SkinLayout*); 1184 1185 SkinWindow* 1186 skin_window_create( SkinLayout* slayout, int x, int y, double scale, int no_display ) 1187 { 1188 SkinWindow* window; 1189 1190 /* If scale is <= 0, we want to check that the window's default size if 1191 * not larger than the current screen. Otherwise, we need to compute 1192 * a new scale to ensure it is. 1193 */ 1194 if (scale <= 0) { 1195 SDL_Rect monitor; 1196 int screen_w, screen_h; 1197 int win_w = slayout->size.w; 1198 int win_h = slayout->size.h; 1199 double scale_w, scale_h; 1200 1201 /* To account for things like menu bars, window decorations etc.. 1202 * We only compute 95% of the real screen size. */ 1203 SDL_WM_GetMonitorRect(&monitor); 1204 screen_w = monitor.w * 0.95; 1205 screen_h = monitor.h * 0.95; 1206 1207 scale_w = 1.0; 1208 scale_h = 1.0; 1209 1210 if (screen_w < win_w && win_w > 1.) 1211 scale_w = 1.0 * screen_w / win_w; 1212 if (screen_h < win_h && win_h > 1.) 1213 scale_h = 1.0 * screen_h / win_h; 1214 1215 scale = (scale_w <= scale_h) ? scale_w : scale_h; 1216 1217 VERBOSE_PRINT(init,"autoconfig: -scale %g", scale); 1218 } 1219 1220 ANEW0(window); 1221 1222 window->shrink_scale = scale; 1223 window->shrink = (scale != 1.0); 1224 window->scaler = skin_scaler_create(); 1225 window->no_display = no_display; 1226 1227 /* enable everything by default */ 1228 window->enable_touch = 1; 1229 window->enable_trackball = 1; 1230 window->enable_dpad = 1; 1231 window->enable_qwerty = 1; 1232 1233 window->x_pos = x; 1234 window->y_pos = y; 1235 1236 if (skin_window_reset_internal(window, slayout) < 0) { 1237 skin_window_free(window); 1238 return NULL; 1239 } 1240 SDL_WM_SetPos( x, y ); 1241 1242 /* Check that the window is fully visible */ 1243 if ( !window->no_display && !SDL_WM_IsFullyVisible(0) ) { 1244 SDL_Rect monitor; 1245 int win_x, win_y, win_w, win_h; 1246 int new_x, new_y; 1247 1248 SDL_WM_GetMonitorRect(&monitor); 1249 SDL_WM_GetPos(&win_x, &win_y); 1250 win_w = window->surface->w; 1251 win_h = window->surface->h; 1252 1253 /* First, we recenter the window */ 1254 new_x = (monitor.w - win_w)/2; 1255 new_y = (monitor.h - win_h)/2; 1256 1257 /* If it is still too large, we ensure the top-border is visible */ 1258 if (new_y < 0) 1259 new_y = 0; 1260 1261 /* Done */ 1262 SDL_WM_SetPos(new_x, new_y); 1263 dprint( "emulator window was out of view and was recentered\n" ); 1264 } 1265 1266 skin_window_show_opengles(window); 1267 1268 return window; 1269 } 1270 1271 void 1272 skin_window_enable_touch( SkinWindow* window, int enabled ) 1273 { 1274 window->enable_touch = !!enabled; 1275 } 1276 1277 void 1278 skin_window_enable_trackball( SkinWindow* window, int enabled ) 1279 { 1280 window->enable_trackball = !!enabled; 1281 } 1282 1283 void 1284 skin_window_enable_dpad( SkinWindow* window, int enabled ) 1285 { 1286 window->enable_dpad = !!enabled; 1287 } 1288 1289 void 1290 skin_window_enable_qwerty( SkinWindow* window, int enabled ) 1291 { 1292 window->enable_qwerty = !!enabled; 1293 } 1294 1295 void 1296 skin_window_set_title( SkinWindow* window, const char* title ) 1297 { 1298 if (window && title) 1299 SDL_WM_SetCaption( title, title ); 1300 } 1301 1302 static void 1303 skin_window_resize( SkinWindow* window ) 1304 { 1305 if ( !window->no_display ) 1306 skin_window_hide_opengles(window); 1307 1308 /* now resize window */ 1309 if (window->surface) { 1310 SDL_FreeSurface(window->surface); 1311 window->surface = NULL; 1312 } 1313 1314 if (window->shrink_surface) { 1315 SDL_FreeSurface(window->shrink_surface); 1316 window->shrink_surface = NULL; 1317 } 1318 1319 if (window->shrink_pixels) { 1320 AFREE(window->shrink_pixels); 1321 window->shrink_pixels = NULL; 1322 } 1323 1324 if ( !window->no_display ) { 1325 int layout_w = window->layout.rect.size.w; 1326 int layout_h = window->layout.rect.size.h; 1327 int window_w = layout_w; 1328 int window_h = layout_h; 1329 int window_x = window->x_pos; 1330 int window_y = window->y_pos; 1331 int flags; 1332 SDL_Surface* surface; 1333 double scale = 1.0; 1334 int fullscreen = window->fullscreen; 1335 1336 if (fullscreen) { 1337 SDL_Rect r; 1338 if (SDL_WM_GetMonitorRect(&r) < 0) { 1339 fullscreen = 0; 1340 } else { 1341 double x_scale, y_scale; 1342 1343 window_x = r.x; 1344 window_y = r.y; 1345 window_w = r.w; 1346 window_h = r.h; 1347 1348 x_scale = window_w * 1.0 / layout_w; 1349 y_scale = window_h * 1.0 / layout_h; 1350 1351 scale = (x_scale <= y_scale) ? x_scale : y_scale; 1352 } 1353 } 1354 else if (window->shrink) { 1355 scale = window->shrink_scale; 1356 window_w = (int) ceil(layout_w*scale); 1357 window_h = (int) ceil(layout_h*scale); 1358 } 1359 1360 { 1361 char temp[32]; 1362 sprintf(temp, "%d,%d", window_x, window_y); 1363 setenv("SDL_VIDEO_WINDOW_POS", temp, 1); 1364 setenv("SDL_VIDEO_WINDOW_FORCE_VISIBLE", "1", 1); 1365 } 1366 1367 flags = SDL_SWSURFACE; 1368 if (fullscreen) { 1369 flags |= SDL_FULLSCREEN; 1370 } 1371 surface = SDL_SetVideoMode( window_w, window_h, 32, flags ); 1372 if (surface == NULL) { 1373 fprintf(stderr, "### Error: could not create or resize SDL window: %s\n", SDL_GetError() ); 1374 exit(1); 1375 } 1376 1377 SDL_WM_SetPos( window_x, window_y ); 1378 1379 window->effective_scale = scale; 1380 window->effective_x = 0; 1381 window->effective_y = 0; 1382 1383 if (fullscreen) { 1384 window->effective_x = (window_w - layout_w*scale)*0.5; 1385 window->effective_y = (window_h - layout_h*scale)*0.5; 1386 } 1387 1388 if (scale == 1.0) 1389 { 1390 window->surface = surface; 1391 skin_scaler_set( window->scaler, 1.0, 0, 0 ); 1392 } 1393 else 1394 { 1395 window_w = (int) ceil(window_w / scale ); 1396 window_h = (int) ceil(window_h / scale ); 1397 1398 window->shrink_surface = surface; 1399 AARRAY_NEW0(window->shrink_pixels, window_w * window_h * 4); 1400 if (window->shrink_pixels == NULL) { 1401 fprintf(stderr, "### Error: could not allocate memory for rescaling surface\n"); 1402 exit(1); 1403 } 1404 window->surface = sdl_surface_from_argb32( window->shrink_pixels, window_w, window_h ); 1405 if (window->surface == NULL) { 1406 fprintf(stderr, "### Error: could not create or resize SDL window: %s\n", SDL_GetError() ); 1407 exit(1); 1408 } 1409 skin_scaler_set( window->scaler, scale, window->effective_x, window->effective_y ); 1410 } 1411 1412 skin_window_show_opengles(window); 1413 } 1414 } 1415 1416 static int 1417 skin_window_reset_internal ( SkinWindow* window, SkinLayout* slayout ) 1418 { 1419 Layout layout; 1420 ADisplay* disp; 1421 1422 if ( layout_init( &layout, slayout ) < 0 ) 1423 return -1; 1424 1425 layout_done( &window->layout ); 1426 window->layout = layout; 1427 1428 disp = window->layout.displays; 1429 if (disp != NULL && window->onion) 1430 display_set_onion( disp, 1431 window->onion, 1432 window->onion_rotation, 1433 window->onion_alpha ); 1434 1435 skin_window_resize(window); 1436 1437 finger_state_reset( &window->finger ); 1438 button_state_reset( &window->button ); 1439 ball_state_reset( &window->ball, window ); 1440 1441 skin_window_redraw( window, NULL ); 1442 1443 if (slayout->event_type != 0) { 1444 user_event_generic( slayout->event_type, slayout->event_code, slayout->event_value ); 1445 /* XXX: hack, replace by better code here */ 1446 if (slayout->event_value != 0) 1447 corecmd_set_coarse_orientation( ANDROID_COARSE_PORTRAIT ); 1448 else 1449 corecmd_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE ); 1450 } 1451 1452 return 0; 1453 } 1454 1455 int 1456 skin_window_reset ( SkinWindow* window, SkinLayout* slayout ) 1457 { 1458 if (!window->fullscreen) { 1459 SDL_WM_GetPos(&window->x_pos, &window->y_pos); 1460 } 1461 if (skin_window_reset_internal( window, slayout ) < 0) 1462 return -1; 1463 1464 return 0; 1465 } 1466 1467 void 1468 skin_window_set_lcd_brightness( SkinWindow* window, int brightness ) 1469 { 1470 ADisplay* disp = window->layout.displays; 1471 1472 if (disp != NULL) { 1473 disp->brightness = brightness; 1474 skin_window_redraw( window, NULL ); 1475 } 1476 } 1477 1478 void 1479 skin_window_free ( SkinWindow* window ) 1480 { 1481 if (window) { 1482 if (window->surface) { 1483 SDL_FreeSurface(window->surface); 1484 window->surface = NULL; 1485 } 1486 if (window->shrink_surface) { 1487 SDL_FreeSurface(window->shrink_surface); 1488 window->shrink_surface = NULL; 1489 } 1490 if (window->shrink_pixels) { 1491 AFREE(window->shrink_pixels); 1492 window->shrink_pixels = NULL; 1493 } 1494 if (window->onion) { 1495 skin_image_unref( &window->onion ); 1496 window->onion_rotation = SKIN_ROTATION_0; 1497 } 1498 if (window->scaler) { 1499 skin_scaler_free(window->scaler); 1500 window->scaler = NULL; 1501 } 1502 layout_done( &window->layout ); 1503 AFREE(window); 1504 } 1505 } 1506 1507 void 1508 skin_window_set_onion( SkinWindow* window, 1509 SkinImage* onion, 1510 SkinRotation onion_rotation, 1511 int onion_alpha ) 1512 { 1513 ADisplay* disp; 1514 SkinImage* old = window->onion; 1515 1516 window->onion = skin_image_ref(onion); 1517 window->onion_rotation = onion_rotation; 1518 window->onion_alpha = onion_alpha; 1519 1520 skin_image_unref( &old ); 1521 1522 disp = window->layout.displays; 1523 1524 if (disp != NULL) 1525 display_set_onion( disp, window->onion, onion_rotation, onion_alpha ); 1526 } 1527 1528 static void 1529 skin_window_update_shrink( SkinWindow* window, SkinRect* rect ) 1530 { 1531 skin_scaler_scale( window->scaler, window->shrink_surface, window->surface, 1532 rect->pos.x, rect->pos.y, rect->size.w, rect->size.h ); 1533 } 1534 1535 void 1536 skin_window_set_scale( SkinWindow* window, double scale ) 1537 { 1538 window->shrink = (scale != 1.0); 1539 window->shrink_scale = scale; 1540 1541 skin_window_resize( window ); 1542 skin_window_redraw( window, NULL ); 1543 } 1544 1545 void 1546 skin_window_redraw( SkinWindow* window, SkinRect* rect ) 1547 { 1548 if (window != NULL && window->surface != NULL) { 1549 Layout* layout = &window->layout; 1550 1551 if (rect == NULL) 1552 rect = &layout->rect; 1553 1554 { 1555 SkinRect r; 1556 1557 if ( skin_rect_intersect( &r, rect, &layout->rect ) ) { 1558 SDL_Rect rd; 1559 rd.x = r.pos.x; 1560 rd.y = r.pos.y; 1561 rd.w = r.size.w; 1562 rd.h = r.size.h; 1563 1564 SDL_FillRect( window->surface, &rd, layout->color ); 1565 } 1566 } 1567 1568 { 1569 Background* back = layout->backgrounds; 1570 Background* end = back + layout->num_backgrounds; 1571 for ( ; back < end; back++ ) 1572 background_redraw( back, rect, window->surface ); 1573 } 1574 1575 { 1576 ADisplay* disp = layout->displays; 1577 ADisplay* end = disp + layout->num_displays; 1578 for ( ; disp < end; disp++ ) 1579 display_redraw( disp, rect, window->surface ); 1580 } 1581 1582 { 1583 Button* button = layout->buttons; 1584 Button* end = button + layout->num_buttons; 1585 for ( ; button < end; button++ ) 1586 button_redraw( button, rect, window->surface ); 1587 } 1588 1589 if ( window->ball.tracking ) 1590 ball_state_redraw( &window->ball, rect, window->surface ); 1591 1592 if (window->effective_scale != 1.0) 1593 skin_window_update_shrink( window, rect ); 1594 else 1595 { 1596 SDL_Rect rd; 1597 rd.x = rect->pos.x; 1598 rd.y = rect->pos.y; 1599 rd.w = rect->size.w; 1600 rd.h = rect->size.h; 1601 1602 SDL_UpdateRects( window->surface, 1, &rd ); 1603 } 1604 skin_window_redraw_opengles( window ); 1605 } 1606 } 1607 1608 void 1609 skin_window_toggle_fullscreen( SkinWindow* window ) 1610 { 1611 if (window && window->surface) { 1612 if (!window->fullscreen) 1613 SDL_WM_GetPos( &window->x_pos, &window->y_pos ); 1614 1615 window->fullscreen = !window->fullscreen; 1616 skin_window_resize( window ); 1617 skin_window_redraw( window, NULL ); 1618 } 1619 } 1620 1621 void 1622 skin_window_get_display( SkinWindow* window, ADisplayInfo *info ) 1623 { 1624 ADisplay* disp = window->layout.displays; 1625 1626 if (disp != NULL) { 1627 info->width = disp->datasize.w; 1628 info->height = disp->datasize.h; 1629 info->rotation = disp->rotation; 1630 info->data = disp->data; 1631 } else { 1632 info->width = 0; 1633 info->height = 0; 1634 info->rotation = SKIN_ROTATION_0; 1635 info->data = NULL; 1636 } 1637 } 1638 1639 1640 static void 1641 skin_window_map_to_scale( SkinWindow* window, int *x, int *y ) 1642 { 1643 *x = (*x - window->effective_x) / window->effective_scale; 1644 *y = (*y - window->effective_y) / window->effective_scale; 1645 } 1646 1647 void 1648 skin_window_process_event( SkinWindow* window, SDL_Event* ev ) 1649 { 1650 Button* button; 1651 int mx, my; 1652 1653 if (!window->surface) 1654 return; 1655 1656 switch (ev->type) { 1657 case SDL_MOUSEBUTTONDOWN: 1658 if ( window->ball.tracking ) { 1659 skin_window_trackball_press( window, 1 ); 1660 break; 1661 } 1662 1663 mx = ev->button.x; 1664 my = ev->button.y; 1665 skin_window_map_to_scale( window, &mx, &my ); 1666 skin_window_move_mouse( window, mx, my ); 1667 skin_window_find_finger( window, mx, my ); 1668 #if 0 1669 printf("down: x=%d y=%d fx=%d fy=%d fis=%d\n", 1670 ev->button.x, ev->button.y, window->finger.pos.x, 1671 window->finger.pos.y, window->finger.inside); 1672 #endif 1673 if (window->finger.inside) { 1674 window->finger.tracking = 1; 1675 add_finger_event(window->finger.pos.x, window->finger.pos.y, 1); 1676 } else { 1677 window->button.pressed = NULL; 1678 button = window->button.hover; 1679 if(button) { 1680 button->down += 1; 1681 skin_window_redraw( window, &button->rect ); 1682 window->button.pressed = button; 1683 if(button->keycode) { 1684 user_event_key(button->keycode, 1); 1685 } 1686 } 1687 } 1688 break; 1689 1690 case SDL_MOUSEBUTTONUP: 1691 if ( window->ball.tracking ) { 1692 skin_window_trackball_press( window, 0 ); 1693 break; 1694 } 1695 button = window->button.pressed; 1696 mx = ev->button.x; 1697 my = ev->button.y; 1698 skin_window_map_to_scale( window, &mx, &my ); 1699 if (button) 1700 { 1701 button->down = 0; 1702 skin_window_redraw( window, &button->rect ); 1703 if(button->keycode) { 1704 user_event_key(button->keycode, 0); 1705 } 1706 window->button.pressed = NULL; 1707 window->button.hover = NULL; 1708 skin_window_move_mouse( window, mx, my ); 1709 } 1710 else if (window->finger.tracking) 1711 { 1712 skin_window_move_mouse( window, mx, my ); 1713 window->finger.tracking = 0; 1714 add_finger_event( window->finger.pos.x, window->finger.pos.y, 0); 1715 } 1716 break; 1717 1718 case SDL_MOUSEMOTION: 1719 if ( window->ball.tracking ) { 1720 skin_window_trackball_move( window, ev->motion.xrel, ev->motion.yrel ); 1721 break; 1722 } 1723 mx = ev->button.x; 1724 my = ev->button.y; 1725 skin_window_map_to_scale( window, &mx, &my ); 1726 if ( !window->button.pressed ) 1727 { 1728 skin_window_move_mouse( window, mx, my ); 1729 if ( window->finger.tracking ) { 1730 add_finger_event( window->finger.pos.x, window->finger.pos.y, 1 ); 1731 } 1732 } 1733 break; 1734 1735 case SDL_VIDEOEXPOSE: 1736 skin_window_redraw_opengles(window); 1737 break; 1738 } 1739 } 1740 1741 static ADisplay* 1742 skin_window_display( SkinWindow* window ) 1743 { 1744 return window->layout.displays; 1745 } 1746 1747 void 1748 skin_window_update_display( SkinWindow* window, int x, int y, int w, int h ) 1749 { 1750 ADisplay* disp = skin_window_display(window); 1751 1752 if ( !window->surface ) 1753 return; 1754 1755 if (disp != NULL) { 1756 SkinRect r; 1757 r.pos.x = x; 1758 r.pos.y = y; 1759 r.size.w = w; 1760 r.size.h = h; 1761 1762 skin_rect_rotate( &r, &r, disp->rotation ); 1763 r.pos.x += disp->origin.x; 1764 r.pos.y += disp->origin.y; 1765 1766 if (window->effective_scale != 1.0) 1767 skin_window_redraw( window, &r ); 1768 else 1769 display_redraw( disp, &r, window->surface ); 1770 } 1771 } 1772