blob: bb07943048034381dbad58402656e85153324bc3 [file] [log] [blame]
David 'Digit' Turnerf8456272011-02-02 12:34:14 +01001/* 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
David 'Digit' Turner755811e2011-02-07 13:38:25 +010060user_config_init( void )
David 'Digit' Turnerf8456272011-02-02 12:34:14 +010061{
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
David 'Digit' Turner755811e2011-02-07 13:38:25 +010067user_config_done( void )
David 'Digit' Turnerf8456272011-02-02 12:34:14 +010068{
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
David 'Digit' Turner755811e2011-02-07 13:38:25 +010082user_config_get_window_pos( int *window_x, int *window_y )
David 'Digit' Turnerf8456272011-02-02 12:34:14 +010083{
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{
David 'Digit' Turner755811e2011-02-07 13:38:25 +0100296 user_config_done();
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100297 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);
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100318#if !defined(CONFIG_STANDALONE_UI) && !defined(CONFIG_STANDALONE_CORE)
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100319 android_display_init(ds, qframebuffer_fifo_get());
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100320#endif
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100321}
322
323/* list of skin aliases */
324static const struct {
325 const char* name;
326 const char* alias;
327} skin_aliases[] = {
328 { "QVGA-L", "320x240" },
329 { "QVGA-P", "240x320" },
330 { "HVGA-L", "480x320" },
331 { "HVGA-P", "320x480" },
332 { "QVGA", "320x240" },
333 { "HVGA", "320x480" },
334 { NULL, NULL }
335};
336
337/* this is used by hw/events_device.c to send the charmap name to the system */
338const char* android_skin_keycharmap = NULL;
339
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100340void
341parse_skin_files(const char* skinDirPath,
342 const char* skinName,
343 AndroidOptions* opts,
344 AConfig* *skinConfig,
345 char* *skinPath)
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100346{
347 char tmp[1024];
348 AConfig* root;
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100349 const char* path = NULL;
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100350 AConfig* n;
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100351
352 root = aconfig_node("", "");
353
354 if (skinName == NULL)
355 goto DEFAULT_SKIN;
356
357 /* Support skin aliases like QVGA-H QVGA-P, etc...
358 But first we check if it's a directory that exist before applying
359 the alias */
360 int checkAlias = 1;
361
362 if (skinDirPath != NULL) {
363 bufprint(tmp, tmp+sizeof(tmp), "%s/%s", skinDirPath, skinName);
364 if (path_exists(tmp)) {
365 checkAlias = 0;
366 } else {
367 D("there is no '%s' skin in '%s'", skinName, skinDirPath);
368 }
369 }
370
371 if (checkAlias) {
372 int nn;
373
374 for (nn = 0; ; nn++ ) {
375 const char* skin_name = skin_aliases[nn].name;
376 const char* skin_alias = skin_aliases[nn].alias;
377
378 if (!skin_name)
379 break;
380
381 if (!strcasecmp( skin_name, skinName )) {
382 D("skin name '%s' aliased to '%s'", skinName, skin_alias);
383 skinName = skin_alias;
384 break;
385 }
386 }
387 }
388
389 /* Magically support skins like "320x240" or "320x240x16" */
390 if(isdigit(skinName[0])) {
391 char *x = strchr(skinName, 'x');
392 if(x && isdigit(x[1])) {
393 int width = atoi(skinName);
394 int height = atoi(x+1);
395 int bpp = 16;
396 char* y = strchr(x+1, 'x');
397 if (y && isdigit(y[1])) {
398 bpp = atoi(y+1);
399 }
400 snprintf(tmp, sizeof tmp,
401 "display {\n width %d\n height %d\n bpp %d}\n",
402 width, height,bpp);
403 aconfig_load(root, strdup(tmp));
404 path = ":";
405 D("found magic skin width=%d height=%d bpp=%d\n", width, height, bpp);
406 goto FOUND_SKIN;
407 }
408 }
409
410 if (skinDirPath == NULL) {
411 derror("unknown skin name '%s'", skinName);
412 exit(1);
413 }
414
415 snprintf(tmp, sizeof tmp, "%s/%s/layout", skinDirPath, skinName);
416 D("trying to load skin file '%s'", tmp);
417
418 if(aconfig_load_file(root, tmp) < 0) {
419 dwarning("could not load skin file '%s', using built-in one\n",
420 tmp);
421 goto DEFAULT_SKIN;
422 }
423
424 snprintf(tmp, sizeof tmp, "%s/%s/", skinDirPath, skinName);
425 path = tmp;
426 goto FOUND_SKIN;
427
428FOUND_SKIN:
429 /* the default network speed and latency can now be specified by the device skin */
430 n = aconfig_find(root, "network");
431 if (n != NULL) {
432 skin_network_speed = aconfig_str(n, "speed", 0);
433 skin_network_delay = aconfig_str(n, "delay", 0);
434 }
435
436 *skinConfig = root;
437 *skinPath = strdup(path);
438 return;
439
440DEFAULT_SKIN:
441 {
442 const unsigned char* layout_base;
443 size_t layout_size;
444 char* base;
445
446 skinName = "<builtin>";
447
448 layout_base = android_resource_find( "layout", &layout_size );
449 if (layout_base == NULL) {
450 fprintf(stderr, "Couldn't load builtin skin\n");
451 exit(1);
452 }
453 base = malloc( layout_size+1 );
454 memcpy( base, layout_base, layout_size );
455 base[layout_size] = 0;
456
457 D("parsing built-in skin layout file (%d bytes)", (int)layout_size);
458 aconfig_load(root, base);
459 path = ":";
460 }
461 goto FOUND_SKIN;
462}
463
464
465void
466init_sdl_ui(AConfig* skinConfig,
467 const char* skinPath,
468 AndroidOptions* opts)
469{
470 int win_x, win_y, flags;
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100471
472 signal(SIGINT, SIG_DFL);
473#ifndef _WIN32
474 signal(SIGQUIT, SIG_DFL);
475#endif
476
477 /* we're not a game, so allow the screensaver to run */
478 putenv("SDL_VIDEO_ALLOW_SCREENSAVER=1");
479
480 flags = SDL_INIT_NOPARACHUTE;
481 if (!opts->no_window)
482 flags |= SDL_INIT_VIDEO;
483
484 if(SDL_Init(flags)){
485 fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() );
486 exit(1);
487 }
488
489 if (!opts->no_window) {
490 SDL_EnableUNICODE(!opts->raw_keys);
491 SDL_EnableKeyRepeat(0,0);
492
493 sdl_set_window_icon();
494 }
495 else
496 {
497#ifndef _WIN32
498 /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be
499 * able to run the emulator in the background (e.g. "emulator &").
500 * despite the fact that the emulator should not grab input or try to
501 * write to the output in normal cases, we're stopped on some systems
502 * (e.g. OS X)
503 */
504 signal(SIGTTIN, SIG_IGN);
505 signal(SIGTTOU, SIG_IGN);
506#endif
507 }
508 atexit(sdl_at_exit);
509
David 'Digit' Turner755811e2011-02-07 13:38:25 +0100510 user_config_get_window_pos(&win_x, &win_y);
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100511
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100512 if ( qemulator_init(qemulator_get(), skinConfig, skinPath, win_x, win_y, opts) < 0 ) {
513 fprintf(stderr, "### Error: could not load emulator skin from '%s'\n", skinPath);
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100514 exit(1);
515 }
516
517 android_skin_keycharmap = skin_keyboard_charmap_name(qemulator_get()->keyboard);
518
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100519 /* add an onion overlay image if needed */
520 if (opts->onion) {
521 SkinImage* onion = skin_image_find_simple( opts->onion );
522 int alpha, rotate;
523
524 if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) {
525 alpha = (256*alpha)/100;
526 } else
527 alpha = 128;
528
529 if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) {
530 rotate &= 3;
531 } else
532 rotate = SKIN_ROTATION_0;
533
534 qemulator_get()->onion = onion;
535 qemulator_get()->onion_alpha = alpha;
536 qemulator_get()->onion_rotation = rotate;
537 }
538}
539
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100540int64_t get_screen_pixels(AConfig* skinConfig)
541{
542 int64_t pixels = 0;
543 AConfig* disp;
544
545 if (skinConfig != NULL) {
546 disp = aconfig_find(skinConfig, "display");
547 if (disp != NULL) {
548 int width = aconfig_int(disp, "width", 0);
549 int height = aconfig_int(disp, "height", 0);
550 pixels = (int64_t)width*height;
551 }
552 }
553 if (pixels == 0)
554 pixels = 320*240;
555
556 return pixels;
557}