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