Home | History | Annotate | Download | only in skin
      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