]> git.sesse.net Git - vlc/blob - modules/gui/beos/InterfaceWindow.cpp
* beos/* : do not forgot to destroy the Messages window, so vlc does
[vlc] / 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.24 2003/01/28 08:17:26 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     if( fMessagesWindow )
240         fMessagesWindow->ReallyQuit();
241 }
242
243 /*****************************************************************************
244  * InterfaceWindow::FrameResized
245  *****************************************************************************/
246 void
247 InterfaceWindow::FrameResized(float width, float height)
248 {
249     BRect r(Bounds());
250     fMenuBar->MoveTo(r.LeftTop());
251     fMenuBar->ResizeTo(r.Width(), fMenuBar->Bounds().Height());
252     r.top += fMenuBar->Bounds().Height() + 1.0;
253     p_mediaControl->MoveTo(r.LeftTop());
254     p_mediaControl->ResizeTo(r.Width(), r.Height());
255 }
256
257 /*****************************************************************************
258  * InterfaceWindow::MessageReceived
259  *****************************************************************************/
260 void InterfaceWindow::MessageReceived( BMessage * p_message )
261 {
262     int playback_status;      // remember playback state
263     playback_status = p_wrapper->InputStatus();
264
265     switch( p_message->what )
266     {
267         case B_ABOUT_REQUESTED:
268         {
269             BAlert* alert = new BAlert( VOUT_TITLE,
270                                         "BeOS " VOUT_TITLE "\n\n<www.videolan.org>", "Ok");
271             alert->Go();
272             break;
273         }
274         case TOGGLE_ON_TOP:
275             break;
276             
277         case OPEN_FILE:
278             if( fFilePanel )
279             {
280                 fFilePanel->Show();
281                 break;
282             }
283             fFilePanel = new BFilePanel();
284             fFilePanel->SetTarget( this );
285             fFilePanel->Show();
286             break;
287     
288         case OPEN_PLAYLIST:
289             if (fPlaylistWindow->Lock())
290             {
291                 if (fPlaylistWindow->IsHidden())
292                     fPlaylistWindow->Show();
293                 else
294                     fPlaylistWindow->Activate();
295                 fPlaylistWindow->Unlock();
296             }
297             break;
298         case OPEN_DVD:
299             {
300                 const char *psz_device;
301                 BString type( "dvd" );
302                 if( p_message->FindString( "device", &psz_device ) == B_OK )
303                 {
304                     BString device( psz_device );
305                     p_wrapper->OpenDisc( type, device, 0, 0 );
306                 }
307                 _UpdatePlaylist();
308             }
309             break;
310         
311         case LOAD_SUBFILE:
312             if( fSubtitlesPanel )
313             {
314                 fSubtitlesPanel->Show();
315                 break;
316             }
317             fSubtitlesPanel = new BFilePanel();
318             fSubtitlesPanel->SetTarget( this );
319             fSubtitlesPanel->SetMessage( new BMessage( SUBFILE_RECEIVED ) );
320             fSubtitlesPanel->Show();
321             break;
322
323         case SUBFILE_RECEIVED:
324         {
325             entry_ref ref;
326             if( p_message->FindRef( "refs", 0, &ref ) == B_OK )
327             {
328                 BPath path( &ref );
329                 if ( path.InitCheck() == B_OK )
330                     p_wrapper->LoadSubFile( (char*)path.Path() );
331             }
332             break;
333         }
334     
335         case STOP_PLAYBACK:
336             // this currently stops playback not nicely
337             if (playback_status > UNDEF_S)
338             {
339                 snooze( 400000 );
340                 p_wrapper->PlaylistStop();
341                 p_mediaControl->SetStatus(NOT_STARTED_S, DEFAULT_RATE);
342             }
343             break;
344     
345         case START_PLAYBACK:
346             /*  starts playing in normal mode */
347     
348         case PAUSE_PLAYBACK:
349             /* toggle between pause and play */
350             if (playback_status > UNDEF_S)
351             {
352                 /* pause if currently playing */
353                 if ( playback_status == PLAYING_S )
354                 {
355                     p_wrapper->PlaylistPause();
356                 }
357                 else
358                 {
359                     p_wrapper->PlaylistPlay();
360                 }
361             }
362             else
363             {
364                 /* Play a new file */
365                 p_wrapper->PlaylistPlay();
366             }    
367             break;
368     
369         case FASTER_PLAY:
370             /* cycle the fast playback modes */
371             if (playback_status > UNDEF_S)
372             {
373                 p_wrapper->InputFaster();
374             }
375             break;
376     
377         case SLOWER_PLAY:
378             /*  cycle the slow playback modes */
379             if (playback_status > UNDEF_S)
380             {
381                 p_wrapper->InputSlower();
382             }
383             break;
384     
385         case NORMAL_PLAY:
386             /*  restore speed to normal if already playing */
387             if (playback_status > UNDEF_S)
388             {
389                 p_wrapper->PlaylistPlay();
390             }
391             break;
392     
393         case SEEK_PLAYBACK:
394             /* handled by semaphores */
395             break;
396         // volume related messages
397         case VOLUME_CHG:
398             /* adjust the volume */
399             if (playback_status > UNDEF_S)
400             {
401                 p_wrapper->SetVolume( p_mediaControl->GetVolume() );
402                 p_mediaControl->SetMuted( p_wrapper->IsMuted() );
403             }
404             break;
405     
406         case VOLUME_MUTE:
407             // toggle muting
408             if( p_wrapper->IsMuted() )
409                 p_wrapper->VolumeRestore();
410             else
411                 p_wrapper->VolumeMute();
412             p_mediaControl->SetMuted( p_wrapper->IsMuted() );
413             break;
414     
415         case SELECT_CHANNEL:
416             if ( playback_status > UNDEF_S )
417             {
418                 int32 channel;
419                 if ( p_message->FindInt32( "channel", &channel ) == B_OK )
420                 {
421                     p_wrapper->ToggleLanguage( channel );
422                 }
423             }
424             break;
425     
426         case SELECT_SUBTITLE:
427             if ( playback_status > UNDEF_S )
428             {
429                 int32 subtitle;
430                 if ( p_message->FindInt32( "subtitle", &subtitle ) == B_OK )
431                      p_wrapper->ToggleSubtitle( subtitle );
432             }
433             break;
434     
435         // specific navigation messages
436         case PREV_TITLE:
437         {
438             p_wrapper->PrevTitle();
439             break;
440         }
441         case NEXT_TITLE:
442         {
443             p_wrapper->NextTitle();
444             break;
445         }
446         case TOGGLE_TITLE:
447             if ( playback_status > UNDEF_S )
448             {
449                 int32 index;
450                 if( p_message->FindInt32( "index", &index ) == B_OK )
451                     p_wrapper->ToggleTitle( index );
452             }
453             break;
454         case PREV_CHAPTER:
455         {
456             p_wrapper->PrevChapter();
457             break;
458         }
459         case NEXT_CHAPTER:
460         {
461             p_wrapper->NextChapter();
462             break;
463         }
464         case TOGGLE_CHAPTER:
465             if ( playback_status > UNDEF_S )
466             {
467                 int32 index;
468                 if( p_message->FindInt32( "index", &index ) == B_OK )
469                     p_wrapper->ToggleChapter( index );
470             }
471             break;
472         case PREV_FILE:
473             p_wrapper->PlaylistPrev();
474             break;
475         case NEXT_FILE:
476             p_wrapper->PlaylistNext();
477             break;
478         // general next/prev functionality (skips to whatever makes most sense)
479         case NAVIGATE_PREV:
480             p_wrapper->NavigatePrev();
481             break;
482         case NAVIGATE_NEXT:
483             p_wrapper->NavigateNext();
484             break;
485         // drag'n'drop and system messages
486         case B_REFS_RECEIVED:
487         case B_SIMPLE_DATA:
488             {
489                 /* file(s) opened by the File menu -> append to the playlist;
490                  * file(s) opened by drag & drop -> replace playlist;
491                  * file(s) opened by 'shift' + drag & drop -> append */
492                 bool replace = false;
493                 if ( p_message->WasDropped() )
494                     replace = !( modifiers() & B_SHIFT_KEY );
495                     
496                 // build list of files to be played from message contents
497                 entry_ref ref;
498                 BList files;
499                 for ( int i = 0; p_message->FindRef( "refs", i, &ref ) == B_OK; i++ )
500                 {
501                     BPath path( &ref );
502                     if ( path.InitCheck() == B_OK )
503                     {
504                         bool add = true;
505                         // has the user dropped a dvd disk icon?
506                         BDirectory dir( &ref );
507                         if ( dir.InitCheck() == B_OK && dir.IsRootDirectory() )
508                         {
509                             BVolumeRoster volRoster;
510                             BVolume vol;
511                             BDirectory volumeRoot;
512                             status_t status = volRoster.GetNextVolume( &vol );
513                             while( status == B_NO_ERROR )
514                             {
515                                 if( vol.GetRootDirectory( &volumeRoot ) == B_OK
516                                     && dir == volumeRoot )
517                                 {
518                                     BString volumeName;
519                                     BString deviceName;
520                                     bool isCDROM = false;
521                                     bool success = false;
522                                     deviceName = "";
523                                     volumeName = "";
524                                     char name[B_FILE_NAME_LENGTH];
525                                     if ( vol.GetName( name ) >= B_OK )    // disk is currently mounted
526                                     {
527                                         volumeName = name;
528                                         dev_t dev = vol.Device();
529                                         fs_info info;
530                                         if ( fs_stat_dev( dev, &info ) == B_OK )
531                                         {
532                                             success = true;
533                                             deviceName = info.device_name;
534                                             if ( vol.IsReadOnly() )
535                                             {
536                                                 int i_dev = open( info.device_name, O_RDONLY );
537                                                 if ( i_dev >= 0 )
538                                                 {
539                                                     device_geometry g;
540                                                     if ( ioctl( i_dev, B_GET_GEOMETRY, &g, sizeof( g ) ) >= 0 )
541                                                     isCDROM = ( g.device_type == B_CD );
542                                                     close( i_dev );
543                                                 }
544                                             }
545                                         }
546                                      }
547                                     
548                                     if( success && isCDROM )
549                                     {
550                                         BMessage msg( OPEN_DVD );
551                                         msg.AddString( "device", deviceName.String() );
552                                         PostMessage( &msg );
553                                         add = false;
554                                     }
555                                      break;
556                                 }
557                                 else
558                                 {
559                                      vol.Unset();
560                                     status = volRoster.GetNextVolume( &vol );
561                                 }
562                             }
563                         }
564                         if( add )
565                         {
566                             files.AddItem( new BString( (char*)path.Path() ) );
567                         }
568                     }
569                 }
570                 // give the list to VLC
571                 p_wrapper->OpenFiles(&files, replace);
572                 _UpdatePlaylist();
573             }
574             break;
575
576         case OPEN_PREFERENCES:
577         {
578             if( fPreferencesWindow->Lock() )
579             {
580                 if (fPreferencesWindow->IsHidden())
581                     fPreferencesWindow->Show();
582                 else
583                     fPreferencesWindow->Activate();
584                 fPreferencesWindow->Unlock();
585             }
586             break;
587         }
588
589         case OPEN_MESSAGES:
590         {
591             if( fMessagesWindow->Lock() )
592             {
593                 if (fMessagesWindow->IsHidden())
594                     fMessagesWindow->Show();
595                 else
596                     fMessagesWindow->Activate();
597                 fMessagesWindow->Unlock();
598             }
599             break;
600         }
601                 
602         default:
603             BWindow::MessageReceived( p_message );
604             break;
605     }
606
607 }
608
609 /*****************************************************************************
610  * InterfaceWindow::QuitRequested
611  *****************************************************************************/
612 bool InterfaceWindow::QuitRequested()
613 {
614     p_wrapper->PlaylistStop();
615     p_mediaControl->SetStatus(NOT_STARTED_S, DEFAULT_RATE);
616
617     /* Save interface settings */
618     BRect frame = Frame();
619     config_PutInt( p_intf, "beos-intf-width", (int)frame.Width() );
620     config_PutInt( p_intf, "beos-intf-height", (int)frame.Height() );
621     config_PutInt( p_intf, "beos-intf-xpos", (int)frame.left );
622     config_PutInt( p_intf, "beos-intf-ypos", (int)frame.top );
623     if( fPlaylistWindow->Lock() )
624     {
625         frame = fPlaylistWindow->Frame();
626         config_PutInt( p_intf, "beos-playlist-width", (int)frame.Width() );
627         config_PutInt( p_intf, "beos-playlist-height", (int)frame.Height() );
628         config_PutInt( p_intf, "beos-playlist-xpos", (int)frame.left );
629         config_PutInt( p_intf, "beos-playlist-ypos", (int)frame.top );
630         config_PutInt( p_intf, "beos-playlist-show", !fPlaylistWindow->IsHidden() );
631         fPlaylistWindow->Unlock();
632     }
633     if( fMessagesWindow->Lock() )
634     {
635         config_PutInt( p_intf, "beos-messages-show", !fMessagesWindow->IsHidden() );
636         fMessagesWindow->Unlock();
637     }
638     config_SaveConfigFile( p_intf, "beos" );
639     
640     p_intf->b_die = 1;
641
642     return( true );
643 }
644
645 /*****************************************************************************
646  * InterfaceWindow::UpdateInterface
647  *****************************************************************************/
648 void InterfaceWindow::UpdateInterface()
649 {
650     if( p_wrapper->HasInput() )
651     {
652         if ( acquire_sem( p_mediaControl->fScrubSem ) == B_OK )
653         {
654             p_wrapper->SetTimeAsFloat(p_mediaControl->GetSeekTo());
655         }
656         else if ( Lock() )
657         {
658             p_mediaControl->SetEnabled( true );
659             bool hasTitles = p_wrapper->HasTitles();
660             bool hasChapters = p_wrapper->HasChapters();
661             p_mediaControl->SetStatus( p_wrapper->InputStatus(), 
662                                        p_wrapper->InputRate() );
663             p_mediaControl->SetProgress( p_wrapper->GetTimeAsFloat() );
664             _SetMenusEnabled( true, hasChapters, hasTitles );
665
666             _UpdateSpeedMenu( p_wrapper->InputRate() );
667
668             // enable/disable skip buttons
669             bool canSkipPrev;
670             bool canSkipNext;
671             p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
672             p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
673
674             if ( p_wrapper->HasAudio() )
675             {
676                 p_mediaControl->SetAudioEnabled( true );
677                 p_mediaControl->SetMuted( p_wrapper->IsMuted() );
678             } else
679                 p_mediaControl->SetAudioEnabled( false );
680
681             Unlock();
682         }
683         // update playlist as well
684         if ( fPlaylistWindow->Lock() )
685         {
686             fPlaylistWindow->UpdatePlaylist();
687             fPlaylistWindow->Unlock();
688         }
689     }
690     else
691     {
692         _SetMenusEnabled( false );
693         if( !( p_wrapper->PlaylistSize() > 0 ) )
694            p_mediaControl->SetEnabled( false );
695         else
696             p_mediaControl->SetProgress( 0 );
697     }
698
699     /* always force the user-specified volume */
700     /* FIXME : I'm quite sure there is a cleaner way to do this */
701     int i_volume = p_mediaControl->GetVolume();
702     if( p_wrapper->GetVolume() != i_volume )
703     {
704         p_wrapper->SetVolume( i_volume );
705     }
706     
707     fMessagesWindow->UpdateMessages();
708
709     fLastUpdateTime = system_time();
710 }
711
712 /*****************************************************************************
713  * InterfaceWindow::IsStopped
714  *****************************************************************************/
715 bool
716 InterfaceWindow::IsStopped() const
717 {
718     return (system_time() - fLastUpdateTime > INTERFACE_UPDATE_TIMEOUT);
719 }
720
721 /*****************************************************************************
722  * InterfaceWindow::_UpdatePlaylist
723  *****************************************************************************/
724 void
725 InterfaceWindow::_UpdatePlaylist()
726 {
727     if ( fPlaylistWindow->Lock() )
728     {
729         fPlaylistWindow->UpdatePlaylist( true );
730         fPlaylistWindow->Unlock();
731         p_mediaControl->SetEnabled( p_wrapper->PlaylistSize() );
732     }
733 }
734
735 /*****************************************************************************
736  * InterfaceWindow::_SetMenusEnabled
737  *****************************************************************************/
738 void
739 InterfaceWindow::_SetMenusEnabled(bool hasFile, bool hasChapters, bool hasTitles)
740 {
741     if (!hasFile)
742     {
743         hasChapters = false;
744         hasTitles = false;
745     }
746     if (Lock())
747     {
748         if (fNextChapterMI->IsEnabled() != hasChapters)
749             fNextChapterMI->SetEnabled(hasChapters);
750         if (fPrevChapterMI->IsEnabled() != hasChapters)
751             fPrevChapterMI->SetEnabled(hasChapters);
752         if (fChapterMenu->IsEnabled() != hasChapters)
753             fChapterMenu->SetEnabled(hasChapters);
754         if (fNextTitleMI->IsEnabled() != hasTitles)
755             fNextTitleMI->SetEnabled(hasTitles);
756         if (fPrevTitleMI->IsEnabled() != hasTitles)
757             fPrevTitleMI->SetEnabled(hasTitles);
758         if (fTitleMenu->IsEnabled() != hasTitles)
759             fTitleMenu->SetEnabled(hasTitles);
760         if (fAudioMenu->IsEnabled() != hasFile)
761             fAudioMenu->SetEnabled(hasFile);
762         if (fNavigationMenu->IsEnabled() != hasFile)
763             fNavigationMenu->SetEnabled(hasFile);
764         if (fLanguageMenu->IsEnabled() != hasFile)
765             fLanguageMenu->SetEnabled(hasFile);
766         if (fSubtitlesMenu->IsEnabled() != hasFile)
767             fSubtitlesMenu->SetEnabled(hasFile);
768         if (fSpeedMenu->IsEnabled() != hasFile)
769             fSpeedMenu->SetEnabled(hasFile);
770         Unlock();
771     }
772 }
773
774 /*****************************************************************************
775  * InterfaceWindow::_UpdateSpeedMenu
776  *****************************************************************************/
777 void
778 InterfaceWindow::_UpdateSpeedMenu( int rate )
779 {
780     if ( rate == DEFAULT_RATE )
781     {
782         if ( !fNormalMI->IsMarked() )
783             fNormalMI->SetMarked( true );
784     }
785     else if ( rate < DEFAULT_RATE )
786     {
787         if ( !fFasterMI->IsMarked() )
788             fFasterMI->SetMarked( true );
789     }
790     else
791     {
792         if ( !fSlowerMI->IsMarked() )
793             fSlowerMI->SetMarked( true );
794     }
795 }
796
797 /*****************************************************************************
798  * InterfaceWindow::_InputStreamChanged
799  *****************************************************************************/
800 void
801 InterfaceWindow::_InputStreamChanged()
802 {
803     // TODO: move more stuff from updateInterface() here!
804     snooze( 400000 );
805     p_wrapper->SetVolume( p_mediaControl->GetVolume() );
806 }
807
808 void
809 make_sure_frame_is_within_limits( BRect& frame, float minWidth, float minHeight,
810                                   float maxWidth, float maxHeight )
811 {
812     if ( frame.Width() < minWidth )
813         frame.right = frame.left + minWidth;
814     if ( frame.Height() < minHeight )
815         frame.bottom = frame.top + minHeight;
816     if ( frame.Width() > maxWidth )
817         frame.right = frame.left + maxWidth;
818     if ( frame.Height() > maxHeight )
819         frame.bottom = frame.top + maxHeight;
820 }
821
822 /*****************************************************************************
823  * CDMenu::CDMenu
824  *****************************************************************************/
825 CDMenu::CDMenu(const char *name)
826       : BMenu(name)
827 {
828 }
829
830 /*****************************************************************************
831  * CDMenu::~CDMenu
832  *****************************************************************************/
833 CDMenu::~CDMenu()
834 {
835 }
836
837 /*****************************************************************************
838  * CDMenu::AttachedToWindow
839  *****************************************************************************/
840 void CDMenu::AttachedToWindow(void)
841 {
842     // remove all items
843     while (BMenuItem* item = RemoveItem(0L))
844         delete item;
845     GetCD("/dev/disk");
846     BMenu::AttachedToWindow();
847 }
848
849 /*****************************************************************************
850  * CDMenu::GetCD
851  *****************************************************************************/
852 int CDMenu::GetCD( const char *directory )
853 {
854     BVolumeRoster *volRoster;
855     BVolume       *vol;
856     BDirectory    *dir;
857     int           status;
858     int           mounted;   
859     char          name[B_FILE_NAME_LENGTH]; 
860     fs_info       info;
861     dev_t         dev;
862     
863     volRoster = new BVolumeRoster();
864     vol = new BVolume();
865     dir = new BDirectory();
866     status = volRoster->GetNextVolume(vol);
867     status = vol->GetRootDirectory(dir);
868     while (status ==  B_NO_ERROR)
869     {
870         mounted = vol->GetName(name);    
871         if ((mounted == B_OK) && /* Disk is currently Mounted */
872             (vol->IsReadOnly()) ) /* Disk is read-only */
873         {
874             dev = vol->Device();
875             fs_stat_dev(dev, &info);
876             
877             device_geometry g;
878             int i_dev;
879             i_dev = open( info.device_name, O_RDONLY );
880            
881             if( i_dev >= 0 )
882             {
883                 if( ioctl(i_dev, B_GET_GEOMETRY, &g, sizeof(g)) >= 0 )
884                 {
885                     if( g.device_type == B_CD ) //ensure the drive is a CD-ROM
886                     {
887                         BMessage *msg;
888                         msg = new BMessage( OPEN_DVD );
889                         msg->AddString( "device", info.device_name );
890                         BMenuItem *menu_item;
891                         menu_item = new BMenuItem( name, msg );
892                         AddItem( menu_item );
893                     }
894                     close(i_dev);
895                 }
896             }
897          }
898          vol->Unset();
899         status = volRoster->GetNextVolume(vol);
900     }
901     return 0;
902 }
903
904 /*****************************************************************************
905  * LanguageMenu::LanguageMenu
906  *****************************************************************************/
907 LanguageMenu::LanguageMenu( const char *name, int menu_kind, 
908                             VlcWrapper *p_wrapper )
909     :BMenu(name)
910 {
911     kind = menu_kind;
912     this->p_wrapper = p_wrapper;
913 }
914
915 /*****************************************************************************
916  * LanguageMenu::~LanguageMenu
917  *****************************************************************************/
918 LanguageMenu::~LanguageMenu()
919 {
920 }
921
922 /*****************************************************************************
923  * LanguageMenu::AttachedToWindow
924  *****************************************************************************/
925 void LanguageMenu::AttachedToWindow()
926 {
927     // remove all items
928     while ( BMenuItem* item = RemoveItem( 0L ) )
929         delete item;
930
931     SetRadioMode( true );
932     _GetChannels();
933     BMenu::AttachedToWindow();
934 }
935
936 /*****************************************************************************
937  * LanguageMenu::_GetChannels
938  *****************************************************************************/
939 void LanguageMenu::_GetChannels()
940 {
941     BMenuItem *item;
942     BList *list;
943     
944     if( ( list = p_wrapper->GetChannels( kind ) ) == NULL )
945         return;
946     
947     for( int i = 0; i < list->CountItems(); i++ )
948     {
949         item = (BMenuItem*)list->ItemAt( i );
950         AddItem( item );
951     }
952     
953     if( list->CountItems() > 1 )
954         AddItem( new BSeparatorItem(), 1 );
955 }
956
957
958 /*****************************************************************************
959  * TitleMenu::TitleMenu
960  *****************************************************************************/
961 TitleMenu::TitleMenu( const char *name, intf_thread_t  *p_interface )
962     : BMenu(name),
963     p_intf( p_interface )
964 {
965 }
966
967 /*****************************************************************************
968  * TitleMenu::~TitleMenu
969  *****************************************************************************/
970 TitleMenu::~TitleMenu()
971 {
972 }
973
974 /*****************************************************************************
975  * TitleMenu::AttachedToWindow
976  *****************************************************************************/
977 void TitleMenu::AttachedToWindow()
978 {
979     BMenuItem *item;
980     BList *list;
981
982     while( ( item = RemoveItem( 0L ) ) )
983         delete item;
984     
985     if( ( list = p_intf->p_sys->p_wrapper->GetTitles() ) == NULL )
986         return;
987     
988     for( int i = 0; i < list->CountItems(); i++ )
989     {
990         item = (BMenuItem*)list->ItemAt( i );
991         AddItem( item );
992     }
993     
994     BMenu::AttachedToWindow();
995 }
996
997
998 /*****************************************************************************
999  * ChapterMenu::ChapterMenu
1000  *****************************************************************************/
1001 ChapterMenu::ChapterMenu( const char *name, intf_thread_t  *p_interface )
1002     : BMenu(name),
1003     p_intf( p_interface )
1004 {
1005 }
1006
1007 /*****************************************************************************
1008  * ChapterMenu::~ChapterMenu
1009  *****************************************************************************/
1010 ChapterMenu::~ChapterMenu()
1011 {
1012 }
1013
1014 /*****************************************************************************
1015  * ChapterMenu::AttachedToWindow
1016  *****************************************************************************/
1017 void ChapterMenu::AttachedToWindow()
1018 {
1019     BMenuItem *item;
1020     BList *list;
1021
1022     while( ( item = RemoveItem( 0L ) ) )
1023         delete item;
1024     
1025     if( ( list = p_intf->p_sys->p_wrapper->GetChapters() ) == NULL )
1026         return;
1027     
1028     for( int i = 0; i < list->CountItems(); i++ )
1029     {
1030         item = (BMenuItem*)list->ItemAt( i );
1031         AddItem( item );
1032     }
1033     
1034     BMenu::AttachedToWindow();
1035 }
1036