g15mpd

I try to rewrite g15mpd to be more usefull.I've downloaded latest version from svn and add some features. But not all:
1) How can I output non-english (i.e. russian) symbols to G15 screen?
2) Progress indicator didn't update
3) I want to change volume on mpd by Ctrl+Wheel.

There is my g15mpd.c file now (all code is only in this file):

/*<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include </p>
<p>#include<br />
#include<br />
#include<br />
#include<br />
#include </p>
<p>#include </p>
<p>extern int debug_level;<br />
int g15screen_fd, retval;<br />
g15canvas *canvas;<br />
int current_fg_check=0;<br />
static int playing;<br />
static int paused=0;<br />
static int quickscroll = 0;</p>
<p>MpdObj *obj = NULL;</p>
<p>int leaving = 0;<br />
static int voltimeout=0;<br />
static int own_keyboard=0;</p>
<p>pthread_mutex_t daemon_mutex;<br />
pthread_mutex_t lockit;</p>
<p>int mmedia_fd; </p>
<p>static int menulevel=0;<br />
#define MENU_MODE1 0<br />
#define MENU_MODE2 1<br />
#define MAX_MENU_MODES 2<br />
/* playlist mode takes over all keys on the keyboard - allowing searches/playlist scroll via volume ctrl etc.<br />
all non-valid keys are sent elsewhere via the xtest extension */<br />
static int playlist_mode=0;<br />
int playlist_selection=0;<br />
int item_selected=0;<br />
int volume_adjust=0;<br />
int mute=0;<br />
int muted_volume=0;</p>
<p>struct track_info {<br />
    char artist[100];<br />
    char title[100];<br />
    char album[100];<br />
    char date[4];<br />
    int total;<br />
    int elapsed;<br />
    int volume;<br />
    int repeat;<br />
    int random;<br />
    int playstate;<br />
    int totalsongs_in_playlist;<br />
    int currentsong;<br />
} track_info;<br />
char albumstring[105];</p>
<p>void error_callback(MpdObj *mi,int errorid, char *msg, void *userdata)<br />
{<br />
} </p>
<p>void *Lkeys_thread() {<br />
    int keystate = 0;<br />
    int volume;<br />
    struct pollfd fds;<br />
    char ver[5];</p>
<p>    strncpy(ver,G15DAEMON_VERSION,3);<br />
    float g15v;<br />
    sscanf(ver,"%f",&g15v);</p>
<p>    fds.fd = g15screen_fd;<br />
    fds.events = POLLIN;</p>
<p>    while(!leaving){<br />
        int foo=0;<br />
        current_fg_check = g15_send_cmd (g15screen_fd, G15DAEMON_IS_FOREGROUND, foo);<br />
        static int last_fg_check = 0;<br />
        if(playlist_mode && last_fg_check != current_fg_check){<br />
            if(own_keyboard){<br />
                if(current_fg_check==0){<br />
                    own_keyboard=0;<br />
                }<br />
            }else if(current_fg_check && !own_keyboard) {<br />
                own_keyboard=1;<br />
            }<br />
            last_fg_check = current_fg_check;<br />
        }</p>
<p>        /* g15daemon series 1.2 need key request packets */<br />
        pthread_mutex_lock(&daemon_mutex);<br />
        if((g15v*10)<=18) {<br />
            keystate = g15_send_cmd (g15screen_fd, G15DAEMON_GET_KEYSTATE, foo);<br />
        } else {<br />
            if ((poll(&fds, 1, 5)) > 0)<br />
                read (g15screen_fd, &keystate, sizeof (keystate));<br />
        }<br />
        pthread_mutex_unlock(&daemon_mutex);</p>
<p>        if (keystate)<br />
        {<br />
            switch (keystate)<br />
            {<br />
                case G15_KEY_L1:<br />
                    exit(1); // FIXME quick hack to exit<br />
                    break;<br />
                case G15_KEY_L2:<br />
                    menulevel++;<br />
                    if(menulevel>=MAX_MENU_MODES)<br />
                        menulevel=0;<br />
                    break;<br />
                case G15_KEY_L3:<br />
                    if(!own_keyboard){<br />
                        own_keyboard=playlist_mode=1;<br />
                        mpd_Song *song = mpd_playlist_get_current_song(obj);<br />
                        if(song)<br />
                            if(song->pos)<br />
                                track_info.currentsong=song->pos;<br />
                    }else{ //de-activate<br />
                        own_keyboard=playlist_mode=0;<br />
                    }<br />
                    break;<br />
                case G15_KEY_L4:<br />
                    if(menulevel==MENU_MODE1){<br />
                        mpd_player_set_random(obj,mpd_player_get_random(obj)^1);<br />
                    }<br />
                    if(menulevel==MENU_MODE2){<br />
                        volume=mpd_status_get_volume(obj);<br />
                        if(volume>0)<br />
                            volume-=5;<br />
                        mpd_status_set_volume (obj,volume);<br />
                    }<br />
                    break;<br />
                case G15_KEY_L5:<br />
                    if(menulevel==MENU_MODE1){<br />
                        mpd_player_set_repeat(obj, mpd_player_get_repeat(obj)^1);<br />
                    }<br />
                    if(menulevel==MENU_MODE2){<br />
                        volume=mpd_status_get_volume(obj);<br />
                        if(volume<100)<br />
                            volume+=5;<br />
                        mpd_status_set_volume (obj,volume);<br />
                    }<br />
                    break;<br />
                default:<br />
                    break;<br />
            }<br />
            keystate = 0;<br />
        }<br />
        usleep(100*1000);<br />
    }<br />
    return NULL;<br />
}</p>
<p>void *event_key_thread() {</p>
<p>    struct input_event *event;<br />
    event=malloc(sizeof(struct input_event));<br />
    struct pollfd fds;</p>
<p>    int retval;<br />
    while(!leaving) {</p>
<p>        event->value=0;<br />
        event->code=0;<br />
        fds.fd=mmedia_fd;<br />
        fds.events=POLLIN;</p>
<p>        if(poll(&fds,1,500)<1)<br />
            continue;</p>
<p>        retval=read(mmedia_fd,event,sizeof(struct input_event));</p>
<p>        if(event->value==0||current_fg_check==0)<br />
            continue;</p>
<p>        int keycode = event->code;<br />
        int code_audio_play = KEY_PLAYPAUSE;<br />
        int code_audio_stop = KEY_STOPCD;<br />
        int code_audio_next = KEY_NEXTSONG;<br />
        int code_audio_prev = KEY_PREVIOUSSONG;<br />
        int code_audio_raisevol = KEY_VOLUMEUP;<br />
        int code_audio_lowervol = KEY_VOLUMEDOWN;<br />
        int code_audio_mute = KEY_MUTE;</p>
<p>        /*     printf("keycode = %d\n", keycode); */</p>
<p>        if(keycode == code_audio_play) {<br />
            if(playing && !playlist_mode) {<br />
                if (paused==1)  {<br />
                    mpd_player_play(obj);<br />
                    paused = 0;<br />
                } else {<br />
                    mpd_player_pause(obj);<br />
                    paused = 1;</p>
<p>                }</p>
<p>            } else {<br />
                mpd_player_play(obj);<br />
                playing = 1;<br />
            }<br />
            if(playlist_mode){<br />
                mpd_player_play_id(obj, item_selected);<br />
            }<br />
        }</p>
<p>        if(keycode == code_audio_stop) {<br />
            mpd_player_stop(obj);<br />
            playing = 0;<br />
            continue;<br />
        }</p>
<p>        if(keycode == code_audio_next) {<br />
          if(playlist_mode)<br />
            playlist_selection+=1;<br />
          else<br />
            mpd_player_next(obj);<br />
          continue;<br />
        }</p>
<p>        if(keycode == code_audio_prev) {<br />
          if(playlist_mode)<br />
            playlist_selection-=1;<br />
          else<br />
            mpd_player_prev(obj);<br />
          continue;<br />
        }</p>
<p>        if(keycode == code_audio_raisevol){<br />
          if(playlist_mode && quickscroll)<br />
            playlist_selection+=1;<br />
        /*  else {<br />
            pthread_mutex_lock(&daemon_mutex);<br />
            volume_adjust+=1;<br />
            pthread_mutex_unlock(&daemon_mutex);<br />
            continue;<br />
          }*/<br />
        }<br />
        if(keycode == code_audio_lowervol){<br />
          if(playlist_mode && quickscroll)<br />
            playlist_selection-=1;<br />
          /*else {<br />
            pthread_mutex_lock(&daemon_mutex);<br />
            volume_adjust-=1;<br />
            pthread_mutex_unlock(&daemon_mutex);<br />
            continue;<br />
          }*/<br />
        }</p>
<p>        if(keycode == code_audio_mute){<br />
            pthread_mutex_lock(&daemon_mutex);<br />
            mute = 1;<br />
            pthread_mutex_unlock(&daemon_mutex);<br />
            continue;<br />
        }</p>
<p>        /* now the default stuff */<br />
        if(own_keyboard) {<br />
            menulevel=MENU_MODE1;<br />
            continue;<br />
        }<br />
    }<br />
    free(event);<br />
    return NULL;<br />
}</p>
<p>/* take the track_info structure and render it */<br />
void *g15display_thread(){<br />
    long chksum=0;<br />
    static long last_chksum;<br />
    int i;<br />
    unsigned char time_elapsed[41];<br />
    unsigned char time_total[41];<br />
    static int current = 0;<br />
    int changed =0;<br />
    while(!leaving){<br />
        if(playlist_mode){</p>
<p>            int y=0;<br />
            int offset=2;<br />
            changed = 0;</p>
<p>            if(track_info.currentsong>-1){<br />
                current=track_info.currentsong;<br />
                track_info.currentsong = -1;<br />
                changed = 1;<br />
            }</p>
<p>            if(playlist_selection>0){<br />
                if(current+1title!=NULL)<br />
                            strncpy(title,song->title,99);<br />
                        else<br />
                            strncpy(title,"",99);<br />
                        if(song->artist!=NULL){<br />
                            strncat(title," - ",99);<br />
                            strncat(title,song->artist,99);<br />
                        }<br />
                    }<br />
                    /* sanitise the display */<br />
                    if(i==mpd_playlist_get_playlist_length(obj))<br />
                        strncpy(title,"End of PlayList",99);<br />
                    if(i>mpd_playlist_get_playlist_length(obj))<br />
                        break;<br />
                    if(i<0)<br />
                        strncpy(title,"",99);</p>
<p>                    if(y==offset){<br />
                        g15r_pixelBox (canvas, 0, 7*offset, 159 , 7*(offset+1), G15_COLOR_BLACK, 1, 1);<br />
                        canvas->mode_xor=1;<br />
                        if(song)<br />
                            if(song->id)<br />
                                item_selected=song->id;<br />
                    }<br />
                    g15r_renderString (canvas, (unsigned char *)title, y, G15_TEXT_SMALL, 1, 1);<br />
                    canvas->mode_xor=0;<br />
                    y++;<br />
                }<br />
            }<br />
        }else{<br />
            /* track info */<br />
            g15r_pixelBox (canvas, 0, 0, 159, 42, G15_COLOR_WHITE, 1, 1);<br />
            g15r_renderString (canvas, (unsigned char *)track_info.title, 0, G15_TEXT_LARGE, 80-(strlen(track_info.title)*8)/2, 0);<br />
            g15r_renderString (canvas, (unsigned char *)track_info.artist, 0, G15_TEXT_MED, 80-(strlen(track_info.artist)*5)/2, 9);<br />
	    g15r_renderString (canvas, (unsigned char *)track_info.album, 0, G15_TEXT_MED, 80-(strlen(track_info.album)*5)/2, 16);</p>
<p>            /* elapsed time */<br />
            memset(time_elapsed,0,41);<br />
            memset(time_total,0,41);<br />
            if (track_info.total != 0) {<br />
                snprintf((char*)time_elapsed,40,"%02i:%02i",track_info.elapsed/60, track_info.elapsed%60);<br />
                snprintf((char*)time_total,40,"%02i:%02i",track_info.total/60, track_info.total%60);<br />
            }<br />
            if(track_info.elapsed>0&&track_info.total>0)<br />
                g15r_drawBar (canvas, 24, 26, 135, 30, G15_COLOR_BLACK, track_info.elapsed, track_info.total, 1);<br />
            canvas->mode_xor=1;<br />
            g15r_renderString (canvas,(unsigned char*)time_elapsed,0,G15_TEXT_SMALL,0,26);<br />
            g15r_renderString (canvas,(unsigned char*)time_total,0,G15_TEXT_SMALL,137,26);<br />
            canvas->mode_xor=0;</p>
<p>            switch(track_info.playstate)<br />
            {<br />
                case MPD_PLAYER_PLAY:<br />
                    playing=1;<br />
                    paused=0;<br />
                    break;<br />
                case MPD_PLAYER_PAUSE:<br />
                    //g15r_pixelBox (canvas, 0, 22, 159, 30, G15_COLOR_WHITE, 1, 1);<br />
                    //g15r_renderString (canvas, (unsigned char *)"Playback Paused", 0, G15_TEXT_LARGE, 22, 23);<br />
                    paused=1;<br />
                    break;<br />
                case MPD_PLAYER_STOP:<br />
                    g15r_pixelBox (canvas, 0, 22, 159, 30, G15_COLOR_WHITE, 1, 1);<br />
                    g15r_renderString (canvas, (unsigned char *)"Playback Stopped", 0, G15_TEXT_LARGE, 18, 24);<br />
                    playing=0;<br />
                    paused=0;<br />
                    break;<br />
                default:<br />
                    break;<br />
            }</p>
<p>            g15r_pixelBox (canvas, 0, 34, 159, 41, G15_COLOR_WHITE, 1, 1);<br />
            g15r_pixelBox (canvas, 0, 34, 16, 42, G15_COLOR_BLACK, 1, 1);<br />
            canvas->mode_xor=1;<br />
            g15r_renderString (canvas, (unsigned char *)"Mode", 0, G15_TEXT_SMALL, 1, 36);<br />
            canvas->mode_xor=0;</p>
<p>            if(menulevel==MENU_MODE1){<br />
                if(track_info.random){<br />
                    canvas->mode_xor=1;<br />
                    g15r_pixelBox (canvas, 105, 34, 131, 42, G15_COLOR_BLACK, 1, 1);<br />
                }else{<br />
                    g15r_pixelBox (canvas, 105, 34, 131, 42, G15_COLOR_BLACK, 1, 0);<br />
                }<br />
                g15r_renderString (canvas, (unsigned char *)"Random", 0, G15_TEXT_SMALL, 107, 36);<br />
                canvas->mode_xor=0;</p>
<p>                if(track_info.repeat){<br />
                    canvas->mode_xor=1;<br />
                    g15r_pixelBox (canvas, 133, 34, 159, 42, G15_COLOR_BLACK, 1, 1);<br />
                }else {<br />
                    g15r_pixelBox (canvas, 133, 34, 159, 42, G15_COLOR_BLACK, 1, 0);<br />
                }</p>
<p>                g15r_renderString (canvas, (unsigned char *)"Repeat", 0, G15_TEXT_SMALL, 135, 36);<br />
                canvas->mode_xor=0;</p>
<p>                        // 2nd box from left - if you want it...<br />
                //g15r_pixelBox (canvas, 34, 34, 54 , 42, G15_COLOR_BLACK, 1, 0);<br />
                //g15r_renderString (canvas, (unsigned char *)"test", 0, G15_TEXT_SMALL, 36, 36);</p>
<p>                if(playlist_mode==0){<br />
                    g15r_pixelBox (canvas, 18, 34, 54 , 42, G15_COLOR_BLACK, 1, 0);<br />
                    g15r_renderString (canvas, (unsigned char *)"Playlist", 0, G15_TEXT_SMALL, 20, 36);<br />
                }else{<br />
                    canvas->mode_xor=1;<br />
                    g15r_pixelBox (canvas, 18, 34, 54 , 42, G15_COLOR_BLACK, 1, 1);<br />
                    g15r_renderString (canvas, (unsigned char *)"Playlist", 0, G15_TEXT_SMALL, 20, 36);<br />
                    canvas->mode_xor=0;<br />
                }<br />
            }</p>
<p>            if(menulevel==MENU_MODE2){<br />
                g15r_pixelBox (canvas, 106, 34, 132 , 42, G15_COLOR_BLACK, 1, 0);<br />
                g15r_renderString (canvas, (unsigned char *)"Vol-", 0, G15_TEXT_SMALL, 112, 36);</p>
<p>                g15r_pixelBox (canvas, 134, 34, 159 , 42, G15_COLOR_BLACK, 1, 0);<br />
                g15r_renderString (canvas, (unsigned char *)"Vol+", 0, G15_TEXT_SMALL, 140, 36);</p>
<p>            if(muted_volume != 0){<br />
                g15r_drawBar (canvas, 0, 26, 160, 30, G15_COLOR_WHITE, 100, 100, 1);<br />
                g15r_renderString (canvas, (unsigned char *)"MUTE", 0, G15_TEXT_LARGE, 60, 24);<br />
            }<br />
            else if(voltimeout){<br />
                g15r_pixelBox (canvas, 0, 26, 160 , 30, G15_COLOR_WHITE, 1, 1);<br />
                g15r_drawBar (canvas, 24, 26, 135, 30, G15_COLOR_BLACK, track_info.volume, 100, 1);<br />
                canvas->mode_xor=1;<br />
                g15r_renderString (canvas,(unsigned char*)"Vol -",0,G15_TEXT_SMALL,2,26);<br />
                g15r_renderString (canvas,(unsigned char*)"Vol +",0,G15_TEXT_SMALL,141,26);<br />
                canvas->mode_xor=0;<br />
            }<br />
	    }<br />
        }</p>
