blob: 0a58edae4fa9e1872403d310dd46b0614dd00383 [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);
284#if !defined(CONFIG_STANDALONE_UI) && !defined(CONFIG_STANDALONE_CORE)
285 android_display_init(ds, qframebuffer_fifo_get());
286#endif
287}
288
289typedef struct part_properties part_properties;
290struct part_properties {
291 const char* name;
292 int width;
293 int height;
294 part_properties* next;
295};
296
297part_properties*
298read_all_part_properties(AConfig* parts)
299{
300 part_properties* head = NULL;
301 part_properties* prev = NULL;
302
303 AConfig *node = parts->first_child;
304 while (node) {
305 part_properties* t = calloc(1, sizeof(part_properties));
306 t->name = node->name;
307
308 AConfig* bg = aconfig_find(node, "background");
309 if (bg != NULL) {
310 t->width = aconfig_int(bg, "width", 0);
311 t->height = aconfig_int(bg, "height", 0);
312 }
313
314 if (prev == NULL) {
315 head = t;
316 } else {
317 prev->next = t;
318 }
319 prev = t;
320 node = node->next;
321 }
322
323 return head;
324}
325
326void
327free_all_part_properties(part_properties* head)
328{
329 part_properties* prev = head;
330 while (head) {
331 prev = head;
332 head = head->next;
333 free(prev);
334 }
335}
336
337part_properties*
338get_part_properties(part_properties* allparts, char *partname)
339{
340 part_properties* p;
341 for (p = allparts; p != NULL; p = p->next) {
342 if (!strcmp(partname, p->name))
343 return p;
344 }
345
346 return NULL;
347}
348
349void
350add_parts_to_layout(AConfig* layout,
351 char* parts[],
352 int n_parts,
353 part_properties *props,
354 int xoffset,
355 int x_margin,
356 int y_margin)
357{
358 int i;
359 int y = 10;
360 char tmp[512];
361 for (i = 0; i < n_parts; i++) {
362 part_properties *p = get_part_properties(props, parts[i]);
363 snprintf(tmp, sizeof tmp,
364 "part%d {\n \
365 name %s\n \
366 x %d\n \
367 y %d\n \
368 }",
369 i + 2, // layout already has the device part as part1, so start from part2
370 p->name,
371 xoffset + x_margin,
372 y
373 );
374 y += p->height + y_margin;
375 aconfig_load(layout, strdup(tmp));
376 }
377}
378
379int
380load_dynamic_skin(AndroidHwConfig* hwConfig,
381 char** skinDirPath,
382 int width,
383 int height,
384 AConfig* root)
385{
386 char tmp[1024];
387 AConfig* node;
388 int i;
389 int max_part_width;
390
391 *skinDirPath = avdInfo_getDynamicSkinPath(android_avdInfo);
392 if (*skinDirPath == NULL) {
393 dwarning("Unable to locate dynamic skin directory. Will not use dynamic skin.");
394 return 0;
395 }
396
397 snprintf(tmp, sizeof(tmp), "%s/layout", *skinDirPath);
398 D("trying to load skin file '%s'", tmp);
399
400 if(aconfig_load_file(root, tmp) < 0) {
401 dwarning("could not load skin file '%s', won't use a skin\n", tmp);
402 return 0;
403 }
404
405 /* Fix the width and height specified for the "device" part in the layout */
406 node = aconfig_find(root, "parts");
407 if (node != NULL) {
408 node = aconfig_find(node, "device");
409 if (node != NULL) {
410 node = aconfig_find(node, "display");
411 if (node != NULL) {
412 snprintf(tmp, sizeof tmp, "%d", width);
413 aconfig_set(node, "width", strdup(tmp));
414 snprintf(tmp, sizeof tmp, "%d", height);
415 aconfig_set(node, "height", strdup(tmp));
416 }
417 }
418 }
419
420 /* The dynamic layout declares all the parts that are available statically
421 in the layout file. Now we need to dynamically generate the
422 appropriate layout based on the hardware config */
423
424 part_properties* props = read_all_part_properties(aconfig_find(root, "parts"));
425
426 const int N_PARTS = 4;
427 char* parts[N_PARTS];
428 parts[0] = "basic_controls";
429 parts[1] = hwConfig->hw_mainKeys ? "hwkeys_on" : "hwkeys_off";
430 parts[2] = hwConfig->hw_dPad ? "dpad_on" : "dpad_off";
431 parts[3] = hwConfig->hw_keyboard ? "keyboard_on" : "keyboard_off";
432
433 for (i = 0, max_part_width = 0; i < N_PARTS; i++) {
434 part_properties *p = get_part_properties(props, parts[i]);
435 if (p != NULL && p->width > max_part_width)
436 max_part_width = p->width;
437 }
438
439 int x_margin = 10;
440 int y_margin = 10;
441 snprintf(tmp, sizeof tmp,
442 "layouts {\n \
443 portrait {\n \
444 width %d\n \
445 height %d\n \
446 color 0x404040\n \
447 event EV_SW:0:1\n \
448 part1 {\n name device\n x 0\n y 0\n}\n \
449 }\n \
450 landscape {\n \
451 width %d\n \
452 height %d\n \
453 color 0x404040\n \
454 event EV_SW:0:0\n \
455 dpad-rotation 3\n \
456 part1 {\n name device\n x 0\n y %d\n rotation 3\n }\n \
457 }\n \
458 }\n \
459 }\n",
460 width + max_part_width + 2 * x_margin,
461 height,
462 height + max_part_width + 2 * x_margin,
463 width,
464 width);
465 aconfig_load(root, strdup(tmp));
466
467 /* Add parts to portrait orientation */
468 node = aconfig_find(root, "layouts");
469 if (node != NULL) {
470 node = aconfig_find(node, "portrait");
471 if (node != NULL) {
472 add_parts_to_layout(node, parts, N_PARTS, props, width, x_margin, y_margin);
473 }
474 }
475
476 /* Add parts to landscape orientation */
477 node = aconfig_find(root, "layouts");
478 if (node != NULL) {
479 node = aconfig_find(node, "landscape");
480 if (node != NULL) {
481 add_parts_to_layout(node, parts, N_PARTS, props, height, x_margin, y_margin);
482 }
483 }
484
485 free_all_part_properties(props);
486
487 return 1;
488}
489
490/* list of skin aliases */
491static const struct {
492 const char* name;
493 const char* alias;
494} skin_aliases[] = {
495 { "QVGA-L", "320x240" },
496 { "QVGA-P", "240x320" },
497 { "HVGA-L", "480x320" },
498 { "HVGA-P", "320x480" },
499 { "QVGA", "320x240" },
500 { "HVGA", "320x480" },
501 { NULL, NULL }
502};
503
504void
505parse_skin_files(const char* skinDirPath,
506 const char* skinName,
507 AndroidOptions* opts,
508 AndroidHwConfig* hwConfig,
509 AConfig* *skinConfig,
510 char* *skinPath)
511{
512 char tmp[1024];
513 AConfig* root;
514 const char* path = NULL;
515 AConfig* n;
516
517 root = aconfig_node("", "");
518
519 if (skinName == NULL)
520 goto DEFAULT_SKIN;
521
522 /* Support skin aliases like QVGA-H QVGA-P, etc...
523 But first we check if it's a directory that exist before applying
524 the alias */
525 int checkAlias = 1;
526
527 if (skinDirPath != NULL) {
528 bufprint(tmp, tmp+sizeof(tmp), "%s/%s", skinDirPath, skinName);
529 if (path_exists(tmp)) {
530 checkAlias = 0;
531 } else {
532 D("there is no '%s' skin in '%s'", skinName, skinDirPath);
533 }
534 }
535
536 if (checkAlias) {
537 int nn;
538
539 for (nn = 0; ; nn++ ) {
540 const char* skin_name = skin_aliases[nn].name;
541 const char* skin_alias = skin_aliases[nn].alias;
542
543 if (!skin_name)
544 break;
545
546 if (!strcasecmp( skin_name, skinName )) {
547 D("skin name '%s' aliased to '%s'", skinName, skin_alias);
548 skinName = skin_alias;
549 break;
550 }
551 }
552 }
553
554 /* Magically support skins like "320x240" or "320x240x16" */
555 if(isdigit(skinName[0])) {
556 char *x = strchr(skinName, 'x');
557 if(x && isdigit(x[1])) {
558 int width = atoi(skinName);
559 int height = atoi(x+1);
560 int bpp = 16;
561 char* y = strchr(x+1, 'x');
562 if (y && isdigit(y[1])) {
563 bpp = atoi(y+1);
564 }
565
566 if (opts->dynamic_skin) {
567 char *dynamicSkinDirPath;
568 if (load_dynamic_skin(hwConfig, &dynamicSkinDirPath, width, height, root)) {
569 path = dynamicSkinDirPath;
570 D("loaded dynamic skin width=%d height=%d bpp=%d\n", width, height, bpp);
571 goto FOUND_SKIN;
572 }
573 }
574
575 snprintf(tmp, sizeof tmp,
576 "display {\n width %d\n height %d\n bpp %d}\n",
577 width, height,bpp);
578 aconfig_load(root, strdup(tmp));
579 path = ":";
580 D("found magic skin width=%d height=%d bpp=%d\n", width, height, bpp);
581 goto FOUND_SKIN;
582 }
583 }
584
585 if (skinDirPath == NULL) {
586 derror("unknown skin name '%s'", skinName);
587 exit(1);
588 }
589
590 snprintf(tmp, sizeof tmp, "%s/%s/layout", skinDirPath, skinName);
591 D("trying to load skin file '%s'", tmp);
592
593 if(aconfig_load_file(root, tmp) < 0) {
594 dwarning("could not load skin file '%s', using built-in one\n",
595 tmp);
596 goto DEFAULT_SKIN;
597 }
598
599 snprintf(tmp, sizeof tmp, "%s/%s/", skinDirPath, skinName);
600 path = tmp;
601 goto FOUND_SKIN;
602
603FOUND_SKIN:
604 /* the default network speed and latency can now be specified by the device skin */
605 n = aconfig_find(root, "network");
606 if (n != NULL) {
607 skin_network_speed = aconfig_str(n, "speed", 0);
608 skin_network_delay = aconfig_str(n, "delay", 0);
609 }
610
611 /* extract framebuffer information from the skin.
612 *
613 * for version 1 of the skin format, they are in the top-level
614 * 'display' element.
615 *
616 * for version 2 of the skin format, they are under parts.device.display
617 */
618 n = aconfig_find(root, "display");
619 if (n == NULL) {
620 n = aconfig_find(root, "parts");
621 if (n != NULL) {
622 n = aconfig_find(n, "device");
623 if (n != NULL) {
624 n = aconfig_find(n, "display");
625 }
626 }
627 }
628
629 if (n != NULL) {
630 int width = aconfig_int(n, "width", hwConfig->hw_lcd_width);
631 int height = aconfig_int(n, "height", hwConfig->hw_lcd_height);
632 int depth = aconfig_int(n, "bpp", hwConfig->hw_lcd_depth);
633
634 if (width > 0 && height > 0) {
635 /* The emulated framebuffer wants sizes that are multiples of 4 */
636 if (((width|height) & 3) != 0) {
637 width = (width+3) & ~3;
638 height = (height+3) & ~3;
639 D("adjusting LCD dimensions to (%dx%dx)", width, height);
640 }
641
642 /* only depth values of 16 and 32 are correct. 16 is the default. */
643 if (depth != 32 && depth != 16) {
644 depth = 16;
645 D("adjusting LCD bit depth to %d", depth);
646 }
647
648 hwConfig->hw_lcd_width = width;
649 hwConfig->hw_lcd_height = height;
650 hwConfig->hw_lcd_depth = depth;
651 }
652 else {
653 D("ignoring invalid skin LCD dimensions (%dx%dx%d)",
654 width, height, depth);
655 }
656 }
657
658 *skinConfig = root;
659 *skinPath = strdup(path);
660 return;
661
662DEFAULT_SKIN:
663 {
664 const unsigned char* layout_base;
665 size_t layout_size;
666 char* base;
667
668 skinName = "<builtin>";
669
670 layout_base = android_resource_find( "layout", &layout_size );
671 if (layout_base == NULL) {
672 fprintf(stderr, "Couldn't load builtin skin\n");
673 exit(1);
674 }
675 base = malloc( layout_size+1 );
676 memcpy( base, layout_base, layout_size );
677 base[layout_size] = 0;
678
679 D("parsing built-in skin layout file (%d bytes)", (int)layout_size);
680 aconfig_load(root, base);
681 path = ":";
682 }
683 goto FOUND_SKIN;
684}
685
686
687void
688init_sdl_ui(AConfig* skinConfig,
689 const char* skinPath,
690 AndroidOptions* opts)
691{
692 int win_x, win_y, flags;
693
694 signal(SIGINT, SIG_DFL);
695#ifndef _WIN32
696 signal(SIGQUIT, SIG_DFL);
697#endif
698
699 /* we're not a game, so allow the screensaver to run */
700 setenv("SDL_VIDEO_ALLOW_SCREENSAVER","1",1);
701
702 flags = SDL_INIT_NOPARACHUTE;
703 if (!opts->no_window)
704 flags |= SDL_INIT_VIDEO;
705
706 if(SDL_Init(flags)){
707 fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() );
708 exit(1);
709 }
710
711 if (!opts->no_window) {
712 SDL_EnableUNICODE(!opts->raw_keys);
713 SDL_EnableKeyRepeat(0,0);
714
715 sdl_set_window_icon();
716 }
717 else
718 {
719#ifndef _WIN32
720 /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be
721 * able to run the emulator in the background (e.g. "emulator &").
722 * despite the fact that the emulator should not grab input or try to
723 * write to the output in normal cases, we're stopped on some systems
724 * (e.g. OS X)
725 */
726 signal(SIGTTIN, SIG_IGN);
727 signal(SIGTTOU, SIG_IGN);
728#endif
729 }
730 atexit(sdl_at_exit);
731
732 user_config_get_window_pos(&win_x, &win_y);
733
734 if ( qemulator_init(qemulator_get(), skinConfig, skinPath, win_x, win_y, opts) < 0 ) {
735 fprintf(stderr, "### Error: could not load emulator skin from '%s'\n", skinPath);
736 exit(1);
737 }
738
739 /* add an onion overlay image if needed */
740 if (opts->onion) {
741 SkinImage* onion = skin_image_find_simple( opts->onion );
742 int alpha, rotate;
743
744 if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) {
745 alpha = (256*alpha)/100;
746 } else
747 alpha = 128;
748
749 if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) {
750 rotate &= 3;
751 } else
752 rotate = SKIN_ROTATION_0;
753
754 qemulator_get()->onion = onion;
755 qemulator_get()->onion_alpha = alpha;
756 qemulator_get()->onion_rotation = rotate;
757 }
758}