• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 ** GNU General Public License for more details.
11 */
12 #include "android/skin/window.h"
13 #include "android/skin/image.h"
14 #include "android/skin/scaler.h"
15 #include "android/charmap.h"
16 #include "android/utils/debug.h"
17 #include "android/utils/system.h"
18 #include "android/utils/duff.h"
19 #include "android/protocol/core-commands-api.h"
20 #include <SDL_syswm.h>
21 #include "user-events.h"
22 #include <math.h>
23 
24 #include "android/framebuffer.h"
25 #include "android/opengles.h"
26 
27 /* when shrinking, we reduce the pixel ratio by this fixed amount */
28 #define  SHRINK_SCALE  0.6
29 
30 /* maximum value of LCD brighness */
31 #define  LCD_BRIGHTNESS_MIN      0
32 #define  LCD_BRIGHTNESS_DEFAULT  128
33 #define  LCD_BRIGHTNESS_MAX      255
34 
35 typedef struct Background {
36     SkinImage*   image;
37     SkinRect     rect;
38     SkinPos      origin;
39 } Background;
40 
41 static void
background_done(Background * back)42 background_done( Background*  back )
43 {
44     skin_image_unref( &back->image );
45 }
46 
47 static void
background_init(Background * back,SkinBackground * sback,SkinLocation * loc,SkinRect * frame)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
background_redraw(Background * back,SkinRect * rect,SDL_Surface * surface)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
display_done(ADisplay * disp)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
display_init(ADisplay * disp,SkinDisplay * sdisp,SkinLocation * loc,SkinRect * frame)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 
rgb565_to_rgba32(uint32_t pix,uint32_t rshift,uint32_t gshift,uint32_t bshift,uint32_t amask)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  */
xbgr_to_rgba32(uint32_t pix,uint32_t rshift,uint32_t gshift,uint32_t bshift,uint32_t amask)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
display_set_onion(ADisplay * disp,SkinImage * onion,SkinRotation rotation,int blend)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
dotmatrix_dither_argb32(unsigned char * pixels,int x,int y,int w,int h,int pitch)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
lcd_brightness_argb32(unsigned char * pixels,SkinRect * r,int pitch,int brightness)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
lcd_off_argb32(unsigned char * pixels,SkinRect * r,int pitch)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
display_redraw_rect16(ADisplay * disp,SkinRect * rect,SDL_Surface * surface)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
display_redraw_rect32(ADisplay * disp,SkinRect * rect,SDL_Surface * surface)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
display_redraw(ADisplay * disp,SkinRect * rect,SDL_Surface * surface)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
button_done(Button * button)642 button_done( Button*  button )
643 {
644     skin_image_unref( &button->image );
645     button->background = NULL;
646 }
647 
648 static void
button_init(Button * button,SkinButton * sbutton,SkinLocation * loc,Background * back,SkinRect * frame,SkinLayout * slayout)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
button_redraw(Button * button,SkinRect * rect,SDL_Surface * surface)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
finger_state_reset(FingerState * finger)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
button_state_reset(ButtonState * button)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
ball_state_reset(BallState * state,SkinWindow * window)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
ball_state_redraw(BallState * state,SkinRect * rect,SDL_Surface * surface)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
ball_state_show(BallState * state,int enable)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
ball_state_set(BallState * state,SkinTrackBall * ball)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
layout_done(Layout * layout)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
layout_init(Layout * layout,SkinLayout * slayout)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
add_finger_event(unsigned x,unsigned y,unsigned state)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/goldfish_events.c to differentiate
978      * between a touch-screen and a trackball event
979      */
980     user_event_mouse(x, y, 0, state);
981 }
982 
983 static void
skin_window_find_finger(SkinWindow * window,int x,int y)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
skin_window_move_mouse(SkinWindow * window,int x,int y)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
skin_window_trackball_press(SkinWindow * window,int down)1121 skin_window_trackball_press( SkinWindow*  window, int  down )
1122 {
1123     user_event_key( BTN_MOUSE, down );
1124 }
1125 
1126 static void
skin_window_trackball_move(SkinWindow * window,int xrel,int yrel)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
skin_window_set_trackball(SkinWindow * window,SkinTrackBall * ball)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
skin_window_show_trackball(SkinWindow * window,int enable)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
skin_window_hide_opengles(SkinWindow * window)1157 skin_window_hide_opengles( SkinWindow* window )
1158 {
1159     android_hideOpenglesWindow();
1160 }
1161 
1162 /* Show the OpenGL ES framebuffer window */
1163 static void
skin_window_show_opengles(SkinWindow * window)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
skin_window_redraw_opengles(SkinWindow * window)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*
skin_window_create(SkinLayout * slayout,int x,int y,double scale,int no_display)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
skin_window_enable_touch(SkinWindow * window,int enabled)1283 skin_window_enable_touch( SkinWindow*  window, int  enabled )
1284 {
1285     window->enable_touch = !!enabled;
1286 }
1287 
1288 void
skin_window_enable_trackball(SkinWindow * window,int enabled)1289 skin_window_enable_trackball( SkinWindow*  window, int  enabled )
1290 {
1291     window->enable_trackball = !!enabled;
1292 }
1293 
1294 void
skin_window_enable_dpad(SkinWindow * window,int enabled)1295 skin_window_enable_dpad( SkinWindow*  window, int  enabled )
1296 {
1297     window->enable_dpad = !!enabled;
1298 }
1299 
1300 void
skin_window_enable_qwerty(SkinWindow * window,int enabled)1301 skin_window_enable_qwerty( SkinWindow*  window, int  enabled )
1302 {
1303     window->enable_qwerty = !!enabled;
1304 }
1305 
1306 void
skin_window_set_title(SkinWindow * window,const char * title)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
skin_window_resize(SkinWindow * window)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
skin_window_reset_internal(SkinWindow * window,SkinLayout * slayout)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 && window->onion)
1441         display_set_onion( disp,
1442                            window->onion,
1443                            window->onion_rotation,
1444                            window->onion_alpha );
1445 
1446     skin_window_resize(window);
1447 
1448     finger_state_reset( &window->finger );
1449     button_state_reset( &window->button );
1450     ball_state_reset( &window->ball, window );
1451 
1452     skin_window_redraw( window, NULL );
1453 
1454     if (slayout->event_type != 0) {
1455         user_event_generic( slayout->event_type, slayout->event_code, slayout->event_value );
1456         /* XXX: hack, replace by better code here */
1457         if (slayout->event_value != 0)
1458             corecmd_set_coarse_orientation( ANDROID_COARSE_PORTRAIT );
1459         else
1460             corecmd_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE );
1461     }
1462 
1463     return 0;
1464 }
1465 
1466 int
skin_window_reset(SkinWindow * window,SkinLayout * slayout)1467 skin_window_reset ( SkinWindow*  window, SkinLayout*  slayout )
1468 {
1469     if (!window->fullscreen) {
1470         SDL_WM_GetPos(&window->x_pos, &window->y_pos);
1471     }
1472     if (skin_window_reset_internal( window, slayout ) < 0)
1473         return -1;
1474 
1475     return 0;
1476 }
1477 
1478 void
skin_window_set_lcd_brightness(SkinWindow * window,int brightness)1479 skin_window_set_lcd_brightness( SkinWindow*  window, int  brightness )
1480 {
1481     ADisplay*  disp = window->layout.displays;
1482 
1483     if (disp != NULL) {
1484         disp->brightness = brightness;
1485         skin_window_redraw( window, NULL );
1486     }
1487 }
1488 
1489 void
skin_window_free(SkinWindow * window)1490 skin_window_free  ( SkinWindow*  window )
1491 {
1492     if (window) {
1493         if (window->surface) {
1494             SDL_FreeSurface(window->surface);
1495             window->surface = NULL;
1496         }
1497         if (window->shrink_surface) {
1498             SDL_FreeSurface(window->shrink_surface);
1499             window->shrink_surface = NULL;
1500         }
1501         if (window->shrink_pixels) {
1502             AFREE(window->shrink_pixels);
1503             window->shrink_pixels = NULL;
1504         }
1505         if (window->onion) {
1506             skin_image_unref( &window->onion );
1507             window->onion_rotation = SKIN_ROTATION_0;
1508         }
1509         if (window->scaler) {
1510             skin_scaler_free(window->scaler);
1511             window->scaler = NULL;
1512         }
1513         layout_done( &window->layout );
1514         AFREE(window);
1515     }
1516 }
1517 
1518 void
skin_window_set_onion(SkinWindow * window,SkinImage * onion,SkinRotation onion_rotation,int onion_alpha)1519 skin_window_set_onion( SkinWindow*   window,
1520                        SkinImage*    onion,
1521                        SkinRotation  onion_rotation,
1522                        int           onion_alpha )
1523 {
1524     ADisplay*  disp;
1525     SkinImage*  old = window->onion;
1526 
1527     window->onion          = skin_image_ref(onion);
1528     window->onion_rotation = onion_rotation;
1529     window->onion_alpha    = onion_alpha;
1530 
1531     skin_image_unref( &old );
1532 
1533     disp = window->layout.displays;
1534 
1535     if (disp != NULL)
1536         display_set_onion( disp, window->onion, onion_rotation, onion_alpha );
1537 }
1538 
1539 static void
skin_window_update_shrink(SkinWindow * window,SkinRect * rect)1540 skin_window_update_shrink( SkinWindow*  window, SkinRect*  rect )
1541 {
1542     skin_scaler_scale( window->scaler, window->shrink_surface, window->surface,
1543                        rect->pos.x, rect->pos.y, rect->size.w, rect->size.h );
1544 }
1545 
1546 void
skin_window_set_scale(SkinWindow * window,double scale)1547 skin_window_set_scale( SkinWindow*  window, double  scale )
1548 {
1549     window->shrink       = (scale != 1.0);
1550     window->shrink_scale = scale;
1551 
1552     skin_window_resize( window );
1553     skin_window_redraw( window, NULL );
1554 }
1555 
1556 void
skin_window_redraw(SkinWindow * window,SkinRect * rect)1557 skin_window_redraw( SkinWindow*  window, SkinRect*  rect )
1558 {
1559     if (window != NULL && window->surface != NULL) {
1560         Layout*  layout = &window->layout;
1561 
1562         if (rect == NULL)
1563             rect = &layout->rect;
1564 
1565         {
1566             SkinRect  r;
1567 
1568             if ( skin_rect_intersect( &r, rect, &layout->rect ) ) {
1569                 SDL_Rect  rd;
1570                 rd.x = r.pos.x;
1571                 rd.y = r.pos.y;
1572                 rd.w = r.size.w;
1573                 rd.h = r.size.h;
1574 
1575                 SDL_FillRect( window->surface, &rd, layout->color );
1576             }
1577         }
1578 
1579         {
1580             Background*  back = layout->backgrounds;
1581             Background*  end  = back + layout->num_backgrounds;
1582             for ( ; back < end; back++ )
1583                 background_redraw( back, rect, window->surface );
1584         }
1585 
1586         {
1587             ADisplay*  disp = layout->displays;
1588             ADisplay*  end  = disp + layout->num_displays;
1589             for ( ; disp < end; disp++ )
1590                 display_redraw( disp, rect, window->surface );
1591         }
1592 
1593         {
1594             Button*  button = layout->buttons;
1595             Button*  end    = button + layout->num_buttons;
1596             for ( ; button < end; button++ )
1597                 button_redraw( button, rect, window->surface );
1598         }
1599 
1600         if ( window->ball.tracking )
1601             ball_state_redraw( &window->ball, rect, window->surface );
1602 
1603         if (window->effective_scale != 1.0)
1604             skin_window_update_shrink( window, rect );
1605         else
1606         {
1607             SDL_Rect  rd;
1608             rd.x = rect->pos.x;
1609             rd.y = rect->pos.y;
1610             rd.w = rect->size.w;
1611             rd.h = rect->size.h;
1612 
1613             SDL_UpdateRects( window->surface, 1, &rd );
1614         }
1615         skin_window_redraw_opengles( window );
1616     }
1617 }
1618 
1619 void
skin_window_toggle_fullscreen(SkinWindow * window)1620 skin_window_toggle_fullscreen( SkinWindow*  window )
1621 {
1622     if (window && window->surface) {
1623         if (!window->fullscreen)
1624             SDL_WM_GetPos( &window->x_pos, &window->y_pos );
1625 
1626         window->fullscreen = !window->fullscreen;
1627         skin_window_resize( window );
1628         skin_window_redraw( window, NULL );
1629     }
1630 }
1631 
1632 void
skin_window_get_display(SkinWindow * window,ADisplayInfo * info)1633 skin_window_get_display( SkinWindow*  window, ADisplayInfo  *info )
1634 {
1635     ADisplay*  disp = window->layout.displays;
1636 
1637     if (disp != NULL) {
1638         info->width    = disp->datasize.w;
1639         info->height   = disp->datasize.h;
1640         info->rotation = disp->rotation;
1641         info->data     = disp->data;
1642     } else {
1643         info->width    = 0;
1644         info->height   = 0;
1645         info->rotation = SKIN_ROTATION_0;
1646         info->data     = NULL;
1647     }
1648 }
1649 
1650 
1651 static void
skin_window_map_to_scale(SkinWindow * window,int * x,int * y)1652 skin_window_map_to_scale( SkinWindow*  window, int  *x, int  *y )
1653 {
1654     *x = (*x - window->effective_x) / window->effective_scale;
1655     *y = (*y - window->effective_y) / window->effective_scale;
1656 }
1657 
1658 void
skin_window_process_event(SkinWindow * window,SDL_Event * ev)1659 skin_window_process_event( SkinWindow*  window, SDL_Event*  ev )
1660 {
1661     Button*  button;
1662     int      mx, my;
1663 
1664     if (!window->surface)
1665         return;
1666 
1667     switch (ev->type) {
1668     case SDL_MOUSEBUTTONDOWN:
1669         if ( window->ball.tracking ) {
1670             skin_window_trackball_press( window, 1 );
1671             break;
1672         }
1673 
1674         mx = ev->button.x;
1675         my = ev->button.y;
1676         skin_window_map_to_scale( window, &mx, &my );
1677         skin_window_move_mouse( window, mx, my );
1678         skin_window_find_finger( window, mx, my );
1679 #if 0
1680         printf("down: x=%d y=%d fx=%d fy=%d fis=%d\n",
1681                ev->button.x, ev->button.y, window->finger.pos.x,
1682                window->finger.pos.y, window->finger.inside);
1683 #endif
1684         if (window->finger.inside) {
1685             window->finger.tracking = 1;
1686             add_finger_event(window->finger.pos.x, window->finger.pos.y, 1);
1687         } else {
1688             window->button.pressed = NULL;
1689             button = window->button.hover;
1690             if(button) {
1691                 button->down += 1;
1692                 skin_window_redraw( window, &button->rect );
1693                 window->button.pressed = button;
1694                 if(button->keycode) {
1695                     user_event_key(button->keycode, 1);
1696                 }
1697             }
1698         }
1699         break;
1700 
1701     case SDL_MOUSEBUTTONUP:
1702         if ( window->ball.tracking ) {
1703             skin_window_trackball_press( window, 0 );
1704             break;
1705         }
1706         button = window->button.pressed;
1707         mx = ev->button.x;
1708         my = ev->button.y;
1709         skin_window_map_to_scale( window, &mx, &my );
1710         if (button)
1711         {
1712             button->down = 0;
1713             skin_window_redraw( window, &button->rect );
1714             if(button->keycode) {
1715                 user_event_key(button->keycode, 0);
1716             }
1717             window->button.pressed = NULL;
1718             window->button.hover   = NULL;
1719             skin_window_move_mouse( window, mx, my );
1720         }
1721         else if (window->finger.tracking)
1722         {
1723             skin_window_move_mouse( window, mx, my );
1724             window->finger.tracking = 0;
1725             add_finger_event( window->finger.pos.x, window->finger.pos.y, 0);
1726         }
1727         break;
1728 
1729     case SDL_MOUSEMOTION:
1730         if ( window->ball.tracking ) {
1731             skin_window_trackball_move( window, ev->motion.xrel, ev->motion.yrel );
1732             break;
1733         }
1734         mx = ev->button.x;
1735         my = ev->button.y;
1736         skin_window_map_to_scale( window, &mx, &my );
1737         if ( !window->button.pressed )
1738         {
1739             skin_window_move_mouse( window, mx, my );
1740             if ( window->finger.tracking ) {
1741                 add_finger_event( window->finger.pos.x, window->finger.pos.y, 1 );
1742             }
1743         }
1744         break;
1745 
1746     case SDL_VIDEOEXPOSE:
1747         skin_window_redraw_opengles(window);
1748         break;
1749     }
1750 }
1751 
1752 static ADisplay*
skin_window_display(SkinWindow * window)1753 skin_window_display( SkinWindow*  window )
1754 {
1755     return window->layout.displays;
1756 }
1757 
1758 void
skin_window_update_display(SkinWindow * window,int x,int y,int w,int h)1759 skin_window_update_display( SkinWindow*  window, int  x, int  y, int  w, int  h )
1760 {
1761     ADisplay*  disp = skin_window_display(window);
1762 
1763     if ( !window->surface )
1764         return;
1765 
1766     if (disp != NULL) {
1767         SkinRect  r;
1768         r.pos.x  = x;
1769         r.pos.y  = y;
1770         r.size.w = w;
1771         r.size.h = h;
1772 
1773         skin_rect_rotate( &r, &r, disp->rotation );
1774         r.pos.x += disp->origin.x;
1775         r.pos.y += disp->origin.y;
1776 
1777         if (window->effective_scale != 1.0)
1778             skin_window_redraw( window, &r );
1779         else
1780             display_redraw( disp, &r, window->surface );
1781     }
1782 }
1783