~siretart/gxine/bug.542506

« back to all changes in this revision

Viewing changes to src/playlist.c

  • Committer: Bazaar Package Importer
  • Author(s): Siggi Langauf
  • Date: 2005-01-05 01:49:18 UTC
  • mto: (2.1.1 etch) (1.1.9 upstream)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20050105014918-wgldiqcd79ck2b0v
Tags: upstream-0.4.1
ImportĀ upstreamĀ versionĀ 0.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2002-2003 the xine-project
 
2
 * Copyright (C) 2002-2004 the xine-project
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or
5
5
 * modify it under the terms of the GNU General Public License as
16
16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17
17
 * USA
18
18
 *
19
 
 * $Id: playlist.c,v 1.64 2003/04/08 22:07:47 guenter Exp $
 
19
 * $Id: playlist.c,v 1.93 2004/12/17 00:33:00 dsalt Exp $
20
20
 *
21
21
 * playlist implementation
22
22
 *
23
23
 * .pls parser stolen from totem (C) 2002 Bastien Nocera
24
24
 */
25
25
 
26
 
#include <config.h>
 
26
#include "globals.h"
27
27
 
 
28
#include <errno.h>
28
29
#include <sys/types.h>
29
30
#include <sys/stat.h>
30
31
#include <unistd.h>
32
33
#include <string.h>
33
34
#include <stdio.h>
34
35
#include <stdlib.h>
 
36
#include <stdarg.h>
35
37
 
36
38
#include <X11/Xlib.h>
37
39
 
41
43
 
42
44
#include <pthread.h>
43
45
 
44
 
#include "globals.h"
45
 
#include "gtkxine.h"
46
46
#include "playlist.h"
47
47
#include "http.h"
48
48
#include "utils.h"
49
49
#include "play_item.h"
50
 
#include "actions.h"
 
50
#include "engine.h"
 
51
#include "player.h"
51
52
 
52
53
#include "xmlparser.h"
53
54
 
59
60
static GtkListStore   *pl_store;
60
61
static GtkWidget      *dlg, *tree_view;
61
62
static GtkWidget      *repeat_button, *random_button;
62
 
static int             goto_pos, goto_time;
63
63
static char            logo_mrl[1024];
64
64
static int             logo_mode;
65
 
static pthread_t       play_thread;
66
65
static int             cur_list_pos;
67
 
static char           *cur_mrl;
 
66
 
 
67
#define unmark_play_item() set_mark_play_item (FALSE)
 
68
#define mark_play_item()   set_mark_play_item (TRUE)
 
69
static void set_mark_play_item (gboolean state);
 
70
 
 
71
static inline void remove_trailing_cr (char *str)
 
72
{
 
73
  str = strrchr (str, '\r');
 
74
  if (str && str[1] == 0)
 
75
    *str = 0;
 
76
}
 
77
 
 
78
static int item_marked_current (GtkTreeIter *iter)
 
79
{
 
80
  const char *p;
 
81
  GValue v = { 0 };
 
82
  gtk_tree_model_get_value (GTK_TREE_MODEL (pl_store), iter, 3, &v);
 
83
  p = g_value_peek_pointer (&v);
 
84
  g_value_unset (&v);
 
85
  return p && *p;
 
86
}
68
87
 
69
88
static gboolean close_cb (GtkWidget* widget, gpointer data) {
70
89
  is_visible = FALSE;
71
 
  gtk_widget_unmap (dlg);
 
90
  gtk_widget_hide (dlg);
72
91
 
73
92
  return TRUE;
74
93
}
75
94
 
76
95
void playlist_clear (void) {
77
 
  gtk_xine_stop (GTK_XINE(gtx));
 
96
  se_eval (gse, "player.stop()", NULL, NULL, NULL);
78
97
  gtk_list_store_clear (pl_store);
79
98
}
80
99
 
93
112
 
94
113
  if (gtk_tree_selection_get_selected (sel, NULL, &iter)) {
95
114
 
 
115
    gint        *indices;
 
116
    GtkTreePath *path;
 
117
    gint         pos;
 
118
 
 
119
    path = gtk_tree_model_get_path (GTK_TREE_MODEL (pl_store), &iter);
 
120
    indices = gtk_tree_path_get_indices (path);
 
121
    pos = indices[0];
 
122
 
 
123
    if (pos <= cur_list_pos)
 
124
      --cur_list_pos;
96
125
    gtk_list_store_remove (pl_store, &iter);
 
126
 
 
127
    gtk_tree_selection_select_path (sel, path);
 
128
    gtk_tree_path_free (path);
97
129
  }
98
130
}
99
131
 
101
133
 
102
134
  gchar **files;
103
135
 
104
 
  files = modal_multi_file_dialog ("Select files to add to playlist", NULL);
 
136
  files = modal_multi_file_dialog (_("Select files to add to playlist"), NULL);
105
137
 
106
138
  if (files) {
107
139
 
111
143
    i = 0;
112
144
    while ((mrl = files[i]) ) {
113
145
 
114
 
      playlist_add_mrl (mrl);
 
146
      playlist_add_mrl (mrl, -1);
115
147
 
116
148
      i++;
117
149
    }
121
153
  }
122
154
}
123
155
 
 
156
static void up_cb (GtkWidget* widget, gpointer data) {
 
157
 
 
158
  GtkTreeIter        iter;  
 
159
  GtkTreeSelection  *sel;
 
160
 
 
161
  sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
 
162
 
 
163
  if (gtk_tree_selection_get_selected (sel, NULL, &iter)) {
 
164
    gint        *indices;
 
165
    GtkTreePath *path;
 
166
    int          pos;
 
167
    play_item_t *item;
 
168
    char         str[20];
 
169
    int          marked;
 
170
 
 
171
    path = gtk_tree_model_get_path (GTK_TREE_MODEL (pl_store), &iter);
 
172
    indices = gtk_tree_path_get_indices (path);
 
173
    pos = indices[0];
 
174
    gtk_tree_path_free (path);
 
175
 
 
176
    logprintf ("playlist: got selection, pos=%d\n", pos);
 
177
 
 
178
    if (pos<1)
 
179
      return;
 
180
 
 
181
    item = playlist_get_item (pos);
 
182
 
 
183
    if (pos == cur_list_pos)
 
184
      --cur_list_pos; /* we're moving the item being played */
 
185
    else if (pos == cur_list_pos + 1)
 
186
      ++cur_list_pos; /* we're swapping the item with the one being played */
 
187
 
 
188
    /* FIXME: use gtk_list_store_swap () */
 
189
    marked = item_marked_current (&iter);
 
190
    gtk_list_store_remove (GTK_LIST_STORE (pl_store), &iter);
 
191
    playlist_add (item, --pos);
 
192
    if (marked)
 
193
      mark_play_item ();
 
194
 
 
195
    snprintf (str, 20, "%d", pos);
 
196
    path = gtk_tree_path_new_from_string  (str);
 
197
    gtk_tree_selection_select_path (sel, path);
 
198
    gtk_tree_path_free (path);
 
199
 
 
200
  } else
 
201
    logprintf ("playlist: got no selection\n");
 
202
}
 
203
 
 
204
static void down_cb (GtkWidget* widget, gpointer data) {
 
205
 
 
206
  GtkTreeIter        iter;  
 
207
  GtkTreeSelection  *sel;
 
208
 
 
209
  sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
 
210
 
 
211
  if (gtk_tree_selection_get_selected (sel, NULL, &iter)) {
 
212
    gint        *indices;
 
213
    GtkTreePath *path;
 
214
    int          pos;
 
215
    play_item_t *item;
 
216
    char         str[20];
 
217
    int          marked;
 
218
 
 
219
    path = gtk_tree_model_get_path (GTK_TREE_MODEL (pl_store), &iter);
 
220
    indices = gtk_tree_path_get_indices (path);
 
221
    pos = indices[0];
 
222
    gtk_tree_path_free (path);
 
223
 
 
224
    logprintf ("playlist: got selection, pos=%d\n", pos);
 
225
 
 
226
    if (pos>=(playlist_size()-1))
 
227
      return;
 
228
 
 
229
    item = playlist_get_item (pos);
 
230
 
 
231
    if (pos == cur_list_pos)
 
232
      ++cur_list_pos; /* we're moving the item being played */
 
233
    else if (pos == cur_list_pos - 1)
 
234
      --cur_list_pos; /* we're swapping the item with the one being played */
 
235
 
 
236
    /* FIXME: use gtk_list_store_swap () */
 
237
    marked = item_marked_current (&iter);
 
238
    gtk_list_store_remove (GTK_LIST_STORE (pl_store), &iter);
 
239
    playlist_add (item, ++pos);
 
240
    if (marked)
 
241
      mark_play_item ();
 
242
 
 
243
    snprintf (str, 20, "%d", pos);
 
244
    path = gtk_tree_path_new_from_string  (str);
 
245
    gtk_tree_selection_select_path (sel, path);
 
246
    gtk_tree_path_free (path);
 
247
 
 
248
  } else
 
249
    logprintf ("playlist: got no selection\n");
 
250
}
 
251
 
