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