New simple playlist.
[vlc.git] / plugins / beos / InterfaceWindow.cpp
1 /*****************************************************************************
2  * InterfaceWindow.cpp: beos interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 VideoLAN
5  * $Id: InterfaceWindow.cpp,v 1.2 2001/06/15 09:07:10 tcastley Exp $
6  *
7  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Tony Castley <tony@castley.net>
10  *          Richard Shepherd <richard@rshepherd.demon.co.uk>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26 #include "defs.h"
27
28 /* System headers */
29 #include <kernel/OS.h>
30 #include <InterfaceKit.h>
31 #include <AppKit.h>
32 #include <StorageKit.h>
33 #include <malloc.h>
34 #include <scsi.h>
35 #include <scsiprobe_driver.h>
36
37 /* VLC headers */
38 extern "C"
39 {
40 #include "config.h"
41 #include "common.h"
42 #include "threads.h"
43 #include "mtime.h"
44 #include "main.h"
45 #include "tests.h"
46 #include "stream_control.h"
47 #include "input_ext-intf.h"
48 #include "interface.h"
49 #include "intf_msg.h"
50 #include "intf_playlist.h"
51 #include "audio_output.h"
52 }
53
54 /* BeOS interface headers */
55 #include "MsgVals.h"
56 #include "MediaControlView.h"
57 #include "InterfaceWindow.h"
58 #include "PlayListWindow.h"
59
60 /*****************************************************************************
61  * InterfaceWindow
62  *****************************************************************************/
63
64 InterfaceWindow::InterfaceWindow( BRect frame, const char *name,
65                                   intf_thread_t  *p_interface )
66     : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
67                B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK
68                 | B_ASYNCHRONOUS_CONTROLS )
69 {
70     file_panel = NULL;
71     p_intf = p_interface;
72     BRect controlRect(0,0,0,0);
73     b_empty_playlist = (p_main->p_playlist->i_size < 0);
74
75     /* set the title bar */
76     SetName( "interface" );
77     SetTitle(VOUT_TITLE);
78
79     /* set up the main menu */
80     BMenuBar *menu_bar;
81     menu_bar = new BMenuBar(controlRect, "main menu");
82     AddChild( menu_bar );
83
84     BMenu *mFile;
85     BMenu *mAudio;
86     CDMenu *cd_menu;
87     
88     /* Add the file Menu */
89     BMenuItem *mItem;
90     menu_bar->AddItem( mFile = new BMenu( "File" ) );
91     menu_bar->ResizeToPreferred();
92     mFile->AddItem( mItem = new BMenuItem( "Open File" B_UTF8_ELLIPSIS,
93                                            new BMessage(OPEN_FILE), 'O') );
94     
95     cd_menu = new CDMenu( "Open Disc" );
96     mFile->AddItem( cd_menu );
97     
98     mFile->AddSeparatorItem();
99     mFile->AddItem( mItem = new BMenuItem( "Play List" B_UTF8_ELLIPSIS,
100                                            new BMessage(OPEN_PLAYLIST), 'P') );
101     
102     mFile->AddSeparatorItem();
103     mFile->AddItem( mItem = new BMenuItem( "About" B_UTF8_ELLIPSIS,
104                                        new BMessage(B_ABOUT_REQUESTED), 'A') );
105     mItem->SetTarget( be_app );
106     mFile->AddItem(mItem = new BMenuItem( "Quit",
107                                         new BMessage(B_QUIT_REQUESTED), 'Q') );
108
109     /* Add the Audio menu */
110     menu_bar->AddItem ( mAudio = new BMenu( "Audio" ) );
111     menu_bar->ResizeToPreferred();
112     mAudio->AddItem( new LanguageMenu( "Language", AUDIO_ES, p_intf ) );
113     mAudio->AddItem( new LanguageMenu( "Subtitles", SPU_ES, p_intf ) );
114
115     ResizeTo(260,50 + menu_bar->Bounds().IntegerHeight()+1);
116     controlRect = Bounds();
117     controlRect.top += menu_bar->Bounds().IntegerHeight() + 1;
118
119     p_mediaControl = new MediaControlView( controlRect );
120     p_mediaControl->SetViewColor( ui_color(B_PANEL_BACKGROUND_COLOR) );
121
122     /* Show */
123     AddChild( p_mediaControl );
124     Show();
125     
126 }
127
128 InterfaceWindow::~InterfaceWindow()
129 {
130 }
131
132 /*****************************************************************************
133  * InterfaceWindow::MessageReceived
134  *****************************************************************************/
135 void InterfaceWindow::MessageReceived( BMessage * p_message )
136 {
137     int vol_val = p_mediaControl->GetVolume();    // remember the current volume
138     int playback_status;      // remember playback state
139     int     i_index;
140     BAlert *alert;
141
142     Activate();
143     if (p_intf->p_input)
144     {
145             playback_status = p_intf->p_input->stream.control.i_status;
146         }
147         else
148         {
149             playback_status = UNDEF_S;
150         }
151
152     switch( p_message->what )
153     {
154     case B_ABOUT_REQUESTED:
155         alert = new BAlert(VOUT_TITLE, "BeOS " VOUT_TITLE "\n\n<www.videolan.org>", "Ok");
156         alert->Go();
157         break;
158
159     case OPEN_FILE:
160         if( file_panel )
161         {
162             file_panel->Show();
163             break;
164         }
165         file_panel = new BFilePanel();
166         file_panel->SetTarget( this );
167         file_panel->Show();
168         break;
169
170         case OPEN_PLAYLIST:
171                 {
172                     BRect rect(20,20,320,420);
173             PlayListWindow* playlist_window = new PlayListWindow(rect,
174                          "Playlist", (playlist_t *)p_main->p_playlist);
175             playlist_window->Show();
176         }
177                 break;
178     case OPEN_DVD:
179         const char *psz_device;
180         char psz_source[ B_FILE_NAME_LENGTH + 4 ];
181         if( p_message->FindString("device", &psz_device) != B_ERROR )
182         {
183             snprintf( psz_source, B_FILE_NAME_LENGTH + 4,
184                       "dvd:%s", psz_device );
185             psz_source[ strlen(psz_source) ] = '\0';
186             intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, (char*)psz_source );
187             if( p_intf->p_input != NULL )
188             {
189                 p_intf->p_input->b_eof = 1;
190             }
191             intf_PlaylistJumpto( p_main->p_playlist, 
192                                  p_main->p_playlist->i_size - 1 );
193         }
194         break;
195
196     case STOP_PLAYBACK:
197         // this currently stops playback not nicely
198         if( p_intf->p_input != NULL )
199         {
200             // silence the sound, otherwise very horrible
201             vlc_mutex_lock( &p_aout_bank->lock );
202             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
203             {
204                 p_aout_bank->pp_aout[i_index]->i_savedvolume = p_aout_bank->pp_aout[i_index]->i_volume;
205                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
206             }
207             vlc_mutex_unlock( &p_aout_bank->lock );
208             snooze( 400000 );
209
210             /* end playing item */
211             p_intf->p_input->b_eof = 1;
212             
213             /* update playlist */
214             vlc_mutex_lock( &p_main->p_playlist->change_lock );
215             p_main->p_playlist->i_index--;
216             p_main->p_playlist->b_stopped = 1;
217             vlc_mutex_unlock( &p_main->p_playlist->change_lock );
218         }
219         break;
220
221     case START_PLAYBACK:
222         /*  starts playing in normal mode */
223
224     case PAUSE_PLAYBACK:
225         /* toggle between pause and play */
226         if( p_intf->p_input != NULL )
227         {
228             /* pause if currently playing */
229             if( playback_status == PLAYING_S )
230             {
231                 /* mute the sound */
232                 vlc_mutex_lock( &p_aout_bank->lock );
233                 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
234                 {
235                     p_aout_bank->pp_aout[i_index]->i_savedvolume =
236                                        p_aout_bank->pp_aout[i_index]->i_volume;
237                     p_aout_bank->pp_aout[i_index]->i_volume = 0;
238                 }
239                 vlc_mutex_unlock( &p_aout_bank->lock );
240                 snooze( 400000 );
241                 
242                 /* pause the movie */
243                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PAUSE );
244                 vlc_mutex_lock( &p_main->p_playlist->change_lock );
245                 p_main->p_playlist->b_stopped = 0;
246                 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
247             }
248             else
249             {
250                 /* Play after pausing */
251                 /* Restore the volume */
252                 vlc_mutex_lock( &p_aout_bank->lock );
253                 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
254                 {
255                     p_aout_bank->pp_aout[i_index]->i_volume =
256                                   p_aout_bank->pp_aout[i_index]->i_savedvolume;
257                     p_aout_bank->pp_aout[i_index]->i_savedvolume = 0;
258                 }
259                 vlc_mutex_unlock( &p_aout_bank->lock );
260                 snooze( 400000 );
261                 
262                 /* Start playing */
263                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
264                 p_main->p_playlist->b_stopped = 0;
265             }
266         }
267         else
268         {
269             /* Play a new file */
270             vlc_mutex_lock( &p_main->p_playlist->change_lock );
271             if( p_main->p_playlist->b_stopped )
272             {
273                 if( p_main->p_playlist->i_size )
274                 {
275                     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
276                     intf_PlaylistJumpto( p_main->p_playlist, 
277                                          p_main->p_playlist->i_index );
278                     p_main->p_playlist->b_stopped = 0;
279                 }
280                 else
281                 {
282                     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
283                 }
284             }
285         }    
286         break;
287
288     case FASTER_PLAY:
289         /* cycle the fast playback modes */
290         if( p_intf->p_input != NULL )
291         {
292             /* mute the sound */
293             vlc_mutex_lock( &p_aout_bank->lock );
294             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
295             {
296                 p_aout_bank->pp_aout[i_index]->i_savedvolume =
297                                        p_aout_bank->pp_aout[i_index]->i_volume;
298                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
299             }
300             vlc_mutex_unlock( &p_aout_bank->lock );
301             snooze( 400000 );
302
303             /* change the fast play mode */
304             input_SetStatus( p_intf->p_input, INPUT_STATUS_FASTER );
305             vlc_mutex_lock( &p_main->p_playlist->change_lock );
306             p_main->p_playlist->b_stopped = 0;
307             vlc_mutex_unlock( &p_main->p_playlist->change_lock );
308         }
309         break;
310
311     case SLOWER_PLAY:
312         /*  cycle the slow playback modes */
313         if (p_intf->p_input != NULL )
314         {
315             /* mute the sound */
316             vlc_mutex_lock( &p_aout_bank->lock );
317             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
318             {
319                 p_aout_bank->pp_aout[i_index]->i_savedvolume =
320                                        p_aout_bank->pp_aout[i_index]->i_volume;
321                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
322             }
323             vlc_mutex_unlock( &p_aout_bank->lock );
324             snooze( 400000 );
325
326             /* change the slower play */
327             input_SetStatus( p_intf->p_input, INPUT_STATUS_SLOWER );
328             vlc_mutex_lock( &p_main->p_playlist->change_lock );
329             p_main->p_playlist->b_stopped = 0;
330             vlc_mutex_unlock( &p_main->p_playlist->change_lock );
331         }
332         break;
333
334     case SEEK_PLAYBACK:
335         /* handled by semaphores */
336         break;
337
338     case VOLUME_CHG:
339         /* adjust the volume */
340         vlc_mutex_lock( &p_aout_bank->lock );
341         for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
342         {
343             if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
344             {
345                 p_aout_bank->pp_aout[i_index]->i_savedvolume = vol_val;
346             }
347             else
348             {
349                 p_aout_bank->pp_aout[i_index]->i_volume = vol_val;
350             }
351         }
352         vlc_mutex_unlock( &p_aout_bank->lock );
353         break;
354
355     case VOLUME_MUTE:
356         /* toggle muting */
357         vlc_mutex_lock( &p_aout_bank->lock );
358         for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
359         {
360             if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
361             {
362                 p_aout_bank->pp_aout[i_index]->i_volume =
363                                   p_aout_bank->pp_aout[i_index]->i_savedvolume;
364                 p_aout_bank->pp_aout[i_index]->i_savedvolume = 0;
365             }
366             else
367             {
368                 p_aout_bank->pp_aout[i_index]->i_savedvolume =
369                                        p_aout_bank->pp_aout[i_index]->i_volume;
370                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
371             }
372         }
373         vlc_mutex_unlock( &p_aout_bank->lock );
374         break;
375
376     case SELECT_CHANNEL:
377         {
378             int32 i = p_message->FindInt32( "channel" );
379             if ( i == -1 )
380             {
381                 input_ChangeES( p_intf->p_input, NULL, AUDIO_ES );
382             }
383             else
384             {
385                 input_ChangeES( p_intf->p_input,
386                         p_intf->p_input->stream.pp_es[i], AUDIO_ES );
387             }
388         }
389         break;
390
391     case SELECT_SUBTITLE:
392         {
393             int32 i = p_message->FindInt32( "subtitle" );
394             if ( i == -1 )
395             {
396                 input_ChangeES( p_intf->p_input, NULL, SPU_ES);
397             }
398             else
399             {
400                 input_ChangeES( p_intf->p_input,
401                         p_intf->p_input->stream.pp_es[i], SPU_ES );
402             }
403         }
404         break;
405
406     case B_REFS_RECEIVED:
407     case B_SIMPLE_DATA:
408         {
409             entry_ref ref;
410             if( p_message->FindRef( "refs", &ref ) == B_OK )
411             {
412                 BPath path( &ref );
413                 intf_PlaylistAdd( p_main->p_playlist,
414                                   PLAYLIST_END, (char*)path.Path() );
415                 if( p_intf->p_input != NULL )
416                 {
417                     p_intf->p_input->b_eof = 1;
418                 }
419                 intf_PlaylistJumpto( p_main->p_playlist, 
420                                      p_main->p_playlist->i_size - 1 );
421                                   
422              }
423         }
424         break;
425
426     default:
427         BWindow::MessageReceived( p_message );
428         break;
429     }
430
431 }
432
433 /*****************************************************************************
434  * InterfaceWindow::updateInterface
435  *****************************************************************************/
436 void InterfaceWindow::updateInterface()
437 {
438     float progress;
439     
440         if ( p_intf->p_input )
441         {
442         if ( acquire_sem(p_mediaControl->fScrubSem) == B_OK )
443         {
444             uint32 seekTo = (p_mediaControl->GetSeekTo() *
445                         p_intf->p_input->stream.p_selected_area->i_size) / 100;
446             input_Seek( p_intf->p_input, seekTo );
447         }
448         else if( Lock() )
449         {
450             progress = (100. * p_intf->p_input->stream.p_selected_area->i_tell) /
451                         p_intf->p_input->stream.p_selected_area->i_size;
452             p_mediaControl->SetStatus(p_intf->p_input->stream.control.i_status, 
453                                       p_intf->p_input->stream.control.i_rate);
454             p_mediaControl->SetProgress(progress);
455             Unlock();
456         }
457     }
458     if ( b_empty_playlist != (p_main->p_playlist->i_size < 1) )
459     {
460         if (Lock())
461         {
462             b_empty_playlist = !b_empty_playlist;
463             p_mediaControl->SetEnabled( !b_empty_playlist );
464             Unlock();
465         }
466     }
467 }
468
469 /*****************************************************************************
470  * InterfaceWindow::QuitRequested
471  *****************************************************************************/
472 bool InterfaceWindow::QuitRequested()
473 {
474     p_intf->b_die = 1;
475
476     return( false );
477 }
478
479 /*****************************************************************************
480  * CDMenu::CDMenu
481  *****************************************************************************/
482 CDMenu::CDMenu(const char *name)
483       : BMenu(name)
484 {
485 }
486
487 /*****************************************************************************
488  * CDMenu::~CDMenu
489  *****************************************************************************/
490 CDMenu::~CDMenu()
491 {
492 }
493
494 /*****************************************************************************
495  * CDMenu::AttachedToWindow
496  *****************************************************************************/
497 void CDMenu::AttachedToWindow(void)
498 {
499     while (RemoveItem((long int)0) != NULL);  // remove all items
500     GetCD("/dev/disk");
501     BMenu::AttachedToWindow();
502 }
503
504 /*****************************************************************************
505  * CDMenu::GetCD
506  *****************************************************************************/
507 int CDMenu::GetCD( const char *directory )
508 {
509     int i_dev;
510     BDirectory dir;
511     dir.SetTo( directory );
512
513     if( dir.InitCheck() != B_NO_ERROR )
514     {
515         return B_ERROR;
516     }
517
518     dir.Rewind();
519     BEntry entry;
520
521     while( dir.GetNextEntry(&entry) >= 0 )
522     {
523         const char *name;
524         entry_ref e;
525         BPath path;
526
527         if( entry.GetPath(&path) != B_NO_ERROR )
528         {
529             continue;
530         }
531
532         name = path.Path();
533
534         if( entry.GetRef(&e) != B_NO_ERROR )
535         {
536             continue;
537         }
538
539         if( entry.IsDirectory() )
540         {
541             if( strcmp(e.name, "floppy") == 0 )
542             {
543                 continue; // ignore floppy (it is not silent)
544             }
545
546             i_dev = GetCD( name );
547
548             if( i_dev >= 0 )
549             {
550                 return i_dev;
551             }
552         }
553         else
554         {
555             device_geometry g;
556             status_t m;
557
558             if( strcmp(e.name, "raw") != 0 )
559             {
560                 continue; // ignore partitions
561             }
562
563             i_dev = open( name, O_RDONLY );
564
565             if( i_dev < 0 )
566             {
567                 continue;
568             }
569
570             if( ioctl(i_dev, B_GET_GEOMETRY, &g, sizeof(g)) >= 0 )
571             {
572                 if( g.device_type == B_CD ) //ensure the drive is a CD-ROM
573                 {
574                     if( ioctl(i_dev, B_GET_MEDIA_STATUS, &m, sizeof(m)) >= 0 )
575                     {
576                         if( m == B_NO_ERROR ) //ensure media is present
577                         {
578                             BMessage *msg;
579                             msg = new BMessage( OPEN_DVD );
580                             msg->AddString( "device", name );
581                             BMenuItem *menu_item;
582                             menu_item = new BMenuItem( name, msg );
583                             AddItem( menu_item );
584                             continue;
585                         }
586                     }
587                 }
588             }
589             close( i_dev );
590         }
591     }
592     return B_ERROR;
593 }
594
595 /*****************************************************************************
596  * LanguageMenu::LanguageMenu
597  *****************************************************************************/
598 LanguageMenu::LanguageMenu(const char *name, int menu_kind, 
599                             intf_thread_t  *p_interface)
600     :BMenu(name)
601 {
602     kind = menu_kind;
603     p_intf = p_interface;
604 }
605
606 /*****************************************************************************
607  * LanguageMenu::~LanguageMenu
608  *****************************************************************************/
609 LanguageMenu::~LanguageMenu()
610 {
611 }
612
613 /*****************************************************************************
614  * LanguageMenu::AttachedToWindow
615  *****************************************************************************/
616 void LanguageMenu::AttachedToWindow(void)
617 {
618     while( RemoveItem((long int)0) != NULL )
619     {
620         ; // remove all items
621     }
622
623     SetRadioMode(true);
624     GetChannels();
625     BMenu::AttachedToWindow();
626 }
627
628 /*****************************************************************************
629  * LanguageMenu::GetChannels
630  *****************************************************************************/
631 int LanguageMenu::GetChannels()
632 {
633     char  *psz_name;
634     bool   b_active;
635     BMessage *msg;
636     int    i;
637     es_descriptor_t *p_es  = NULL;
638
639     /* Insert the null */
640     if( kind == AUDIO_ES ) //audio
641     {
642         msg = new BMessage(SELECT_CHANNEL);
643         msg->AddInt32("channel", -1);
644     }
645     else
646     {
647         msg = new BMessage(SELECT_SUBTITLE);
648         msg->AddInt32("subtitle", -1);
649     }
650     BMenuItem *menu_item;
651     menu_item = new BMenuItem("None", msg);
652     AddItem(menu_item);
653     menu_item->SetMarked(TRUE);
654
655     if( p_intf->p_input == NULL )
656     {
657         return 1;
658     }
659
660
661     vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
662     for( i = 0; i < p_intf->p_input->stream.i_selected_es_number; i++ )
663     {
664         if( kind == p_intf->p_input->stream.pp_selected_es[i]->i_cat )
665         {
666             p_es = p_intf->p_input->stream.pp_selected_es[i];
667         }
668     }
669
670     for( i = 0; i < p_intf->p_input->stream.i_es_number; i++ )
671     {
672         if( kind == p_intf->p_input->stream.pp_es[i]->i_cat )
673         {
674             psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
675             if( kind == AUDIO_ES ) //audio
676             {
677                 msg = new BMessage(SELECT_CHANNEL);
678                 msg->AddInt32("channel", i);
679             }
680             else
681             {
682                 msg = new BMessage(SELECT_SUBTITLE);
683                 msg->AddInt32("subtitle", i);
684             }
685             BMenuItem *menu_item;
686             menu_item = new BMenuItem(psz_name, msg);
687             AddItem(menu_item);
688             b_active = (p_es == p_intf->p_input->stream.pp_es[i]);
689             menu_item->SetMarked(b_active);
690         }
691     }
692     vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
693
694 }
695
696
697