124
252
static void edit_cb (GtkWidget* widget, gpointer data) {
125
253
 
126
254
  GtkTreeView       *tree = (GtkTreeView *) data;
132
260
  if (gtk_tree_selection_get_selected (sel, NULL, &iter)) {
133
261
    GValue       v;
134
262
    play_item_t *play_item;
 
263
    const char  *title;
135
264
 
136
265
    memset (&v, 0, sizeof (GValue));
137
 
    gtk_tree_model_get_value (GTK_TREE_MODEL (pl_store),
138
 
                              &iter, 2, &v);
 
266
    gtk_tree_model_get_value (GTK_TREE_MODEL (pl_store), &iter, 2, &v);
139
267
    play_item = g_value_peek_pointer (&v);
140
 
      
141
 
    play_item_edit (play_item);
142
 
 
143
 
    gtk_list_store_set (pl_store, &iter, 
144
 
                        0, play_item->title, 
145
 
                        1, play_item->mrl, 2, play_item, -1);
 
268
 
 
269
    title = item_marked_current (&iter)
 
270
            ? xine_get_meta_info (stream, XINE_META_INFO_TITLE) : NULL;
 
271
 
 
272
    if (play_item_edit (play_item, PLAY_ITEM_LIST, title))
 
273
      gtk_list_store_set (pl_store, &iter,
 
274
                          0, play_item->title,
 
275
                          1, play_item->mrl, 2, play_item, -1);
146
276
 
147
277
    g_value_unset (&v);
148
278
  }
155
285
  if (!fname)
156
286
    fname = g_strconcat(g_get_home_dir(), "/.gxine/playlist", NULL);
157
287
 
158
 
  plfile = read_entire_file_ascii (fname);
 
288
  plfile = read_entire_file (fname, NULL);
159
289
 
160
290
  if (plfile) {
161
291
 
181
311
            gtk_list_store_append (pl_store, &iter);
182
312
 
183
313
            gtk_list_store_set (pl_store, &iter, 0, play_item->title, 1, 
184
 
                                play_item->mrl, 2, play_item, -1);
 
314
                                play_item->mrl, 2, play_item, 3, "", -1);
185
315
          }
186
316
 
187
317
          node = node->next;
188
318
        }
189
319
      } else {
190
 
        display_error ("Playlist load failed",
191
 
                       "Loading of playlist file failed:\n"
192
 
                       "%s is not an asx file", fname);
 
320
        display_error (_("Playlist load failed"),
 
321
                       _("Loading of playlist file failed:\n"
 
322
                       "%s is not an ASX file"), fname);
193
323
        return 0;
194
324
      }
195
325
    } else {
196
 
      display_error ("Playlist load failed",
197
 
                     "Loading of playlist file failed:\n"
198
 
                     "%s is not a valid xml/asx file", fname);
 
326
      display_error (_("Playlist load failed"),
 
327
                     _("Loading of playlist file failed:\n"
 
328
                     "%s is not a valid XML/ASX file"), fname);
199
329
      return 0;
200
330
    }
201
331
 
202
332
  } else {
203
 
    display_error ("Playlist load failed",
204
 
                   "Loading of playlist file failed:\n"
205
 
                   "Failed to open file '%s'", fname);
 
333
    if (errno != ENOENT)
 
334
      display_error (_("Playlist load failed"),
 
335
                     _("Loading of playlist file failed:\n"
 
336
                     "Failed to open file '%s'\n%s"), fname, strerror (errno));
206
337
    return 0;
207
338
  }
208
339
  return 1;
241
372
    }
242
373
 
243
374
    fprintf (f, "</ASX>\n");
244
 
    fclose (f);
 
375
    if (ferror (f))
 
376
      printf (_("playlist: save failed: %s\n"), strerror (errno));
 
377
    if (fclose (f))
 
378
      printf (_("playlist: save failed: %s\n"), strerror (errno));
245
379
  } else {
246
 
    printf ("playlist: save failed!\n");
 
380
    printf (_("playlist: save failed: %s\n"), strerror (errno));
247
381
  }
248
382
}
249
383
 
251
385
 
252
386
  char *filename;
253
387
 
254
 
  filename = modal_file_dialog ("select playlist...", "*.asx");
 
388
  filename = modal_file_dialog (_("Select playlist..."), "*.asx");
255
389
 
256
390
  if (!filename)
257
391
    return;
264
398
 
265
399
  char *filename;
266
400
 
267
 
  filename = modal_file_dialog ("save playlist as...", "*.asx");
 
401
  filename = modal_file_dialog (_("Save playlist as..."), "*.asx");
268
402
 
269
403
  if (!filename)
270
404
    return;
355
489
  return retval;
356
490
}
357
491
 
358
 