<p>        /* do a quicky checksum - only send frame if different */<br />
        chksum=0;<br />
        for(i=0;ibuffer[i]*i;<br />
        }<br />
        pthread_mutex_lock(&daemon_mutex);<br />
        if(last_chksum!=chksum) {<br />
            while(g15_send(g15screen_fd,(char *)canvas->buffer,G15_BUFFER_LEN)<0 && !leaving) {<br />
                perror("lost connection, tryng again\n");<br />
                usleep(10000);<br />
                /* connection error occurred - try to reconnect to the daemon */<br />
                g15screen_fd=new_g15_screen(G15_G15RBUF);<br />
            }<br />
        }<br />
        pthread_mutex_unlock(&daemon_mutex);<br />
        last_chksum=chksum;<br />
        usleep(75*1000);<br />
        if(playlist_mode)<br />
            usleep(75*1000);</p>
<p>    }<br />
    return NULL;<br />
}</p>
<p>void status_changed(MpdObj *mi, ChangedStatusType what)<br />
{<br />
    pthread_mutex_lock(&lockit);</p>
<p>    mpd_Song *song = mpd_playlist_get_current_song(mi);<br />
    //printf (song->date);<br />
    if(song) {<br />
        if (song->artist!=NULL) {<br />
            strncpy(track_info.artist,song->artist,99);<br />
        } else {<br />
            track_info.artist[0] = 0;<br />
        }<br />
        if (song->title!=NULL) {<br />
            strncpy(track_info.title,song->title,99);<br />
        } else {<br />
            track_info.title[0] = 0;<br />
        }<br />
	if (song->album!=NULL) {<br />
            strncpy(track_info.album,song->album,99);<br />
        } else {<br />
            track_info.album[0] = 0;<br />
        }<br />
	/*if (song->album!=NULL) {<br />
            if (song->date!=NULL) {<br />
               strncpy(track_info.album,song->date,99);<br />
               strncat(track_info.album," ",99);<br />
               strncat(track_info.album,song->album,99);<br />
            } else {<br />
                 strncpy(track_info.album,song->date,99);}<br />
        } else {<br />
            track_info.album[0] = 0;}*/<br />
    }</p>
<p>    if(what&MPD_CST_CROSSFADE){<br />
        // printf(GREEN"X-Fade:"RESET" %i sec.\n",mpd_status_get_crossfade(mi));<br />
    }</p>
<p>    if(what&MPD_CST_PLAYLIST)<br />
    {<br />
        // printf(GREEN"Playlist changed"RESET"\n");<br />
        track_info.totalsongs_in_playlist = mpd_playlist_get_playlist_length(mi);</p>
<p>    }</p>
<p>    if(what&MPD_CST_ELAPSED_TIME && !voltimeout){<br />
        track_info.elapsed = mpd_status_get_elapsed_song_time(mi);<br />
        track_info.total = mpd_status_get_total_song_time(mi);<br />
    }</p>
<p>    if(what&MPD_CST_VOLUME){<br />
        voltimeout=500;<br />
        track_info.volume = mpd_status_get_volume(mi);<br />
    }</p>
<p>    if(what&MPD_CST_STATE) {<br />
        track_info.playstate = mpd_player_get_state(mi);<br />
    }</p>
<p>    track_info.repeat = mpd_player_get_repeat(obj);<br />
    track_info.random = mpd_player_get_random(obj);</p>
<p>    pthread_mutex_unlock(&lockit);<br />
    usleep(10*1000);<br />
}</p>
<p>int main(int argc, char **argv)<br />
{<br />
    int fdstdin = 0;<br />
    pthread_t Lkeys;<br />
    pthread_t g15display;<br />
    pthread_t EKeys;<br />
    int volume;<br />
    int volume_new;<br />
    char devname[256] = "Unknown";<br />
    int iport = 6600;<br />
    char *hostname = getenv("MPD_HOST");<br />
    char *port = getenv("MPD_PORT");<br />
    char *password = getenv("MPD_PASSWORD");<br />
    int eventdev;<br />
    char evdev_name[128];<br />
    pthread_mutex_init(&lockit,NULL);<br />
    pthread_mutex_init(&daemon_mutex,NULL);<br />
    int i;</p>
<p>    for (i=0;ibuffer, 0, G15_BUFFER_LEN);<br />
        canvas->mode_cache = 0;<br />
        canvas->mode_reverse = 0;<br />
        canvas->mode_xor = 0;<br />
    }</p>
