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