static int playlist_load_m3u (const char *mrl) {
 
492
static int playlist_load_m3u (const char *mrl, gint ins_pos) {
359
493
  gboolean  retval = FALSE;
360
494
  char     *contents, **lines;
361
495
  int       size, i, first;
365
499
  first = -1;
366
500
 
367
501
  if (! (contents = read_entire_file (mrl, &size)) )
368
 
    return FALSE;
 
502
    return -1;
369
503
 
370
504
  lines = g_strsplit (contents, "\n", 0);
371
505
  g_free (contents);
372
506
 
373
507
  for (i = 0; lines[i] != NULL; ++i) {
 
508
    remove_trailing_cr (lines[i]);
374
509
    /* Either it's a URI, or it has a proper path */
375
510
    if (strstr(lines[i], "://") != NULL
376
511
        || lines[i][0] == G_DIR_SEPARATOR)  {
383
518
      }
384
519
 
385
520
      if (first >= 0) {
386
 
          playlist_add_mrl (g_strconcat(lines[i],suffix,NULL));
 
521
        playlist_add_mrl (g_strconcat(lines[i],suffix,NULL), ins_pos);
387
522
      }
388
523
      else {
389
 
          first = playlist_add_mrl (g_strconcat(lines[i],suffix,NULL));
 
524
        first = playlist_add_mrl (g_strconcat(lines[i],suffix,NULL), ins_pos);
390
525
      }
391
526
 
392
527
      retval = TRUE;
401
536
    return -1;
402
537
}
403
538
 
404
 
static int playlist_load_smil (const char *mrl) {
 
539
static int playlist_load_smil (const char *mrl, gint ins_pos) {
405
540
  gboolean  retval = FALSE;
406
541
  char     *contents, **lines;
407
542
  int       size, i, first;
410
545
  first = -1;
411
546
 
412
547
  if (! (contents = read_entire_file (mrl, &size)) )
413
 
    return FALSE;
 
548
    return -1;
414
549
 
415
550
  lines = g_strsplit (contents, "\n", 0);
416
551
  g_free (contents);
424
559
      if (!end) end=strchr(begin, '\'');
425
560
      if (!end) return -1;
426
561
      *end=0;
427
 
#ifdef LOG
428
 
      printf("playlist: got '%s'\n", begin);
429
 
#endif
 
562
      logprintf("playlist: got '%s'\n", begin);
430
563
      if (first >= 0) {
431
 
          playlist_add_mrl (begin);
 
564
        playlist_add_mrl (begin, ins_pos);
432
565
      }
433
566
      else {
434
 
          first = playlist_add_mrl (begin);
 
567
        first = playlist_add_mrl (begin, ins_pos);
435
568
      }
436
569
 
437
570
      retval = TRUE;
443
576
      if (!end) end=strchr(begin, '\'');
444
577
      if (!end) return -1;
445
578
      *end=0;
446
 
#ifdef LOG
447
 
      printf ("playlist: got '%s'\n", begin);
448
 
#endif
 
579
      logprintf ("playlist: got '%s'\n", begin);
449
580
      if (first >= 0) {
450
 
          playlist_add_mrl (begin);
 
581
        playlist_add_mrl (begin, ins_pos);
451
582
      }
452
583
      else {
453
 
          first = playlist_add_mrl (begin);
 
584
        first = playlist_add_mrl (begin, ins_pos);
454
585
      }
455
586
 
456
587
      retval = TRUE;
466
597
    return -1;
467
598
}
468
599
 
469
 
int playlist_add (play_item_t *play_item) {
 
600
int playlist_add (play_item_t *play_item, gint ins_pos) {
470
601
 
471
602
  GtkTreeIter  iter;
472
603
  GtkTreePath *path;
473
604
  gint        *indices;
474
605
  gint         ret;
475
606
 
476
 
  gtk_list_store_append (pl_store, &iter);
 
607
  if (ins_pos<0)
 
608
    gtk_list_store_append (pl_store, &iter);
 
609
  else
 
610
    gtk_list_store_insert (pl_store, &iter, ins_pos);
 
611
    
477
612
  gtk_list_store_set (pl_store, &iter, 0, play_item->title, 
478
 
                      1, play_item->mrl, 2, play_item, -1);
 
613
                      1, play_item->mrl, 2, play_item, 3, "", -1);
479
614
 
480
615
  /*
481
616
   * find out entry number in list
489
624
  return ret;
490
625
}
491
626
 
492
 
void playlist_insert  (play_item_t *play_item, int pos) {
493
 
 
494
 
  GtkTreeIter  iter;
495
 
 
496
 
  gtk_list_store_insert (pl_store, &iter, pos);
497
 
  gtk_list_store_set (pl_store, &iter, 0, play_item->title, 
498
 
                      1, play_item->mrl, 2, play_item, -1);
499
 
}
500
 
 
501
 
 
502
 
static gint playlist_add_int (const char *mrl) {
503
 
 
 
627
static gint playlist_add_int (const char *mrl, gint ins_pos)
 
628
{
504
629
  play_item_t *play_item;
505
 
 
506
 
  play_item = play_item_new (mrl, mrl, 0);
507
 
 
508
 
  return playlist_add (play_item);
 
630
  const char *title;
 
631
  char *retitle = NULL;
 
632
  int i;
 
633
 
 
634
  /* don't add duplicate items */
 
635
  if (ins_pos < 0)
 
636
    for (i = 0; i < playlist_size (); ++i)
 
637
      if (!strcmp (playlist_get_item (i)->mrl, mrl))
 
638
        return i;
 
639
 
 
640
  /* find the leafname of the MRL */
 
641
  title = strrchr (mrl, '/');
 
642
  if (title && !title[1]) /* ends in '/' - look for preceding '/' */
 
643
  {
 
644
    while (*title == '/')
 
645
      if (--title == mrl)
 
646
        break;
 
647
    while (*title != '/')
 
648
      if (--title < mrl)
 
649
        break;
 
650
  }
 
651
 
 
652
  /* at this point, title >= mrl - 1, but mrl[-1] is invalid - this is OK
 
653
   * in the case where title == mrl - 1, we use the full MRL as the title
 
654
   */
 
655
 
 
656
  if (title >= mrl && title[1])
 
657
  {
 
658
    int j;
 
659
    char *dot;
 
660
 
 
661
    /* URL-decode the leafname */
 
662
    title = retitle = strdup (title + 1);
 
663
    j = i = -1;
 
664
    while (title[++i])
 
665
    {
 
666
      if (title[i] == '%')
 
667
      {
 
668
        char c[3] = { title[i+1], title[i+2], 0 };
 
669
        i += 2;
 
670
        retitle[++j] = (char) strtol (c, NULL, 16);
 
671
      }
 
672
      else
 
673
        retitle[++j] = title[i];
 
674
    }
 
675
    /* NUL-terminate, strip trailing / */
 
676
    retitle[j + (retitle[j] != '/')] = 0;
 
677
 
 
678
    /* Strip the extension (if present) */
 
679
    dot = strrchr (retitle, '.');
 
680
    if (dot)
 
681
      *dot = 0;
 
682
  }
 
683
  else
 
684
    title = mrl;
 
685
 
 
686
  play_item = play_item_new (title, mrl, 0);
 
687
  free (retitle);
 
688
 
 
689
  return playlist_add (play_item, ins_pos);
509
690
}
510
691
 
511
 
static int playlist_load_ram (const char *mrl) {
 
692
static int playlist_load_ram (const char *mrl, gint ins_pos) {
512
693
  gboolean  retval = FALSE;
513
694
  char      contents[1024], mime_type[256], **lines;
514
695
  char      *contents_ptr;
515
696
  int       size, i, first;
516
 
#if 0 /* FIXME: remove ? */
517
 
  char     *extension;
518
 
  char     *suffix;
519
 
#endif
520
697
  int       fd;
521
698
  int       pos; 
522
699
 
551
728
    /* this is a real media file ... */
552
729
    /* add it directly to the playlist. */
553
730
 
554
 
    pos = playlist_add_int (mrl);
 
731
    pos = playlist_add_int (mrl, ins_pos);
555
732
 
556
733
    return pos;
557
734
  }
558
735
    
559
736
  if (! (contents_ptr = read_entire_file (mrl, &size)) )
560
 
    return FALSE;
 
737
    return -1;
561
738
 
562
739
  lines = g_strsplit (contents_ptr, "\n", 0);
563
740
  g_free (contents_ptr);
575
752
        || strstr(lines[i], "pnm://") != NULL
576
753
        || strstr(lines[i], "http://") != NULL)  {
577
754
      /* we assume real media */
578
 
      
579
 
      /* delete \r at the end */
580
 
      contents_ptr=strchr(lines[i],'\r');
581
 
      if (contents_ptr) *contents_ptr=0;
 
755
 
 
756
      remove_trailing_cr (lines[i]);
582
757
 
583
758
      if (first >= 0) {
584
 
        playlist_add_mrl (lines[i]);
 
759
        playlist_add_mrl (lines[i], ins_pos);
585
760
      }
586
761
      else {
587
 
        first = playlist_add_mrl (lines[i]);
 
762
        first = playlist_add_mrl (lines[i], ins_pos);
588
763
      }
589
764
      retval = TRUE;
590
765
    }
599
774
    return -1;
600
775
}
601
776
 
602
 
static int playlist_load_pls (const char *mrl) {
 
777
static int playlist_load_pls (const char *mrl, gint ins_pos) {
603
778
 
604
779
  gboolean  retval = FALSE;
605
780
  char     *contents=NULL, **lines;
616
791
    if (!strcmp(mime_type, "audio/mpeg")) {
617
792
      /* add directly to playlist */
618
793
 
619
 
      return playlist_add_int (mrl);
 
794
      return playlist_add_int (mrl, ins_pos);
620
795
    }
621
796
 
622
797
    if (! (contents = http_download (mrl, &size)))
623
 
      return FALSE;
 
798
      return -1;
624
799
  } else {
625
800
 
626
801
    if (! (contents = read_entire_file (mrl, &size)) )
627
 
      return FALSE;
 
802
      return -1;
628
803
  }
629
804
 
630
805
  lines = g_strsplit (contents, "\n", 0);
662
837
        pos --;
663
838
      }
664
839
 
665
 
      return playlist_add_mrl (file);
 
840
      return playlist_add_mrl (file, ins_pos);
666
841
 
667
842
      g_free (file);
668
843
      g_free (title);
677
852
  return retval;
678
853
}
679
854
 
680
 
static int playlist_load_asx (const char *mrl) {
 
855
static int playlist_load_asx (const char *mrl, gint ins_pos) {
681
856
 
682
857
  char             *contents;
683
858
  char            **lines;
705
880
    for (i = 0; lines[i] != NULL; ++i) {
706
881
      /* look for mms:// in a line */
707
882
      if (strstr(lines[i], "mms://"))  {
708
 
        /* delete \r at the end */
709
 
        contents=strchr(lines[i],'\r');
710
 
        if (contents) *contents=0;
 
883
        remove_trailing_cr (lines[i]);
711
884
        /* add to playlist */
712
885
        if (ret >= 0)
713
 
          playlist_add_mrl (strstr(lines[i], "mms://"));
 
886
          playlist_add_mrl (strstr(lines[i], "mms://"), ins_pos);
714
887
        else
715
 
          ret = playlist_add_mrl (strstr(lines[i], "mms://"));
 
888
          ret = playlist_add_mrl (strstr(lines[i], "mms://"), ins_pos);
716
889
      }
717
890
    }
718
891
    return ret;
720
893
 
721
894
  /* check ASX */
722
895
  if (strcmp(xml_tree->name, "ASX") == 0) {
723
 
#ifdef LOG
724
 
    printf("playlist: ASX tag detected\n");
725
 
#endif
 
896
    logprintf("playlist: ASX tag detected\n");
726
897
 
727
898
    /* check version */
728
899
    asx_version = xml_parser_get_property_int (xml_tree, "VERSION", 3);
729
900
 
730
901
    if (asx_version == 3) {
731
902
 
732
 
#ifdef LOG
733
 
      printf("playlist: VERSION 3.0 detected\n");
734
 
#endif
 
903
      logprintf("playlist: VERSION 3.0 detected\n");
735
904
 
736
905
      /* play each entry */
737
906
      current_node_l1 = xml_tree->child;
738
907
      while (current_node_l1) {
739
908
        /* entry */
740
909
        if (strcmp(current_node_l1->name, "ENTRY") == 0) {
741
 
          char *title;
742
 
          
743
 
          title = NULL;
744
 
          
745
 
#ifdef LOG
746
 
          printf("playlist: ENTRY detected\n");
747
 
#endif
748
 
          
 
910
          char *title = NULL;
 
911
 
 
912
          logprintf("playlist: ENTRY detected\n");
 
913
 
749
914
          /* play the first ref which is playable */
750
915
          current_node_l2 = current_node_l1->child;
751
916
          while (current_node_l2) {
752
917
            if (strcmp(current_node_l2->name, "REF") == 0) {
753
 
#ifdef LOG
754
 
              printf("playlist: REF detected\n");
755
 
#endif
 
918
              logprintf("playlist: REF detected\n");
756
919
              /* find href property */
757
920
              property = current_node_l2->props;
758
921
              while ((property) && (strcmp(property->name, "HREF"))) {
760
923
              }
761
924
              if (property) {
762
925
                play_item_t *item;
763
 
                
764
 
#ifdef LOG
765
 
                printf("playlist: HREF property detected\n");
766
 
                
767
 
                printf ("playlist: found an mrl: %s\n",
768
 
                        property->value);
769
 
#endif
 
926
 
 
927
                logprintf("playlist: HREF property detected\n"
 
928
                          "playlist: found an mrl: %s\n", property->value);
 
929
 
770
930
                if (title)
771
931
                  item = play_item_new (title, property->value, 0);
772
932
                else
774
934
                
775
935
                
776
936
                if (ret >= 0)
777
 
                  playlist_add (item);
 
937
                  playlist_add (item, ins_pos);
778
938
                else
779
 
                  ret = playlist_add (item);
 
939
                  ret = playlist_add (item, ins_pos);
780
940
                
781
941
                /* jump to next entry */
782
942
                current_node_l2 = NULL;
795
955
#endif
796
956
                
797
957
              } else {
798
 
                printf("playlist: no HREF property\n");
 
958
                printf(_("playlist: no HREF property\n"));
799
959
              } /* if (property) */
800
960
              
801
961
            } else if (strcmp(current_node_l2->name, "TITLE") == 0) {
802
962
              title = current_node_l2->data;
803
963
            } else {
804
 
#ifdef LOG
805
 
              printf("playlist: unknown tag %s detected\n", 
806
 
                     current_node_l2->name);
807
 
#endif
 
964
              logprintf("playlist: unknown tag %s detected\n", 
 
965
                        current_node_l2->name);
808
966
            } /* end if (strcmp(current_node_l2->name, "REF") == 0) */
809
967
            if (current_node_l2) {
810
968
              current_node_l2 = current_node_l2->next;
814
972
          
815
973
          /* entryref */
816
974
          if (strcmp(current_node_l1->name, "ENTRYREF") == 0) {
817
 
#ifdef LOG
818
 
            printf("playlist: ENTRYREF detected\n");
819
 
#endif
 
975
            logprintf("playlist: ENTRYREF detected\n");
820
976
            property = current_node_l1->props;
821
977
            while ((property) && (strcmp(property->name, "HREF"))) {
822
978
              property = property->next;
823
979
            }
824
980
            if (property) {
825
 
#ifdef LOG
826
 
              printf("playlist: HREF property detected\n");
827
 
              
828
 
              printf ("playlist: found an mrl: %s\n",
829
 
                      property->value);
830
 
#endif
831
 
              
 
981
              logprintf ("playlist: HREF property detected\n"
 
982
                         "playlist: found an MRL: %s\n", property->value);
 
983
 
832
984
              if (ret >= 0)
833
 
                playlist_add_mrl (property->value);
 
985
                playlist_add_mrl (property->value, ins_pos);
834
986
              else
835
 
                ret = playlist_add_mrl (property->value);
 
987
                ret = playlist_add_mrl (property->value, ins_pos); 
836
988
              
837
989
              /* jump to next entry */
838
990
              current_node_l2 = NULL;
850
1002
              }
851
1003
#endif
852
1004
            } else {
853
 
              printf("playlist: no HREF property\n");
 
1005
              printf(_("playlist: no HREF property\n"));
854
1006
            } /* if (property) */
855
1007
          } else {
856
1008
            
857
1009
            /* title */
858
1010
            if (strcmp(current_node_l1->name, "TITLE") == 0) {
859
 
#ifdef LOG
860
 
              printf("playlist: TITLE detected\n");
861
 
#endif
 
1011
              logprintf("playlist: TITLE detected\n");
862
1012
              /* change title */
863
1013
            } else {
864
 
              printf("playlist: unknown tag %s detected\n", 
 
1014
              printf(_("playlist: unknown tag %s detected\n"),
865
1015
                     current_node_l1->name);
866
1016
            }
867
1017
          }
870
1020
      }
871
1021
      
872
1022
    } else {
873
 
      printf("playlist: sorry, asx version %d not implemented yet\n",
 
1023
      printf(_("playlist: sorry, ASX version %d not implemented yet\n"),
874
1024
             asx_version);
875
1025
    }
876
1026
  } else {
877
 
    printf("playlist: no ASX tag\n");
 
1027
    printf(_("playlist: no ASX tag\n"));
878
1028
  }
879
 
 
880
 
 
881
1029
  return ret;
882
1030
}
883
1031
 
884
 
int playlist_add_mrl (const char *mrl) {
885
 
 
886
 
  /* printf ("playlist_add called >%s<\n", mrl); */
 
1032
static int playlist_add_playlist_mrl (const char *mrl, gint ins_pos)
 
1033
{
 
1034
  const char *extension = strrchr(mrl, '.');
 
1035
  if (extension)
 
1036
  {
 
1037
    if (!strncasecmp (extension, ".pls", 4))
 
1038
      return playlist_load_pls (mrl, ins_pos);
 
1039
 
 
1040
    if (!strncasecmp (extension, ".m3u", 4))
 
1041
      return playlist_load_m3u (mrl, ins_pos);
 
1042
 
 
1043
    if (!strcasecmp (extension, ".ra") ||
 
1044
        !strcasecmp (extension, ".rm") ||
 
1045
        !strncasecmp (extension, ".ram", 4) ||
 
1046
        !strncasecmp (extension, ".rpm", 4) ||
 
1047
        !strncasecmp (extension, ".lsc", 4) ||
 
1048
        !strncasecmp (extension, ".pl", 3))
 
1049
      return playlist_load_ram (mrl, ins_pos);
 
1050
 
 
1051
    if (!strncasecmp (extension, ".asx", 4))
 
1052
      return playlist_load_asx (mrl, ins_pos);
 
1053
 
 
1054
    if (!strncasecmp (extension, ".smi", 4))
 
1055
      return playlist_load_smil (mrl, ins_pos);
 
1056
  }
 
1057
 
 
1058
  return -2; /* not recognised */
 
1059
}
 
1060
 
 
1061
static int playlist_add_mrl_internal (const char *mrl, gint ins_pos)
 
1062
{
 
1063
  /* Helper function. Call only from playlist_add_mrl(). */
 
1064
  int ret;
887
1065
 
888
1066
  /*
889
1067
   * is this mrl in fact a simple filename?
891
1069
 
892
1070
  if ( !strstr (mrl, ":/") ) {
893
1071
 
894
 
    char *extension;
895
 
 
896
1072
    /* is it a playlist file? */
897
 
 
898
 
    extension = strrchr(mrl, '.');
899
 
 
900
 
    if (extension && !strncasecmp (extension, ".pls", 4)) {
901
 
 
902
 
      return playlist_load_pls (mrl);
903
 
 
904
 
    } else if (extension && !strncasecmp (extension, ".m3u", 4)) {
905
 
 
906
 
      return playlist_load_m3u (mrl);
907
 
 
908
 
    } else if (extension && !strncasecmp (extension, ".ra", 4)) {
909
 
 
910
 
      return playlist_load_ram (mrl);
911
 
 
912
 
    } else if (extension && !strncasecmp (extension, ".rm", 4)) {
913
 
 
914
 
      return playlist_load_ram (mrl);
915
 
 
916
 
    } else if (extension && !strncasecmp (extension, ".ram", 4)) {
917
 
 
918
 
      return playlist_load_ram (mrl);
919
 
 
920
 
    } else if (extension && !strncasecmp (extension, ".rpm", 4)) {
921
 
 
922
 
      return playlist_load_ram (mrl);
923
 
 
924
 
    } else if (extension && !strncasecmp (extension, ".lsc", 4)) {
925
 
 
926
 
      return playlist_load_ram (mrl);
927
 
 
928
 
    } else if (extension && !strncasecmp (extension, ".pl", 3)) {
929
 
 
930
 
      return playlist_load_ram (mrl);
931
 
 
932
 
    } else if (extension && !strncasecmp (extension, ".asx", 4)) {
933
 
 
934
 
      return playlist_load_asx (mrl);
935
 
 
936
 
    } else if (extension && !strncasecmp (extension, ".smi", 4)) {
937
 
 
938
 
      return playlist_load_smil (mrl);
939
 
 
940
 
    } else if (!strncmp (mrl, "cdda:", 5)) {
941
 
 
942
 
      return playlist_add_int (strdup(mrl));
943
 
 
944
 
    } else if (mrl[0]!='/') {
 
1073
    ret = playlist_add_playlist_mrl (mrl, ins_pos);
 
1074
    if (ret != -2)
 
1075
      return ret;
 
1076
 
 
1077
    if (!strncasecmp (mrl, "cdda:", 5))
 
1078
      return playlist_add_int (mrl, ins_pos);
 
1079
 
 
1080
    if (mrl[0]!='/') {
945
1081
 
946
1082
      /* make filename an absolute pathname */
947
1083
 
948
 
      char  buf[1024];
 
1084
      char  buf[PATH_MAX];
949
1085
      char *pathname;
950
1086
      int   l1, l2;
951
1087
 
952
 
      getcwd (buf, 1024);
 
1088
      getcwd (buf, sizeof (buf));
953
1089
 
954
1090
      l1 = strlen(buf);
955
1091
      l2 = strlen(mrl);
960
1096
      memcpy (&pathname[l1+1], mrl, l2);
961
1097
      pathname[l1+l2+1]=0;
962
1098
 
963
 
      return playlist_add_int (pathname);
964
 
 
965
 
    } else
966
 
      return playlist_add_int (strdup(mrl));
967
 
 
968
 
 
969
 
  } else if (!strncasecmp (mrl, "http://", 7)) {
970
 
 
 
1099
      return playlist_add_int (pathname, ins_pos);
 
1100
    }
 
1101
 
 
1102
    return playlist_add_int (mrl, ins_pos);
 
1103
  }
 
1104
 
 
1105
  if (!strncasecmp (mrl, "http://", 7)) {
971
1106
    /*
972
1107
     * could still be a pls/asx playlist, but if so we
973
1108
     * need to download it first
974
1109
     */
975
1110
 
976
 
    char *extension;
977
 
 
978
1111
    /* is it a playlist file? */
979
 
 
980
 
    extension = strrchr(mrl, '.');
981
 
 
982
 
    if (extension && !strncasecmp (extension, ".pls", 4)) {
983
 
 
984
 
      return playlist_load_pls (mrl);
985
 
 
986
 
    } else if (extension && !strncasecmp (extension, ".m3u", 4)) {
987
 
 
988
 
      return playlist_load_m3u (mrl);
989
 
 
990
 
    } else if (extension && !strncasecmp (extension, ".ra", 4)) {
991
 
 
992
 
      return playlist_load_ram (mrl);
993
 
 
994
 
    } else if (extension && !strncasecmp (extension, ".rm", 4)) {
995
 
 
996
 
      return playlist_load_ram (mrl);
997
 
 
998
 
    } else if (extension && !strncasecmp (extension, ".ram", 4)) {
999
 
 
1000
 
      return playlist_load_ram (mrl);
1001
 
 
1002
 
    } else if (extension && !strncasecmp (extension, ".rpm", 4)) {
1003
 
 
1004
 
      return playlist_load_ram (mrl);
1005
 
 
1006
 
    } else if (extension && !strncasecmp (extension, ".lsc", 4)) {
1007
 
 
1008
 
      return playlist_load_ram (mrl);
1009
 
 
1010
 
    } else if (extension && !strncasecmp (extension, ".pl", 3)) {
1011
 
 
1012
 
      return playlist_load_ram (mrl);
1013
 
 
1014
 
    } else if (extension && !strncasecmp (extension, ".asx", 4)) {
1015
 
 
1016
 
      return playlist_load_asx (mrl);
1017
 
 
1018
 
    } else if (extension && !strncasecmp (extension, ".smi", 4)) {
1019
 
 
1020
 
      return playlist_load_smil (mrl);
1021
 
 
1022
 
    } else
1023
 
      return playlist_add_int (strdup(mrl));
1024
 
 
1025
 
  } else if (!strncasecmp (mrl, "mmshttp://", 10)) {
1026
 
 
1027
 
#ifdef LOG
1028
 
    printf ("playlist: adding regular asx from mmshttp %s\n", mrl);
1029
 
#endif
1030
 
 
1031
 
    return playlist_load_asx (&mrl[3]);
1032
 
 
1033
 
  } else {
1034
 
#ifdef LOG
1035
 
    printf ("playlist: adding regular mrl %s\n", mrl);
1036
 
#endif
1037
 
    return playlist_add_int (strdup(mrl));
1038
 
  }
1039
 
 
1040
 
#ifdef LOG
1041
 
  printf ("playlist: help, how did i get here? \n");
1042
 
#endif
1043
 
  
1044
 
  return 0;
1045
 
}
1046
 
 
1047
 
static void show_metadata () {
1048
 
 
1049
 
  char  title[2048];
1050
 
  const char *t;
1051
 
 
1052
 
  if ( (t=gtk_xine_get_meta_info (GTK_XINE(gtx), XINE_META_INFO_TITLE)) ) {
1053
 
    const char *a;
1054
 
 
1055
 
    if ( (a=gtk_xine_get_meta_info (GTK_XINE(gtx), XINE_META_INFO_ARTIST)) ) {
1056
 
      snprintf (title, 2048, "%s (%s) - gxine %s", t, a, VERSION);
1057
 
      infobar_line1 (bar, "%s (%s)", t, a);
1058
 
    } else {
1059
 
      snprintf (title, 2048, "%s - gxine %s", t, VERSION);
1060
 
      infobar_line1 (bar, "%s", t);
1061
 
    }
1062
 
  } else {
1063
 
    if (strlen (cur_mrl) > 0) {
1064
 
 
1065
 
      char *str = strrchr (cur_mrl, '/');
1066
 
 
1067
 
      if (str) {
1068
 
        snprintf (title, 2048, "%s - gxine %s", str+1, VERSION);
1069
 
        infobar_line1 (bar, "%s", str+1);
1070
 
      } else {
1071
 
        snprintf (title, 2048, "%s - gxine %s", cur_mrl, VERSION);
1072
 
        infobar_line1 (bar, "%s", cur_mrl);
1073
 
      }
1074
 
    } else {
1075
 
      snprintf (title, 2048, "gxine %s", VERSION);
1076
 
      infobar_line1 (bar, "%s", title);
1077
 
    }
1078
 
  }
1079
 
  normalize_to_ascii (title);
1080
 
  gtk_window_set_title (GTK_WINDOW (app), title);
1081
 
 
1082
 
  /*
1083
 
   * display some metainfo
1084
 
   */
1085
 
 
1086
 
  if (gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_HAS_AUDIO)
1087
 
      && gtk_xine_get_meta_info (GTK_XINE(gtx), XINE_META_INFO_VIDEOCODEC)
1088
 
      && gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_HAS_VIDEO)
1089
 
      && gtk_xine_get_meta_info (GTK_XINE(gtx), XINE_META_INFO_AUDIOCODEC))
1090
 
    infobar_line2 (bar, "%d kBit/s %s, %dx%d %s, %d kHz %d kBit/s %s",
1091
 
                   gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_BITRATE)/1000,
1092
 
                   gtk_xine_get_meta_info   (GTK_XINE(gtx), XINE_META_INFO_SYSTEMLAYER),
1093
 
                   gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_VIDEO_WIDTH),
1094
 
                   gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_VIDEO_HEIGHT),
1095
 
                   gtk_xine_get_meta_info   (GTK_XINE(gtx), XINE_META_INFO_VIDEOCODEC),
1096
 
                   gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_AUDIO_SAMPLERATE)/1000,
1097
 
                   gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_AUDIO_BITRATE)/1000,
1098
 
                   gtk_xine_get_meta_info   (GTK_XINE(gtx), XINE_META_INFO_AUDIOCODEC));