<p>    /* Create mpd object */<br />
    obj = mpd_new(hostname, iport,password);<br />
    /* Connect signals */<br />
    mpd_signal_connect_error(obj,(ErrorCallback)error_callback, NULL);<br />
    mpd_signal_connect_status_changed(obj,(StatusChangedCallback)status_changed, NULL);<br />
    /* Set timeout */<br />
    mpd_set_connection_timeout(obj, 10);</p>
<p>    if(0==mpd_connect(obj))<br />
    {<br />
        char buffer[20];<br />
        pthread_attr_t attr;</p>
<p>        mpd_send_password(obj);<br />
        memset(buffer, '\0', 20);<br />
        pthread_attr_init(&attr);<br />
        pthread_attr_setstacksize(&attr,32*1024); /* set stack to 64k - dont need 8Mb !! */</p>
<p>        pthread_create(&Lkeys, &attr, Lkeys_thread, NULL);<br />
        pthread_create(&EKeys, &attr,event_key_thread, NULL);<br />
        pthread_create(&g15display, &attr, g15display_thread, NULL);</p>
<p>        do{<br />
            pthread_mutex_lock(&daemon_mutex);<br />
            if(mute){<br />
                volume_adjust = 0;<br />
                mute = 0;<br />
                if (muted_volume == 0) {<br />
                    //printf("mute\n");<br />
                    muted_volume = mpd_status_get_volume(obj);<br />
                    mpd_status_set_volume (obj,0);<br />
                } else {<br />
                    //printf("unmute\n");<br />
                    if (mpd_status_get_volume(obj) == 0) { /* if no other client has set volume up */<br />
                        mpd_status_set_volume (obj,muted_volume);<br />
                    }<br />
                    muted_volume = 0;<br />
                }<br />
            }<br />
            if(volume_adjust != 0){<br />
                if (muted_volume != 0) {<br />
                    volume=muted_volume;<br />
                } else {<br />
                    volume=mpd_status_get_volume(obj);<br />
                }<br />
                volume_new = volume + volume_adjust;<br />
                volume_adjust = 0;<br />
                if(volume_new < 0)<br />
                    volume_new = 0;<br />
                if(volume_new > 100)<br />
                    volume_new = 100;<br />
                if(volume != volume_new || muted_volume){<br />
                    //printf("volume %d -> %d\n", volume, volume_new);<br />
                    mpd_status_set_volume (obj,volume_new);<br />
                }<br />
                voltimeout=200;<br />
                muted_volume=0;<br />
            }<br />
            mpd_status_update(obj);<br />
            pthread_mutex_unlock(&daemon_mutex);</p>
<p>        }while(!usleep(5000) &&  !leaving);<br />
      leaving = 1;<br />
      pthread_join(Lkeys,NULL);<br />
      pthread_join(g15display,NULL);<br />
    }else<br />
      printf("Unable to connect to MPD server. Exiting\n");</p>
<p>    if(obj)<br />
      mpd_free(obj);<br />
    close(fdstdin);</p>
<p>    if(canvas!=NULL)<br />
        free(canvas);</p>
<p>    close(g15screen_fd);<br />
    close(mmedia_fd);</p>
<p>    pthread_mutex_destroy(&lockit);</p>
<p>    return 1;<br />
}<br />