Update to MPlayer SVN rev 33132.
[vaapi:miks-mplayer.git] / gui / mplayer / gtk / .svn / text-base / pl.c.svn-base
1 /*
2  * This file is part of MPlayer.
3  *
4  * MPlayer is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * MPlayer is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <string.h>
22 #include <dirent.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include <gdk/gdkkeysyms.h>
28 #include <gtk/gtk.h>
29
30 #include "config.h"
31 #include "help_mp.h"
32 #include "stream/stream.h"
33
34 #include "gui/interface.h"
35 #include "gui/mplayer/widgets.h"
36 #include "pl.h"
37 #include "gtk_common.h"
38
39 static char * book_open_xpm[] = {
40         "16 16 4 1",
41         "       c None s None",
42         ".      c black",
43         "X      c #808080",
44         "o      c white",
45         "                ",
46         "  ..            ",
47         " .Xo.    ...    ",
48         " .Xoo. ..oo.    ",
49         " .Xooo.Xooo...  ",
50         " .Xooo.oooo.X.  ",
51         " .Xooo.Xooo.X.  ",
52         " .Xooo.oooo.X.  ",
53         " .Xooo.Xooo.X.  ",
54         " .Xooo.oooo.X.  ",
55         "  .Xoo.Xoo..X.  ",
56         "   .Xo.o..ooX.  ",
57         "    .X..XXXXX.  ",
58         "    ..X.......  ",
59         "     ..         ",
60         "                "};
61
62 static char * book_closed_xpm[] = {
63         "16 16 6 1",
64         "       c None s None",
65         ".      c black",
66         "X      c blue",
67         "o      c yellow",
68         "O      c #007FEA",
69         "#      c white",
70         "                ",
71         "       ..       ",
72         "     ..XX.      ",
73         "   ..XXXXX.     ",
74         " ..XXXXXXXX.    ",
75         ".ooXXXXXXXXX.   ",
76         "..ooXXXXXXXXX.  ",
77         ".X.ooXXXXXXXXX. ",
78         ".XX.ooXXXXXX..  ",
79         " .XX.ooXXX..#O  ",
80         "  .XX.oo..##OO. ",
81         "   .XX..##OO..  ",
82         "    .X.#OO..    ",
83         "     ..O..      ",
84         "      ..        ",
85         "                "};
86
87        GtkWidget * PlayList = NULL;
88 static GtkWidget * CTDirTree;
89 static GtkWidget * CLFiles;
90 static GtkWidget * CLSelected;
91 static GtkWidget * Add;
92 static GtkWidget * Remove;
93 static GtkWidget * Ok;
94 static GtkWidget * Cancel;
95 static GdkPixmap * pxOpenedBook;
96 static GdkPixmap * pxClosedBook;
97 static GdkBitmap * msOpenedBook;
98 static GdkBitmap * msClosedBook;
99
100 static int   NrOfEntrys = 0;
101 static int   NrOfSelected = 0;
102 static int * CLFileSelected = NULL;
103 static int * CLListSelected = NULL;
104
105 static int sigSel;
106 static int sigUnsel;
107
108 typedef struct
109 {
110  int    scaned;
111  char * path;
112 } DirNodeType;
113
114 static GtkCTreeNode * sibling;
115 static GtkCTreeNode * parent;
116 static gchar        * current_path;
117 static gchar        * old_path = NULL;
118
119 static int compare_func(const void *a, const void *b)
120 {
121  char * tmp;
122  int    i;
123  if ( !a || !b || !( (DirNodeType *)a )->path ) return -1;
124  tmp=strdup( (char *)b ); tmp[strlen( tmp )-1]=0;
125  i=strcmp( ( (DirNodeType *)a )->path,tmp );
126  free( tmp );
127  return i;
128 }
129
130 static void scan_dir( char * path );
131
132 void ShowPlayList( void )
133 {
134  if ( PlayList ) gtkActive( PlayList );
135   else PlayList=create_PlayList();
136
137  if ( old_path && *old_path )
138   {
139    char         * currentdir = strdup( old_path );
140    char         * tpath,* pos;
141    GtkCTreeNode * node,* nextnode;
142    gboolean       leaf;
143    tpath=strdup( "/" );
144    pos=strtok( currentdir,"/" );
145    node=gtk_ctree_find_by_row_data_custom( GTK_CTREE( CTDirTree ),NULL,"/",compare_func );
146    do
147     {
148      char * tpathnew = g_strconcat( tpath,pos,"/",NULL );
149      free( tpath ); tpath=tpathnew;
150      nextnode=gtk_ctree_find_by_row_data_custom( GTK_CTREE( CTDirTree ),node,tpath,compare_func );
151      if ( !nextnode ) break;
152      node=nextnode;
153      pos=strtok( NULL,"/" );
154      gtk_ctree_get_node_info( GTK_CTREE( CTDirTree ),node,NULL,NULL,NULL,NULL,NULL,NULL,&leaf,NULL );
155      if ( !leaf && pos ) gtk_ctree_expand( GTK_CTREE( CTDirTree ),node );
156       else
157        {
158         DirNodeType * DirNode;
159         gtk_ctree_select( GTK_CTREE( CTDirTree ),node );
160         DirNode=gtk_ctree_node_get_row_data( GTK_CTREE( CTDirTree ),node );
161         current_path=DirNode->path;
162         scan_dir( DirNode->path );
163         free( CLFileSelected );
164         CLFileSelected=calloc( 1,NrOfEntrys * sizeof( int ) );
165         break;
166        }
167     } while( pos );
168    free( tpath );
169    free( currentdir );
170   }
171   else gtk_ctree_select( GTK_CTREE( CTDirTree ),parent );
172
173  gtk_clist_freeze( GTK_CLIST( CLSelected ) );
174  gtk_clist_clear( GTK_CLIST( CLSelected ) );
175  if ( plList )
176   {
177    gchar * name, * path;
178    plItem * next = plList;
179    while ( next || next->next )
180     {
181      char * text[1][3]; text[0][2]="";
182      name = g_filename_to_utf8( next->name, -1, NULL, NULL, NULL );
183      path = g_filename_to_utf8( next->path, -1, NULL, NULL, NULL );
184      text[0][0]=name ? name : next->name;
185      text[0][1]=path ? path : next->path;
186      gtk_clist_append( GTK_CLIST( CLSelected ),text[0] );
187      g_free( path );
188      g_free( name );
189      NrOfSelected++;
190      if ( next->next ) next=next->next; else break;
191     }
192    CLListSelected=calloc( 1,NrOfSelected * sizeof( int ) );
193   }
194  gtk_clist_thaw( GTK_CLIST( CLSelected ) );
195
196  gtk_widget_show( PlayList );
197 }
198
199 void HidePlayList( void )
200 {
201  if ( !PlayList ) return;
202  NrOfSelected=NrOfEntrys=0;
203  gfree( (void **)&CLListSelected ); gfree( (void **)&CLFileSelected );
204  free( old_path );
205  old_path=strdup( current_path );
206  gtk_widget_hide( PlayList );
207  gtk_widget_destroy( PlayList );
208  PlayList=NULL;
209 }
210
211 static void plRowSelect( GtkCList * clist,gint row,gint column,GdkEvent * event,gpointer user_data )
212 {
213  switch ( (int) user_data )
214   {
215    case 0: CLFileSelected[row]=1; break;
216    case 1: CLListSelected[row]=1; break;
217   }
218 }
219
220 static void plUnRowSelect( GtkCList * clist,gint row,gint column,GdkEvent * event,gpointer user_data )
221 {
222  switch ( (int) user_data )
223   {
224    case 0: CLFileSelected[row]=0; break;
225    case 1: CLListSelected[row]=0; break;
226   }
227 }
228
229 static void plButtonReleased( GtkButton * button,gpointer user_data )
230 {
231  switch ( (int) user_data )
232  {
233   case 1: // ok
234        {
235         int i;
236         if ( plList ) gtkSet( gtkDelPl,0,NULL );
237         for ( i=0;i<NrOfSelected;i++ )
238          {
239           plItem * item;
240           char * text[3];
241           item=calloc( 1,sizeof( plItem ) );
242           gtk_clist_get_text( GTK_CLIST( CLSelected ),i,0,&text[0] );
243           gtk_clist_get_text( GTK_CLIST( CLSelected ),i,1,&text[1] );
244           item->name=g_filename_from_utf8( text[0], -1, NULL, NULL, NULL );
245           if ( !item->name ) item->name = strdup( text[0] );
246           item->path=g_filename_from_utf8( text[1], -1, NULL, NULL, NULL );
247           if ( !item->path ) item->path = strdup( text[1] );
248           gtkSet( gtkAddPlItem,0,(void*)item );
249          }
250         if ( plCurrent )
251          {
252           mplSetFileName( plCurrent->path,plCurrent->name,STREAMTYPE_FILE );
253 //        guiSetDF( guiIntfStruct.Filename,plCurrent->path,plCurrent->name );
254 //        guiIntfStruct.FilenameChanged=1;
255 //        guiIntfStruct.StreamType=STREAMTYPE_FILE;
256          }
257        }
258   case 0: // cancel
259        HidePlayList();
260        break;
261   case 2: // remove
262        {
263         int i; int j; int c=0;
264
265         gtk_signal_handler_block( GTK_OBJECT( CLSelected ),sigSel );
266         gtk_signal_handler_block( GTK_OBJECT( CLSelected ),sigUnsel );
267
268         gtk_clist_freeze( GTK_CLIST( CLSelected ) );
269         for ( i=0;i<NrOfSelected-c;i++ )
270          if ( CLListSelected[i] )
271           {
272            gtk_clist_remove( GTK_CLIST( CLSelected ),i - c );
273            c++;
274            for ( j=i;j<NrOfSelected-c;j++ )
275                 CLListSelected[i] = CLListSelected[i+1];
276           }
277         NrOfSelected-=c;
278         gtk_clist_thaw( GTK_CLIST( CLSelected ) );
279
280         gtk_signal_handler_unblock( GTK_OBJECT( CLSelected ),sigSel );
281         gtk_signal_handler_unblock( GTK_OBJECT( CLSelected ),sigUnsel );
282
283        }
284        break;
285   case 3: // add
286        {
287         int i;
288         void *p;
289         char * itext[1][2];
290         gchar * cpath;
291         char * text[1][3]; text[0][2]="";
292         gtk_clist_freeze( GTK_CLIST( CLSelected ) );
293         for ( i=0;i<NrOfEntrys;i++ )
294          {
295           if ( CLFileSelected[i] )
296            {
297             NrOfSelected++;
298             p=realloc( CLListSelected,NrOfSelected * sizeof( int ) );
299             if ( !p ) NrOfSelected--;
300             else
301              {
302               CLListSelected=p;
303               CLListSelected[NrOfSelected - 1]=0;
304               gtk_clist_get_text( GTK_CLIST( CLFiles ),i,0,(char **)&itext );
305               cpath=g_filename_to_utf8( current_path, -1, NULL, NULL, NULL );
306               text[0][0]=itext[0][0]; text[0][1]=cpath ? cpath : current_path;
307               gtk_clist_append( GTK_CLIST( CLSelected ),text[0] );
308               g_free( cpath );
309              }
310            }
311          }
312         gtk_clist_thaw( GTK_CLIST( CLSelected ) );
313        }
314        break;
315  }
316 }
317
318 static int check_for_subdir( gchar * path )
319 {
320  DIR           * dir;
321  struct dirent * dirent;
322  struct stat     statbuf;
323  gchar         * npath;
324
325  if ( (dir=opendir( path )) )
326   {
327    while ( (dirent=readdir( dir )) )
328     {
329      if ( dirent->d_name[0] != '.' )
330       {
331        npath=calloc( 1,strlen( path ) + strlen( dirent->d_name ) + 3 );
332        sprintf( npath,"%s/%s",path,dirent->d_name );
333        if ( stat( npath,&statbuf ) != -1 && S_ISDIR( statbuf.st_mode ) )
334         { free( npath ); closedir( dir ); return 1; }
335        free( npath );
336       }
337     }
338    closedir( dir );
339   }
340  return 0;
341 }
342
343 static void plCTree( GtkCTree * ctree,GtkCTreeNode * parent_node,gpointer user_data )
344 {
345  GtkCTreeNode  * node;
346  DirNodeType   * DirNode;
347  gchar             * text, * name = NULL;
348  gchar             * dummy = "dummy";
349  int                     subdir = 1;
350  DIR               * dir = NULL;
351  struct dirent * dirent;
352  gchar             * path;
353  struct                  stat statbuf;
354
355  DirNode=gtk_ctree_node_get_row_data( ctree,parent_node );
356  if ( !DirNode->scaned )
357   {
358    DirNode->scaned=1; current_path=DirNode->path;
359    gtk_clist_freeze( GTK_CLIST( ctree ) );
360    node=gtk_ctree_find_by_row_data( ctree,parent_node,NULL );
361    gtk_ctree_remove_node( ctree,node );
362
363    if ( (dir=opendir( DirNode->path ) ) )
364     {
365      while( (dirent=readdir( dir )) )
366       {
367        path=calloc( 1,strlen( DirNode->path ) + strlen( dirent->d_name ) + 2 );
368        if ( !strcmp( current_path,"/" ) ) sprintf( path,"/%s",dirent->d_name );
369         else sprintf( path,"%s/%s",current_path,dirent->d_name );
370        text=dirent->d_name;
371        g_free( name );
372        name=g_filename_to_utf8( text, -1, NULL, NULL, NULL );
373
374        if ( stat( path,&statbuf ) != -1 && S_ISDIR( statbuf.st_mode ) && dirent->d_name[0] != '.' )
375         {
376          DirNode=malloc( sizeof( DirNodeType ) ); DirNode->scaned=0; DirNode->path=strdup( path );
377          subdir=check_for_subdir( path );
378          node=gtk_ctree_insert_node( ctree,parent_node,NULL,(name ? &name : &text ),4,pxOpenedBook,msOpenedBook,pxClosedBook,msClosedBook,!subdir,FALSE );
379          gtk_ctree_node_set_row_data_full( ctree,node,DirNode,NULL );
380          if ( subdir ) node=gtk_ctree_insert_node( ctree,node,NULL,&dummy,4,NULL,NULL,NULL,NULL,FALSE,FALSE );
381         }
382        free( path ); path=NULL;
383       }
384      closedir( dir );
385     }
386
387    gtk_ctree_sort_node( ctree,parent_node );
388    gtk_clist_thaw( GTK_CLIST( ctree ) );
389   }
390
391   g_free( name );
392 }
393
394 static void scan_dir( char * path )
395 {
396  DIR               * dir = NULL;
397  char              * curr;
398  struct dirent * dirent;
399  struct                  stat statbuf;
400  gchar             * name;
401  char              * text[1][2]; text[0][1]="";
402
403  gtk_clist_clear( GTK_CLIST( CLFiles ) );
404  if ( (dir=opendir( path )) )
405   {
406    NrOfEntrys=0;
407    while( (dirent=readdir( dir )) )
408     {
409          curr=calloc( 1,strlen( path ) + strlen( dirent->d_name ) + 3 ); sprintf( curr,"%s/%s",path,dirent->d_name );
410          if ( stat( curr,&statbuf ) != -1 && ( S_ISREG( statbuf.st_mode ) || S_ISLNK( statbuf.st_mode ) ) )
411           {
412            name=g_filename_to_utf8( dirent->d_name, -1, NULL, NULL, NULL );
413            text[0][0]=name ? name : dirent->d_name;
414            gtk_clist_append( GTK_CLIST( CLFiles ), text[0] );
415            g_free( name );
416            NrOfEntrys++;
417           }
418          free( curr );
419         }
420    closedir( dir );
421    gtk_clist_sort( GTK_CLIST( CLFiles ) );
422   }
423 }
424
425 static void plCTRow(GtkWidget * widget, gint row, gint column, GdkEventButton * bevent, gpointer data)
426 {
427  DirNodeType  * DirNode;
428  GtkCTreeNode * node;
429  node=gtk_ctree_node_nth( GTK_CTREE( widget ),row );
430  DirNode=gtk_ctree_node_get_row_data( GTK_CTREE( widget ),node );
431  current_path=DirNode->path;
432  gtk_ctree_expand( GTK_CTREE( widget ),node );
433  scan_dir( DirNode->path );
434  free( CLFileSelected );
435  CLFileSelected=calloc( 1,NrOfEntrys * sizeof( int ) );
436 }
437
438 GtkWidget * create_PlayList( void )
439 {
440   GtkWidget     * vbox1;
441   GtkWidget     * hbox1;
442   GtkWidget     * scrolledwindow1;
443   GtkWidget     * vbox2;
444   GtkWidget     * scrolledwindow2;
445   GtkWidget     * scrolledwindow3;
446   GtkWidget     * hbuttonbox1;
447   GtkAccelGroup * accel_group;
448   GdkColor        transparent = { 0,0,0,0 };
449   gchar         * root = "/";
450   gchar         * dummy = "dummy";
451   DirNodeType   * DirNode;
452
453   accel_group=gtk_accel_group_new();
454
455   PlayList=gtk_window_new( GTK_WINDOW_TOPLEVEL );
456   gtk_object_set_data( GTK_OBJECT( PlayList ),"PlayList",PlayList );
457   gtk_widget_set_usize( PlayList,512,384 );
458   gtk_window_set_title( GTK_WINDOW( PlayList ),MSGTR_PlayList );
459   gtk_window_set_position( GTK_WINDOW( PlayList ),GTK_WIN_POS_CENTER );
460 //  gtk_window_set_policy( GTK_WINDOW( PlayList ),FALSE,FALSE,FALSE );
461   gtk_window_set_wmclass( GTK_WINDOW( PlayList ),"Playlist","MPlayer" );
462
463   gtk_widget_realize( PlayList );
464   gtkAddIcon( PlayList );
465
466   vbox1=AddVBox( AddDialogFrame( PlayList ),0 );
467   hbox1=AddHBox( NULL,1 );
468    gtk_box_pack_start( GTK_BOX( vbox1 ),hbox1,TRUE,TRUE,0 );
469
470   scrolledwindow1=gtk_scrolled_window_new( NULL,NULL );
471   gtk_widget_show( scrolledwindow1 );
472   gtk_container_add( GTK_CONTAINER(
473     AddFrame( NULL,0,hbox1,1 ) ),scrolledwindow1 );
474   gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolledwindow1 ),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC );
475
476   CTDirTree=gtk_ctree_new( 1,0 );
477   gtk_signal_connect( GTK_OBJECT( CTDirTree ),"tree_expand",GTK_SIGNAL_FUNC( plCTree ),(void*)0 );
478   gtk_signal_connect( GTK_OBJECT( CTDirTree ),"select_row",GTK_SIGNAL_FUNC( plCTRow ),(void *)0 );
479   gtk_container_add( GTK_CONTAINER( scrolledwindow1 ),CTDirTree );
480   gtk_clist_set_column_auto_resize( GTK_CLIST( CTDirTree ),0,TRUE );
481   gtk_clist_set_column_width( GTK_CLIST( CTDirTree ),0,80 );
482   gtk_clist_set_selection_mode( GTK_CLIST( CTDirTree ),GTK_SELECTION_SINGLE );
483   gtk_ctree_set_line_style( GTK_CTREE( CTDirTree ),GTK_CTREE_LINES_SOLID );
484   gtk_clist_column_titles_show( GTK_CLIST( CTDirTree ) );
485   gtk_clist_set_shadow_type( GTK_CLIST( CTDirTree ),GTK_SHADOW_NONE );
486
487   if ( !pxOpenedBook ) pxOpenedBook=gdk_pixmap_create_from_xpm_d( PlayList->window,&msOpenedBook,&transparent,book_closed_xpm );
488   if ( !pxClosedBook ) pxClosedBook=gdk_pixmap_create_from_xpm_d( PlayList->window,&msClosedBook,&transparent,book_open_xpm );
489
490   parent=gtk_ctree_insert_node( GTK_CTREE( CTDirTree ),NULL,NULL,&root,4,pxOpenedBook,msOpenedBook,pxClosedBook,msClosedBook,FALSE,FALSE );
491   DirNode=malloc( sizeof( DirNodeType ) );
492   DirNode->scaned=0; DirNode->path=strdup( root );
493   gtk_ctree_node_set_row_data_full(GTK_CTREE( CTDirTree ),parent,DirNode,NULL );
494   sibling=gtk_ctree_insert_node( GTK_CTREE( CTDirTree ),parent,NULL,&dummy,4,NULL,NULL,NULL,NULL,TRUE,TRUE );
495   gtk_ctree_expand( GTK_CTREE( CTDirTree ),parent );
496   gtk_widget_show( CTDirTree );
497
498
499   gtk_clist_set_column_widget( GTK_CLIST( CTDirTree ),0,
500     AddLabel( MSGTR_PLAYLIST_DirectoryTree,NULL ) );
501
502   vbox2=AddVBox(
503     AddFrame( NULL,1,hbox1,1 ),0 );
504
505   scrolledwindow2=gtk_scrolled_window_new( NULL,NULL );
506   gtk_widget_show( scrolledwindow2 );
507   gtk_box_pack_start( GTK_BOX( vbox2 ),scrolledwindow2,TRUE,TRUE,0 );
508   gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolledwindow2 ),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC );
509
510   CLFiles=gtk_clist_new( 1 );
511   gtk_widget_show( CLFiles );
512   gtk_container_add( GTK_CONTAINER( scrolledwindow2 ),CLFiles );
513   gtk_clist_set_column_width( GTK_CLIST( CLFiles ),0,80 );
514   gtk_clist_set_selection_mode( GTK_CLIST( CLFiles ),GTK_SELECTION_EXTENDED );
515   gtk_clist_column_titles_show( GTK_CLIST( CLFiles ) );
516   gtk_clist_set_shadow_type( GTK_CLIST( CLFiles ),GTK_SHADOW_NONE );
517
518   gtk_clist_set_column_widget( GTK_CLIST( CLFiles ),0,
519     AddLabel( MSGTR_PLAYLIST_Files,NULL ) );
520
521   AddHSeparator( vbox2 );
522
523   scrolledwindow3=gtk_scrolled_window_new( NULL,NULL );
524   gtk_widget_show( scrolledwindow3 );
525   gtk_box_pack_start( GTK_BOX( vbox2 ),scrolledwindow3,TRUE,TRUE,0 );
526   gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolledwindow3 ),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC );
527
528   CLSelected=gtk_clist_new( 2 );
529   gtk_widget_show( CLSelected );
530   gtk_container_add( GTK_CONTAINER( scrolledwindow3 ),CLSelected );
531   gtk_clist_set_column_width( GTK_CLIST( CLSelected ),0,295 );
532   gtk_clist_set_column_width( GTK_CLIST( CLSelected ),1,295 );
533   gtk_clist_set_selection_mode( GTK_CLIST( CLSelected ),GTK_SELECTION_MULTIPLE );
534   gtk_clist_column_titles_show( GTK_CLIST( CLSelected ) );
535   gtk_clist_set_shadow_type( GTK_CLIST( CLSelected ),GTK_SHADOW_NONE );
536
537   gtk_clist_set_column_widget( GTK_CLIST( CLSelected ),0,
538     AddLabel( MSGTR_PLAYLIST_Selected,NULL ) );
539
540   gtk_clist_set_column_widget( GTK_CLIST( CLSelected ),1,
541     AddLabel( MSGTR_PLAYLIST_Path,NULL ) );
542
543   AddHSeparator( vbox1 );
544
545   hbuttonbox1=AddHButtonBox( vbox1 );
546     gtk_button_box_set_layout( GTK_BUTTON_BOX( hbuttonbox1 ),GTK_BUTTONBOX_END );
547     gtk_button_box_set_spacing( GTK_BUTTON_BOX( hbuttonbox1 ),10 );
548
549   Add=AddButton( MSGTR_Add,hbuttonbox1 );
550   Remove=AddButton( MSGTR_Remove,hbuttonbox1 );
551   Ok=AddButton( MSGTR_Ok,hbuttonbox1 );
552   Cancel=AddButton( MSGTR_Cancel,hbuttonbox1 );
553
554   gtk_widget_add_accelerator( Cancel,"clicked",accel_group,GDK_Escape,0,GTK_ACCEL_VISIBLE );
555
556   gtk_signal_connect( GTK_OBJECT( PlayList ),"destroy",GTK_SIGNAL_FUNC( WidgetDestroy ),&PlayList );
557
558   gtk_signal_connect( GTK_OBJECT( CLFiles ),"select_row",GTK_SIGNAL_FUNC( plRowSelect ),(void *)0 );
559   gtk_signal_connect( GTK_OBJECT( CLFiles ),"unselect_row",GTK_SIGNAL_FUNC( plUnRowSelect ),(void *)0 );
560   sigSel=gtk_signal_connect( GTK_OBJECT( CLSelected ),"select_row",GTK_SIGNAL_FUNC( plRowSelect ),(void*)1 );
561   sigUnsel=gtk_signal_connect( GTK_OBJECT( CLSelected ),"unselect_row",GTK_SIGNAL_FUNC( plUnRowSelect ),(void*)1 );
562
563   gtk_signal_connect( GTK_OBJECT( Add ),"clicked",GTK_SIGNAL_FUNC( plButtonReleased ),(void*)3 );
564   gtk_signal_connect( GTK_OBJECT( Remove ),"clicked",GTK_SIGNAL_FUNC( plButtonReleased ),(void*)2 );
565   gtk_signal_connect( GTK_OBJECT( Ok ),"clicked",GTK_SIGNAL_FUNC( plButtonReleased ),(void*)1 );
566   gtk_signal_connect( GTK_OBJECT( Cancel ),"clicked",GTK_SIGNAL_FUNC( plButtonReleased ),(void*)0 );
567
568   gtk_window_add_accel_group( GTK_WINDOW( PlayList ),accel_group );
569
570   return PlayList;
571 }