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