main-common.c revision f845627c83ce6ce3e306f9b6842d1e30ef89ae97
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#include <signal.h> 13#include <unistd.h> 14#include <string.h> 15#include <sys/time.h> 16#include <errno.h> 17#include <fcntl.h> 18#ifdef _WIN32 19#include <process.h> 20#endif 21 22#include <SDL.h> 23#include <SDL_syswm.h> 24 25#include "console.h" 26 27#include "android/utils/debug.h" 28#include "android/utils/path.h" 29#include "android/utils/bufprint.h" 30#include "android/main-common.h" 31#include "android/globals.h" 32#include "android/resource.h" 33#include "android/user-config.h" 34#include "android/qemulator.h" 35#include "android/display.h" 36#include "android/skin/image.h" 37#include "android/skin/trackball.h" 38#include "android/skin/keyboard.h" 39#include "android/skin/file.h" 40#include "android/skin/window.h" 41 42 43 44/***********************************************************************/ 45/***********************************************************************/ 46/***** *****/ 47/***** U T I L I T Y R O U T I N E S *****/ 48/***** *****/ 49/***********************************************************************/ 50/***********************************************************************/ 51 52#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0) 53 54/*** CONFIGURATION 55 ***/ 56 57static AUserConfig* userConfig; 58 59void 60emulator_config_init( void ) 61{ 62 userConfig = auserConfig_new( android_avdInfo ); 63} 64 65/* only call this function on normal exits, so that ^C doesn't save the configuration */ 66void 67emulator_config_done( void ) 68{ 69 int win_x, win_y; 70 71 if (!userConfig) { 72 D("no user configuration?"); 73 return; 74 } 75 76 SDL_WM_GetPos( &win_x, &win_y ); 77 auserConfig_setWindowPos(userConfig, win_x, win_y); 78 auserConfig_save(userConfig); 79} 80 81void 82emulator_config_get_window_pos( int *window_x, int *window_y ) 83{ 84 *window_x = *window_y = 10; 85 86 if (userConfig) 87 auserConfig_getWindowPos(userConfig, window_x, window_y); 88} 89 90unsigned convertBytesToMB( uint64_t size ) 91{ 92 if (size == 0) 93 return 0; 94 95 size = (size + ONE_MB-1) >> 20; 96 if (size > UINT_MAX) 97 size = UINT_MAX; 98 99 return (unsigned) size; 100} 101 102uint64_t convertMBToBytes( unsigned megaBytes ) 103{ 104 return ((uint64_t)megaBytes << 20); 105} 106 107 108/***********************************************************************/ 109/***********************************************************************/ 110/***** *****/ 111/***** K E Y S E T R O U T I N E S *****/ 112/***** *****/ 113/***********************************************************************/ 114/***********************************************************************/ 115 116#define KEYSET_FILE "default.keyset" 117 118SkinKeyset* android_keyset = NULL; 119 120static int 121load_keyset(const char* path) 122{ 123 if (path_can_read(path)) { 124 AConfig* root = aconfig_node("",""); 125 if (!aconfig_load_file(root, path)) { 126 android_keyset = skin_keyset_new(root); 127 if (android_keyset != NULL) { 128 D( "keyset loaded from: %s", path); 129 return 0; 130 } 131 } 132 } 133 return -1; 134} 135 136void 137parse_keyset(const char* keyset, AndroidOptions* opts) 138{ 139 char kname[MAX_PATH]; 140 char temp[MAX_PATH]; 141 char* p; 142 char* end; 143 144 /* append .keyset suffix if needed */ 145 if (strchr(keyset, '.') == NULL) { 146 p = kname; 147 end = p + sizeof(kname); 148 p = bufprint(p, end, "%s.keyset", keyset); 149 if (p >= end) { 150 derror( "keyset name too long: '%s'\n", keyset); 151 exit(1); 152 } 153 keyset = kname; 154 } 155 156 /* look for a the keyset file */ 157 p = temp; 158 end = p + sizeof(temp); 159 p = bufprint_config_file(p, end, keyset); 160 if (p < end && load_keyset(temp) == 0) 161 return; 162 163 p = temp; 164 p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->sysdir, keyset); 165 if (p < end && load_keyset(temp) == 0) 166 return; 167 168 p = temp; 169 p = bufprint_app_dir(p, end); 170 p = bufprint(p, end, PATH_SEP "keysets" PATH_SEP "%s", keyset); 171 if (p < end && load_keyset(temp) == 0) 172 return; 173 174 return; 175} 176 177void 178write_default_keyset( void ) 179{ 180 char path[MAX_PATH]; 181 182 bufprint_config_file( path, path+sizeof(path), KEYSET_FILE ); 183 184 /* only write if there is no file here */ 185 if ( !path_exists(path) ) { 186 int fd = open( path, O_WRONLY | O_CREAT, 0666 ); 187 int ret; 188 const char* ks = skin_keyset_get_default(); 189 190 191 D( "writing default keyset file to %s", path ); 192 193 if (fd < 0) { 194 D( "%s: could not create file: %s", __FUNCTION__, strerror(errno) ); 195 return; 196 } 197 CHECKED(ret, write(fd, ks, strlen(ks))); 198 close(fd); 199 } 200} 201 202 203 204/***********************************************************************/ 205/***********************************************************************/ 206/***** *****/ 207/***** S D L S U P P O R T *****/ 208/***** *****/ 209/***********************************************************************/ 210/***********************************************************************/ 211 212void *readpng(const unsigned char* base, size_t size, unsigned *_width, unsigned *_height); 213 214#ifdef CONFIG_DARWIN 215# define ANDROID_ICON_PNG "android_icon_256.png" 216#else 217# define ANDROID_ICON_PNG "android_icon_16.png" 218#endif 219 220static void 221sdl_set_window_icon( void ) 222{ 223 static int window_icon_set; 224 225 if (!window_icon_set) 226 { 227#ifdef _WIN32 228 HANDLE handle = GetModuleHandle( NULL ); 229 HICON icon = LoadIcon( handle, MAKEINTRESOURCE(1) ); 230 SDL_SysWMinfo wminfo; 231 232 SDL_GetWMInfo(&wminfo); 233 234 SetClassLong( wminfo.window, GCL_HICON, (LONG)icon ); 235#else /* !_WIN32 */ 236 unsigned icon_w, icon_h; 237 size_t icon_bytes; 238 const unsigned char* icon_data; 239 void* icon_pixels; 240 241 window_icon_set = 1; 242 243 icon_data = android_icon_find( ANDROID_ICON_PNG, &icon_bytes ); 244 if ( !icon_data ) 245 return; 246 247 icon_pixels = readpng( icon_data, icon_bytes, &icon_w, &icon_h ); 248 if ( !icon_pixels ) 249 return; 250 251 /* the data is loaded into memory as RGBA bytes by libpng. we want to manage 252 * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending 253 * on our CPU endianess 254 */ 255 { 256 unsigned* d = icon_pixels; 257 unsigned* d_end = d + icon_w*icon_h; 258 259 for ( ; d < d_end; d++ ) { 260 unsigned pix = d[0]; 261#if HOST_WORDS_BIGENDIAN 262 /* R,G,B,A read as RGBA => ARGB */ 263 pix = ((pix >> 8) & 0xffffff) | (pix << 24); 264#else 265 /* R,G,B,A read as ABGR => ARGB */ 266 pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16); 267#endif 268 d[0] = pix; 269 } 270 } 271 272 SDL_Surface* icon = sdl_surface_from_argb32( icon_pixels, icon_w, icon_h ); 273 if (icon != NULL) { 274 SDL_WM_SetIcon(icon, NULL); 275 SDL_FreeSurface(icon); 276 free( icon_pixels ); 277 } 278#endif /* !_WIN32 */ 279 } 280} 281 282/***********************************************************************/ 283/***********************************************************************/ 284/***** *****/ 285/***** S K I N S U P P O R T *****/ 286/***** *****/ 287/***********************************************************************/ 288/***********************************************************************/ 289 290const char* skin_network_speed = NULL; 291const char* skin_network_delay = NULL; 292 293 294static void sdl_at_exit(void) 295{ 296 emulator_config_done(); 297 qemulator_done(qemulator_get()); 298 SDL_Quit(); 299} 300 301 302void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) 303{ 304 QEmulator* emulator = qemulator_get(); 305 SkinDisplay* disp = skin_layout_get_display(emulator->layout); 306 int width, height; 307 char buf[128]; 308 309 if (disp->rotation & 1) { 310 width = disp->rect.size.h; 311 height = disp->rect.size.w; 312 } else { 313 width = disp->rect.size.w; 314 height = disp->rect.size.h; 315 } 316 317 snprintf(buf, sizeof buf, "width=%d,height=%d", width, height); 318 android_display_init(ds, qframebuffer_fifo_get()); 319} 320 321/* list of skin aliases */ 322static const struct { 323 const char* name; 324 const char* alias; 325} skin_aliases[] = { 326 { "QVGA-L", "320x240" }, 327 { "QVGA-P", "240x320" }, 328 { "HVGA-L", "480x320" }, 329 { "HVGA-P", "320x480" }, 330 { "QVGA", "320x240" }, 331 { "HVGA", "320x480" }, 332 { NULL, NULL } 333}; 334 335/* this is used by hw/events_device.c to send the charmap name to the system */ 336const char* android_skin_keycharmap = NULL; 337 338void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts) 339{ 340 char tmp[1024]; 341 AConfig* root; 342 AConfig* n; 343 int win_x, win_y, flags; 344 345 signal(SIGINT, SIG_DFL); 346#ifndef _WIN32 347 signal(SIGQUIT, SIG_DFL); 348#endif 349 350 /* we're not a game, so allow the screensaver to run */ 351 putenv("SDL_VIDEO_ALLOW_SCREENSAVER=1"); 352 353 flags = SDL_INIT_NOPARACHUTE; 354 if (!opts->no_window) 355 flags |= SDL_INIT_VIDEO; 356 357 if(SDL_Init(flags)){ 358 fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() ); 359 exit(1); 360 } 361 362 if (!opts->no_window) { 363 SDL_EnableUNICODE(!opts->raw_keys); 364 SDL_EnableKeyRepeat(0,0); 365 366 sdl_set_window_icon(); 367 } 368 else 369 { 370#ifndef _WIN32 371 /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be 372 * able to run the emulator in the background (e.g. "emulator &"). 373 * despite the fact that the emulator should not grab input or try to 374 * write to the output in normal cases, we're stopped on some systems 375 * (e.g. OS X) 376 */ 377 signal(SIGTTIN, SIG_IGN); 378 signal(SIGTTOU, SIG_IGN); 379#endif 380 } 381 atexit(sdl_at_exit); 382 383 root = aconfig_node("", ""); 384 385 if(name) { 386 /* Support skin aliases like QVGA-H QVGA-P, etc... 387 But first we check if it's a directory that exist before applying 388 the alias */ 389 int checkAlias = 1; 390 391 if (path != NULL) { 392 bufprint(tmp, tmp+sizeof(tmp), "%s/%s", path, name); 393 if (path_exists(tmp)) { 394 checkAlias = 0; 395 } else { 396 D("there is no '%s' skin in '%s'", name, path); 397 } 398 } 399 400 if (checkAlias) { 401 int nn; 402 403 for (nn = 0; ; nn++ ) { 404 const char* skin_name = skin_aliases[nn].name; 405 const char* skin_alias = skin_aliases[nn].alias; 406 407 if ( !skin_name ) 408 break; 409 410 if ( !strcasecmp( skin_name, name ) ) { 411 D("skin name '%s' aliased to '%s'", name, skin_alias); 412 name = skin_alias; 413 break; 414 } 415 } 416 } 417 418 /* Magically support skins like "320x240" or "320x240x16" */ 419 if(isdigit(name[0])) { 420 char *x = strchr(name, 'x'); 421 if(x && isdigit(x[1])) { 422 int width = atoi(name); 423 int height = atoi(x+1); 424 int bpp = 16; 425 char* y = strchr(x+1, 'x'); 426 if (y && isdigit(y[1])) { 427 bpp = atoi(y+1); 428 } 429 sprintf(tmp,"display {\n width %d\n height %d\n bpp %d}\n", 430 width, height,bpp); 431 aconfig_load(root, strdup(tmp)); 432 path = ":"; 433 goto found_a_skin; 434 } 435 } 436 437 if (path == NULL) { 438 derror("unknown skin name '%s'", name); 439 exit(1); 440 } 441 442 sprintf(tmp, "%s/%s/layout", path, name); 443 D("trying to load skin file '%s'", tmp); 444 445 if(aconfig_load_file(root, tmp) >= 0) { 446 sprintf(tmp, "%s/%s/", path, name); 447 path = tmp; 448 goto found_a_skin; 449 } else { 450 dwarning("could not load skin file '%s', using built-in one\n", 451 tmp); 452 } 453 } 454 455 { 456 const unsigned char* layout_base; 457 size_t layout_size; 458 459 name = "<builtin>"; 460 461 layout_base = android_resource_find( "layout", &layout_size ); 462 if (layout_base != NULL) { 463 char* base = malloc( layout_size+1 ); 464 memcpy( base, layout_base, layout_size ); 465 base[layout_size] = 0; 466 467 D("parsing built-in skin layout file (size=%d)", (int)layout_size); 468 aconfig_load(root, base); 469 path = ":"; 470 } else { 471 fprintf(stderr, "Couldn't load builtin skin\n"); 472 exit(1); 473 } 474 } 475 476found_a_skin: 477 emulator_config_get_window_pos(&win_x, &win_y); 478 479 if ( qemulator_init(qemulator_get(), root, path, win_x, win_y, opts ) < 0 ) { 480 fprintf(stderr, "### Error: could not load emulator skin '%s'\n", name); 481 exit(1); 482 } 483 484 android_skin_keycharmap = skin_keyboard_charmap_name(qemulator_get()->keyboard); 485 486 /* the default network speed and latency can now be specified by the device skin */ 487 n = aconfig_find(root, "network"); 488 if (n != NULL) { 489 skin_network_speed = aconfig_str(n, "speed", 0); 490 skin_network_delay = aconfig_str(n, "delay", 0); 491 } 492 493#if 0 494 /* create a trackball if needed */ 495 n = aconfig_find(root, "trackball"); 496 if (n != NULL) { 497 SkinTrackBallParameters params; 498 499 params.x = aconfig_unsigned(n, "x", 0); 500 params.y = aconfig_unsigned(n, "y", 0); 501 params.diameter = aconfig_unsigned(n, "diameter", 20); 502 params.ring = aconfig_unsigned(n, "ring", 1); 503 504 params.ball_color = aconfig_unsigned(n, "ball-color", 0xffe0e0e0); 505 params.dot_color = aconfig_unsigned(n, "dot-color", 0xff202020 ); 506 params.ring_color = aconfig_unsigned(n, "ring-color", 0xff000000 ); 507 508 qemu_disp->trackball = skin_trackball_create( ¶ms ); 509 skin_trackball_refresh( qemu_disp->trackball ); 510 } 511#endif 512 513 /* add an onion overlay image if needed */ 514 if (opts->onion) { 515 SkinImage* onion = skin_image_find_simple( opts->onion ); 516 int alpha, rotate; 517 518 if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) { 519 alpha = (256*alpha)/100; 520 } else 521 alpha = 128; 522 523 if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) { 524 rotate &= 3; 525 } else 526 rotate = SKIN_ROTATION_0; 527 528 qemulator_get()->onion = onion; 529 qemulator_get()->onion_alpha = alpha; 530 qemulator_get()->onion_rotation = rotate; 531 } 532} 533 534