Home | History | Annotate | Download | only in skin
      1 /* Copyright (C) 2007-2008 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 "android/skin/file.h"
     13 #include "android/utils/path.h"
     14 #include "android/charmap.h"
     15 #include "android/utils/bufprint.h"
     16 #include "android/utils/system.h"
     17 #include "android/utils/debug.h"
     18 
     19 //#include "qemu-common.h"
     20 
     21 /** UTILITY ROUTINES
     22  **/
     23 static SkinImage*
     24 skin_image_find_in( const char*  dirname, const char*  filename )
     25 {
     26     char   buffer[1024];
     27     char*  p   = buffer;
     28     char*  end = p + sizeof(buffer);
     29 
     30     p = bufprint( p, end, "%s" PATH_SEP "%s", dirname, filename );
     31     if (p >= end)
     32         return SKIN_IMAGE_NONE;
     33 
     34     return skin_image_find_simple(buffer);
     35 }
     36 
     37 /** SKIN BACKGROUND
     38  **/
     39 
     40 static void
     41 skin_background_done( SkinBackground*  background )
     42 {
     43     if (background->image)
     44         skin_image_unref(&background->image);
     45 }
     46 
     47 static int
     48 skin_background_init_from( SkinBackground*  background,
     49                            AConfig*         node,
     50                            const char*      basepath )
     51 {
     52     const char* img = aconfig_str(node, "image", NULL);
     53     int         x   = aconfig_int(node, "x", 0);
     54     int         y   = aconfig_int(node, "y", 0);
     55 
     56     background->valid = 0;
     57 
     58     if (img == NULL)   /* no background */
     59         return -1;
     60 
     61     background->image = skin_image_find_in( basepath, img );
     62     if (background->image == SKIN_IMAGE_NONE) {
     63         background->image = NULL;
     64         return -1;
     65     }
     66 
     67     background->rect.pos.x  = x;
     68     background->rect.pos.y  = y;
     69     background->rect.size.w = skin_image_w( background->image );
     70     background->rect.size.h = skin_image_h( background->image );
     71 
     72     background->valid = 1;
     73 
     74     return 0;
     75 }
     76 
     77 /** SKIN DISPLAY
     78  **/
     79 
     80 static void
     81 skin_display_done( SkinDisplay*  display )
     82 {
     83     qframebuffer_done( display->qfbuff );
     84 }
     85 
     86 static int
     87 skin_display_init_from( SkinDisplay*  display, AConfig*  node )
     88 {
     89     display->rect.pos.x  = aconfig_int(node, "x", 0);
     90     display->rect.pos.y  = aconfig_int(node, "y", 0);
     91     display->rect.size.w = aconfig_int(node, "width", 0);
     92     display->rect.size.h = aconfig_int(node, "height", 0);
     93     display->rotation    = aconfig_unsigned(node, "rotation", SKIN_ROTATION_0);
     94 
     95     display->valid = ( display->rect.size.w > 0 && display->rect.size.h > 0 );
     96 
     97     if (display->valid) {
     98         SkinRect  r;
     99         skin_rect_rotate( &r, &display->rect, -display->rotation );
    100         qframebuffer_init( display->qfbuff,
    101                            r.size.w,
    102                            r.size.h,
    103                            0,
    104                            QFRAME_BUFFER_RGB565 );
    105 
    106         qframebuffer_fifo_add( display->qfbuff );
    107     }
    108     return display->valid ? 0 : -1;
    109 }
    110 
    111 /** SKIN BUTTON
    112  **/
    113 
    114 typedef struct
    115 {
    116     const char*     name;
    117     AndroidKeyCode  code;
    118 } KeyInfo;
    119 
    120 static KeyInfo  _keyinfo_table[] = {
    121     { "dpad-up",      kKeyCodeDpadUp },
    122     { "dpad-down",    kKeyCodeDpadDown },
    123     { "dpad-left",    kKeyCodeDpadLeft },
    124     { "dpad-right",   kKeyCodeDpadRight },
    125     { "dpad-center",  kKeyCodeDpadCenter },
    126     { "soft-left",    kKeyCodeSoftLeft },
    127     { "soft-right",   kKeyCodeSoftRight },
    128     { "search",       kKeyCodeSearch },
    129     { "volume-up",    kKeyCodeVolumeUp },
    130     { "volume-down",  kKeyCodeVolumeDown },
    131     { "power",        kKeyCodePower },
    132     { "home",         kKeyCodeHome },
    133     { "back",         kKeyCodeBack },
    134     { "del",          kKeyCodeDel },
    135     { "0",            kKeyCode0 },
    136     { "1",            kKeyCode1 },
    137     { "2",            kKeyCode2 },
    138     { "3",            kKeyCode3 },
    139     { "4",            kKeyCode4 },
    140     { "5",            kKeyCode5 },
    141     { "6",            kKeyCode6 },
    142     { "7",            kKeyCode7 },
    143     { "8",            kKeyCode8 },
    144     { "9",            kKeyCode9 },
    145     { "star",         kKeyCodeStar },
    146     { "pound",        kKeyCodePound },
    147     { "phone-dial",   kKeyCodeCall },
    148     { "phone-hangup", kKeyCodeEndCall },
    149     { "q",            kKeyCodeQ },
    150     { "w",            kKeyCodeW },
    151     { "e",            kKeyCodeE },
    152     { "r",            kKeyCodeR },
    153     { "t",            kKeyCodeT },
    154     { "y",            kKeyCodeY },
    155     { "u",            kKeyCodeU },
    156     { "i",            kKeyCodeI },
    157     { "o",            kKeyCodeO },
    158     { "p",            kKeyCodeP },
    159     { "a",            kKeyCodeA },
    160     { "s",            kKeyCodeS },
    161     { "d",            kKeyCodeD },
    162     { "f",            kKeyCodeF },
    163     { "g",            kKeyCodeG },
    164     { "h",            kKeyCodeH },
    165     { "j",            kKeyCodeJ },
    166     { "k",            kKeyCodeK },
    167     { "l",            kKeyCodeL },
    168     { "DEL",          kKeyCodeDel },
    169     { "z",            kKeyCodeZ },
    170     { "x",            kKeyCodeX },
    171     { "c",            kKeyCodeC },
    172     { "v",            kKeyCodeV },
    173     { "b",            kKeyCodeB },
    174     { "n",            kKeyCodeN },
    175     { "m",            kKeyCodeM },
    176     { "COMMA",        kKeyCodeComma },
    177     { "PERIOD",       kKeyCodePeriod },
    178     { "ENTER",        kKeyCodeNewline },
    179     { "AT",           kKeyCodeAt },
    180     { "SPACE",        kKeyCodeSpace },
    181     { "SLASH",        kKeyCodeSlash },
    182     { "CAP",          kKeyCodeCapLeft },
    183     { "SYM",          kKeyCodeSym },
    184     { "ALT",          kKeyCodeAltLeft },
    185     { "ALT2",         kKeyCodeAltRight },
    186     { "CAP2",         kKeyCodeCapRight },
    187     { 0, 0 },
    188 };
    189 
    190 static unsigned
    191 keyinfo_lookup_code(const char *name)
    192 {
    193     KeyInfo *ki = _keyinfo_table;
    194     while(ki->name) {
    195         if(!strcmp(name, ki->name))
    196             return ki->code;
    197         ki++;
    198     }
    199     return 0;
    200 }
    201 
    202 
    203 static void
    204 skin_button_free( SkinButton*  button )
    205 {
    206     if (button) {
    207         skin_image_unref( &button->image );
    208         AFREE(button);
    209     }
    210 }
    211 
    212 static SkinButton*
    213 skin_button_create_from( AConfig*   node, const char*  basepath )
    214 {
    215     SkinButton*  button;
    216     ANEW0(button);
    217     if (button) {
    218         const char*  img = aconfig_str(node, "image", NULL);
    219         int          x   = aconfig_int(node, "x", 0);
    220         int          y   = aconfig_int(node, "y", 0);
    221 
    222         button->name       = node->name;
    223         button->rect.pos.x = x;
    224         button->rect.pos.y = y;
    225 
    226         if (img != NULL)
    227             button->image = skin_image_find_in( basepath, img );
    228 
    229         if (button->image == SKIN_IMAGE_NONE) {
    230             skin_button_free(button);
    231             return NULL;
    232         }
    233 
    234         button->rect.size.w = skin_image_w( button->image );
    235         button->rect.size.h = skin_image_h( button->image );
    236 
    237         button->keycode = keyinfo_lookup_code( button->name );
    238         if (button->keycode == 0) {
    239             dprint( "Warning: skin file button uses unknown key name '%s'", button->name );
    240         }
    241     }
    242     return button;
    243 }
    244 
    245 /** SKIN PART
    246  **/
    247 
    248 static void
    249 skin_part_free( SkinPart*  part )
    250 {
    251     if (part) {
    252         skin_background_done( part->background );
    253         skin_display_done( part->display );
    254 
    255         SKIN_PART_LOOP_BUTTONS(part,button)
    256             skin_button_free(button);
    257         SKIN_PART_LOOP_END
    258         part->buttons = NULL;
    259         AFREE(part);
    260     }
    261 }
    262 
    263 static SkinLocation*
    264 skin_location_create_from_v2( AConfig*  node, SkinPart*  parts )
    265 {
    266     const char*    partname = aconfig_str(node, "name", NULL);
    267     int            x        = aconfig_int(node, "x", 0);
    268     int            y        = aconfig_int(node, "y", 0);
    269     SkinRotation   rot      = aconfig_int(node, "rotation", SKIN_ROTATION_0);
    270     SkinPart*      part;
    271     SkinLocation*  location;
    272 
    273     if (partname == NULL) {
    274         dprint( "### WARNING: ignoring part location without 'name' element" );
    275         return NULL;
    276     }
    277 
    278     for (part = parts; part; part = part->next)
    279         if (!strcmp(part->name, partname))
    280             break;
    281 
    282     if (part == NULL) {
    283         dprint( "### WARNING: ignoring part location with unknown name '%s'", partname );
    284         return NULL;
    285     }
    286 
    287     ANEW0(location);
    288     location->part     = part;
    289     location->anchor.x = x;
    290     location->anchor.y = y;
    291     location->rotation = rot;
    292 
    293     return location;
    294 }
    295 
    296 static SkinPart*
    297 skin_part_create_from_v1( AConfig*  root, const char*  basepath )
    298 {
    299     SkinPart*  part;
    300     AConfig*  node;
    301     SkinBox   box;
    302 
    303     ANEW0(part);
    304     part->name = root->name;
    305 
    306     node = aconfig_find(root, "background");
    307     if (node)
    308         skin_background_init_from(part->background, node, basepath);
    309 
    310     node = aconfig_find(root, "display");
    311     if (node)
    312         skin_display_init_from(part->display, node);
    313 
    314     node = aconfig_find(root, "button");
    315     if (node) {
    316         for (node = node->first_child; node != NULL; node = node->next)
    317         {
    318             SkinButton*  button = skin_button_create_from(node, basepath);
    319 
    320             if (button != NULL) {
    321                 button->next  = part->buttons;
    322                 part->buttons = button;
    323             }
    324         }
    325     }
    326 
    327     skin_box_minmax_init( &box );
    328 
    329     if (part->background->valid)
    330         skin_box_minmax_update( &box, &part->background->rect );
    331 
    332     if (part->display->valid)
    333         skin_box_minmax_update( &box, &part->display->rect );
    334 
    335     SKIN_PART_LOOP_BUTTONS(part, button)
    336         skin_box_minmax_update( &box, &button->rect );
    337     SKIN_PART_LOOP_END
    338 
    339     if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) {
    340         skin_part_free(part);
    341         part = NULL;
    342     }
    343 
    344     return part;
    345 }
    346 
    347 static SkinPart*
    348 skin_part_create_from_v2( AConfig*  root, const char*  basepath )
    349 {
    350     SkinPart*  part;
    351     AConfig*  node;
    352     SkinBox   box;
    353 
    354     ANEW0(part);
    355     part->name = root->name;
    356 
    357     node = aconfig_find(root, "background");
    358     if (node)
    359         skin_background_init_from(part->background, node, basepath);
    360 
    361     node = aconfig_find(root, "display");
    362     if (node)
    363         skin_display_init_from(part->display, node);
    364 
    365     node = aconfig_find(root, "buttons");
    366     if (node) {
    367         for (node = node->first_child; node != NULL; node = node->next)
    368         {
    369             SkinButton*  button = skin_button_create_from(node, basepath);
    370 
    371             if (button != NULL) {
    372                 button->next  = part->buttons;
    373                 part->buttons = button;
    374             }
    375         }
    376     }
    377 
    378     skin_box_minmax_init( &box );
    379 
    380     if (part->background->valid)
    381         skin_box_minmax_update( &box, &part->background->rect );
    382 
    383     if (part->display->valid)
    384         skin_box_minmax_update( &box, &part->display->rect );
    385 
    386     SKIN_PART_LOOP_BUTTONS(part, button)
    387         skin_box_minmax_update( &box, &button->rect );
    388     SKIN_PART_LOOP_END
    389 
    390     if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) {
    391         skin_part_free(part);
    392         part = NULL;
    393     }
    394     return part;
    395 }
    396 
    397 /** SKIN LAYOUT
    398  **/
    399 
    400 static void
    401 skin_layout_free( SkinLayout*  layout )
    402 {
    403     if (layout) {
    404         SKIN_LAYOUT_LOOP_LOCS(layout,loc)
    405             AFREE(loc);
    406         SKIN_LAYOUT_LOOP_END
    407         layout->locations = NULL;
    408         AFREE(layout);
    409     }
    410 }
    411 
    412 SkinDisplay*
    413 skin_layout_get_display( SkinLayout*  layout )
    414 {
    415     SKIN_LAYOUT_LOOP_LOCS(layout,loc)
    416         SkinPart*  part = loc->part;
    417         if (part->display->valid) {
    418             return part->display;
    419         }
    420     SKIN_LAYOUT_LOOP_END
    421     return NULL;
    422 }
    423 
    424 SkinRotation
    425 skin_layout_get_dpad_rotation( SkinLayout*  layout )
    426 {
    427     if (layout->has_dpad_rotation)
    428         return layout->dpad_rotation;
    429 
    430     SKIN_LAYOUT_LOOP_LOCS(layout, loc)
    431         SkinPart*  part = loc->part;
    432         SKIN_PART_LOOP_BUTTONS(part,button)
    433             if (button->keycode == kKeyCodeDpadUp)
    434                 return loc->rotation;
    435         SKIN_PART_LOOP_END
    436     SKIN_LAYOUT_LOOP_END
    437 
    438     return SKIN_ROTATION_0;
    439 }
    440 
    441 
    442 static int
    443 skin_layout_event_decode( const char*  event, int  *ptype, int  *pcode, int *pvalue )
    444 {
    445     typedef struct {
    446         const char*  name;
    447         int          value;
    448     } EventName;
    449 
    450     static const EventName  _event_names[] = {
    451         { "EV_SW", 0x05 },
    452         { NULL, 0 },
    453     };
    454 
    455     const char*       x = strchr(event, ':');
    456     const char*       y = NULL;
    457     const EventName*  ev = _event_names;
    458 
    459     if (x != NULL)
    460         y = strchr(x+1, ':');
    461 
    462     if (x == NULL || y == NULL) {
    463         dprint( "### WARNING: invalid skin layout event format: '%s', should be '<TYPE>:<CODE>:<VALUE>'", event );
    464         return -1;
    465     }
    466 
    467     for ( ; ev->name != NULL; ev++ )
    468         if (!memcmp( event, ev->name, x - event ) && ev->name[x-event] == 0)
    469             break;
    470 
    471     if (!ev->name) {
    472         dprint( "### WARNING: unrecognized skin layout event name: %.*s", x-event, event );
    473         return -1;
    474     }
    475 
    476     *ptype  = ev->value;
    477     *pcode  = strtol(x+1, NULL, 0);
    478     *pvalue = strtol(y+1, NULL, 0);
    479     return 0;
    480 }
    481 
    482 static SkinLayout*
    483 skin_layout_create_from_v2( AConfig*  root, SkinPart*  parts )
    484 {
    485     SkinLayout*    layout;
    486     int            width, height;
    487     SkinLocation** ptail;
    488     AConfig*       node;
    489 
    490     ANEW0(layout);
    491 
    492     width  = aconfig_int( root, "width", 400 );
    493     height = aconfig_int( root, "height", 400 );
    494 
    495     node = aconfig_find( root, "event" );
    496     if (node != NULL) {
    497         skin_layout_event_decode( node->value,
    498                                   &layout->event_type,
    499                                   &layout->event_code,
    500                                   &layout->event_value );
    501     } else {
    502         layout->event_type  = 0x05;  /* close keyboard by default */
    503         layout->event_code  = 0;
    504         layout->event_value = 1;
    505     }
    506 
    507     layout->name  = root->name;
    508     layout->color = aconfig_unsigned( root, "color", 0x808080 ) | 0xff000000;
    509     ptail         = &layout->locations;
    510 
    511     node = aconfig_find( root, "dpad-rotation" );
    512     if (node != NULL) {
    513         layout->dpad_rotation     = aconfig_int( root, "dpad-rotation", 0 );
    514         layout->has_dpad_rotation = 1;
    515     }
    516 
    517     for (node = root->first_child; node; node = node->next)
    518     {
    519         if (!memcmp(node->name, "part", 4)) {
    520             SkinLocation*  location = skin_location_create_from_v2( node, parts );
    521             if (location == NULL) {
    522                 continue;
    523             }
    524             *ptail = location;
    525             ptail  = &location->next;
    526         }
    527     }
    528 
    529     if (layout->locations == NULL)
    530         goto Fail;
    531 
    532     layout->size.w = width;
    533     layout->size.h = height;
    534 
    535     return layout;
    536 
    537 Fail:
    538     skin_layout_free(layout);
    539     return NULL;
    540 }
    541 
    542 /** SKIN FILE
    543  **/
    544 
    545 static int
    546 skin_file_load_from_v1( SkinFile*  file, AConfig*  aconfig, const char*  basepath )
    547 {
    548     SkinPart*      part;
    549     SkinLayout*    layout;
    550     SkinLayout**   ptail = &file->layouts;
    551     SkinLocation*  location;
    552     int            nn;
    553 
    554     file->parts = part = skin_part_create_from_v1( aconfig, basepath );
    555     if (part == NULL)
    556         return -1;
    557 
    558     for (nn = 0; nn < 2; nn++)
    559     {
    560         ANEW0(layout);
    561 
    562         layout->color = 0xff808080;
    563 
    564         ANEW0(location);
    565 
    566         layout->event_type  = 0x05;  /* close keyboard by default */
    567         layout->event_code  = 0;
    568         layout->event_value = 1;
    569 
    570         location->part     = part;
    571         switch (nn) {
    572             case 0:
    573                 location->anchor.x = 0;
    574                 location->anchor.y = 0;
    575                 location->rotation = SKIN_ROTATION_0;
    576                 layout->size       = part->rect.size;
    577                 break;
    578 
    579 #if 0
    580             case 1:
    581                 location->anchor.x = part->rect.size.h;
    582                 location->anchor.y = 0;
    583                 location->rotation = SKIN_ROTATION_90;
    584                 layout->size.w     = part->rect.size.h;
    585                 layout->size.h     = part->rect.size.w;
    586                 layout->event_value = 0;
    587                 break;
    588 
    589             case 2:
    590                 location->anchor.x = part->rect.size.w;
    591                 location->anchor.y = part->rect.size.h;
    592                 location->rotation = SKIN_ROTATION_180;
    593                 layout->size       = part->rect.size;
    594                 break;
    595 #endif
    596             default:
    597                 location->anchor.x = 0;
    598                 location->anchor.y = part->rect.size.w;
    599                 location->rotation = SKIN_ROTATION_270;
    600                 layout->size.w     = part->rect.size.h;
    601                 layout->size.h     = part->rect.size.w;
    602                 layout->event_value = 0;
    603                 break;
    604         }
    605         layout->locations = location;
    606 
    607         *ptail = layout;
    608         ptail  = &layout->next;
    609     }
    610     return 0;
    611 }
    612 
    613 static int
    614 skin_file_load_from_v2( SkinFile*  file, AConfig*  aconfig, const char*  basepath )
    615 {
    616     AConfig*  node;
    617 
    618     /* first, load all parts */
    619     node = aconfig_find(aconfig, "parts");
    620     if (node == NULL)
    621         return -1;
    622     else
    623     {
    624         SkinPart**  ptail = &file->parts;
    625         for (node = node->first_child; node != NULL; node = node->next)
    626         {
    627             SkinPart*  part = skin_part_create_from_v2( node, basepath );
    628             if (part == NULL) {
    629                 dprint( "## WARNING: can't load part '%s' from skin\n", node->name ? "<NULL>" : node->name );
    630                 continue;
    631             }
    632             part->next = NULL;
    633             *ptail     = part;
    634             ptail      = &part->next;
    635         }
    636     }
    637 
    638     if (file->parts == NULL)
    639         return -1;
    640 
    641     /* then load all layouts */
    642     node = aconfig_find(aconfig, "layouts");
    643     if (node == NULL)
    644         return -1;
    645     else
    646     {
    647         SkinLayout**  ptail = &file->layouts;
    648         for (node = node->first_child; node != NULL; node = node->next)
    649         {
    650             SkinLayout*  layout = skin_layout_create_from_v2( node, file->parts );
    651             if (layout == NULL) {
    652                 dprint( "## WARNING: ignoring layout in skin file" );
    653                 continue;
    654             }
    655             *ptail = layout;
    656             layout->next = NULL;
    657             ptail        = &layout->next;
    658         }
    659     }
    660     if (file->layouts == NULL)
    661         return -1;
    662 
    663     return 0;
    664 }
    665 
    666 SkinFile*
    667 skin_file_create_from_aconfig( AConfig*   aconfig, const char*  basepath )
    668 {
    669     SkinFile*  file;
    670 
    671     ANEW0(file);
    672     if ( aconfig_find(aconfig, "parts") != NULL) {
    673         if (skin_file_load_from_v2( file, aconfig, basepath ) < 0) {
    674             skin_file_free( file );
    675             file = NULL;
    676         }
    677     }
    678     else {
    679         if (skin_file_load_from_v1( file, aconfig, basepath ) < 0) {
    680             skin_file_free( file );
    681             file = NULL;
    682         }
    683     }
    684     return file;
    685 }
    686 
    687 void
    688 skin_file_free( SkinFile*  file )
    689 {
    690     if (file) {
    691         SKIN_FILE_LOOP_LAYOUTS(file,layout)
    692             skin_layout_free(layout);
    693         SKIN_FILE_LOOP_END_LAYOUTS
    694         file->layouts = NULL;
    695 
    696         SKIN_FILE_LOOP_PARTS(file,part)
    697             skin_part_free(part);
    698         SKIN_FILE_LOOP_END_PARTS
    699         file->parts = NULL;
    700 
    701         AFREE(file);
    702     }
    703 }
    704