cfd8698ffd88474e51fdcbff4d4b15dd016324e8
[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.4 2001/10/21 06:05:30 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         p_mediaControl->SetStatus(NOT_STARTED_S,DEFAULT_RATE);
220         break;
221
222     case START_PLAYBACK:
223         /*  starts playing in normal mode */
224
225     case PAUSE_PLAYBACK:
226         /* toggle between pause and play */
227         if( p_intf->p_input != NULL )
228         {
229             /* pause if currently playing */
230             if( playback_status == PLAYING_S )
231             {
232                 /* mute the sound */
233                 vlc_mutex_lock( &p_aout_bank->lock );
234                 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
235                 {
236                     p_aout_bank->pp_aout[i_index]->i_savedvolume =
237                                        p_aout_bank->pp_aout[i_index]->i_volume;
238                     p_aout_bank->pp_aout[i_index]->i_volume = 0;
239                 }
240                 vlc_mutex_unlock( &p_aout_bank->lock );
241                 snooze( 400000 );
242                 
243                 /* pause the movie */
244                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PAUSE );
245                 vlc_mutex_lock( &p_main->p_playlist->change_lock );
246                 p_main->p_playlist->b_stopped = 0;
247                 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
248             }
249             else
250             {
251                 /* Play after pausing */
252                 /* Restore the volume */
253                 vlc_mutex_lock( &p_aout_bank->lock );
254                 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
255                 {
256                     p_aout_bank->pp_aout[i_index]->i_volume =
257                                   p_aout_bank->pp_aout[i_index]->i_savedvolume;
258                     p_aout_bank->pp_aout[i_index]->i_savedvolume = 0;
259                 }
260                 vlc_mutex_unlock( &p_aout_bank->lock );
261                 snooze( 400000 );
262                 
263                 /* Start playing */
264                 input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
265                 p_main->p_playlist->b_stopped = 0;
266             }
267         }
268         else
269         {
270             /* Play a new file */
271             vlc_mutex_lock( &p_main->p_playlist->change_lock );
272             if( p_main->p_playlist->b_stopped )
273             {
274                 if( p_main->p_playlist->i_size )
275                 {
276                     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
277                     intf_PlaylistJumpto( p_main->p_playlist, 
278                                          p_main->p_playlist->i_index );
279                     p_main->p_playlist->b_stopped = 0;
280                 }
281                 else
282                 {
283                     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
284                 }
285             }
286         }    
287         break;
288
289     case FASTER_PLAY:
290         /* cycle the fast playback modes */
291         if( p_intf->p_input != NULL )
292         {
293             /* mute the sound */
294             vlc_mutex_lock( &p_aout_bank->lock );
295             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
296             {
297                 p_aout_bank->pp_aout[i_index]->i_savedvolume =
298                                        p_aout_bank->pp_aout[i_index]->i_volume;
299                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
300             }
301             vlc_mutex_unlock( &p_aout_bank->lock );
302             snooze( 400000 );
303
304             /* change the fast play mode */
305             input_SetStatus( p_intf->p_input, INPUT_STATUS_FASTER );
306             vlc_mutex_lock( &p_main->p_playlist->change_lock );
307             p_main->p_playlist->b_stopped = 0;
308             vlc_mutex_unlock( &p_main->p_playlist->change_lock );
309         }
310         break;
311
312     case SLOWER_PLAY:
313         /*  cycle the slow playback modes */
314         if (p_intf->p_input != NULL )
315         {
316             /* mute the sound */
317             vlc_mutex_lock( &p_aout_bank->lock );
318             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
319             {
320                 p_aout_bank->pp_aout[i_index]->i_savedvolume =
321                                        p_aout_bank->pp_aout[i_index]->i_volume;
322                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
323             }
324             vlc_mutex_unlock( &p_aout_bank->lock );
325             snooze( 400000 );
326
327             /* change the slower play */
328             input_SetStatus( p_intf->p_input, INPUT_STATUS_SLOWER );
329             vlc_mutex_lock( &p_main->p_playlist->change_lock );
330             p_main->p_playlist->b_stopped = 0;
331             vlc_mutex_unlock( &p_main->p_playlist->change_lock );
332         }
333         break;
334
335     case SEEK_PLAYBACK:
336         /* handled by semaphores */
337         break;
338
339     case VOLUME_CHG:
340         /* adjust the volume */
341         vlc_mutex_lock( &p_aout_bank->lock );
342         for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
343         {
344             if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
345             {
346                 p_aout_bank->pp_aout[i_index]->i_savedvolume = vol_val;
347             }
348             else
349             {
350                 p_aout_bank->pp_aout[i_index]->i_volume = vol_val;
351             }
352         }
353         vlc_mutex_unlock( &p_aout_bank->lock );
354         break;
355
356     case VOLUME_MUTE:
357         /* toggle muting */
358         vlc_mutex_lock( &p_aout_bank->lock );
359         for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
360         {
361             if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
362             {
363                 p_aout_bank->pp_aout[i_index]->i_volume =
364                                   p_aout_bank->pp_aout[i_index]->i_savedvolume;
365                 p_aout_bank->pp_aout[i_index]->i_savedvolume = 0;
366             }
367             else
368             {
369                 p_aout_bank->pp_aout[i_index]->i_savedvolume =
370                                        p_aout_bank->pp_aout[i_index]->i_volume;
371                 p_aout_bank->pp_aout[i_index]->i_volume = 0;
372             }
373         }
374         vlc_mutex_unlock( &p_aout_bank->lock );
375         break;
376
377     case SELECT_CHANNEL:
378         {
379             int32 i = p_message->FindInt32( "channel" );
380             if ( i == -1 )
381             {
382                 input_ChangeES( p_intf->p_input, NULL, AUDIO_ES );
383             }
384             else
385             {
386                 input_ChangeES( p_intf->p_input,
387                         p_intf->p_input->stream.pp_es[i], AUDIO_ES );
388             }
389         }
390         break;
391
392     case SELECT_SUBTITLE:
393         {
394             int32 i = p_message->FindInt32( "subtitle" );
395             if ( i == -1 )
396             {
397                 input_ChangeES( p_intf->p_input, NULL, SPU_ES);
398             }
399             else
400             {
401                 input_ChangeES( p_intf->p_input,
402                         p_intf->p_input->stream.pp_es[i], SPU_ES );
403             }
404         }
405         break;
406
407     case B_REFS_RECEIVED:
408     case B_SIMPLE_DATA:
409         {
410             entry_ref ref;
411             if( p_message->FindRef( "refs", &ref ) == B_OK )
412             {
413                 BPath path( &ref );
414                 intf_PlaylistAdd( p_main->p_playlist,
415                                   PLAYLIST_END, (char*)path.Path() );
416                 if( p_intf->p_input != NULL )
417                 {
418                     p_intf->p_input->b_eof = 1;
419                 }
420                 intf_PlaylistJumpto( p_main->p_playlist, 
421                                      p_main->p_playlist->i_size - 1 );
422                                   
423              }
424         }
425         break;
426
427     default:
428         BWindow::MessageReceived( p_message );
429         break;
430     }
431
432 }
433
434 /*****************************************************************************
435  * InterfaceWindow::updateInterface
436  *****************************************************************************/
437 void InterfaceWindow::updateInterface()
438 {
439         if ( p_intf->p_input )
440         {
441         if ( acquire_sem(p_mediaControl->fScrubSem) == B_OK )
442         {
443             uint64 seekTo = (p_mediaControl->GetSeekTo() *
444                         p_intf->p_input->stream.p_selected_area->i_size) / 100;
445             input_Seek( p_intf->p_input, seekTo);
446         }
447         else if( Lock() )
448         {
449             p_mediaControl->SetStatus(p_intf->p_input->stream.control.i_status, 
450                                       p_intf->p_input->stream.control.i_rate);
451             p_mediaControl->SetProgress(p_intf->p_input->stream.p_selected_area->i_tell,
452                                         p_intf->p_input->stream.p_selected_area->i_size);
453             Unlock();
454         }
455     }
456     if ( b_empty_playlist != (p_main->p_playlist->i_size < 1) )
457     {
458         if (Lock())
459         {
460             b_empty_playlist = !b_empty_playlist;
461             p_mediaControl->SetEnabled( !b_empty_playlist );
462             Unlock();
463         }
464     }
465 }
466
467 /*****************************************************************************
468  * InterfaceWindow::QuitRequested
469  *****************************************************************************/
470 bool InterfaceWindow::QuitRequested()
471 {
472     p_intf->b_die = 1;
473
474     return( false );
475 }
476
477 /*****************************************************************************
478  * CDMenu::CDMenu
479  *****************************************************************************/
480 CDMenu::CDMenu(const char *name)
481       : BMenu(name)
482 {
483 }
484
485 /*****************************************************************************
486  * CDMenu::~CDMenu
487  *****************************************************************************/
488 CDMenu::~CDMenu()
489 {
490 }
491
492 /*****************************************************************************
493  * CDMenu::AttachedToWindow
494  *****************************************************************************/
495 void CDMenu::AttachedToWindow(void)
496 {
497     while (RemoveItem((long int)0) != NULL);  // remove all items
498     GetCD("/dev/disk");
499     BMenu::AttachedToWindow();
500 }
501
502 /*****************************************************************************
503  * CDMenu::GetCD
504  *****************************************************************************/
505 int CDMenu::GetCD( const char *directory )
506 {
507     int i_dev;
508     BDirectory dir;
509     dir.SetTo( directory );
510
511     if( dir.InitCheck() != B_NO_ERROR )
512     {
513         return B_ERROR;
514     }
515
516     dir.Rewind();
517     BEntry entry;
518
519     while( dir.GetNextEntry(&entry) >= 0 )
520     {
521         const char *name;
522         entry_ref e;
523         BPath path;
524
525         if( entry.GetPath(&path) != B_NO_ERROR )
526         {
527             continue;
528         }
529
530         name = path.Path();
531
532         if( entry.GetRef(&e) != B_NO_ERROR )
533         {
534             continue;
535         }
536
537         if( entry.IsDirectory() )
538         {
539             if( strcmp(e.name, "floppy") == 0 )
540             {
541                 continue; // ignore floppy (it is not silent)
542             }
543
544             i_dev = GetCD( name );
545
546             if( i_dev >= 0 )
547             {
548                 return i_dev;
549             }
550         }
551         else
552         {
553             device_geometry g;
554             status_t m;
555
556             if( strcmp(e.name, "raw") != 0 )
557             {
558                 continue; // ignore partitions
559             }
560
561             i_dev = open( name, O_RDONLY );
562
563             if( i_dev < 0 )
564             {
565                 continue;
566             }
567
568             if( ioctl(i_dev, B_GET_GEOMETRY, &g, sizeof(g)) >= 0 )
569             {
570                 if( g.device_type == B_CD ) //ensure the drive is a CD-ROM
571                 {
572                     if( ioctl(i_dev, B_GET_MEDIA_STATUS, &m, sizeof(m)) >= 0 )
573                     {
574                         if( m == B_NO_ERROR ) //ensure media is present
575                         {
576                             BMessage *msg;
577                             msg = new BMessage( OPEN_DVD );
578                             msg->AddString( "device", name );
579                             BMenuItem *menu_item;
580                             menu_item = new BMenuItem( name, msg );
581                             AddItem( menu_item );
582                             continue;
583                         }
584                     }
585                 }
586             }
587             close( i_dev );
588         }
589     }
590     return B_ERROR;
591 }
592
593 /*****************************************************************************
594  * LanguageMenu::LanguageMenu
595  *****************************************************************************/
596 LanguageMenu::LanguageMenu(const char *name, int menu_kind, 
597                             intf_thread_t  *p_interface)
598     :BMenu(name)
599 {
600     kind = menu_kind;
601     p_intf = p_interface;
602 }
603
604 /*****************************************************************************
605  * LanguageMenu::~LanguageMenu
606  *****************************************************************************/
607 LanguageMenu::~LanguageMenu()
608 {
609 }
610
611 /*****************************************************************************
612  * LanguageMenu::AttachedToWindow
613  *****************************************************************************/
614 void LanguageMenu::AttachedToWindow(void)
615 {
616     while( RemoveItem((long int)0) != NULL )
617     {
618         ; // remove all items
619     }
620
621     SetRadioMode(true);
622     GetChannels();
623     BMenu::AttachedToWindow();
624 }
625
626 /*****************************************************************************
627  * LanguageMenu::GetChannels
628  *****************************************************************************/
629 int LanguageMenu::GetChannels()
630 {
631     char  *psz_name;
632     bool   b_active;
633     BMessage *msg;
634     int    i;
635     es_descriptor_t *p_es  = NULL;
636
637     /* Insert the null */
638     if( kind == AUDIO_ES ) //audio
639     {
640         msg = new BMessage(SELECT_CHANNEL);
641         msg->AddInt32("channel", -1);
642     }
643     else
644     {
645         msg = new BMessage(SELECT_SUBTITLE);
646         msg->AddInt32("subtitle", -1);
647     }
648     BMenuItem *menu_item;
649     menu_item = new BMenuItem("None", msg);
650     AddItem(menu_item);
651     menu_item->SetMarked(TRUE);
652
653     if( p_intf->p_input == NULL )
654     {
655         return 1;
656     }
657
658
659     vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
660     for( i = 0; i < p_intf->p_input->stream.i_selected_es_number; i++ )
661     {
662         if( kind == p_intf->p_input->stream.pp_selected_es[i]->i_cat )
663         {
664             p_es = p_intf->p_input->stream.pp_selected_es[i];
665         }
666     }
667
668     for( i = 0; i < p_intf->p_input->stream.i_es_number; i++ )
669     {
670         if( kind == p_intf->p_input->stream.pp_es[i]->i_cat )
671         {
672             psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
673             if( kind == AUDIO_ES ) //audio
674             {
675                 msg = new BMessage(SELECT_CHANNEL);
676                 msg->AddInt32("channel", i);
677             }
678             else
679             {
680                 msg = new BMessage(SELECT_SUBTITLE);
681                 msg->AddInt32("subtitle", i);
682             }
683             BMenuItem *menu_item;
684             menu_item = new BMenuItem(psz_name, msg);
685             AddItem(menu_item);
686             b_active = (p_es == p_intf->p_input->stream.pp_es[i]);
687             menu_item->SetMarked(b_active);
688         }
689     }
690     vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
691
692 }
693
694
695