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