blob: 5689a111dd903316cf0f911c6178a622156a0ded [file] [log] [blame]
David 'Digit' Turnerd1744342014-07-11 14:03:25 +02001/* Copyright (C) 2011 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
13#include <SDL.h>
14#include <SDL_syswm.h>
15
16#include "android/avd/util.h"
17#include "android/globals.h"
18#include "android/main-common.h"
19#include "android/qemulator.h"
20#include "android/display.h"
21#include "android/resource.h"
22#include "android/skin/image.h"
23#include "android/skin/trackball.h"
24#include "android/skin/keyboard.h"
25#include "android/skin/file.h"
26#include "android/skin/window.h"
27#include "android/user-config.h"
28#include "android/utils/bufprint.h"
29#include "android/utils/debug.h"
30#include "android/utils/eintr_wrapper.h"
31#include "android/utils/path.h"
32
33#include "ui/console.h"
34
35#include <stdlib.h>
36
37#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
38
39/*** CONFIGURATION
40 ***/
41
42static AUserConfig* userConfig;
43
44void
45user_config_init( void )
46{
47 userConfig = auserConfig_new( android_avdInfo );
48}
49
50/* only call this function on normal exits, so that ^C doesn't save the configuration */
51void
52user_config_done( void )
53{
54 int win_x, win_y;
55
56 if (!userConfig) {
57 D("no user configuration?");
58 return;
59 }
60
61 SDL_WM_GetPos( &win_x, &win_y );
62 auserConfig_setWindowPos(userConfig, win_x, win_y);
63 auserConfig_save(userConfig);
64}
65
66void
67user_config_get_window_pos( int *window_x, int *window_y )
68{
69 *window_x = *window_y = 10;
70
71 if (userConfig)
72 auserConfig_getWindowPos(userConfig, window_x, window_y);
73}
74
75/***********************************************************************/
76/***********************************************************************/
77/***** *****/
78/***** K E Y S E T R O U T I N E S *****/
79/***** *****/
80/***********************************************************************/
81/***********************************************************************/
82
83#define KEYSET_FILE "default.keyset"
84
85SkinKeyset* android_keyset = NULL;
86
87static int
88load_keyset(const char* path)
89{
90 if (path_can_read(path)) {
91 AConfig* root = aconfig_node("","");
92 if (!aconfig_load_file(root, path)) {
93 android_keyset = skin_keyset_new(root);
94 if (android_keyset != NULL) {
95 D( "keyset loaded from: %s", path);
96 return 0;
97 }
98 }
99 }
100 return -1;
101}
102
103void
104parse_keyset(const char* keyset, AndroidOptions* opts)
105{
106 char kname[MAX_PATH];
107 char temp[MAX_PATH];
108 char* p;
109 char* end;
110
111 /* append .keyset suffix if needed */
112 if (strchr(keyset, '.') == NULL) {
113 p = kname;
114 end = p + sizeof(kname);
115 p = bufprint(p, end, "%s.keyset", keyset);
116 if (p >= end) {
117 derror( "keyset name too long: '%s'\n", keyset);
118 exit(1);
119 }
120 keyset = kname;
121 }
122
123 /* look for a the keyset file */
124 p = temp;
125 end = p + sizeof(temp);
126 p = bufprint_config_file(p, end, keyset);
127 if (p < end && load_keyset(temp) == 0)
128 return;
129
130 p = temp;
131 p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->sysdir, keyset);
132 if (p < end && load_keyset(temp) == 0)
133 return;
134
135 p = temp;
136 p = bufprint_app_dir(p, end);
137 p = bufprint(p, end, PATH_SEP "keysets" PATH_SEP "%s", keyset);
138 if (p < end && load_keyset(temp) == 0)
139 return;
140
141 return;
142}
143
144void
145write_default_keyset( void )
146{
147 char path[MAX_PATH];
148
149 bufprint_config_file( path, path+sizeof(path), KEYSET_FILE );
150
151 /* only write if there is no file here */
152 if (!path_exists(path)) {
153 int fd = open( path, O_WRONLY | O_CREAT, 0666 );
154 const char* ks = skin_keyset_get_default();
155
156
157 D( "writing default keyset file to %s", path );
158
159 if (fd < 0) {
160 D( "%s: could not create file: %s", __FUNCTION__, strerror(errno) );
161 return;
162 }
163 HANDLE_EINTR(write(fd, ks, strlen(ks)));
164 IGNORE_EINTR(close(fd));
165 }
166}
167
168
169
170/***********************************************************************/
171/***********************************************************************/
172/***** *****/
173/***** S D L S U P P O R T *****/
174/***** *****/
175/***********************************************************************/
176/***********************************************************************/
177
178void *readpng(const unsigned char* base, size_t size, unsigned *_width, unsigned *_height);
179
180#ifdef CONFIG_DARWIN
181# define ANDROID_ICON_PNG "android_icon_256.png"
182#else
183# define ANDROID_ICON_PNG "android_icon_16.png"
184#endif
185
186static void
187sdl_set_window_icon( void )
188{
189 static int window_icon_set;
190
191 if (!window_icon_set)
192 {
193#ifdef _WIN32
194 HANDLE handle = GetModuleHandle( NULL );
195 HICON icon = LoadIcon( handle, MAKEINTRESOURCE(1) );
196 SDL_SysWMinfo wminfo;
197
198 SDL_GetWMInfo(&wminfo);
199
200 SetClassLongPtr( wminfo.window, GCLP_HICON, (LONG)icon );
201#else /* !_WIN32 */
202 unsigned icon_w, icon_h;
203 size_t icon_bytes;
204 const unsigned char* icon_data;
205 void* icon_pixels;
206
207 window_icon_set = 1;
208
209 icon_data = android_icon_find( ANDROID_ICON_PNG, &icon_bytes );
210 if ( !icon_data )
211 return;
212
213 icon_pixels = readpng( icon_data, icon_bytes, &icon_w, &icon_h );
214 if ( !icon_pixels )
215 return;
216
217 /* the data is loaded into memory as RGBA bytes by libpng. we want to manage
218 * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending
219 * on our CPU endianess
220 */
221 {
222 unsigned* d = icon_pixels;
223 unsigned* d_end = d + icon_w*icon_h;
224
225 for ( ; d < d_end; d++ ) {
226 unsigned pix = d[0];
227#if HOST_WORDS_BIGENDIAN
228 /* R,G,B,A read as RGBA => ARGB */
229 pix = ((pix >> 8) & 0xffffff) | (pix << 24);
230#else
231 /* R,G,B,A read as ABGR => ARGB */
232 pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16);
233#endif
234 d[0] = pix;
235 }
236 }
237
238 SDL_Surface* icon = sdl_surface_from_argb32( icon_pixels, icon_w, icon_h );
239 if (icon != NULL) {
240 SDL_WM_SetIcon(icon, NULL);
241 SDL_FreeSurface(icon);
242 free( icon_pixels );
243 }
244#endif /* !_WIN32 */
245 }
246}
247
248/***********************************************************************/
249/***********************************************************************/
250/***** *****/
251/***** S K I N S U P P O R T *****/
252/***** *****/
253/***********************************************************************/
254/***********************************************************************/
255
256const char* skin_network_speed = NULL;
257const char* skin_network_delay = NULL;
258
259
260static void sdl_at_exit(void)
261{
262 user_config_done();
263 qemulator_done(qemulator_get());
264 SDL_Quit();
265}
266
267
268void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
269{
270 QEmulator* emulator = qemulator_get();
271 SkinDisplay* disp = skin_layout_get_display(emulator->layout);
272 int width, height;
273 char buf[128];
274
275 if (disp->rotation & 1) {
276 width = disp->rect.size.h;
277 height = disp->rect.size.w;
278 } else {
279 width = disp->rect.size.w;
280 height = disp->rect.size.h;
281 }
282
283 snprintf(buf, sizeof buf, "width=%d,height=%d", width, height);
David 'Digit' Turnerd1744342014-07-11 14:03:25 +0200284 android_display_init(ds, qframebuffer_fifo_get());
David 'Digit' Turnerd1744342014-07-11 14:03:25 +0200285}
286
287typedef struct part_properties part_properties;
288struct part_properties {
289 const char* name;
290 int width;
291 int height;
292 part_properties* next;
293};
294
295part_properties*
296read_all_part_properties(AConfig* parts)
297{
298 part_properties* head = NULL;
299 part_properties* prev = NULL;
300
301 AConfig *node = parts->first_child;
302 while (node) {
303 part_properties* t = calloc(1, sizeof(part_properties));
304 t->name = node->name;
305
306 AConfig* bg = aconfig_find(node, "background");
307 if (bg != NULL) {
308 t->width = aconfig_int(bg, "width", 0);
309 t->height = aconfig_int(bg, "height", 0);
310 }
311
312 if (prev == NULL) {
313 head = t;
314 } else {
315 prev->next = t;
316 }
317 prev = t;
318 node = node->next;
319 }
320
321 return head;
322}
323
324void
325free_all_part_properties(part_properties* head)
326{
327 part_properties* prev = head;
328 while (head) {
329 prev = head;
330 head = head->next;
331 free(prev);
332 }
333}
334
335part_properties*
336get_part_properties(part_properties* allparts, char *partname)
337{
338 part_properties* p;
339 for (p = allparts; p != NULL; p = p->next) {
340 if (!strcmp(partname, p->name))
341 return p;
342 }
343
344 return NULL;
345}
346
347void
348add_parts_to_layout(AConfig* layout,
349 char* parts[],
350 int n_parts,
351 part_properties *props,
352 int xoffset,
353 int x_margin,
354 int y_margin)
355{
356 int i;
357 int y = 10;
358 char tmp[512];
359 for (i = 0; i < n_parts; i++) {
360 part_properties *p = get_part_properties(props, parts[i]);
361 snprintf(tmp, sizeof tmp,
362 "part%d {\n \
363 name %s\n \
364 x %d\n \
365 y %d\n \
366 }",
367 i + 2, // layout already has the device part as part1, so start from part2
368 p->name,
369 xoffset + x_margin,
370 y
371 );
372 y += p->height + y_margin;
373 aconfig_load(layout, strdup(tmp));
374 }
375}
376
377int
378load_dynamic_skin(AndroidHwConfig* hwConfig,
379 char** skinDirPath,
380 int width,
381 int height,
382 AConfig* root)
383{
384 char tmp[1024];
385 AConfig* node;
386 int i;
387 int max_part_width;
388
389 *skinDirPath = avdInfo_getDynamicSkinPath(android_avdInfo);
390 if (*skinDirPath == NULL) {
391 dwarning("Unable to locate dynamic skin directory. Will not use dynamic skin.");
392 return 0;
393 }
394
395 snprintf(tmp, sizeof(tmp), "%s/layout", *skinDirPath);
396 D("trying to load skin file '%s'", tmp);
397
398 if(aconfig_load_file(root, tmp) < 0) {
399 dwarning("could not load skin file '%s', won't use a skin\n", tmp);
400 return 0;
401 }
402
403 /* Fix the width and height specified for the "device" part in the layout */
404 node = aconfig_find(root, "parts");
405 if (node != NULL) {
406 node = aconfig_find(node, "device");
407 if (node != NULL) {
408 node = aconfig_find(node, "display");
409 if (node != NULL) {
410 snprintf(tmp, sizeof tmp, "%d", width);
411 aconfig_set(node, "width", strdup(tmp));
412 snprintf(tmp, sizeof tmp, "%d", height);
413 aconfig_set(node, "height", strdup(tmp));
414 }
415 }
416 }
417
418 /* The dynamic layout declares all the parts that are available statically
419 in the layout file. Now we need to dynamically generate the
420 appropriate layout based on the hardware config */
421
422 part_properties* props = read_all_part_properties(aconfig_find(root, "parts"));
423
424 const int N_PARTS = 4;
425 char* parts[N_PARTS];
426 parts[0] = "basic_controls";
427 parts[1] = hwConfig->hw_mainKeys ? "hwkeys_on" : "hwkeys_off";
428 parts[2] = hwConfig->hw_dPad ? "dpad_on" : "dpad_off";
429 parts[3] = hwConfig->hw_keyboard ? "keyboard_on" : "keyboard_off";
430
431 for (i = 0, max_part_width = 0; i < N_PARTS; i++) {
432 part_properties *p = get_part_properties(props, parts[i]);
433 if (p != NULL && p->width > max_part_width)
434 max_part_width = p->width;
435 }
436
437 int x_margin = 10;
438 int y_margin = 10;
439 snprintf(tmp, sizeof tmp,
440 "layouts {\n \
441 portrait {\n \
442 width %d\n \
443 height %d\n \
444 color 0x404040\n \
445 event EV_SW:0:1\n \
446 part1 {\n name device\n x 0\n y 0\n}\n \
447 }\n \
448 landscape {\n \
449 width %d\n \
450 height %d\n \
451 color 0x404040\n \
452 event EV_SW:0:0\n \
453 dpad-rotation 3\n \
454 part1 {\n name device\n x 0\n y %d\n rotation 3\n }\n \
455 }\n \
456 }\n \
457 }\n",
458 width + max_part_width + 2 * x_margin,
459 height,
460 height + max_part_width + 2 * x_margin,
461 width,
462 width);
463 aconfig_load(root, strdup(tmp));
464
465 /* Add parts to portrait orientation */
466 node = aconfig_find(root, "layouts");
467 if (node != NULL) {
468 node = aconfig_find(node, "portrait");
469 if (node != NULL) {
470 add_parts_to_layout(node, parts, N_PARTS, props, width, x_margin, y_margin);
471 }
472 }
473
474 /* Add parts to landscape orientation */
475 node = aconfig_find(root, "layouts");
476 if (node != NULL) {
477 node = aconfig_find(node, "landscape");
478 if (node != NULL) {
479 add_parts_to_layout(node, parts, N_PARTS, props, height, x_margin, y_margin);
480 }
481 }
482
483 free_all_part_properties(props);
484
485 return 1;
486}
487
488/* list of skin aliases */
489static const struct {
490 const char* name;
491 const char* alias;
492} skin_aliases[] = {
493 { "QVGA-L", "320x240" },
494 { "QVGA-P", "240x320" },
495 { "HVGA-L", "480x320" },
496 { "HVGA-P", "320x480" },
497 { "QVGA", "320x240" },
498 { "HVGA", "320x480" },
499 { NULL, NULL }
500};
501
502void
503parse_skin_files(const char* skinDirPath,
504 const char* skinName,
505 AndroidOptions* opts,
506 AndroidHwConfig* hwConfig,
507 AConfig* *skinConfig,
508 char* *skinPath)
509{
510 char tmp[1024];
511 AConfig* root;
512 const char* path = NULL;
513 AConfig* n;
514
515 root = aconfig_node("", "");
516
517 if (skinName == NULL)
518 goto DEFAULT_SKIN;
519
520 /* Support skin aliases like QVGA-H QVGA-P, etc...
521 But first we check if it's a directory that exist before applying
522 the alias */
523 int checkAlias = 1;
524
525 if (skinDirPath != NULL) {
526 bufprint(tmp, tmp+sizeof(tmp), "%s/%s", skinDirPath, skinName);
527 if (path_exists(tmp)) {
528 checkAlias = 0;
529 } else {
530 D("there is no '%s' skin in '%s'", skinName, skinDirPath);
531 }
532 }
533
534 if (checkAlias) {
535 int nn;
536
537 for (nn = 0; ; nn++ ) {
538 const char* skin_name = skin_aliases[nn].name;
539 const char* skin_alias = skin_aliases[nn].alias;
540
541 if (!skin_name)
542 break;
543
544 if (!strcasecmp( skin_name, skinName )) {
545 D("skin name '%s' aliased to '%s'", skinName, skin_alias);
546 skinName = skin_alias;
547 break;
548 }
549 }
550 }
551
552 /* Magically support skins like "320x240" or "320x240x16" */
553 if(isdigit(skinName[0])) {
554 char *x = strchr(skinName, 'x');
555 if(x && isdigit(x[1])) {
556 int width = atoi(skinName);
557 int height = atoi(x+1);
558 int bpp = 16;
559 char* y = strchr(x+1, 'x');
560 if (y && isdigit(y[1])) {
561 bpp = atoi(y+1);
562 }
563
564 if (opts->dynamic_skin) {
565 char *dynamicSkinDirPath;
566 if (load_dynamic_skin(hwConfig, &dynamicSkinDirPath, width, height, root)) {
567 path = dynamicSkinDirPath;
568 D("loaded dynamic skin width=%d height=%d bpp=%d\n", width, height, bpp);
569 goto FOUND_SKIN;
570 }
571 }
572
573 snprintf(tmp, sizeof tmp,
574 "display {\n width %d\n height %d\n bpp %d}\n",
575 width, height,bpp);
576 aconfig_load(root, strdup(tmp));
577 path = ":";
578 D("found magic skin width=%d height=%d bpp=%d\n", width, height, bpp);
579 goto FOUND_SKIN;
580 }
581 }
582
583 if (skinDirPath == NULL) {
584 derror("unknown skin name '%s'", skinName);
585 exit(1);
586 }
587
588 snprintf(tmp, sizeof tmp, "%s/%s/layout", skinDirPath, skinName);
589 D("trying to load skin file '%s'", tmp);
590
591 if(aconfig_load_file(root, tmp) < 0) {
592 dwarning("could not load skin file '%s', using built-in one\n",
593 tmp);
594 goto DEFAULT_SKIN;
595 }
596
597 snprintf(tmp, sizeof tmp, "%s/%s/", skinDirPath, skinName);
598 path = tmp;
599 goto FOUND_SKIN;
600
601FOUND_SKIN:
602 /* the default network speed and latency can now be specified by the device skin */
603 n = aconfig_find(root, "network");
604 if (n != NULL) {
605 skin_network_speed = aconfig_str(n, "speed", 0);
606 skin_network_delay = aconfig_str(n, "delay", 0);
607 }
608
609 /* extract framebuffer information from the skin.
610 *
611 * for version 1 of the skin format, they are in the top-level
612 * 'display' element.
613 *
614 * for version 2 of the skin format, they are under parts.device.display
615 */
616 n = aconfig_find(root, "display");
617 if (n == NULL) {
618 n = aconfig_find(root, "parts");
619 if (n != NULL) {
620 n = aconfig_find(n, "device");
621 if (n != NULL) {
622 n = aconfig_find(n, "display");
623 }
624 }
625 }
626
627 if (n != NULL) {
628 int width = aconfig_int(n, "width", hwConfig->hw_lcd_width);
629 int height = aconfig_int(n, "height", hwConfig->hw_lcd_height);
630 int depth = aconfig_int(n, "bpp", hwConfig->hw_lcd_depth);
631
632 if (width > 0 && height > 0) {
633 /* The emulated framebuffer wants sizes that are multiples of 4 */
634 if (((width|height) & 3) != 0) {
635 width = (width+3) & ~3;
636 height = (height+3) & ~3;
637 D("adjusting LCD dimensions to (%dx%dx)", width, height);
638 }
639
640 /* only depth values of 16 and 32 are correct. 16 is the default. */
641 if (depth != 32 && depth != 16) {
642 depth = 16;
643 D("adjusting LCD bit depth to %d", depth);
644 }
645
646 hwConfig->hw_lcd_width = width;
647 hwConfig->hw_lcd_height = height;
648 hwConfig->hw_lcd_depth = depth;
649 }
650 else {
651 D("ignoring invalid skin LCD dimensions (%dx%dx%d)",
652 width, height, depth);
653 }
654 }
655
656 *skinConfig = root;
657 *skinPath = strdup(path);
658 return;
659
660DEFAULT_SKIN:
661 {
662 const unsigned char* layout_base;
663 size_t layout_size;
664 char* base;
665
666 skinName = "<builtin>";
667
668 layout_base = android_resource_find( "layout", &layout_size );
669 if (layout_base == NULL) {
670 fprintf(stderr, "Couldn't load builtin skin\n");
671 exit(1);
672 }
673 base = malloc( layout_size+1 );
674 memcpy( base, layout_base, layout_size );
675 base[layout_size] = 0;
676
677 D("parsing built-in skin layout file (%d bytes)", (int)layout_size);
678 aconfig_load(root, base);
679 path = ":";
680 }
681 goto FOUND_SKIN;
682}
683
684
685void
686init_sdl_ui(AConfig* skinConfig,
687 const char* skinPath,
688 AndroidOptions* opts)
689{
690 int win_x, win_y, flags;
691
692 signal(SIGINT, SIG_DFL);
693#ifndef _WIN32
694 signal(SIGQUIT, SIG_DFL);
695#endif
696
697 /* we're not a game, so allow the screensaver to run */
698 setenv("SDL_VIDEO_ALLOW_SCREENSAVER","1",1);
699
700 flags = SDL_INIT_NOPARACHUTE;
701 if (!opts->no_window)
702 flags |= SDL_INIT_VIDEO;
703
704 if(SDL_Init(flags)){
705 fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() );
706 exit(1);
707 }
708
709 if (!opts->no_window) {
710 SDL_EnableUNICODE(!opts->raw_keys);
711 SDL_EnableKeyRepeat(0,0);
712
713 sdl_set_window_icon();
714 }
715 else
716 {
717#ifndef _WIN32
718 /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be
719 * able to run the emulator in the background (e.g. "emulator &").
720 * despite the fact that the emulator should not grab input or try to
721 * write to the output in normal cases, we're stopped on some systems
722 * (e.g. OS X)
723 */
724 signal(SIGTTIN, SIG_IGN);
725 signal(SIGTTOU, SIG_IGN);
726#endif
727 }
728 atexit(sdl_at_exit);
729
730 user_config_get_window_pos(&win_x, &win_y);
731
732 if ( qemulator_init(qemulator_get(), skinConfig, skinPath, win_x, win_y, opts) < 0 ) {
733 fprintf(stderr, "### Error: could not load emulator skin from '%s'\n", skinPath);
734 exit(1);
735 }
736
737 /* add an onion overlay image if needed */
738 if (opts->onion) {
739 SkinImage* onion = skin_image_find_simple( opts->onion );
740 int alpha, rotate;
741
742 if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) {
743 alpha = (256*alpha)/100;
744 } else
745 alpha = 128;
746
747 if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) {
748 rotate &= 3;
749 } else
750 rotate = SKIN_ROTATION_0;
751
752 qemulator_get()->onion = onion;
753 qemulator_get()->onion_alpha = alpha;
754 qemulator_get()->onion_rotation = rotate;
755 }
756}