1099
 
  else if (gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_HAS_AUDIO)
1100
 
           && gtk_xine_get_meta_info (GTK_XINE(gtx), XINE_META_INFO_AUDIOCODEC))
1101
 
    infobar_line2 (bar, "%s, %d kHz %d kBit/s %s",
1102
 
                   gtk_xine_get_meta_info   (GTK_XINE(gtx), XINE_META_INFO_SYSTEMLAYER),
1103
 
                   gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_AUDIO_SAMPLERATE)/1000,
1104
 
                   gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_AUDIO_BITRATE)/1000,
1105
 
                   gtk_xine_get_meta_info   (GTK_XINE(gtx), XINE_META_INFO_AUDIOCODEC));
1106
 
  else if (gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_HAS_VIDEO)
1107
 
           && gtk_xine_get_meta_info (GTK_XINE(gtx), XINE_META_INFO_VIDEOCODEC))
1108
 
    infobar_line2 (bar, "%s, %dx%d %s",
1109
 
                   gtk_xine_get_meta_info   (GTK_XINE(gtx), XINE_META_INFO_SYSTEMLAYER),
1110
 
                   gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_VIDEO_WIDTH),
1111
 
                   gtk_xine_get_stream_info (GTK_XINE(gtx), XINE_STREAM_INFO_VIDEO_HEIGHT),
