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