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