1112
 
                   gtk_xine_get_meta_info   (GTK_XINE(gtx), XINE_META_INFO_VIDEOCODEC));
1113
 
 
1114
 
}
1115
 
 
1116
 
static void *play_exec (void *queue_gen) {
1117
 
 
1118
 
  pthread_mutex_lock (&engine_lock);
1119
 
 
1120
 
  gdk_threads_enter();
1121
 
  infobar_line1 (bar, "opening...");
1122
 
  infobar_line2 (bar, "");
1123
 
  gdk_threads_leave();
1124
 
 
1125
 
  if (!gtk_xine_open (GTK_XINE(gtx), cur_mrl)) {
1126
 
 
1127
 
    gdk_threads_enter();
1128
 
    switch (gtk_xine_get_error (GTK_XINE (gtx))) {
1129
 
    case XINE_ERROR_NO_INPUT_PLUGIN:
1130
 
 
1131
 
      display_error ("xine engine error",
1132
 
                     "xine engine failed to start.\n\n"
1133
 
                     "No input plugin found.\n"
1134
 
                     "Maybe the file does not exist, has wrong "
1135
 
                     "permissions or\nurl syntax error");
1136
 
 
1137
 
      break;
1138
 
    case XINE_ERROR_NO_DEMUX_PLUGIN:
1139
 
 
1140
 
      display_error ("xine engine error",
1141
 
                     "xine engine failed to start.\n\n"
1142
 
                     "No demuxer found - stream format not recognized");
1143
 
 
1144
 
      break;
1145
 
 
1146
 
    default:
1147
 
      display_error ("xine engine error",
1148
 
                     "xine engine failed to start.\n\n"
1149
 
                     "unknown error.");
1150
 
    }
1151
 
 
1152
 
    infobar_line1 (bar, "gxine %s", VERSION);
1153
 
    infobar_line2 (bar, "");
1154
 
 
1155
 
    gdk_threads_leave();
1156
 
 
1157
 
    pthread_mutex_unlock (&engine_lock);
1158
 
    pthread_exit (NULL);
1159
 
 
1160
 
    return NULL;
1161
 
  }
1162
 
 
1163
 
  gdk_threads_enter();
1164
 
  if (logo_mode) {
1165
 
    char  title[2048];
1166
 
    sprintf (title, "gxine %s", VERSION);
1167
 
    infobar_line1 (bar, title);
1168
 
    infobar_line2 (bar, "");
1169
 
    gtk_window_set_title (GTK_WINDOW (app), title);
1170
 
  } else
1171
 
    show_metadata ();
1172
 
  gdk_threads_leave();
1173
 
 
1174
 
  gtk_xine_play (GTK_XINE(gtx), goto_pos, goto_time);
1175
 
  goto_pos = 0;
1176
 
  goto_time = 0;
1177
 
 
1178
 
  pthread_mutex_unlock (&engine_lock);
1179
 
 
1180
 
  pthread_exit (NULL);
1181
 
 
1182
 
  return NULL;
1183
 
}
1184
 
 
1185
 
void playlist_play_from (int list_pos, int pos, int pos_time) {
1186
 
 
1187
 
  int          err;
1188
 
  GtkTreePath *path;
1189
 
  char         indices[10];
1190
 
  play_item_t *play_item;
1191
 
  GList       *option;
1192
 
 
1193
 
  logo_mode = 0;
1194
 
 
1195
 
  if (list_pos<0)
1196
 
    list_pos = 0;
1197
 
 
1198
 
  play_item = playlist_get_item (list_pos);
1199
 
 
1200
 
  if (!play_item) {
1201
 
    cur_list_pos = 0;
1202
 
    playlist_logo ();
1203
 
    return;
1204
 
  }
1205
 
 
1206
 
  cur_mrl   = play_item->mrl;
1207
 
  goto_pos  = pos;
1208
 
  goto_time = pos_time;
1209
 
 
1210
 
  snprintf (indices, 10, "%d", list_pos);
1211
 
  path = gtk_tree_path_new_from_string (indices);
1212
 
  gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), 
