1/* 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 android_display_init(ds, qframebuffer_fifo_get()); 285} 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} 757