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