1213
 
                            path, NULL, FALSE);
1214
 
  gtk_tree_path_free (path);
1215
 
 
1216
 
  cur_list_pos  = list_pos;
1217
 
 
1218
 
  /*
1219
 
   * execute any optional commands which may be associated with this play item
1220
 
   * (e.g. set volume etc.)
1221
 
   */
1222
 
 
1223
 
  option = play_item->options;
1224
 
 
1225
 
  while (option) {
1226
 
 
1227
 
    char *cmd = (char *) option->data;
1228
 
 
1229
 
    action_exec (cmd, NULL, NULL);
1230
 
 
1231
 
    option = g_list_next (option);
1232
 
  }
1233
 
 
1234
 
  /*
1235
 
   * start seperate thread, so xine_open will not block ui
1236
 
   */
1237
 
 
1238
 
  if ((err = pthread_create (&play_thread,
1239
 
                             NULL, play_exec, NULL)) != 0) {
1240
 
    printf ("playlist: can't create new thread (%s)\n",
1241
 
            strerror(err));
1242
 
    abort();
1243
 
  }
1244
 
 
1245
 
  pthread_detach (play_thread);
 
1112
    ret = playlist_add_playlist_mrl (mrl, ins_pos);
 
1113
    if (ret != -2)
 
1114
      return ret;
 
1115
 
 
1116
    return playlist_add_int (mrl, ins_pos);
 
1117
  }
 
1118
 
 
1119
  if (!strncasecmp (mrl, "mmshttp://", 10)) {
 
1120
    logprintf ("playlist: adding regular ASX from mmshttp %s\n", mrl);
 
1121
    return playlist_load_asx (&mrl[3], ins_pos);
 
1122
  }
 
1123
 
 
1124
  logprintf ("playlist: adding regular mrl %s\n", mrl);
 
1125
  return playlist_add_int (mrl, ins_pos);
 
1126
}
 
1127
 
 
1128
int playlist_add_mrl (const char *mrl, gint ins_pos /* -1 => append */)
 
1129
{
 
1130
  static GSList *queued = NULL;
 
1131
  int ret;
 
1132
 
 
1133
  /* printf ("playlist_add called >%s<\n", mrl); */
 
1134
 
 
1135
  /* handle recursive playlists */
 
1136
  if (g_slist_find_custom (queued, mrl, (GCompareFunc) strcmp))
 
1137
  {
 
1138
    printf (_("recursion in playlist: %s\n"), mrl);
 
1139
    return 0;
 
1140
  }
 
1141
 
 
1142
  queued = g_slist_prepend (queued, (char *)mrl);
 
1143
  ret = playlist_add_mrl_internal (mrl, ins_pos);
 
1144
  queued = g_slist_remove (queued, mrl);
 
1145
 
 
1146
  return ret;
1246
1147
}
1247
1148
 
1248
1149
void playlist_play (int list_pos) {
1257
1158
    return;
1258
1159
  }  
1259
1160
 
1260
 
  playlist_play_from (list_pos, 0, item->start_time);
 
1161
  playlist_play_from (list_pos, 0, item->start_time); 
1261
1162
}
1262
1163
 
 
1164
static void set_mark_play_item (gboolean state)
 
1165
{
 
1166
  if (cur_list_pos >= 0 && cur_list_pos < playlist_size ())
 
1167
  {
 
1168
    GtkTreeIter iter;
 
1169
    gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (pl_store), &iter, NULL,
 
1170
                                   cur_list_pos);
 
1171
    gtk_list_store_set (pl_store, &iter, 3, state ? "ā€¢" : "", -1);
 
1172
  }
 
1173
}
1263
1174
 
1264
1175
void playlist_logo (void) {
1265
1176
 
1266
 
  int err;
 
1177
  /* int err; */
1267
1178
 
 
1179
  unmark_play_item ();
1268
1180
  logo_mode = 1;
1269
1181
 
1270
 
  cur_mrl = logo_mrl;
1271
 
 
1272
 
  /*
1273
 
   * start seperate thread, so xine_open will not block ui
1274
 
   */
1275
 
 
1276
 
  if ((err = pthread_create (&play_thread,
1277
 
                             NULL, play_exec, NULL)) != 0) {
1278
 
    fprintf (stderr, "events: can't create new thread (%s)\n",
1279
 
             strerror(err));
1280
 
    abort();
1281
 
  }
1282
 
 
1283
 
  pthread_detach (play_thread);
1284
 
 
 
1182
  player_launch (logo_mrl, 0, 0);
1285
1183
}
1286
1184
 
1287
1185
void playlist_show (void) {
1292
1190
  } else {
1293
1191
    is_visible = TRUE;
1294
1192
    gtk_widget_show_all (dlg);
1295
 
    gtk_widget_map (dlg);
 
1193
    gtk_tree_view_columns_autosize (GTK_TREE_VIEW(tree_view));
1296
1194
  }
1297
1195
}
1298
1196
 
 
1197
int playlist_showing_logo (void)
 
1198
{
 
1199
  return logo_mode;
 
1200
}
 
1201
 
1299
1202
static gboolean button_press_lcb (GtkWidget *widget, GdkEventButton *event, 
1300
1203
                                  gpointer data) {
1301
 
 
1302
1204
  if (event && (event->type==GDK_2BUTTON_PRESS)) {
1303
1205
    GtkTreeSelection  *sel;
1304
1206
    GtkTreeIter        iter;  
1337
1239
  is_repeat = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (repeat_button));
1338
1240
  is_random = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_button));
1339
1241
 
 
1242
  unmark_play_item ();
 
1243
 
1340
1244
  if (is_random) {
1341
1245
 
1342
1246
    int count;
1380
1284
    play_item_t *item;
1381
1285
    item = playlist_get_item (cur_list_pos);
1382
1286
    item->played = 1;
1383
 
 
 
1287
    mark_play_item ();
1384
1288
    playlist_play (cur_list_pos);
1385
1289
  } else {
1386
1290
    cur_list_pos = 0;
1411
1315
 
1412
1316
      gdk_threads_enter();
1413
1317
      if (prg->percent>99)
1414
 
        show_metadata ();
 
1318
        infobar_show_metadata ();
1415
1319
      else {
1416
1320
        struct timeval  tv;
1417
1321
        int             age;
1424
1328
          break;
1425
1329
        }
1426
1330
 
1427
 
        infobar_line1 (bar, "%s %d%%", prg->description, prg->percent);
 
1331
        infobar_line (bar, 0, "%s %d%%", prg->description, prg->percent);
1428
1332
      }
1429
1333
      gdk_flush();
1430
1334
      gdk_threads_leave();
1433
1337
  case XINE_EVENT_UI_SET_TITLE:
1434
1338
    {
1435
1339
      gdk_threads_enter();
1436
 
      show_metadata ();
 
1340
      infobar_show_metadata ();
1437
1341
      gdk_flush();
1438
1342
      gdk_threads_leave();
1439
1343
    }
1442
1346
    {
1443
1347
      xine_mrl_reference_data_t *ref = (xine_mrl_reference_data_t *) event->data;
1444
1348
 
1445
 
      printf ("playlist: got an reference event (ref mrl: %s)\n",
 
1349
      logprintf ("playlist: got a reference event (ref MRL: %s)\n",
1446
1350
              ref->mrl);
1447
1351
      
1448
1352
      if (ref->alternative == 0) {
1451
1355
 
1452
1356
        item = play_item_new (ref->mrl, ref->mrl, 0);
1453
1357
 
1454
 
        playlist_insert (item, playlist_get_list_pos()+1);
 
1358
        playlist_add (item, playlist_get_list_pos()+1);
1455
1359
      }
1456
1360
    }
1457
1361
    break;
1458
1362
  case XINE_EVENT_UI_MESSAGE: 
1459
1363
    {
1460
1364
      xine_ui_message_data_t *data = (xine_ui_message_data_t *) event->data;
 
1365
      void (*msg)(const gchar *, const gchar *, ...);
1461
1366
 
1462
1367
      gdk_threads_enter();
1463
1368
 
1464
 
      /* TODO: use all parameters, provide customized messages, hints... */
 
1369
      switch (data->type)
 
1370
      {
 
1371
      default:
 
1372
        puts ("xine_event_cb: unknown XINE_MSG_*");
 
1373
      case XINE_MSG_AUDIO_OUT_UNAVAILABLE:
 
1374
      case XINE_MSG_ENCRYPTED_SOURCE:
 
1375
        msg = display_info;
 
1376
        break;
 
1377
 
 
1378
      case XINE_MSG_GENERAL_WARNING:
 
1379
      case XINE_MSG_NETWORK_UNREACHABLE:
 
1380
      case XINE_MSG_UNKNOWN_HOST:
 
1381
        msg = display_warning;
 
1382
        break;
 
1383
 
 
1384
      case XINE_MSG_READ_ERROR:
 
1385
      case XINE_MSG_LIBRARY_LOAD_ERROR:
 
1386
 
 
1387
      case XINE_MSG_CONNECTION_REFUSED:
 
1388
      case XINE_MSG_FILE_NOT_FOUND:
 
1389
      case XINE_MSG_PERMISSION_ERROR:
 
1390
      case XINE_MSG_SECURITY:
 
1391
      case XINE_MSG_UNKNOWN_DEVICE:
 
1392
        msg = display_error;
 
1393
        break;
 
1394
      }
 
1395
 
 
1396
      /* TODO: provide customized messages, hints... */
1465
1397
      if (data->num_parameters) {
1466
 
 
1467
 
        char *param;
1468
 
 
1469
 
        param = data->messages + strlen (data->messages) +1;
1470
 
 
1471
 
        display_info ("xine engine message", "%s %s",
1472
 
                      data->messages, param);
1473
 
      } else {
1474
 
        display_info ("xine engine message", data->messages);
 
1398
        int i;
 
1399
        const char *param = data->messages + strlen (data->messages) + 1;
 
1400
        char *txt = strdup (data->messages);
 
1401
        for (i = 0; i < data->num_parameters; ++i)
 
1402
        {
 
1403
          asreprintf (&txt, "%s %s", txt, param);
 
1404
          param += strlen (param) + 1;
 
1405
        }
 
1406
        msg (_("xine engine message"), "%s", txt);
 
1407
        free (txt);
1475
1408
      }
 
1409
      else
 
1410
        msg (_("xine engine message"), "%s", data->messages);
1476
1411
      gdk_threads_leave();
1477
1412
    }
1478
1413
    break;
1481
1416
 
1482
1417
}
1483
1418
 
 
1419
/*
 
1420
 * drag and drop
 
1421
 */
 
