]> git.sesse.net Git - vlc/blob - plugins/gtk/gtk_playlist.c
* ncurses compilation fix by Michael Mondragon <mammon@lokmail.net>.
[vlc] / plugins / gtk / gtk_playlist.c
1 /*****************************************************************************
2  * gtk_playlist.c : Interface for the playlist dialog
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: gtk_playlist.c,v 1.18 2001/07/25 03:12:33 sam Exp $
6  *
7  * Authors: Pierre Baillet <oct@zoy.org>
8  *          Stéphane Borel <stef@via.ecp.fr>
9  *      
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include "defs.h"
29
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <sys/types.h>          /* for readdir  and stat stuff */
34
35 #ifndef WIN32
36 #   include <dirent.h>
37 #endif
38
39 #include <sys/stat.h>
40 #include <unistd.h>
41
42 #define gtk 12
43 #define gnome 42
44 #if ( MODULE_NAME == gtk )
45 #   include <gtk/gtk.h>
46 #elif ( MODULE_NAME == gnome )
47 #   include <gnome.h>
48 #endif
49 #undef gtk
50 #undef gnome
51
52 #include "config.h"
53 #include "common.h"
54 #include "threads.h"
55 #include "mtime.h"
56
57 #include "stream_control.h"
58 #include "input_ext-intf.h"
59
60 #include "interface.h"
61 #include "intf_playlist.h"
62 #include "intf_msg.h"
63
64 #include "gtk_callbacks.h"
65 #include "gtk_interface.h"
66 #include "gtk_support.h"
67 #include "gtk_playlist.h"
68 #include "intf_gtk.h"
69
70 #include "main.h"
71
72 #include "modules_export.h"
73
74 /****************************************************************************
75  * Playlist window management
76  ****************************************************************************/
77 gboolean GtkPlaylistShow( GtkWidget       *widget,
78                           GdkEventButton  *event,
79                           gpointer         user_data )
80 {
81     intf_thread_t *p_intf = GetIntf( GTK_WIDGET(widget), (char*)user_data );
82
83     if( !GTK_IS_WIDGET( p_intf->p_sys->p_playlist ) )
84     {
85         /* The data types we are allowed to receive */
86         static GtkTargetEntry target_table[] =
87         {
88             { "text/uri-list", 0, DROP_ACCEPT_TEXT_URI_LIST },
89             { "text/plain", 0, DROP_ACCEPT_TEXT_PLAIN }
90         };
91
92         p_intf->p_sys->p_playlist = create_intf_playlist();
93         gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_playlist ),
94                              "p_intf", p_intf );
95
96         /* Accept file drops on the playlist window */
97         gtk_drag_dest_set( GTK_WIDGET( lookup_widget( p_intf->p_sys->p_playlist,
98                                        "playlist_clist") ),
99                            GTK_DEST_DEFAULT_ALL, target_table,
100                            1, GDK_ACTION_COPY );
101     }
102
103     if( GTK_WIDGET_VISIBLE( p_intf->p_sys->p_playlist ) )
104     {
105         gtk_widget_hide( p_intf->p_sys->p_playlist );
106     } 
107     else 
108     {        
109         GtkCList * p_clist;
110
111         p_clist = GTK_CLIST( gtk_object_get_data(
112             GTK_OBJECT( p_intf->p_sys->p_playlist ), "playlist_clist" ) );
113         GtkRebuildCList( p_clist , p_main->p_playlist );
114         gtk_widget_show( p_intf->p_sys->p_playlist );
115         gdk_window_raise( p_intf->p_sys->p_playlist->window );
116     }
117
118     return TRUE;
119 }
120
121
122 void GtkPlaylistOk( GtkButton * button, gpointer user_data )
123 {
124      gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
125 }
126
127
128 void GtkPlaylistCancel( GtkButton * button, gpointer user_data )
129 {
130      gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
131 }
132
133
134
135 gboolean GtkPlaylistPrev( GtkWidget       *widget,
136                           GdkEventButton  *event,
137                           gpointer         user_data )
138 {
139     intf_thread_t *p_intf = GetIntf( GTK_WIDGET(widget), (char*)user_data );
140
141     if( p_intf->p_input != NULL )
142     {
143         /* FIXME: temporary hack */
144         intf_PlaylistPrev( p_main->p_playlist );
145         intf_PlaylistPrev( p_main->p_playlist );
146         p_intf->p_input->b_eof = 1;
147     }
148
149     return TRUE;
150 }
151
152
153 gboolean GtkPlaylistNext( GtkWidget       *widget,
154                           GdkEventButton  *event,
155                           gpointer         user_data)
156 {
157     intf_thread_t *p_intf = GetIntf( GTK_WIDGET(widget), (char*)user_data );
158
159     if( p_intf->p_input != NULL )
160     {
161         /* FIXME: temporary hack */
162         p_intf->p_input->b_eof = 1;
163     }
164
165     return TRUE;
166 }
167
168 /****************************************************************************
169  * Menu callbacks for playlist functions
170  ****************************************************************************/
171 void GtkPlaylistActivate( GtkMenuItem * menuitem, gpointer user_data )
172 {
173     GtkPlaylistShow( GTK_WIDGET( menuitem ), NULL, user_data );
174 }
175
176
177 void GtkNextActivate( GtkMenuItem * menuitem, gpointer user_data )
178 {
179     GtkPlaylistNext( GTK_WIDGET( menuitem ), NULL, user_data );
180 }
181
182
183 void GtkPrevActivate( GtkMenuItem * menuitem, gpointer user_data )
184 {
185     GtkPlaylistPrev( GTK_WIDGET( menuitem ), NULL, user_data );
186 }
187
188
189 /****************************************************************************
190  * Playlist core functions
191  ****************************************************************************/
192 void GtkPlaylistAddUrl( GtkMenuItem * menuitem, gpointer user_data )
193 {
194
195 }
196
197
198 void GtkPlaylistDeleteAll( GtkMenuItem * menuitem, gpointer user_data )
199 {
200
201 }
202
203
204 void GtkPlaylistDeleteSelected( GtkMenuItem * menuitem, gpointer user_data )
205 {
206     /* user wants to delete a file in the queue */
207     GList *     p_selection;
208     GtkCList *  p_clist;
209     playlist_t *p_playlist;
210     
211     /* catch the thread back */
212     intf_thread_t *p_intf = GetIntf( GTK_WIDGET(menuitem), /*(char*)user_data*/"intf_playlist" );
213
214     p_playlist = p_main->p_playlist;
215     
216     /* lock the struct */
217     vlc_mutex_lock( &p_intf->change_lock );
218
219     p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT(
220         p_intf->p_sys->p_playlist ), "playlist_clist" ) );
221     
222     /* I use UNDOCUMENTED features to retrieve the selection... */
223     p_selection = p_clist->selection;
224     
225     if( g_list_length( p_selection ) > 0 )
226     {
227         /* reverse-sort so that we can delete from the furthest
228          * to the closest item to delete...
229          */
230         p_selection = g_list_sort( p_selection, GtkCompareItems );
231         g_list_foreach( p_selection, GtkDeleteGListItem, p_intf );
232         /* rebuild the CList */
233         GtkRebuildCList( p_clist, p_playlist );
234     }
235     
236     vlc_mutex_unlock( &p_intf->change_lock );
237 }
238
239 void GtkPlaylistCrop( GtkMenuItem * menuitem, gpointer user_data )
240 {
241     /* Ok, this is a really small thing, but, hey, it works and
242        might be useful, who knows ? */
243     GtkPlaylistInvert( menuitem, user_data );
244     GtkPlaylistDeleteSelected( menuitem, user_data );
245 }
246
247 void GtkPlaylistInvert( GtkMenuItem * menuitem, gpointer user_data )
248 {
249     playlist_t *p_playlist;
250     GtkCList *  p_clist;
251     int *       pi_selected;
252     int         i_sel_l;
253     int         i_dummy;
254     
255     /* catch the thread back */
256     intf_thread_t *p_intf = GetIntf( GTK_WIDGET(menuitem), (char*)user_data );
257
258     p_playlist = p_main->p_playlist;
259     
260     /* lock the struct */
261     vlc_mutex_lock( &p_intf->change_lock );
262
263     p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT(
264         p_intf->p_sys->p_playlist ), "playlist_clist" ) );
265     
266     /* have to copy the selection to an int *
267        I wasn't able to copy the g_list to another g_list
268        glib only does pointer copies, not real copies :( */
269     
270     pi_selected = malloc( sizeof(int) *g_list_length( p_clist->selection ) );
271     i_sel_l = g_list_length( p_clist->selection );
272
273     for( i_dummy = 0 ; i_dummy < i_sel_l ; i_dummy++)
274     {
275         pi_selected[i_dummy] = (int)g_list_nth_data( p_clist->selection,
276                                                      i_dummy );
277     }
278     
279     gtk_clist_freeze( p_clist );
280     gtk_clist_select_all( p_clist );
281
282     for( i_dummy = 0; i_dummy < i_sel_l; i_dummy++)
283     {
284         gtk_clist_unselect_row( p_clist, pi_selected[i_dummy], 0 );
285         gtk_clist_unselect_row( p_clist, pi_selected[i_dummy], 1 );
286     }
287
288     free( pi_selected );
289     gtk_clist_thaw( p_clist );
290
291     vlc_mutex_unlock( &p_intf->change_lock );
292 }
293
294 void GtkPlaylistSelect( GtkMenuItem * menuitem, gpointer user_data)
295 {
296
297 }
298
299 gboolean GtkPlaylistEvent( GtkWidget * widget,
300                            GdkEvent  * event,
301                            gpointer    user_data)
302 {
303     intf_thread_t *p_intf = GetIntf( GTK_WIDGET(widget), (char*)user_data );
304
305     if( ( event->button ).type == GDK_2BUTTON_PRESS )
306     {
307         GtkCList *  p_clist;
308         gint        i_row;
309         gint        i_col;
310
311         p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT(
312             p_intf->p_sys->p_playlist ), "playlist_clist" ) );
313         
314         if( gtk_clist_get_selection_info( p_clist, (event->button).x, 
315                     (event->button).y, &i_row, &i_col ) == 1 )
316         {
317             /* clicked is in range. */
318             if( p_intf->p_input != NULL )
319             {
320                 /* FIXME: temporary hack */
321                 p_intf->p_input->b_eof = 1;
322             }
323
324             intf_PlaylistJumpto( p_main->p_playlist, i_row - 1 );
325         }
326         return TRUE;
327     }
328
329     return FALSE;
330 }
331
332 void GtkPlaylistDragData( GtkWidget       *widget,
333                           GdkDragContext  *drag_context,
334                           gint             x,
335                           gint             y,
336                           GtkSelectionData *data,
337                           guint            info,
338                           guint            time,
339                           gpointer         user_data )
340 {
341     intf_thread_t * p_intf;
342     GtkCList *      p_clist;
343     gint            i_row;
344     gint            i_col;
345     int             i_end = p_main->p_playlist->i_size;
346
347     /* catch the interface back */
348     p_intf = GetIntf( GTK_WIDGET(widget), (char*)user_data );
349
350     p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT(
351         p_intf->p_sys->p_playlist ), "playlist_clist" ) );
352    
353     if( gtk_clist_get_selection_info( p_clist, x, y, &i_row, &i_col ) == 1 )
354     {
355         /* we are dropping somewhere into the clist items */
356         GtkDropDataReceived( p_intf, data, info, i_row );
357     } 
358     else 
359     {
360         /* else, put that at the end of the playlist */
361         GtkDropDataReceived( p_intf, data, info, PLAYLIST_END );
362     }
363
364     intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
365 }
366
367
368 gboolean GtkPlaylistDragMotion( GtkWidget       *widget,
369                                 GdkDragContext  *drag_context,
370                                 gint             x,
371                                 gint             y,
372                                 guint            time,
373                                 gpointer         user_data )
374 {
375     intf_thread_t *p_intf;
376     GtkCList *  p_clist;
377     gint        i_row;
378     gint        i_col;
379     int         i_dummy;
380     GdkColor    color;
381
382     p_intf = GetIntf( GTK_WIDGET(widget), (char*)user_data );
383
384     p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT(
385         p_intf->p_sys->p_playlist ), "playlist_clist" ) );
386
387     if( !GTK_WIDGET_TOPLEVEL(widget) )
388     {
389         gdk_window_raise( p_intf->p_sys->p_playlist->window );
390     }
391
392     color.red =   0xffff;
393     color.blue =  0xffff;
394     color.green = 0xffff;
395
396     gtk_clist_freeze( p_clist );
397     
398     for( i_dummy = 0; i_dummy < p_clist->rows; i_dummy++)
399     {
400        gtk_clist_set_background ( p_clist, i_dummy , &color);
401     }
402
403     color.red = 0xffff;
404     color.blue = 0;
405     color.green = 0;
406     gtk_clist_set_background( p_clist, p_main->p_playlist->i_index , &color );
407         
408     if( gtk_clist_get_selection_info( p_clist, x, y, &i_row, &i_col ) == 1)
409     {
410         color.red = 0;
411         color.blue = 0xf000;
412         color.green = 0x9000;
413         gtk_clist_set_background ( p_clist, i_row - 1, &color);
414         gtk_clist_set_background ( p_clist, i_row, &color);
415     }
416
417     gtk_clist_thaw( p_clist );
418     
419     return TRUE;
420 }
421
422 void GtkDropDataReceived( intf_thread_t * p_intf,
423         GtkSelectionData * p_data, guint i_info, int i_position)
424 {
425     /* first we'll have to split against all the '\n' we have */
426     gchar *     p_protocol;
427     gchar *     p_temp;
428     gchar *     p_string = p_data->data ;
429     GList *     p_files = NULL;
430     GtkCList *  p_clist;
431
432     
433     /* catch the playlist back */
434     playlist_t * p_playlist = p_main->p_playlist;
435    
436
437     /* if this has been URLencoded, decode it
438      * 
439      * Is it a good thing to do it in place ?
440      * probably not... 
441      */
442     if( i_info == DROP_ACCEPT_TEXT_URI_LIST )
443     {
444         intf_UrlDecode( p_string );
445     }
446     
447     /* this cuts string into single file drops */
448     /* this code was borrowed from xmms, thx guys :) */
449     while( *p_string)
450     {
451         p_temp = strchr( p_string, '\n' );
452         if( p_temp )
453         {
454             if( *( p_temp - 1 ) == '\r' )
455             {
456                 *( p_temp - 1) = '\0';
457             }
458             *p_temp = '\0';
459         }
460
461         /* do we have a protocol or something ? */
462         p_protocol = strstr( p_string, ":/" );
463         if( p_protocol != NULL )
464         {
465             p_protocol = calloc( p_protocol - p_string + 2, sizeof(char) );
466             p_protocol = strncpy( p_protocol, p_string,
467                                   strstr( p_string, ":/" ) + 1 - p_string );
468
469             intf_WarnMsg( 4, "Protocol dropped is %s", p_protocol );
470             p_string += strlen( p_protocol );
471
472             /* Allowed things are proto: or proto:// */
473             if( p_string[0] == '/' && p_string[1] == '/')
474             {
475                 /* eat one '/' */
476                 p_string++;
477             }
478             intf_WarnMsg( 4, " Dropped %s", p_string );
479         } 
480         else 
481         {
482             p_protocol = strdup( "" );
483         }
484          
485         /* if it uses the file protocol we can do something, else, sorry :( 
486          * I think this is a good choice for now, as we don't have any
487          * ability to read http:// or ftp:// files
488          * what about adding dvd:// to the list of authorized proto ? */
489         
490         if( strcmp( p_protocol, "file:" ) == 0 )
491         {
492             p_files = g_list_concat( p_files, GtkReadFiles( p_string ) ); 
493         }
494        
495         /* free the malloc and go on... */
496         free( p_protocol );
497         if( !p_temp )
498         {
499             break;
500         }
501         p_string = p_temp + 1;
502     }
503    
504     /* At this point, we have a nice big list maybe NULL */
505     if( p_files != NULL )
506     {
507         /* lock the interface */
508         vlc_mutex_lock( &p_intf->change_lock );
509
510         intf_WarnMsg( 4, "List has %d elements", g_list_length( p_files ) ); 
511         GtkAppendList( p_playlist, i_position, p_files );
512
513         /* get the CList  and rebuild it. */
514         p_clist = GTK_CLIST( lookup_widget( p_intf->p_sys->p_playlist,
515                                             "playlist_clist" ) ); 
516         GtkRebuildCList( p_clist , p_playlist );
517         
518         /* unlock the interface */
519         vlc_mutex_unlock( &p_intf->change_lock );
520     }
521 }
522
523
524 void GtkDeleteGListItem( gpointer data, gpointer param )
525 {
526     int i_cur_row = ( int )data;
527     intf_thread_t * p_intf = param;    
528     
529     intf_PlaylistDelete( p_main->p_playlist, i_cur_row );
530
531     /* are we deleting the current played stream */
532     if( p_intf->p_sys->i_playing == i_cur_row )
533     {
534         /* next ! */
535         p_intf->p_input->b_eof = 1;
536         /* this has to set the slider to 0 */
537         
538         /* step minus one */
539         p_intf->p_sys->i_playing-- ;
540
541         vlc_mutex_lock( &p_main->p_playlist->change_lock );
542         p_main->p_playlist->i_index-- ;
543         vlc_mutex_unlock( &p_main->p_playlist->change_lock );
544     }
545 }
546
547
548 gint GtkCompareItems( gconstpointer a, gconstpointer b )
549 {
550     return b - a;
551 }
552
553
554 /* check a file (string) against supposed valid extension */
555 int GtkHasValidExtension( gchar * psz_filename )
556 {
557     char * ppsz_ext[6] = { "mpg", "mpeg", "vob", "mp2", "ts", "ps" };
558     int  i_ext = 6;
559     int  i_dummy;
560
561     gchar * psz_ext = strrchr( psz_filename, '.' ) + sizeof( char );
562
563     for( i_dummy = 0 ; i_dummy < i_ext ; i_dummy++ )
564     {
565         if( strcmp( psz_ext, ppsz_ext[i_dummy] ) == 0 )
566         {
567             return 1;
568         }
569     }
570
571     return 0;
572 }
573
574 /* recursive function: descend into folders and build a list of
575  * valid filenames */
576 GList * GtkReadFiles( gchar * psz_fsname )
577 {
578     struct stat statbuf;
579     GList  *    p_current = NULL;
580
581     /* get the attributes of this file */
582     stat( psz_fsname, &statbuf );
583     
584     /* is it a regular file ? */
585     if( S_ISREG( statbuf.st_mode ) )
586     {
587         if( GtkHasValidExtension( psz_fsname ) )
588         {
589             intf_WarnMsg( 2, "%s is a valid file. Stacking on the playlist",
590                           psz_fsname );
591             return g_list_append( NULL, g_strdup( psz_fsname ) );
592         } 
593         else
594         {
595             return NULL;
596         }
597     } 
598     /* is it a directory (should we check for symlinks ?) */
599     else if( S_ISDIR( statbuf.st_mode ) ) 
600     {
601         /* have to cd into this dir */
602         DIR *           p_current_dir = opendir( psz_fsname );
603         struct dirent * p_dir_content; 
604         
605         intf_WarnMsg( 2, "%s is a folder.", psz_fsname );
606         
607         if( p_current_dir == NULL )
608         {
609             /* something went bad, get out of here ! */
610             return p_current;
611         }
612         p_dir_content = readdir( p_current_dir );
613
614         /* while we still have entries in the directory */
615         while( p_dir_content != NULL )
616         {
617             /* if it is "." or "..", forget it */
618             if( ( strcmp( p_dir_content->d_name, "." ) != 0 ) &&
619                 ( strcmp( p_dir_content->d_name, ".." ) != 0 ) )
620             {
621                 /* else build the new directory by adding
622                    fsname "/" and the current entry name 
623                    (kludgy :()
624                   */
625                 char *  psz_newfs = malloc ( 2 + strlen( psz_fsname ) +
626                             strlen( p_dir_content->d_name ) * sizeof(char) );
627                 strcpy( psz_newfs, psz_fsname );
628                 strcpy( psz_newfs + strlen( psz_fsname ) + 1,
629                         p_dir_content->d_name );
630                 psz_newfs[strlen( psz_fsname )] = '/';
631                 
632                 p_current = g_list_concat( p_current,
633                                            GtkReadFiles( psz_newfs ) );
634                     
635                 g_free( psz_newfs );
636             }
637             p_dir_content = readdir( p_current_dir );
638         }
639         return p_current;
640     }
641     return NULL;
642 }
643
644 /* add items in a playlist 
645  * when i_pos==-1 add to the end of the list... 
646  */
647 int GtkAppendList( playlist_t * p_playlist, int i_pos, GList * p_list )
648 {
649     guint i_dummy;
650     guint i_length;
651
652     i_length = g_list_length( p_list );
653
654     for( i_dummy = 0; i_dummy < i_length ; i_dummy++ )
655     {
656         intf_PlaylistAdd( p_playlist, 
657                 /* ok; this is a really nasty trick to insert
658                    the item where they are suppose to go but, hey
659                    this works :P (btw, you are really nasty too) */
660                 i_pos==PLAYLIST_END?PLAYLIST_END:( i_pos + i_dummy ), 
661                 g_list_nth_data( p_list, i_dummy ) );
662     }
663     return 0;
664 }
665
666 /* statis timeouted function */
667 void GtkPlayListManage( intf_thread_t * p_intf )
668 {
669     /* this thing really sucks for now :( */
670
671     /* TODO speak more with interface/intf_playlist.c */
672
673     playlist_t *    p_playlist = p_main->p_playlist ;
674     GtkCList *      p_clist;
675
676     if( GTK_IS_WIDGET( p_intf->p_sys->p_playlist ) )
677     {
678         p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT(
679                        p_intf->p_sys->p_playlist ), "playlist_clist" ) );
680     
681         vlc_mutex_lock( &p_playlist->change_lock );
682     
683         if( p_intf->p_sys->i_playing != p_playlist->i_index )
684         {
685             GdkColor color;
686     
687             color.red = 0xffff;
688             color.blue = 0;
689             color.green = 0;
690     
691             gtk_clist_set_background( p_clist, p_playlist->i_index, &color );
692     
693             if( p_intf->p_sys->i_playing != -1 )
694             {
695                 color.red = 0xffff;
696                 color.blue = 0xffff;
697                 color.green = 0xffff;
698                 gtk_clist_set_background( p_clist, p_intf->p_sys->i_playing,
699                                           &color);
700             }
701             p_intf->p_sys->i_playing = p_playlist->i_index;
702         }
703     
704         vlc_mutex_unlock( &p_playlist->change_lock );
705     }
706 }
707
708 void GtkRebuildCList( GtkCList * p_clist, playlist_t * p_playlist )
709 {
710     int         i_dummy;
711     gchar *     ppsz_text[2];
712     GdkColor    red;
713     red.red     = 65535;
714     red.blue    = 0;
715     red.green   = 0;
716     
717     gtk_clist_freeze( p_clist );
718     gtk_clist_clear( p_clist );
719    
720     for( i_dummy = 0; i_dummy < p_playlist->i_size ; i_dummy++ )
721     {
722 #ifdef WIN32 /* WIN32 HACK */
723         ppsz_text[0] = g_strdup( "" );
724 #else
725         ppsz_text[0] = g_strdup( rindex( (char *)(p_playlist->p_item[
726                 p_playlist->i_size - 1 - i_dummy].psz_name ), '/' ) + 1 );
727 #endif
728         ppsz_text[1] = g_strdup( "no info");
729         
730         gtk_clist_insert( p_clist, 0, ppsz_text );
731         
732         free( ppsz_text[0] );
733         free( ppsz_text[1] );
734     }
735     gtk_clist_set_background( p_clist, p_playlist->i_index, &red);
736     gtk_clist_thaw( p_clist );
737 }
738