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