1422
 
 
1423
static const GtkTargetEntry target_table[] = {
 
1424
        { "text/uri-list", 0, 0 },
 
1425
};
 
1426
 
 
1427
static void drop_cb (GtkWidget          *widget,
 
1428
                     GdkDragContext     *context,
 
1429
                     gint                x,
 
1430
                     gint                y,
 
1431
                     GtkSelectionData   *data,
 
1432
                     guint               info,
 
1433
                     guint               time) {
 
1434
 
 
1435
  GtkTreePath *path;
 
1436
  gint         cx, cy;
 
1437
  gint         ins_pos;
 
1438
 
 
1439
  logprintf ("drag_drop: drop callback, length=%d, format=%d\n, x=%d, y=%d\n",
 
1440
             data->length, data->format, x, y);
 
1441
 
 
1442
  if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view), x, y, &path, 
 
1443
                                     NULL, &cx, &cy)) {
 
1444
    
 
1445
    gint        *indices;
 
1446
    
 
1447
    indices = gtk_tree_path_get_indices (path);
 
1448
    ins_pos = indices[0];
 
1449
 
 
1450
    logprintf ("playlist: mapping to tree view worked: cx=%d, cy=%d, path=%s, row=%d\n",
 
1451
               cx, cy, gtk_tree_path_to_string (path), ins_pos);
 
1452
 
 
1453
    gtk_tree_path_free (path);
 
1454
  } else
 
1455
    ins_pos = -1;
 
1456
    
 
1457
 
 
1458
  if (data->format == 8) {
 
1459
    
 
1460
    gint  i, len;
 
1461
    gchar str[MAX_MRL_LEN];
 
1462
    
 
1463
    len = 0; i = 0;
 
1464
 
 
1465
    while (i<data->length) {
 
1466
 
 
1467
      char c;
 
1468
 
 
1469
      c = data->data[i];
 
1470
 
 
1471
      if ( (len<(MAX_MRL_LEN-1)) 
 
1472
           && (c != '\r') 
 
1473
           && (c != '\n') ) {
 
1474
        str[len] = c;
 
1475
        len++;
 
1476
      } else if (c=='\r') {
 
1477
 
 
1478
        str[len] = 0;
 
1479
 
 
1480
        playlist_add_mrl (str, ins_pos);
 
1481
 
 
1482
        if (ins_pos >= 0 && ins_pos++ <= cur_list_pos)
 
1483
          ++cur_list_pos;
 
1484
 
 
1485
        len = 0;
 
1486
 
 
1487
      } 
 
1488
      i++;
 
1489
    }
 
1490
  }
 
1491
 
 
1492
  gtk_drag_finish (context, TRUE, FALSE, time);
 
1493
}
 
1494
 
 
1495
/*
 
1496
 * js functions
 
1497
 */
 
1498
 
 
1499
static JSBool js_playlist_get_item (JSContext *cx, JSObject *obj, uintN argc, 
 
1500
                                    jsval *argv, jsval *rval) {
 
1501
 
 
1502
  /* se_t *se = (se_t *) JS_GetContextPrivate(cx); */
 
1503
  int   speed;
 
1504
 
 
1505
  se_log_fncall ("playlist_get_item");
 
1506
 
 
1507
  speed = xine_get_param (stream, XINE_PARAM_SPEED);
 
1508
 
 
1509
  *rval = INT_TO_JSVAL (playlist_get_list_pos());
 
1510
 
 
1511
  return JS_TRUE;
 
1512
}
 
1513
 
 
1514
static JSBool js_playlist_clear (JSContext *cx, JSObject *obj, uintN argc, 
 
1515
                                 jsval *argv, jsval *rval) {
 
1516
 
 
1517
  /* se_t *se = (se_t *) JS_GetContextPrivate(cx); */
 
1518
 
 
1519
  se_log_fncall ("playlist_clear");
 
1520
 
 
1521
  playlist_clear ();
 
1522
 
 
1523
  return JS_TRUE;
 
1524
}
 
1525
 
 
1526
static JSBool js_playlist_add (JSContext *cx, JSObject *obj, uintN argc, 
 
1527
                               jsval *argv, jsval *rval) {
 
1528
 
 
1529
  se_t     *se = (se_t *) JS_GetContextPrivate(cx);
 
1530
  JSString *str;
 
1531
  char     *mrl;
 
1532
  int       item;
 
1533
 
 
1534
  se_log_fncall ("playlist_add");
 
1535
 
 
1536
  se_argc_check (1, "playlist_add");
 
1537
  se_arg_is_string (0, "playlist_add");
 
1538
 
 
1539
  str = JS_ValueToString (cx, argv[0]);
 
1540
  mrl = JS_GetStringBytes (str);
 
1541
 
 
1542
  logprintf ("playlist_add: MRL=%s\n", mrl);
 
1543
  item = playlist_add_mrl (mrl, -1);
 
1544
 
 
1545
  *rval = INT_TO_JSVAL (item);
 
1546
 
 
1547
  return JS_TRUE;
 
1548
}
 
1549
 
 
1550
static JSBool js_playlist_play (JSContext *cx, JSObject *obj, uintN argc, 
 
1551
                                jsval *argv, jsval *rval) {
 
1552
 
 
1553
  se_t *se = (se_t *) JS_GetContextPrivate(cx);
 
1554
  int   item;
 
1555
 
 
1556
  se_log_fncall ("playlist_play");
 
1557
 
 
1558
  se_argc_check (1, "playlist_play");
 
1559
  se_arg_is_int (0, "playlist_play");
 
1560
 
 
1561
  JS_ValueToInt32 (cx, argv[0], &item);
 
1562
 
 
1563
  if (item<0)
 
1564
    item = 0;
 
1565
 
 
1566
  playlist_play (item);
 
1567
  
 
1568
  return JS_TRUE;
 
1569
}
 
1570
 
 
1571
static JSBool js_playlist_show (JSContext *cx, JSObject *obj, uintN argc, 
 
1572
                                jsval *argv, jsval *rval) {
 
1573
 
 
1574
  /* se_t *se = (se_t *) JS_GetContextPrivate(cx); */
 
1575
 
 
1576
  se_log_fncall ("playlist_show");
 
1577
 
 
1578
  playlist_show ();
 
1579
  
 
1580
  return JS_TRUE;
 
1581
}
 
1582
 
 
1583
void playlist_play_from (int list_pos, int pos, int pos_time) {
 
1584
 
 
1585
  /* int          err; */
 
1586
  GtkTreePath *path;
 
1587
  char         indices[10];
 
1588
  play_item_t *play_item;
 
1589
 
 
1590
  logo_mode = 0;
 
1591
 
 
1592
  if (list_pos<0)
 
1593
    list_pos = 0;
 
1594
 
 
1595
  unmark_play_item ();
 
1596
 
 
1597
  play_item = playlist_get_item (list_pos);
 
1598
 
 
1599
  if (!play_item) {
 
1600
    cur_list_pos = 0;
 
1601
    playlist_logo ();
 
1602
    return;
 
1603
  }
 
1604
 
 
1605
  play_item_play (play_item);
 
1606
  
 
1607
  snprintf (indices, 10, "%d", list_pos);
 
1608
  path = gtk_tree_path_new_from_string (indices);
 
1609
  gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), 
 
1610
                            path, NULL, FALSE);
 
1611
  gtk_tree_path_free (path);
 
1612
 
 
1613
  cur_list_pos  = list_pos;
 
1614
  mark_play_item ();
 
1615
 
 
1616
 
 
1617
}
 
1618
 
