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