Disabled DVD menus by default for 0.5.0
[vlc.git] / modules / gui / beos / InterfaceWindow.cpp
1 /*****************************************************************************
2  * InterfaceWindow.cpp: beos interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 VideoLAN
5  * $Id: InterfaceWindow.cpp,v 1.23 2003/01/27 10:29:21 titer 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  *          Stephan Aßmus <stippi@yellowbites.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
26  *****************************************************************************/
27
28 /* System headers */
29 #include <kernel/OS.h>
30 #include <InterfaceKit.h>
31 #include <AppKit.h>
32 #include <StorageKit.h>
33 #include <SupportKit.h>
34 #include <malloc.h>
35 #include <scsi.h>
36 #include <scsiprobe_driver.h>
37 #include <fs_info.h>
38 #include <string.h>
39
40 /* VLC headers */
41 #include <vlc/vlc.h>
42 #include <vlc/aout.h>
43 #include <vlc/intf.h>
44
45 /* BeOS interface headers */
46 #include "VlcWrapper.h"
47 #include "MsgVals.h"
48 #include "MediaControlView.h"
49 #include "PlayListWindow.h"
50 #include "PreferencesWindow.h"
51 #include "MessagesWindow.h"
52 #include "InterfaceWindow.h"
53
54 #define INTERFACE_UPDATE_TIMEOUT 80000 // 2 frames if at 25 fps
55
56
57 /*****************************************************************************
58  * InterfaceWindow
59  *****************************************************************************/
60
61 InterfaceWindow::InterfaceWindow( BRect frame, const char *name,
62                                   intf_thread_t  *p_interface )
63     : BWindow( frame, name, B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
64                B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS ),
65       p_intf( p_interface ),
66       fFilePanel( NULL ),
67       fSubtitlesPanel( NULL ),
68       fLastUpdateTime( system_time() )
69 {
70     p_intf = p_interface;
71     p_wrapper = p_intf->p_sys->p_wrapper;
72     p_intf->p_sys->b_dvdmenus = false;
73     
74     fPlaylistIsEmpty = !( p_wrapper->PlaylistSize() > 0 );
75     
76     BScreen *p_screen = new BScreen();
77     BRect screen_rect = p_screen->Frame();
78     delete p_screen;
79     BRect window_rect;
80     window_rect.Set( ( screen_rect.right - PREFS_WINDOW_WIDTH ) / 2,
81                      ( screen_rect.bottom - PREFS_WINDOW_HEIGHT ) / 2,
82                      ( screen_rect.right + PREFS_WINDOW_WIDTH ) / 2,
83                      ( screen_rect.bottom + PREFS_WINDOW_HEIGHT ) / 2 );
84     fPreferencesWindow = new PreferencesWindow( p_intf, window_rect, "Preferences" );
85     window_rect.Set( screen_rect.right - 500,
86                      screen_rect.top + 50,
87                      screen_rect.right - 150,
88                      screen_rect.top + 250 );
89     fPlaylistWindow = new PlayListWindow( window_rect, "Playlist", this, p_intf );
90     window_rect.Set( screen_rect.right - 500,
91                      screen_rect.top + 300,
92                      screen_rect.right - 150,
93                      screen_rect.top + 600 );
94     fMessagesWindow = new MessagesWindow( p_intf, window_rect, "Messages" );
95
96     // set the title bar
97     SetName( "interface" );
98     SetTitle( VOUT_TITLE );
99
100     // the media control view
101     p_mediaControl = new MediaControlView( BRect( 0.0, 0.0, 250.0, 50.0 ),
102                                            p_intf );
103     p_mediaControl->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
104
105     float width, height;
106     p_mediaControl->GetPreferredSize( &width, &height );
107
108     // set up the main menu
109     fMenuBar = new BMenuBar( BRect(0.0, 0.0, width, 15.0), "main menu",
110                              B_FOLLOW_NONE, B_ITEMS_IN_ROW, false );
111
112     // make menu bar resize to correct height
113     float menuWidth, menuHeight;
114     fMenuBar->GetPreferredSize( &menuWidth, &menuHeight );
115     fMenuBar->ResizeTo( width, menuHeight );    // don't change! it's a workarround!
116     // take care of proper size for ourself
117     height += fMenuBar->Bounds().Height();
118     ResizeTo( width, height );
119
120     p_mediaControl->MoveTo( fMenuBar->Bounds().LeftBottom() + BPoint(0.0, 1.0) );
121     AddChild( fMenuBar );
122     AddChild( p_mediaControl );
123
124     // Add the file Menu
125     BMenu* fileMenu = new BMenu( "File" );
126     fMenuBar->AddItem( fileMenu );
127     fileMenu->AddItem( new BMenuItem( "Open File" B_UTF8_ELLIPSIS,
128                                       new BMessage( OPEN_FILE ), 'O') );
129     
130     fileMenu->AddItem( new CDMenu( "Open Disc" ) );
131
132     fileMenu->AddItem( new BMenuItem( "Load a subtitle file" B_UTF8_ELLIPSIS,
133                                       new BMessage( LOAD_SUBFILE ) ) );
134     
135     fileMenu->AddSeparatorItem();
136     BMenuItem* item = new BMenuItem( "About" B_UTF8_ELLIPSIS,
137                                      new BMessage( B_ABOUT_REQUESTED ), 'A');
138     item->SetTarget( be_app );
139     fileMenu->AddItem( item );
140     fileMenu->AddItem( new BMenuItem( "Quit", new BMessage( B_QUIT_REQUESTED ), 'Q') );
141
142     fLanguageMenu = new LanguageMenu("Language", AUDIO_ES, p_wrapper);
143     fSubtitlesMenu = new LanguageMenu("Subtitles", SPU_ES, p_wrapper);
144
145     /* Add the Audio menu */
146     fAudioMenu = new BMenu( "Audio" );
147     fMenuBar->AddItem ( fAudioMenu );
148     fAudioMenu->AddItem( fLanguageMenu );
149     fAudioMenu->AddItem( fSubtitlesMenu );
150
151     fPrevTitleMI = new BMenuItem( "Prev Title", new BMessage( PREV_TITLE ) );
152     fNextTitleMI = new BMenuItem( "Next Title", new BMessage( NEXT_TITLE ) );
153     fPrevChapterMI = new BMenuItem( "Prev Chapter", new BMessage( PREV_CHAPTER ) );
154     fNextChapterMI = new BMenuItem( "Next Chapter", new BMessage( NEXT_CHAPTER ) );
155
156     /* Add the Navigation menu */
157     fNavigationMenu = new BMenu( "Navigation" );
158     fMenuBar->AddItem( fNavigationMenu );
159     fNavigationMenu->AddItem( fPrevTitleMI );
160     fNavigationMenu->AddItem( fNextTitleMI );
161     fNavigationMenu->AddItem( fTitleMenu = new TitleMenu( "Go to Title", p_intf ) );
162     fNavigationMenu->AddSeparatorItem();
163     fNavigationMenu->AddItem( fPrevChapterMI );
164     fNavigationMenu->AddItem( fNextChapterMI );
165     fNavigationMenu->AddItem( fChapterMenu = new ChapterMenu( "Go to Chapter", p_intf ) );
166
167     /* Add the Speed menu */
168     fSpeedMenu = new BMenu( "Speed" );
169     fSpeedMenu->SetRadioMode( true );
170     fSpeedMenu->AddItem( fSlowerMI = new BMenuItem( "Slower", new BMessage( SLOWER_PLAY ) ) );
171     fNormalMI = new BMenuItem( "Normal", new BMessage( NORMAL_PLAY ) );
172     fNormalMI->SetMarked(true); // default to normal speed
173     fSpeedMenu->AddItem( fNormalMI );
174     fSpeedMenu->AddItem( fFasterMI = new BMenuItem( "Faster", new BMessage( FASTER_PLAY) ) );
175     fSpeedMenu->SetTargetForItems( this );
176     fMenuBar->AddItem( fSpeedMenu );
177
178     /* Add the Show menu */
179     fShowMenu = new BMenu( "Show" );
180     fShowMenu->AddItem( new BMenuItem( "Play List" B_UTF8_ELLIPSIS,
181                                        new BMessage( OPEN_PLAYLIST ), 'P') );
182     fShowMenu->AddItem( new BMenuItem( "Messages" B_UTF8_ELLIPSIS,
183                                        new BMessage( OPEN_MESSAGES ), 'M' ) );
184     fShowMenu->AddItem( new BMenuItem( "Settings" B_UTF8_ELLIPSIS,
185                                        new BMessage( OPEN_PREFERENCES ), 'S' ) );
186     fMenuBar->AddItem( fShowMenu );                            
187
188     /* Prepare fow showing */
189     _SetMenusEnabled( false );
190     p_mediaControl->SetEnabled( false );
191     
192     /* Restore interface settings */
193     int i_width = config_GetInt( p_intf, "beos-intf-width" ),
194         i_height = config_GetInt( p_intf, "beos-intf-height" ),
195         i_xpos = config_GetInt( p_intf, "beos-intf-xpos" ),
196         i_ypos = config_GetInt( p_intf, "beos-intf-ypos" );
197     if( i_width && i_height && i_xpos && i_ypos )
198     {
199         /* main window size and position */
200         ResizeTo( i_width, i_height );
201         MoveTo( i_xpos, i_ypos );
202     }
203     i_width = config_GetInt( p_intf, "beos-playlist-width" ),
204     i_height = config_GetInt( p_intf, "beos-playlist-height" ),
205     i_xpos = config_GetInt( p_intf, "beos-playlist-xpos" ),
206     i_ypos = config_GetInt( p_intf, "beos-playlist-ypos" );
207     if( i_width && i_height && i_xpos && i_ypos )
208     {
209         /* playlist window size and position */
210         fPlaylistWindow->ResizeTo( i_width, i_height );
211         fPlaylistWindow->MoveTo( i_xpos, i_ypos );
212     }
213     if( config_GetInt( p_intf, "beos-playlist-show" ) )
214     {
215         /* playlist showing */
216         if( fPlaylistWindow->Lock() )
217         {
218             fPlaylistWindow->Show();
219             fPlaylistWindow->Unlock();
220         }
221     }
222     if( config_GetInt( p_intf, "beos-messages-show" ) )
223     {
224         /* messages showing */
225         if( fMessagesWindow->Lock() )
226         {
227             fMessagesWindow->Show();
228             fMessagesWindow->Unlock();
229         }
230     }
231     
232     Show();
233 }
234
235 InterfaceWindow::~InterfaceWindow()
236 {
237     if (fPlaylistWindow)
238         fPlaylistWindow->ReallyQuit();
239 }
240
241 /*****************************************************************************
242  * InterfaceWindow::FrameResized
243  *****************************************************************************/
244 void
245 InterfaceWindow::FrameResized(float width, float height)
246 {
247     BRect r(Bounds());
248     fMenuBar->MoveTo(r.LeftTop());
249     fMenuBar->ResizeTo(r.Width(), fMenuBar->Bounds().Height());
250     r.top += fMenuBar->Bounds().Height() + 1.0;
251     p_mediaControl->MoveTo(r.LeftTop());
252     p_mediaControl->ResizeTo(r.Width(), r.Height());
253 }
254
255 /*****************************************************************************
256  * InterfaceWindow::MessageReceived
257  *****************************************************************************/
258 void InterfaceWindow::MessageReceived( BMessage * p_message )
259 {
260     int playback_status;      // remember playback state
261     playback_status = p_wrapper->InputStatus();
262
263     switch( p_message->what )
264     {
265         case B_ABOUT_REQUESTED:
266         {
267             BAlert* alert = new BAlert( VOUT_TITLE,
268                                         "BeOS " VOUT_TITLE "\n\n<www.videolan.org>", "Ok");
269             alert->Go();
270             break;
271         }
272         case TOGGLE_ON_TOP:
273             break;
274             
275         case OPEN_FILE:
276             if( fFilePanel )
277             {
278                 fFilePanel->Show();
279                 break;
280             }
281             fFilePanel = new BFilePanel();
282             fFilePanel->SetTarget( this );
283             fFilePanel->Show();
284             break;
285     
286         case OPEN_PLAYLIST:
287             if (fPlaylistWindow->Lock())
288             {
289                 if (fPlaylistWindow->IsHidden())
290                     fPlaylistWindow->Show();
291                 else
292                     fPlaylistWindow->Activate();
293                 fPlaylistWindow->Unlock();
294             }
295             break;
296         case OPEN_DVD:
297             {
298                 const char *psz_device;
299                 BString type( "dvd" );
300                 if( p_message->FindString( "device", &psz_device ) == B_OK )
301                 {
302                     BString device( psz_device );
303                     p_wrapper->OpenDisc( type, device, 0, 0 );
304                 }
305                 _UpdatePlaylist();
306             }
307             break;
308         
309         case LOAD_SUBFILE:
310             if( fSubtitlesPanel )
311             {
312                 fSubtitlesPanel->Show();
313                 break;
314             }
315             fSubtitlesPanel = new BFilePanel();
316             fSubtitlesPanel->SetTarget( this );
317             fSubtitlesPanel->SetMessage( new BMessage( SUBFILE_RECEIVED ) );
318             fSubtitlesPanel->Show();
319             break;
320
321         case SUBFILE_RECEIVED:
322         {
323             entry_ref ref;
324             if( p_message->FindRef( "refs", 0, &ref ) == B_OK )
325             {
326                 BPath path( &ref );
327                 if ( path.InitCheck() == B_OK )
328                     p_wrapper->LoadSubFile( (char*)path.Path() );
329             }
330             break;
331         }
332     
333         case STOP_PLAYBACK:
334             // this currently stops playback not nicely
335             if (playback_status > UNDEF_S)
336             {
337                 snooze( 400000 );
338                 p_wrapper->PlaylistStop();
339                 p_mediaControl->SetStatus(NOT_STARTED_S, DEFAULT_RATE);
340             }
341             break;
342     
343         case START_PLAYBACK:
344             /*  starts playing in normal mode */
345     
346         case PAUSE_PLAYBACK:
347             /* toggle between pause and play */
348             if (playback_status > UNDEF_S)
349             {
350                 /* pause if currently playing */
351                 if ( playback_status == PLAYING_S )
352                 {
353                     p_wrapper->PlaylistPause();
354                 }
355                 else
356                 {
357                     p_wrapper->PlaylistPlay();
358                 }
359             }
360             else
361             {
362                 /* Play a new file */
363                 p_wrapper->PlaylistPlay();
364             }    
365             break;
366     
367         case FASTER_PLAY:
368             /* cycle the fast playback modes */
369             if (playback_status > UNDEF_S)
370             {
371                 p_wrapper->InputFaster();
372             }
373             break;
374     
375         case SLOWER_PLAY:
376             /*  cycle the slow playback modes */
377             if (playback_status > UNDEF_S)
378             {
379                 p_wrapper->InputSlower();
380             }
381             break;
382     
383         case NORMAL_PLAY:
384             /*  restore speed to normal if already playing */
385             if (playback_status > UNDEF_S)
386             {
387                 p_wrapper->PlaylistPlay();
388             }
389             break;
390     
391         case SEEK_PLAYBACK:
392             /* handled by semaphores */
393             break;
394         // volume related messages
395         case VOLUME_CHG:
396             /* adjust the volume */
397             if (playback_status > UNDEF_S)
398             {
399                 p_wrapper->SetVolume( p_mediaControl->GetVolume() );
400                 p_mediaControl->SetMuted( p_wrapper->IsMuted() );
401             }
402             break;
403     
404         case VOLUME_MUTE:
405             // toggle muting
406             if( p_wrapper->IsMuted() )
407                 p_wrapper->VolumeRestore();
408             else
409                 p_wrapper->VolumeMute();
410             p_mediaControl->SetMuted( p_wrapper->IsMuted() );
411             break;
412     
413         case SELECT_CHANNEL:
414             if ( playback_status > UNDEF_S )
415             {
416                 int32 channel;
417                 if ( p_message->FindInt32( "channel", &channel ) == B_OK )
418                 {
419                     p_wrapper->ToggleLanguage( channel );
420                 }
421             }
422             break;
423     
424         case SELECT_SUBTITLE:
425             if ( playback_status > UNDEF_S )
426             {
427                 int32 subtitle;
428                 if ( p_message->FindInt32( "subtitle", &subtitle ) == B_OK )
429                      p_wrapper->ToggleSubtitle( subtitle );
430             }
431             break;
432     
433         // specific navigation messages
434         case PREV_TITLE:
435         {
436             p_wrapper->PrevTitle();
437             break;
438         }
439         case NEXT_TITLE:
440         {
441             p_wrapper->NextTitle();
442             break;
443         }
444         case TOGGLE_TITLE:
445             if ( playback_status > UNDEF_S )
446             {
447                 int32 index;
448                 if( p_message->FindInt32( "index", &index ) == B_OK )
449                     p_wrapper->ToggleTitle( index );
450             }
451             break;
452         case PREV_CHAPTER:
453         {
454             p_wrapper->PrevChapter();
455             break;
456         }
457         case NEXT_CHAPTER:
458         {
459             p_wrapper->NextChapter();
460             break;
461         }
462         case TOGGLE_CHAPTER:
463             if ( playback_status > UNDEF_S )
464             {
465                 int32 index;
466                 if( p_message->FindInt32( "index", &index ) == B_OK )
467                     p_wrapper->ToggleChapter( index );
468             }
469             break;
470         case PREV_FILE:
471             p_wrapper->PlaylistPrev();
472             break;
473         case NEXT_FILE:
474             p_wrapper->PlaylistNext();
475             break;
476         // general next/prev functionality (skips to whatever makes most sense)
477         case NAVIGATE_PREV:
478             p_wrapper->NavigatePrev();
479             break;
480         case NAVIGATE_NEXT:
481             p_wrapper->NavigateNext();
482             break;
483         // drag'n'drop and system messages
484         case B_REFS_RECEIVED:
485         case B_SIMPLE_DATA:
486             {
487                 /* file(s) opened by the File menu -> append to the playlist;
488                  * file(s) opened by drag & drop -> replace playlist;
489                  * file(s) opened by 'shift' + drag & drop -> append */
490                 bool replace = false;
491                 if ( p_message->WasDropped() )
492                     replace = !( modifiers() & B_SHIFT_KEY );
493                     
494                 // build list of files to be played from message contents
495                 entry_ref ref;
496                 BList files;
497                 for ( int i = 0; p_message->FindRef( "refs", i, &ref ) == B_OK; i++ )
498                 {
499                     BPath path( &ref );
500                     if ( path.InitCheck() == B_OK )
501                     {
502                         bool add = true;
503                         // has the user dropped a dvd disk icon?
504                         BDirectory dir( &ref );
505                         if ( dir.InitCheck() == B_OK && dir.IsRootDirectory() )
506                         {
507                             BVolumeRoster volRoster;
508                             BVolume vol;
509                             BDirectory volumeRoot;
510                             status_t status = volRoster.GetNextVolume( &vol );
511                             while( status == B_NO_ERROR )
512                             {
513                                 if( vol.GetRootDirectory( &volumeRoot ) == B_OK
514                                     && dir == volumeRoot )
515                                 {
516                                     BString volumeName;
517                                     BString deviceName;
518                                     bool isCDROM = false;
519                                     bool success = false;
520                                     deviceName = "";
521                                     volumeName = "";
522                                     char name[B_FILE_NAME_LENGTH];
523                                     if ( vol.GetName( name ) >= B_OK )    // disk is currently mounted
524                                     {
525                                         volumeName = name;
526                                         dev_t dev = vol.Device();
527                                         fs_info info;
528                                         if ( fs_stat_dev( dev, &info ) == B_OK )
529                                         {
530                                             success = true;
531                                             deviceName = info.device_name;
532                                             if ( vol.IsReadOnly() )
533                                             {
534                                                 int i_dev = open( info.device_name, O_RDONLY );
535                                                 if ( i_dev >= 0 )
536                                                 {
537                                                     device_geometry g;
538                                                     if ( ioctl( i_dev, B_GET_GEOMETRY, &g, sizeof( g ) ) >= 0 )
539                                                     isCDROM = ( g.device_type == B_CD );
540                                                     close( i_dev );
541                                                 }
542                                             }
543                                         }
544                                      }
545                                     
546                                     if( success && isCDROM )
547                                     {
548                                         BMessage msg( OPEN_DVD );
549                                         msg.AddString( "device", deviceName.String() );
550                                         PostMessage( &msg );
551                                         add = false;
552                                     }
553                                      break;
554                                 }
555                                 else
556                                 {
557                                      vol.Unset();
558                                     status = volRoster.GetNextVolume( &vol );
559                                 }
560                             }
561                         }
562                         if( add )
563                         {
564                             files.AddItem( new BString( (char*)path.Path() ) );
565                         }
566                     }
567                 }
568                 // give the list to VLC
569                 p_wrapper->OpenFiles(&files, replace);
570                 _UpdatePlaylist();
571             }
572             break;
573
574         case OPEN_PREFERENCES:
575         {
576             if( fPreferencesWindow->Lock() )
577             {
578                 if (fPreferencesWindow->IsHidden())
579                     fPreferencesWindow->Show();
580                 else
581                     fPreferencesWindow->Activate();
582                 fPreferencesWindow->Unlock();
583             }
584             break;
585         }
586
587         case OPEN_MESSAGES:
588         {
589             if( fMessagesWindow->Lock() )
590             {
591                 if (fMessagesWindow->IsHidden())
592                     fMessagesWindow->Show();
593                 else
594                     fMessagesWindow->Activate();
595                 fMessagesWindow->Unlock();
596             }
597             break;
598         }
599                 
600         default:
601             BWindow::MessageReceived( p_message );
602             break;
603     }
604
605 }
606
607 /*****************************************************************************
608  * InterfaceWindow::QuitRequested
609  *****************************************************************************/
610 bool InterfaceWindow::QuitRequested()
611 {
612     p_wrapper->PlaylistStop();
613     p_mediaControl->SetStatus(NOT_STARTED_S, DEFAULT_RATE);
614
615     /* Save interface settings */
616     BRect frame = Frame();
617     config_PutInt( p_intf, "beos-intf-width", (int)frame.Width() );
618     config_PutInt( p_intf, "beos-intf-height", (int)frame.Height() );
619     config_PutInt( p_intf, "beos-intf-xpos", (int)frame.left );
620     config_PutInt( p_intf, "beos-intf-ypos", (int)frame.top );
621     if( fPlaylistWindow->Lock() )
622     {
623         frame = fPlaylistWindow->Frame();
624         config_PutInt( p_intf, "beos-playlist-width", (int)frame.Width() );
625         config_PutInt( p_intf, "beos-playlist-height", (int)frame.Height() );
626         config_PutInt( p_intf, "beos-playlist-xpos", (int)frame.left );
627         config_PutInt( p_intf, "beos-playlist-ypos", (int)frame.top );
628         config_PutInt( p_intf, "beos-playlist-show", !fPlaylistWindow->IsHidden() );
629         fPlaylistWindow->Unlock();
630     }
631     if( fMessagesWindow->Lock() )
632     {
633         config_PutInt( p_intf, "beos-messages-show", !fMessagesWindow->IsHidden() );
634         fMessagesWindow->Unlock();
635     }
636     config_SaveConfigFile( p_intf, "beos" );
637     
638     p_intf->b_die = 1;
639
640     return( true );
641 }
642
643 /*****************************************************************************
644  * InterfaceWindow::UpdateInterface
645  *****************************************************************************/
646 void InterfaceWindow::UpdateInterface()
647 {
648     if( p_wrapper->HasInput() )
649     {
650         if ( acquire_sem( p_mediaControl->fScrubSem ) == B_OK )
651         {
652             p_wrapper->SetTimeAsFloat(p_mediaControl->GetSeekTo());
653         }
654         else if ( Lock() )
655         {
656             p_mediaControl->SetEnabled( true );
657             bool hasTitles = p_wrapper->HasTitles();
658             bool hasChapters = p_wrapper->HasChapters();
659             p_mediaControl->SetStatus( p_wrapper->InputStatus(), 
660                                        p_wrapper->InputRate() );
661             p_mediaControl->SetProgress( p_wrapper->GetTimeAsFloat() );
662             _SetMenusEnabled( true, hasChapters, hasTitles );
663
664             _UpdateSpeedMenu( p_wrapper->InputRate() );
665
666             // enable/disable skip buttons
667             bool canSkipPrev;
668             bool canSkipNext;
669             p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
670             p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
671
672             if ( p_wrapper->HasAudio() )
673             {
674                 p_mediaControl->SetAudioEnabled( true );
675                 p_mediaControl->SetMuted( p_wrapper->IsMuted() );
676             } else
677                 p_mediaControl->SetAudioEnabled( false );
678
679             Unlock();
680         }
681         // update playlist as well
682         if ( fPlaylistWindow->Lock() )
683         {
684             fPlaylistWindow->UpdatePlaylist();
685             fPlaylistWindow->Unlock();
686         }
687     }
688     else
689     {
690         _SetMenusEnabled( false );
691         if( !( p_wrapper->PlaylistSize() > 0 ) )
692            p_mediaControl->SetEnabled( false );
693         else
694             p_mediaControl->SetProgress( 0 );
695     }
696
697     /* always force the user-specified volume */
698     /* FIXME : I'm quite sure there is a cleaner way to do this */
699     int i_volume = p_mediaControl->GetVolume();
700     if( p_wrapper->GetVolume() != i_volume )
701     {
702         p_wrapper->SetVolume( i_volume );
703     }
704     
705     fMessagesWindow->UpdateMessages();
706
707     fLastUpdateTime = system_time();
708 }
709
710 /*****************************************************************************
711  * InterfaceWindow::IsStopped
712  *****************************************************************************/
713 bool
714 InterfaceWindow::IsStopped() const
715 {
716     return (system_time() - fLastUpdateTime > INTERFACE_UPDATE_TIMEOUT);
717 }
718
719 /*****************************************************************************
720  * InterfaceWindow::_UpdatePlaylist
721  *****************************************************************************/
722 void
723 InterfaceWindow::_UpdatePlaylist()
724 {
725     if ( fPlaylistWindow->Lock() )
726     {
727         fPlaylistWindow->UpdatePlaylist( true );
728         fPlaylistWindow->Unlock();
729         p_mediaControl->SetEnabled( p_wrapper->PlaylistSize() );
730     }
731 }
732
733 /*****************************************************************************
734  * InterfaceWindow::_SetMenusEnabled
735  *****************************************************************************/
736 void
737 InterfaceWindow::_SetMenusEnabled(bool hasFile, bool hasChapters, bool hasTitles)
738 {
739     if (!hasFile)
740     {
741         hasChapters = false;
742         hasTitles = false;
743     }
744     if (Lock())
745     {
746         if (fNextChapterMI->IsEnabled() != hasChapters)
747             fNextChapterMI->SetEnabled(hasChapters);
748         if (fPrevChapterMI->IsEnabled() != hasChapters)
749             fPrevChapterMI->SetEnabled(hasChapters);
750         if (fChapterMenu->IsEnabled() != hasChapters)
751             fChapterMenu->SetEnabled(hasChapters);
752         if (fNextTitleMI->IsEnabled() != hasTitles)
753             fNextTitleMI->SetEnabled(hasTitles);
754         if (fPrevTitleMI->IsEnabled() != hasTitles)
755             fPrevTitleMI->SetEnabled(hasTitles);
756         if (fTitleMenu->IsEnabled() != hasTitles)
757             fTitleMenu->SetEnabled(hasTitles);
758         if (fAudioMenu->IsEnabled() != hasFile)
759             fAudioMenu->SetEnabled(hasFile);
760         if (fNavigationMenu->IsEnabled() != hasFile)
761             fNavigationMenu->SetEnabled(hasFile);
762         if (fLanguageMenu->IsEnabled() != hasFile)
763             fLanguageMenu->SetEnabled(hasFile);
764         if (fSubtitlesMenu->IsEnabled() != hasFile)
765             fSubtitlesMenu->SetEnabled(hasFile);
766         if (fSpeedMenu->IsEnabled() != hasFile)
767             fSpeedMenu->SetEnabled(hasFile);
768         Unlock();
769     }
770 }
771
772 /*****************************************************************************
773  * InterfaceWindow::_UpdateSpeedMenu
774  *****************************************************************************/
775 void
776 InterfaceWindow::_UpdateSpeedMenu( int rate )
777 {
778     if ( rate == DEFAULT_RATE )
779     {
780         if ( !fNormalMI->IsMarked() )
781             fNormalMI->SetMarked( true );
782     }
783     else if ( rate < DEFAULT_RATE )
784     {
785         if ( !fFasterMI->IsMarked() )
786             fFasterMI->SetMarked( true );
787     }
788     else
789     {
790         if ( !fSlowerMI->IsMarked() )
791             fSlowerMI->SetMarked( true );
792     }
793 }
794
795 /*****************************************************************************
796  * InterfaceWindow::_InputStreamChanged
797  *****************************************************************************/
798 void
799 InterfaceWindow::_InputStreamChanged()
800 {
801     // TODO: move more stuff from updateInterface() here!
802     snooze( 400000 );
803     p_wrapper->SetVolume( p_mediaControl->GetVolume() );
804 }
805
806 void
807 make_sure_frame_is_within_limits( BRect& frame, float minWidth, float minHeight,
808                                   float maxWidth, float maxHeight )
809 {
810     if ( frame.Width() < minWidth )
811         frame.right = frame.left + minWidth;
812     if ( frame.Height() < minHeight )
813         frame.bottom = frame.top + minHeight;
814     if ( frame.Width() > maxWidth )
815         frame.right = frame.left + maxWidth;
816     if ( frame.Height() > maxHeight )
817         frame.bottom = frame.top + maxHeight;
818 }
819
820 /*****************************************************************************
821  * CDMenu::CDMenu
822  *****************************************************************************/
823 CDMenu::CDMenu(const char *name)
824       : BMenu(name)
825 {
826 }
827
828 /*****************************************************************************
829  * CDMenu::~CDMenu
830  *****************************************************************************/
831 CDMenu::~CDMenu()
832 {
833 }
834
835 /*****************************************************************************
836  * CDMenu::AttachedToWindow
837  *****************************************************************************/
838 void CDMenu::AttachedToWindow(void)
839 {
840     // remove all items
841     while (BMenuItem* item = RemoveItem(0L))
842         delete item;
843     GetCD("/dev/disk");
844     BMenu::AttachedToWindow();
845 }
846
847 /*****************************************************************************
848  * CDMenu::GetCD
849  *****************************************************************************/
850 int CDMenu::GetCD( const char *directory )
851 {
852     BVolumeRoster *volRoster;
853     BVolume       *vol;
854     BDirectory    *dir;
855     int           status;
856     int           mounted;   
857     char          name[B_FILE_NAME_LENGTH]; 
858     fs_info       info;
859     dev_t         dev;
860     
861     volRoster = new BVolumeRoster();
862     vol = new BVolume();
863     dir = new BDirectory();
864     status = volRoster->GetNextVolume(vol);
865     status = vol->GetRootDirectory(dir);
866     while (status ==  B_NO_ERROR)
867     {
868         mounted = vol->GetName(name);    
869         if ((mounted == B_OK) && /* Disk is currently Mounted */
870             (vol->IsReadOnly()) ) /* Disk is read-only */
871         {
872             dev = vol->Device();
873             fs_stat_dev(dev, &info);
874             
875             device_geometry g;
876             int i_dev;
877             i_dev = open( info.device_name, O_RDONLY );
878            
879             if( i_dev >= 0 )
880             {
881                 if( ioctl(i_dev, B_GET_GEOMETRY, &g, sizeof(g)) >= 0 )
882                 {
883                     if( g.device_type == B_CD ) //ensure the drive is a CD-ROM
884                     {
885                         BMessage *msg;
886                         msg = new BMessage( OPEN_DVD );
887                         msg->AddString( "device", info.device_name );
888                         BMenuItem *menu_item;
889                         menu_item = new BMenuItem( name, msg );
890                         AddItem( menu_item );
891                     }
892                     close(i_dev);
893                 }
894             }
895          }
896          vol->Unset();
897         status = volRoster->GetNextVolume(vol);
898     }
899     return 0;
900 }
901
902 /*****************************************************************************
903  * LanguageMenu::LanguageMenu
904  *****************************************************************************/
905 LanguageMenu::LanguageMenu( const char *name, int menu_kind, 
906                             VlcWrapper *p_wrapper )
907     :BMenu(name)
908 {
909     kind = menu_kind;
910     this->p_wrapper = p_wrapper;
911 }
912
913 /*****************************************************************************
914  * LanguageMenu::~LanguageMenu
915  *****************************************************************************/
916 LanguageMenu::~LanguageMenu()
917 {
918 }
919
920 /*****************************************************************************
921  * LanguageMenu::AttachedToWindow
922  *****************************************************************************/
923 void LanguageMenu::AttachedToWindow()
924 {
925     // remove all items
926     while ( BMenuItem* item = RemoveItem( 0L ) )
927         delete item;
928
929     SetRadioMode( true );
930     _GetChannels();
931     BMenu::AttachedToWindow();
932 }
933
934 /*****************************************************************************
935  * LanguageMenu::_GetChannels
936  *****************************************************************************/
937 void LanguageMenu::_GetChannels()
938 {
939     BMenuItem *item;
940     BList *list;
941     
942     if( ( list = p_wrapper->GetChannels( kind ) ) == NULL )
943         return;
944     
945     for( int i = 0; i < list->CountItems(); i++ )
946     {
947         item = (BMenuItem*)list->ItemAt( i );
948         AddItem( item );
949     }
950     
951     if( list->CountItems() > 1 )
952         AddItem( new BSeparatorItem(), 1 );
953 }
954
955
956 /*****************************************************************************
957  * TitleMenu::TitleMenu
958  *****************************************************************************/
959 TitleMenu::TitleMenu( const char *name, intf_thread_t  *p_interface )
960     : BMenu(name),
961     p_intf( p_interface )
962 {
963 }
964
965 /*****************************************************************************
966  * TitleMenu::~TitleMenu
967  *****************************************************************************/
968 TitleMenu::~TitleMenu()
969 {
970 }
971
972 /*****************************************************************************
973  * TitleMenu::AttachedToWindow
974  *****************************************************************************/
975 void TitleMenu::AttachedToWindow()
976 {
977     BMenuItem *item;
978     BList *list;
979
980     while( ( item = RemoveItem( 0L ) ) )
981         delete item;
982     
983     if( ( list = p_intf->p_sys->p_wrapper->GetTitles() ) == NULL )
984         return;
985     
986     for( int i = 0; i < list->CountItems(); i++ )
987     {
988         item = (BMenuItem*)list->ItemAt( i );
989         AddItem( item );
990     }
991     
992     BMenu::AttachedToWindow();
993 }
994
995
996 /*****************************************************************************
997  * ChapterMenu::ChapterMenu
998  *****************************************************************************/
999 ChapterMenu::ChapterMenu( const char *name, intf_thread_t  *p_interface )
1000     : BMenu(name),
1001     p_intf( p_interface )
1002 {
1003 }
1004
1005 /*****************************************************************************
1006  * ChapterMenu::~ChapterMenu
1007  *****************************************************************************/
1008 ChapterMenu::~ChapterMenu()
1009 {
1010 }
1011
1012 /*****************************************************************************
1013  * ChapterMenu::AttachedToWindow
1014  *****************************************************************************/
1015 void ChapterMenu::AttachedToWindow()
1016 {
1017     BMenuItem *item;
1018     BList *list;
1019
1020     while( ( item = RemoveItem( 0L ) ) )
1021         delete item;
1022     
1023     if( ( list = p_intf->p_sys->p_wrapper->GetChapters() ) == NULL )
1024         return;
1025     
1026     for( int i = 0; i < list->CountItems(); i++ )
1027     {
1028         item = (BMenuItem*)list->ItemAt( i );
1029         AddItem( item );
1030     }
1031     
1032     BMenu::AttachedToWindow();
1033 }
1034