1484
1619
void playlist_init (void) {
1485
1620
 
1486
1621
  GtkWidget            *hbox, *button, *scrolled_window;
1488
1623
  GtkTreeViewColumn    *column;
1489
1624
 
1490
1625
  is_visible     = 0;
1491
 
  cur_mrl        = NULL;
1492
1626
  cur_list_pos   = -1;
1493
1627
 
1494
1628
  srand (time (NULL));
1498
1632
   */
1499
1633
 
1500
1634
  dlg = gtk_dialog_new ();
1501
 
  gtk_window_set_title (GTK_WINDOW (dlg), "Edit Playlist...");
 
1635
  gtk_window_set_title (GTK_WINDOW (dlg), _("Edit playlist..."));
1502
1636
  gtk_window_set_default_size (GTK_WINDOW (dlg), 500, 400);
1503
1637
  g_signal_connect (GTK_OBJECT (dlg), "delete_event",
1504
1638
                    G_CALLBACK (close_cb), NULL );
1505
1639
 
1506
1640
  /*
 
1641
   * top button bar (load/save/clear)
 
1642
   */
 
1643
 
 
1644
  hbox = gtk_hbox_new (0, 2);
 
1645
  
 
1646
  button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
 
1647
  g_signal_connect (GTK_OBJECT(button), "clicked", 
 
1648
                    G_CALLBACK(open_cb), 
 
1649
                    tree_view);
 
1650
  gtk_box_pack_start (GTK_BOX(hbox), button, FALSE, FALSE, 2);
 
1651
  button = gtk_button_new_from_stock (GTK_STOCK_SAVE_AS);
 
1652
  g_signal_connect (GTK_OBJECT(button), "clicked", 
 
1653
                    G_CALLBACK(save_as_cb), 
 
1654
                    tree_view);
 
1655
  gtk_box_pack_start (GTK_BOX(hbox), button, FALSE, FALSE, 2);
 
1656
  button = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
 
1657
  g_signal_connect (GTK_OBJECT(button), "clicked", 
 
1658
                    G_CALLBACK(clear_cb), 
 
1659
                    tree_view);
 
1660
  gtk_box_pack_start (GTK_BOX(hbox), button, FALSE, FALSE, 2);
 
1661
 
 
1662
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox,
 
1663
                      FALSE, FALSE, 2);
 
1664
 
 
1665
  /*
1507
1666
   * init tree store
1508
1667
   */
1509
1668
 
1510
 
  pl_store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
 
1669
  pl_store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING,
 
1670
                                 G_TYPE_POINTER, G_TYPE_STRING);
1511
1671
 
1512
1672
  /*
1513
1673
   * tree view widget to display playlist
1519
1679
                    G_CALLBACK(button_press_lcb), NULL);
1520
1680
 
1521
1681
  cell = gtk_cell_renderer_text_new ();
1522
 
  column = gtk_tree_view_column_new_with_attributes ("title",
1523
 
                                                     cell,
1524
 
                                                     "text", 0,
1525
 
                                                     NULL);
1526
 
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
1527
 
                               GTK_TREE_VIEW_COLUMN (column));
1528
 
 
1529
 
  column = gtk_tree_view_column_new_with_attributes ("mrl",
1530
 
                                                     cell,
1531
 
                                                     "text", 1,
1532
 
                                                     NULL);
1533
 
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
1534
 
                               GTK_TREE_VIEW_COLUMN (column));
1535
 
  
1536
 
  gtk_tree_view_set_reorderable (GTK_TREE_VIEW (tree_view), TRUE);
 
1682
  column = gtk_tree_view_column_new_with_attributes (" ", cell,
 
1683
                                                     "text", 3, NULL);
 
1684
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
 
1685
                               GTK_TREE_VIEW_COLUMN (column));
 
1686
 
 
1687
  cell = gtk_cell_renderer_text_new ();
 
1688
  column = gtk_tree_view_column_new_with_attributes (_("Title"), cell,
 
1689
                                                     "text", 0, NULL);
 
1690
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
 
1691
                               GTK_TREE_VIEW_COLUMN (column));
 
1692
 
 
1693
  column = gtk_tree_view_column_new_with_attributes ("MRL", cell,
 
1694
                                                     "text", 1, NULL);
 
1695
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
 
1696
                               GTK_TREE_VIEW_COLUMN (column));
 
1697
 
 
1698
  /* FIXME: interacts badly with own drag&drop stuff 
 
1699
     gtk_tree_view_set_reorderable (GTK_TREE_VIEW (tree_view), TRUE);
 
1700
  */
 
1701
 
 
1702
  g_signal_connect (G_OBJECT (tree_view), "drag_data_received",
 
1703
                    G_CALLBACK (drop_cb), NULL);
 
1704
  gtk_drag_dest_set (tree_view, GTK_DEST_DEFAULT_ALL,
 
1705
                     target_table, 1, GDK_ACTION_COPY);
 
1706
 
 
1707
  gtk_widget_show (tree_view);
1537
1708
 
1538
1709
  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1539
1710
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1541
1712
                                  GTK_POLICY_AUTOMATIC);
1542
1713
  gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
1543
1714
 
 
1715
  
1544
1716
  gtk_box_pack_start (GTK_BOX(GTK_DIALOG (dlg)->vbox), scrolled_window,
1545
1717
                      TRUE, TRUE, 2);
1546
1718
 
1550
1722
 
1551
1723
  hbox = gtk_hbox_new (0,2);
1552
1724
  
1553
 
  repeat_button = gtk_check_button_new_with_label ("repeat");
1554
 
  gtk_box_pack_start (GTK_BOX (hbox), repeat_button, TRUE, TRUE, 2);
 
1725
  repeat_button = gtk_check_button_new_with_label (_("Repeat"));
 
1726
  gtk_box_pack_start (GTK_BOX (hbox), repeat_button, FALSE, FALSE, 2);
1555
1727
 
1556
 
  random_button = gtk_check_button_new_with_label ("random");
1557
 
  gtk_box_pack_start (GTK_BOX (hbox), random_button, TRUE, TRUE, 2);
 
1728
  random_button = gtk_check_button_new_with_label (_("Random"));
 
1729
  gtk_box_pack_start (GTK_BOX (hbox), random_button, FALSE, FALSE, 2);
1558
1730
 
1559
1731
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox,
1560
1732
                      FALSE, FALSE, 2);
1571
1743
                    G_CALLBACK(add_cb), 
1572
1744
                    tree_view);
1573
1745
  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 2);
1574
 
  button = gtk_button_new_from_stock (GTK_STOCK_FIND_AND_REPLACE);
1575
 
  gtk_button_set_label (GTK_BUTTON (button), "Edit");
 
1746
  button = gtk_button_new_with_label (_("Edit"));
1576
1747
  g_signal_connect (GTK_OBJECT(button), "clicked", 
1577
1748
                    G_CALLBACK(edit_cb), 
1578
1749
                    tree_view);
1582
1753
                    G_CALLBACK(del_cb), 
1583
1754
                    tree_view);
1584
1755
  gtk_box_pack_start (GTK_BOX(hbox), button, TRUE, TRUE, 2);
1585
 
  button = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
1586
 
  g_signal_connect (GTK_OBJECT(button), "clicked", 
1587
 
                    G_CALLBACK(clear_cb), 
1588
 
                    tree_view);
1589
 
  gtk_box_pack_start (GTK_BOX(hbox), button, TRUE, TRUE, 2);
1590
 
  button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
1591
 
  g_signal_connect (GTK_OBJECT(button), "clicked", 
1592
 
                    G_CALLBACK(open_cb), 
1593
 
                    tree_view);
1594
 
  gtk_box_pack_start (GTK_BOX(hbox), button, TRUE, TRUE, 2);
1595
 
  button = gtk_button_new_from_stock (GTK_STOCK_SAVE_AS);
1596
 
  g_signal_connect (GTK_OBJECT(button), "clicked", 
1597
 
                    G_CALLBACK(save_as_cb), 
1598
 
                    tree_view);
1599
 
  gtk_box_pack_start (GTK_BOX(hbox), button, TRUE, TRUE, 2);
 
1756
  button = gtk_button_new_from_stock (GTK_STOCK_GO_UP);
 
1757
  g_signal_connect (GTK_OBJECT(button), "clicked", 
 
1758
                    G_CALLBACK(up_cb), 
 
1759
                    tree_view);
 
1760
  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 2);
 
1761
  button = gtk_button_new_from_stock (GTK_STOCK_GO_DOWN);
 
1762
  g_signal_connect (GTK_OBJECT(button), "clicked", 
 
1763
                    G_CALLBACK(down_cb), 
 
1764
                    tree_view);
 
1765
  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 2);
1600
1766
 
1601
1767
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox,
1602
1768
                      FALSE, FALSE, 2);
1608
1774
 
1609
1775
  playlist_load (NULL);
1610
1776
 
1611
 
  sprintf (logo_mrl, "%s/logo.mpv", GXINE_LOGODIR);
 
1777
  sprintf (logo_mrl, "%s/logo.mpv", logodir);
1612
1778
 
1613
1779
  logo_mode = 1;
1614
1780
 
1618
1784
  {
1619
1785
    xine_event_queue_t *queue;
1620
1786
 
1621
 
    queue = xine_event_new_queue (GTK_XINE(gtx)->stream);
 
1787
    queue = xine_event_new_queue (stream);
1622
1788
 
1623
1789
    xine_event_create_listener_thread (queue, xine_event_cb, NULL);
 
1790
  }
1624
1791
 
 
1792
  {
 
1793
    static const se_f_def_t defs[] = {
 
1794
      { "playlist_show", js_playlist_show, 0, 0,
 
1795
        SE_GROUP_DIALOGUE, NULL, NULL },
 
1796
      { "playlist_clear", js_playlist_clear, 0, 0,
 
1797
        SE_GROUP_PLAYLIST, NULL, NULL },
 
1798
      { "playlist_add", js_playlist_add, 0, 0,
 
1799
        SE_GROUP_PLAYLIST, N_("MRL"), NULL },
 
1800
      { "playlist_play", js_playlist_play, 0, 0,
 
1801
        SE_GROUP_PLAYLIST, N_("int"), N_("playlist entry number") },
 
1802
      { "playlist_get_item", js_playlist_get_item, 0, 0,
 
1803
        SE_GROUP_PLAYLIST, NULL, NULL },
 
1804
      { NULL }
 
1805
    };
 
1806
    se_defuns (gse, NULL, defs);
1625
1807
  }
1626
1808
}