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