view gui/skin/skin.c @ 32958:80087dd00035

Fix some debug messages. Avoid debug code if debugging isn't asked for and don't use debug messages in such a way with control structures that there may be compiler warnings.
author ib
date Tue, 08 Mar 2011 09:57:04 +0000
parents c11e65fcb818
children 4905f5a87357
line wrap: on
line source

/*
 * This file is part of MPlayer.
 *
 * MPlayer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * MPlayer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <stdio.h>
#include <string.h>

#include "skin.h"
#include "cut.h"
#include "font.h"
#include "gui/app.h"
#include "gui/mplayer/widgets.h"

#include "config.h"
#include "help_mp.h"
#include "libavutil/avstring.h"
#include "libavutil/common.h"
#include "mp_msg.h"

typedef struct {
    const char *name;
    int (*func)(char *in);
} _item;

static guiItems *skin;

static int linenumber;
static unsigned char path[512];
static unsigned char window_name[32];

static wItem *currSection;
static int *currSubItem;
static wItem *currSubItems;

static void ERRORMESSAGE(const char *format, ...)
{
    char p[512];
    char tmp[512];
    va_list ap;

    va_start(ap, format);
    vsnprintf(p, sizeof(p), format, ap);
    va_end(ap);

    mp_msg(MSGT_GPLAYER, MSGL_ERR, MSGTR_SKIN_ERRORMESSAGE, linenumber, p);

    if (mp_msg_test(MSGT_GPLAYER, MSGL_ERR)) {
        snprintf(tmp, sizeof(tmp), MSGTR_SKIN_ERRORMESSAGE, linenumber, p);
        gtkMessageBox(GTK_MB_FATAL, tmp);
    }
}

#define CHECKDEFLIST(str) \
    { \
        if (skin == NULL) \
        { \
            ERRORMESSAGE(MSGTR_SKIN_ERROR_SECTION, str); \
            return 1; \
        } \
    }

#define CHECKWINLIST(str) \
    { \
        if (!window_name[0]) \
        { \
            ERRORMESSAGE(MSGTR_SKIN_ERROR_WINDOW, str); \
            return 1; \
        } \
    }

#define CHECK(name) \
    { \
        if (!strcmp(window_name, name)) \
        { \
            ERRORMESSAGE(MSGTR_SKIN_ERROR_IN_WINDOW, name); \
            return 1; \
        } \
    }

static char *strlower(char *in)
{
    char *p = in;

    while (*p) {
        if (*p >= 'A' && *p <= 'Z')
            *p += 'a' - 'A';

        p++;
    }

    return in;
}

int skinBPRead(char *fname, txSample *bf)
{
    int i = bpRead(fname, bf);

    switch (i) {
    case -1:
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_16bit, fname);
        break;

    case -2:
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_FileNotFound, fname);
        break;

    case -3:
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_BMPReadError, fname);
        break;

    case -4:
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_TGAReadError, fname);
        break;

    case -5:
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_PNGReadError, fname);
        break;

    case -6:
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_RLENotSupported, fname);
        break;

    case -7:
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_UnknownFileType, fname);
        break;

    case -8:
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_ConversionError, fname);
        break;
    }

    return i;
}

// section=movieplayer
static int cmd_section(char *in)
{
    strlower(in);
    skin = NULL;

    if (!strcmp(in, "movieplayer"))
        skin = &appMPlayer;

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]  section: %s\n", in);

    return 0;
}

// end
static int cmd_end(char *in)
{
#ifdef MP_DEBUG
    char *space, *name;

    if (window_name[0]) {
        space = " ";
        name  = window_name;
    } else {
        space = "";
        name  = "section";
    }
#endif

    (void)in;

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]  %send (%s)\n", space, name);

    if (strlen(window_name)) {
        window_name[0] = 0;
        currSection    = NULL;
        currSubItem    = NULL;
        currSubItems   = NULL;
    } else
        skin = NULL;

    return 0;
}

// window=main|sub|playbar|menu
static int cmd_window(char *in)
{
    CHECKDEFLIST("window");

    av_strlcpy(window_name, strlower(in), sizeof(window_name));

    if (!strncmp(in, "main", 4)) {
        currSection  = &appMPlayer.main;
        currSubItem  = &appMPlayer.IndexOfMainItems;
        currSubItems = appMPlayer.mainItems;
    } else if (!strncmp(in, "sub", 3))
        currSection = &appMPlayer.sub;
    else if (!strncmp(in, "playbar", 7)) {
        currSection  = &appMPlayer.bar;
        currSubItem  = &appMPlayer.IndexOfBarItems;
        currSubItems = appMPlayer.barItems;
    } else if (!strncmp(in, "menu", 4)) {
        currSection  = &appMPlayer.menuBase;
        currSubItem  = &appMPlayer.IndexOfMenuItems;
        currSubItems = appMPlayer.menuItems;
    } else
        ERRORMESSAGE(MSGTR_UNKNOWNWINDOWTYPE);

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]   window: %s\n", window_name);

    return 0;
}

// base=image,x,y[,width,height]
static int cmd_base(char *in)
{
    unsigned char fname[512];
    unsigned char tmp[512];
    int x, y;
    int sx = 0, sy = 0;

    CHECKDEFLIST("base");
    CHECKWINLIST("base");

    cutItem(in, fname, ',', 0);
    x  = cutItemToInt(in, ',', 1);
    y  = cutItemToInt(in, ',', 2);
    sx = cutItemToInt(in, ',', 3);
    sy = cutItemToInt(in, ',', 4);

    if (!strcmp(window_name, "main")) {
        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    image: %s %d,%d\n", fname, x, y);

        skin->main.x    = x;
        skin->main.y    = y;
        skin->main.type = itBase;

        av_strlcpy(tmp, path, sizeof(tmp));
        av_strlcat(tmp, fname, sizeof(tmp));

        if (skinBPRead(tmp, &skin->main.Bitmap) != 0)
            return 1;

        skin->main.width  = skin->main.Bitmap.Width;
        skin->main.height = skin->main.Bitmap.Height;

        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     bitmap: %dx%d\n", skin->main.width, skin->main.height);

#ifdef CONFIG_XSHAPE
        Convert32to1(&skin->main.Bitmap, &skin->main.Mask, 0x00ff00ff);
        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     mask: %lux%lu\n", skin->main.Mask.Width, skin->main.Mask.Height);
#else
        skin->main.Mask.Image = NULL;
#endif
    }

    if (!strcmp(window_name, "sub")) {
        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    image: %s %d,%d\n", fname, x, y);

        skin->sub.type = itBase;

        av_strlcpy(tmp, path, sizeof(tmp));
        av_strlcat(tmp, fname, sizeof(tmp));

        if (skinBPRead(tmp, &skin->sub.Bitmap) != 0)
            return 1;

        skin->sub.x      = x;
        skin->sub.y      = y;
        skin->sub.width  = skin->sub.Bitmap.Width;
        skin->sub.height = skin->sub.Bitmap.Height;

        if (sx && sy) {
            skin->sub.width  = sx;
            skin->sub.height = sy;
        }

        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     bitmap: %dx%d\n", skin->sub.width, skin->sub.height);
    }

    if (!strcmp(window_name, "menu")) {
        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    image: %s\n", fname);

        skin->menuIsPresent = 1;
        skin->menuBase.type = itBase;

        av_strlcpy(tmp, path, sizeof(tmp));
        av_strlcat(tmp, fname, sizeof(tmp));

        if (skinBPRead(tmp, &skin->menuBase.Bitmap) != 0)
            return 1;

        skin->menuBase.width  = skin->menuBase.Bitmap.Width;
        skin->menuBase.height = skin->menuBase.Bitmap.Height;

        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     bitmap: %dx%d\n", skin->menuBase.width, skin->menuBase.height);

#ifdef CONFIG_XSHAPE
        Convert32to1(&skin->menuBase.Bitmap, &skin->menuBase.Mask, 0x00ff00ff);
        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     mask: %lux%lu\n", skin->menuBase.Mask.Width, skin->menuBase.Mask.Height);
#else
        skin->menuBase.Mask.Image = NULL;
#endif
    }

    if (!strcmp(window_name, "playbar")) {
        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    image: %s %d,%d\n", fname, x, y);

        skin->barIsPresent = 1;
        skin->bar.x    = x;
        skin->bar.y    = y;
        skin->bar.type = itBase;

        av_strlcpy(tmp, path, sizeof(tmp));
        av_strlcat(tmp, fname, sizeof(tmp));

        if (skinBPRead(tmp, &skin->bar.Bitmap) != 0)
            return 1;

        skin->bar.width  = skin->bar.Bitmap.Width;
        skin->bar.height = skin->bar.Bitmap.Height;

        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     bitmap: %dx%d\n", skin->bar.width, skin->bar.height);

#ifdef CONFIG_XSHAPE
        Convert32to1(&skin->bar.Bitmap, &skin->bar.Mask, 0x00ff00ff);
        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     mask: %lux%lu\n", skin->bar.Mask.Width, skin->bar.Mask.Height);
#else
        skin->bar.Mask.Image = NULL;
#endif
    }

    return 0;
}

// background=R,G,B
static int cmd_background(char *in)
{
    CHECKDEFLIST("background");
    CHECKWINLIST("background");

    CHECK("menu");
    CHECK("main");

    currSection->R = cutItemToInt(in, ',', 0);
    currSection->G = cutItemToInt(in, ',', 1);
    currSection->B = cutItemToInt(in, ',', 2);

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    background color: #%02x%02x%02x\n", currSection->R, currSection->G, currSection->B);

    return 0;
}

// button=image,x,y,width,height,message
static int cmd_button(char *in)
{
    unsigned char fname[512];
    unsigned char tmp[512];
    int x, y, sx, sy;
    char msg[32];

    CHECKDEFLIST("button");
    CHECKWINLIST("button");

    CHECK("sub");
    CHECK("menu");

    cutItem(in, fname, ',', 0);
    x  = cutItemToInt(in, ',', 1);
    y  = cutItemToInt(in, ',', 2);
    sx = cutItemToInt(in, ',', 3);
    sy = cutItemToInt(in, ',', 4);
    cutItem(in, msg, ',', 5);

    (*currSubItem)++;
    currSubItems[*currSubItem].type   = itButton;
    currSubItems[*currSubItem].x      = x;
    currSubItems[*currSubItem].y      = y;
    currSubItems[*currSubItem].width  = sx;
    currSubItems[*currSubItem].height = sy;

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    button image: %s %d,%d\n", fname, x, y);

    if ((currSubItems[*currSubItem].message = appFindMessage(msg)) == -1) {
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_UnknownMessage, msg);
        return 0;
    }

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     message: %s (#%d)\n", msg, currSubItems[*currSubItem].message);
    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     size: %dx%d\n", sx, sy);

    currSubItems[*currSubItem].pressed = btnReleased;

    if (currSubItems[*currSubItem].message == evPauseSwitchToPlay)
        currSubItems[*currSubItem].pressed = btnDisabled;

    currSubItems[*currSubItem].tmp = 1;

    currSubItems[*currSubItem].Bitmap.Image = NULL;

    if (strcmp(fname, "NULL") != 0) {
        av_strlcpy(tmp, path, sizeof(tmp));
        av_strlcat(tmp, fname, sizeof(tmp));

        if (skinBPRead(tmp, &currSubItems[*currSubItem].Bitmap) != 0)
            return 1;

        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     (bitmap: %lux%lu)\n", currSubItems[*currSubItem].Bitmap.Width, currSubItems[*currSubItem].Bitmap.Height);
    }

    return 0;
}

// selected=image
static int cmd_selected(char *in)
{
    unsigned char fname[512];
    unsigned char tmp[512];

    CHECKDEFLIST("selected");
    CHECKWINLIST("selected");

    CHECK("main");
    CHECK("sub");
    CHECK("playbar");

    cutItem(in, fname, ',', 0);

    skin->menuSelected.type = itBase;

    av_strlcpy(tmp, path, sizeof(tmp));
    av_strlcat(tmp, fname, sizeof(tmp));

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    image selected: %s\n", fname);

    if (skinBPRead(tmp, &skin->menuSelected.Bitmap) != 0)
        return 1;

    skin->menuSelected.width  = skin->menuSelected.Bitmap.Width;
    skin->menuSelected.height = skin->menuSelected.Bitmap.Height;

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     bitmap: %dx%d\n", skin->menuSelected.width, skin->menuSelected.height);

    return 0;
}

// menu=x,y,width,height,message
static int cmd_menu(char *in)
{
    int x, y, sx, sy, message;
    unsigned char tmp[64];

    CHECKDEFLIST("menu");
    CHECKWINLIST("menu");

    CHECK("main");
    CHECK("sub");
    CHECK("playbar");

    x  = cutItemToInt(in, ',', 0);
    y  = cutItemToInt(in, ',', 1);
    sx = cutItemToInt(in, ',', 2);
    sy = cutItemToInt(in, ',', 3);
    cutItem(in, tmp, ',', 4);

    message = appFindMessage(tmp);

    skin->IndexOfMenuItems++;
    skin->menuItems[skin->IndexOfMenuItems].x      = x;
    skin->menuItems[skin->IndexOfMenuItems].y      = y;
    skin->menuItems[skin->IndexOfMenuItems].width  = sx;
    skin->menuItems[skin->IndexOfMenuItems].height = sy;

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    item #%d: %d,%d %dx%d\n", skin->IndexOfMenuItems, x, y, sx, sy);

    if ((skin->menuItems[skin->IndexOfMenuItems].message = message) == -1)
        ERRORMESSAGE(MSGTR_SKIN_BITMAP_UnknownMessage, tmp);

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     message: %s (#%d)\n", tmp, skin->menuItems[skin->IndexOfMenuItems].message);

    skin->menuItems[skin->IndexOfMenuItems].Bitmap.Image = NULL;
    return 0;
}

// hpotmeter=button,bwidth,bheight,phases,numphases,default,x,y,width,height,message
static int cmd_hpotmeter(char *in)
{
    int x, y, pwidth, pheight, ph, sx, sy, message, d;
    unsigned char tmp[512];
    unsigned char pfname[512];
    unsigned char phfname[512];
    wItem *item;

    CHECKDEFLIST("hpotmeter");
    CHECKWINLIST("hpotmeter");

    CHECK("sub");
    CHECK("menu");

    cutItem(in, pfname, ',', 0);
    pwidth  = cutItemToInt(in, ',', 1);
    pheight = cutItemToInt(in, ',', 2);
    cutItem(in, phfname, ',', 3);
    ph = cutItemToInt(in, ',', 4);
    d  = cutItemToInt(in, ',', 5);
    x  = cutItemToInt(in, ',', 6);
    y  = cutItemToInt(in, ',', 7);
    sx = cutItemToInt(in, ',', 8);
    sy = cutItemToInt(in, ',', 9);
    cutItem(in, tmp, ',', 10);

    message = appFindMessage(tmp);

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    h/v potmeter image: %s %d,%d %dx%d\n", phfname, x, y, sx, sy);
    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     button image: %s %dx%d\n", pfname, pwidth, pheight);
    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     numphases: %d, default: %d%%\n", ph, d);
    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     message: %s (#%d)\n", tmp, message);

    (*currSubItem)++;
    item               = &currSubItems[*currSubItem];
    item->type         = itHPotmeter;
    item->x            = x;
    item->y            = y;
    item->width        = sx;
    item->height       = sy;
    item->numphases    = ph;
    item->pwidth       = pwidth;
    item->pheight      = pheight;
    item->message      = message;
    item->value        = (float)d;
    item->pressed      = btnReleased;
    item->Bitmap.Image = NULL;

    if (strcmp(phfname, "NULL") != 0) {
        av_strlcpy(tmp, path, sizeof(tmp));
        av_strlcat(tmp, phfname, sizeof(tmp));

        if (skinBPRead(tmp, &item->Bitmap) != 0)
            return 1;

        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     (potmeter bitmap: %lux%lu)\n", item->Bitmap.Width, item->Bitmap.Height);
    }

    item->Mask.Image = NULL;

    if (strcmp(pfname, "NULL") != 0) {
        av_strlcpy(tmp, path, sizeof(tmp));
        av_strlcat(tmp, pfname, sizeof(tmp));

        if (skinBPRead(tmp, &item->Mask) != 0)
            return 1;

        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     (button bitmap: %lux%lu)\n", item->Mask.Width, item->Mask.Height);
    }

    return 0;
}

// vpotmeter=button,bwidth,bheight,phases,numphases,default,x,y,width,height,message
static int cmd_vpotmeter(char *in)
{
    int r = cmd_hpotmeter(in);
    wItem *item;

    item       = &currSubItems[*currSubItem];
    item->type = itVPotmeter;
    return r;
}

// potmeter=phases,numphases,default,x,y,width,height,message
static int cmd_potmeter(char *in)
{
    int x, y, ph, sx, sy, message, d;
    unsigned char tmp[512];
    unsigned char phfname[512];
    wItem *item;

    CHECKDEFLIST("potmeter");
    CHECKWINLIST("potmeter");

    CHECK("sub");
    CHECK("menu");

    cutItem(in, phfname, ',', 0);
    ph = cutItemToInt(in, ',', 1);
    d  = cutItemToInt(in, ',', 2);
    x  = cutItemToInt(in, ',', 3);
    y  = cutItemToInt(in, ',', 4);
    sx = cutItemToInt(in, ',', 5);
    sy = cutItemToInt(in, ',', 6);
    cutItem(in, tmp, ',', 7);

    message = appFindMessage(tmp);

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    potmeter image: %s %d,%d %dx%d\n", phfname, x, y, sx, sy);
    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     numphases: %d, default: %d%%\n", ph, d);
    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     message: %s (#%d)\n", tmp, message);

    (*currSubItem)++;
    item               = &currSubItems[*currSubItem];
    item->type         = itPotmeter;
    item->x            = x;
    item->y            = y;
    item->width        = sx;
    item->height       = sy;
    item->numphases    = ph;
    item->message      = message;
    item->value        = (float)d;
    item->Bitmap.Image = NULL;

    if (strcmp(phfname, "NULL") != 0) {
        av_strlcpy(tmp, path, sizeof(tmp));
        av_strlcat(tmp, phfname, sizeof(tmp));

        if (skinBPRead(tmp, &item->Bitmap) != 0)
            return 1;

        mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     (bitmap: %lux%lu)\n", item->Bitmap.Width, item->Bitmap.Height);
    }

    return 0;
}

// font=fontfile
static int cmd_font(char *in)
{
    char name[512];
    wItem *item;

    CHECKDEFLIST("font");
    CHECKWINLIST("font");

    CHECK("sub");
    CHECK("menu");

    cutItem(in, name, ',', 0);

    (*currSubItem)++;
    item         = &currSubItems[*currSubItem];
    item->type   = itFont;
    item->fontid = fntRead(path, name);

    switch (item->fontid) {
    case -1:
        ERRORMESSAGE(MSGTR_SKIN_FONT_NotEnoughtMemory);
        return 1;

    case -2:
        ERRORMESSAGE(MSGTR_SKIN_FONT_TooManyFontsDeclared);
        return 1;

    case -3:
        ERRORMESSAGE(MSGTR_SKIN_FONT_FontFileNotFound);
        return 1;

    case -4:
        ERRORMESSAGE(MSGTR_SKIN_FONT_FontImageNotFound);
        return 1;
    }

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    font: %s (#%d)\n", name, fntFindID(name));

    return 0;
}

// slabel=x,y,fontfile,"text"
static int cmd_slabel(char *in)
{
    char tmp[512];
    char sid[64];
    int x, y, id;
    wItem *item;

    CHECKDEFLIST("slabel");
    CHECKWINLIST("slabel");

    CHECK("sub");
    CHECK("menu");

    x = cutItemToInt(in, ',', 0);
    y = cutItemToInt(in, ',', 1);
    cutItem(in, sid, ',', 2);
    cutItem(in, tmp, ',', 3);
    cutItem(tmp, tmp, '"', 1);

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    slabel: \"%s\"\n", tmp);
    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     pos: %d,%d\n", x, y);

    id = fntFindID(sid);

    if (id < 0) {
        ERRORMESSAGE(MSGTR_SKIN_FONT_NonExistentFontID, sid);
        return 1;
    }

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     font: %s (#%d)\n", sid, id);

    (*currSubItem)++;
    item         = &currSubItems[*currSubItem];
    item->type   = itSLabel;
    item->fontid = id;
    item->x      = x;
    item->y      = y;
    item->width  = -1;
    item->height = -1;

    if ((item->label = malloc(strlen(tmp) + 1)) == NULL) {
        ERRORMESSAGE(MSGTR_SKIN_FONT_NotEnoughtMemory);
        return 1;
    }

    strcpy(item->label, tmp);

    return 0;
}

// dlabel=x,y,width,align,fontfile,"text"
static int cmd_dlabel(char *in)
{
    char tmp[512];
    char sid[64];
    int x, y, sx, id, a;
    wItem *item;

    CHECKDEFLIST("dlabel");
    CHECKWINLIST("dlabel");

    CHECK("sub");
    CHECK("menu");

    x  = cutItemToInt(in, ',', 0);
    y  = cutItemToInt(in, ',', 1);
    sx = cutItemToInt(in, ',', 2);
    a  = cutItemToInt(in, ',', 3);
    cutItem(in, sid, ',', 4);
    cutItem(in, tmp, ',', 5);
    cutItem(tmp, tmp, '"', 1);

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    dlabel: \"%s\"\n", tmp);
    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     pos: %d,%d\n", x, y);
    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     width: %d, align: %d\n", sx, a);

    id = fntFindID(sid);

    if (id < 0) {
        ERRORMESSAGE(MSGTR_SKIN_FONT_NonExistentFontID, sid);
        return 1;
    }

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]     font: %s (#%d)\n", sid, id);

    (*currSubItem)++;
    item         = &currSubItems[*currSubItem];
    item->type   = itDLabel;
    item->fontid = id;
    item->align  = a;
    item->x      = x;
    item->y      = y;
    item->width  = sx;
    item->height = -1;

    if ((item->label = malloc(strlen(tmp) + 1)) == NULL) {
        ERRORMESSAGE(MSGTR_SKIN_FONT_NotEnoughtMemory);
        return 1;
    }

    strcpy(item->label, tmp);

    return 0;
}

// decoration=enable|disable
static int cmd_decoration(char *in)
{
    char tmp[512];

    CHECKDEFLIST("decoration");
    CHECKWINLIST("decoration");

    CHECK("sub");
    CHECK("menu");
    CHECK("playbar");

    strlower(in);
    cutItem(in, tmp, ',', 0);

    if (strcmp(tmp, "enable") != 0 && strcmp(tmp, "disable") != 0) {
        ERRORMESSAGE(MSGTR_SKIN_UnknownParameter, tmp);
        return 1;
    }

    if (strcmp(tmp, "enable") != 0)
        skin->mainDecoration = 0;
    else
        skin->mainDecoration = 1;

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin]    decoration: %s\n", tmp);

    return 0;
}

static _item skinItem[] = {
    { "section",    cmd_section    },
    { "end",        cmd_end        },
    { "window",     cmd_window     },
    { "base",       cmd_base       },
    { "button",     cmd_button     },
    { "selected",   cmd_selected   },
    { "background", cmd_background },
    { "vpotmeter",  cmd_vpotmeter  },
    { "hpotmeter",  cmd_hpotmeter  },
    { "potmeter",   cmd_potmeter   },
    { "font",       cmd_font       },
    { "slabel",     cmd_slabel     },
    { "dlabel",     cmd_dlabel     },
    { "decoration", cmd_decoration },
    { "menu",       cmd_menu       }
};

char *strswap(char *in, char what, char whereof)
{
    int i;

    if (strlen(in) == 0)
        return NULL;

    for (i = 0; i < (int)strlen(in); i++)
        if (in[i] == what)
            in[i] = whereof;

    return in;
}

char *trim(char *in)
{
    int c = 0, id = 0, i;

    if (strlen(in) == 0)
        return NULL;

    while (c != (int)strlen(in)) {
        if (in[c] == '"')
            id = !id;

        if ((in[c] == ' ') && (!id)) {
            for (i = 0; i < (int)strlen(in) - c; i++)
                in[c + i] = in[c + i + 1];
            continue;
        }

        c++;
    }

    return in;
}

static char *setname(char *item1, char *item2)
{
    static char fn[512];

    av_strlcpy(fn, item1, sizeof(fn));
    av_strlcat(fn, "/", sizeof(fn));
    av_strlcat(fn, item2, sizeof(fn));
    av_strlcpy(path, fn, sizeof(path));
    av_strlcat(path, "/", sizeof(path));
    av_strlcat(fn, "/skin", sizeof(fn));

    return fn;
}

int skinRead(char *dname)
{
    char *fn;
    FILE *skinFile;
    unsigned char tmp[256];
    unsigned char *ptmp;
    unsigned char command[32];
    unsigned char param[256];
    unsigned int i;

    fn = setname(skinDirInHome, dname);

    if ((skinFile = fopen(fn, "rt")) == NULL) {
        fn = setname(skinMPlayerDir, dname);

        if ((skinFile = fopen(fn, "rt")) == NULL) {
            mp_msg(MSGT_GPLAYER, MSGL_ERR, MSGTR_SKIN_SkinFileNotFound, fn);
            return -1;
        }
    }

    mp_dbg(MSGT_GPLAYER, MSGL_DBG2, "[skin] configuration file: %s\n", fn);

    appFreeStruct();

    linenumber = 0;

    while (fgets(tmp, sizeof(tmp), skinFile)) {
        linenumber++;

        tmp[strcspn(tmp, "\n\r")] = 0; // remove any kind of newline, if any
        strswap(tmp, '\t', ' ');
        trim(tmp);
        ptmp = strchr(tmp, ';');

        if (ptmp)
            *ptmp = 0;

        if (!*tmp)
            continue;

        cutItem(tmp, command, '=', 0);
        cutItem(tmp, param, '=', 1);
        strlower(command);

        for (i = 0; i < FF_ARRAY_ELEMS(skinItem); i++)
            if (!strcmp(command, skinItem[i].name))
                if (skinItem[i].func(param) != 0)
                    return -2;
    }

    if (linenumber == 0) {
        mp_msg(MSGT_GPLAYER, MSGL_ERR, MSGTR_SKIN_SkinFileNotReadable, fn);
        return -1;
    }

    return 0;
}