]> git.sesse.net Git - vlc/blob - modules/gui/beos/InterfaceWindow.cpp
fixed the incorrect window size limits for the interface window
[vlc] / modules / gui / beos / InterfaceWindow.cpp
1 /*****************************************************************************
2  * InterfaceWindow.cpp: beos interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 VideoLAN
5  * $Id$
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 <superstippi@gmx.de>
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 #define INTERFACE_LOCKING_TIMEOUT 5000
56
57 // make_sure_frame_is_on_screen
58 bool
59 make_sure_frame_is_on_screen( BRect& frame )
60 {
61         BScreen screen( B_MAIN_SCREEN_ID );
62         if (frame.IsValid() && screen.IsValid()) {
63                 if (!screen.Frame().Contains(frame)) {
64                         // make sure frame fits in the screen
65                         if (frame.Width() > screen.Frame().Width())
66                                 frame.right -= frame.Width() - screen.Frame().Width() + 10.0;
67                         if (frame.Height() > screen.Frame().Height())
68                                 frame.bottom -= frame.Height() - screen.Frame().Height() + 30.0;
69                         // frame is now at the most the size of the screen
70                         if (frame.right > screen.Frame().right)
71                                 frame.OffsetBy(-(frame.right - screen.Frame().right), 0.0);
72                         if (frame.bottom > screen.Frame().bottom)
73                                 frame.OffsetBy(0.0, -(frame.bottom - screen.Frame().bottom));
74                         if (frame.left < screen.Frame().left)
75                                 frame.OffsetBy((screen.Frame().left - frame.left), 0.0);
76                         if (frame.top < screen.Frame().top)
77                                 frame.OffsetBy(0.0, (screen.Frame().top - frame.top));
78                 }
79                 return true;
80         }
81         return false;
82 }
83
84 // make_sure_frame_is_within_limits
85 void
86 make_sure_frame_is_within_limits( BRect& frame, float minWidth, float minHeight,
87                                   float maxWidth, float maxHeight )
88 {
89     if ( frame.Width() < minWidth )
90         frame.right = frame.left + minWidth;
91     if ( frame.Height() < minHeight )
92         frame.bottom = frame.top + minHeight;
93     if ( frame.Width() > maxWidth )
94         frame.right = frame.left + maxWidth;
95     if ( frame.Height() > maxHeight )
96         frame.bottom = frame.top + maxHeight;
97 }
98
99 // get_volume_info
100 bool
101 get_volume_info( BVolume& volume, BString& volumeName, bool& isCDROM, BString& deviceName )
102 {
103         bool success = false;
104         isCDROM = false;
105         deviceName = "";
106         volumeName = "";
107         char name[B_FILE_NAME_LENGTH];
108         if ( volume.GetName( name ) >= B_OK )   // disk is currently mounted
109         {
110                 volumeName = name;
111                 dev_t dev = volume.Device();
112                 fs_info info;
113                 if ( fs_stat_dev( dev, &info ) == B_OK )
114                 {
115                         success = true;
116                         deviceName = info.device_name;
117                         if ( volume.IsReadOnly() )
118                         {
119                                 int i_dev = open( info.device_name, O_RDONLY );
120                                 if ( i_dev >= 0 )
121                                 {
122                                         device_geometry g;
123                                         if ( ioctl( i_dev, B_GET_GEOMETRY, &g, sizeof( g ) ) >= 0 )
124                                                 isCDROM = ( g.device_type == B_CD );
125                                         close( i_dev );
126                                 }
127                         }
128                 }
129         }
130         return success;
131 }
132
133 // collect_folder_contents
134 void
135 collect_folder_contents( BDirectory& dir, BList& list, bool& deep, bool& asked, BEntry& entry )
136 {
137         while ( dir.GetNextEntry( &entry, true ) == B_OK )
138         {
139                 if ( !entry.IsDirectory() )
140                 {
141                         BPath path;
142                         // since the directory will give us the entries in reverse order,
143                         // we put them each at the same index, effectively reversing the
144                         // items while adding them
145                         if ( entry.GetPath( &path ) == B_OK )
146                         {
147                                 BString* string = new BString( path.Path() );
148                                 if ( !list.AddItem( string, 0 ) )
149                                         delete string;  // at least don't leak
150                         }
151                 }
152                 else
153                 {
154                         if ( !asked )
155                         {
156                                 // ask user if we should parse sub-folders as well
157                                 BAlert* alert = new BAlert( "sub-folders?",
158                                                                                         _("Open files from all sub-folders as well?"),
159                                                                                         _("Cancel"), _("Open"), NULL, B_WIDTH_AS_USUAL,
160                                                                                         B_IDEA_ALERT );
161                                 int32 buttonIndex = alert->Go();
162                                 deep = buttonIndex == 1;
163                                 asked = true;
164                                 // never delete BAlerts!!
165                         }
166                         if ( deep )
167                         {
168                                 BDirectory subDir( &entry );
169                                 if ( subDir.InitCheck() == B_OK )
170                                         collect_folder_contents( subDir, list,
171                                                                                          deep, asked, entry );
172                         }
173                 }
174         }
175 }
176
177
178 /*****************************************************************************
179  * InterfaceWindow
180  *****************************************************************************/
181
182 InterfaceWindow::InterfaceWindow( BRect frame, const char* name,
183                                   intf_thread_t* p_interface )
184     : BWindow( frame, name, B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
185                B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS ),
186       p_intf( p_interface ),
187       fFilePanel( NULL ),
188       fLastUpdateTime( system_time() ),
189           fSettings( new BMessage( 'sett' ) ),
190           p_wrapper( p_intf->p_sys->p_wrapper )
191 {
192     fPlaylistIsEmpty = !( p_wrapper->PlaylistSize() > 0 );
193     
194     BScreen screen;
195     BRect screen_rect = screen.Frame();
196     BRect window_rect;
197     window_rect.Set( ( screen_rect.right - PREFS_WINDOW_WIDTH ) / 2,
198                      ( screen_rect.bottom - PREFS_WINDOW_HEIGHT ) / 2,
199                      ( screen_rect.right + PREFS_WINDOW_WIDTH ) / 2,
200                      ( screen_rect.bottom + PREFS_WINDOW_HEIGHT ) / 2 );
201     fPreferencesWindow = new PreferencesWindow( p_intf, window_rect, _("Preferences") );
202     window_rect.Set( screen_rect.right - 500,
203                      screen_rect.top + 50,
204                      screen_rect.right - 150,
205                      screen_rect.top + 250 );
206     fPlaylistWindow = new PlayListWindow( window_rect, _("Playlist"), this, p_intf );
207     window_rect.Set( screen_rect.right - 550,
208                      screen_rect.top + 300,
209                      screen_rect.right - 150,
210                      screen_rect.top + 500 );
211     fMessagesWindow = new MessagesWindow( p_intf, window_rect, _("Messages") );
212
213     // the media control view
214     p_mediaControl = new MediaControlView( BRect( 0.0, 0.0, 250.0, 50.0 ),
215                                            p_intf );
216     p_mediaControl->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
217
218     float width, height;
219     p_mediaControl->GetPreferredSize( &width, &height );
220
221     // set up the main menu
222     fMenuBar = new BMenuBar( BRect(0.0, 0.0, width, 15.0), "main menu",
223                              B_FOLLOW_NONE, B_ITEMS_IN_ROW, false );
224
225     // make menu bar resize to correct height
226     float menuWidth, menuHeight;
227     fMenuBar->GetPreferredSize( &menuWidth, &menuHeight );
228     fMenuBar->ResizeTo( width, menuHeight );    // don't change! it's a workarround!
229     // take care of proper size for ourself
230     height += fMenuBar->Bounds().Height();
231     ResizeTo( width, height );
232
233     p_mediaControl->MoveTo( fMenuBar->Bounds().LeftBottom() + BPoint(0.0, 1.0) );
234     AddChild( fMenuBar );
235
236     // Add the file Menu
237     BMenu* fileMenu = new BMenu( _("File") );
238     fMenuBar->AddItem( fileMenu );
239     fileMenu->AddItem( new BMenuItem( _AddEllipsis(_("Open File")),
240                                       new BMessage( OPEN_FILE ), 'O') );
241     
242     fileMenu->AddItem( new CDMenu( _("Open Disc") ) );
243
244     fileMenu->AddItem( new BMenuItem( _AddEllipsis(_("Open Subtitles")),
245                                       new BMessage( LOAD_SUBFILE ) ) );
246
247     fileMenu->AddSeparatorItem();
248     BMenuItem* item = new BMenuItem( _AddEllipsis(_("About")),
249                                      new BMessage( B_ABOUT_REQUESTED ), 'A');
250     item->SetTarget( be_app );
251     fileMenu->AddItem( item );
252     fileMenu->AddItem( new BMenuItem( _("Quit"), new BMessage( B_QUIT_REQUESTED ), 'Q') );
253
254     fLanguageMenu = new LanguageMenu( _("Language"), AUDIO_ES, p_wrapper);
255     fSubtitlesMenu = new LanguageMenu( _("Subtitles"), SPU_ES, p_wrapper);
256
257     /* Add the Audio menu */
258     fAudioMenu = new BMenu( _("Audio") );
259     fMenuBar->AddItem ( fAudioMenu );
260     fAudioMenu->AddItem( fLanguageMenu );
261     fAudioMenu->AddItem( fSubtitlesMenu );
262
263     fPrevTitleMI = new BMenuItem( _("Prev Title"), new BMessage( PREV_TITLE ) );
264     fNextTitleMI = new BMenuItem( _("Next Title"), new BMessage( NEXT_TITLE ) );
265     fPrevChapterMI = new BMenuItem( _("Previous chapter"), new BMessage( PREV_CHAPTER ) );
266     fNextChapterMI = new BMenuItem( _("Next chapter"), new BMessage( NEXT_CHAPTER ) );
267     fGotoMenuMI = new BMenuItem( _("Goto Menu"), new BMessage( NAVIGATE_MENU ) );
268
269     /* Add the Navigation menu */
270     fNavigationMenu = new BMenu( _("Navigation") );
271     fMenuBar->AddItem( fNavigationMenu );
272     fNavigationMenu->AddItem( fGotoMenuMI );
273     fNavigationMenu->AddSeparatorItem();
274     fNavigationMenu->AddItem( fPrevTitleMI );
275     fNavigationMenu->AddItem( fNextTitleMI );
276     fNavigationMenu->AddItem( fTitleMenu = new TitleMenu( _("Go to Title"), p_intf ) );
277     fNavigationMenu->AddSeparatorItem();
278     fNavigationMenu->AddItem( fPrevChapterMI );
279     fNavigationMenu->AddItem( fNextChapterMI );
280     fNavigationMenu->AddItem( fChapterMenu = new ChapterMenu( _("Go to Chapter"), p_intf ) );
281
282     /* Add the Speed menu */
283     fSpeedMenu = new BMenu( _("Speed") );
284     fSpeedMenu->SetRadioMode( true );
285     fSpeedMenu->AddItem(
286         fHeighthMI = new BMenuItem( "1/8x", new BMessage( HEIGHTH_PLAY ) ) );
287     fSpeedMenu->AddItem(
288         fQuarterMI = new BMenuItem( "1/4x", new BMessage( QUARTER_PLAY ) ) );
289     fSpeedMenu->AddItem(
290         fHalfMI = new BMenuItem( "1/2x", new BMessage( HALF_PLAY ) ) );
291     fSpeedMenu->AddItem(
292         fNormalMI = new BMenuItem( "1x", new BMessage( NORMAL_PLAY ) ) );
293     fSpeedMenu->AddItem(
294         fTwiceMI = new BMenuItem( "2x", new BMessage( TWICE_PLAY ) ) );
295     fSpeedMenu->AddItem(
296         fFourMI = new BMenuItem( "4x", new BMessage( FOUR_PLAY ) ) );
297     fSpeedMenu->AddItem(
298         fHeightMI = new BMenuItem( "8x", new BMessage( HEIGHT_PLAY ) ) );
299     fMenuBar->AddItem( fSpeedMenu );
300
301     /* Add the Show menu */
302     fShowMenu = new BMenu( _("Window") );
303     fShowMenu->AddItem( new BMenuItem( _AddEllipsis(_("Playlist")),
304                                        new BMessage( OPEN_PLAYLIST ), 'P') );
305     fShowMenu->AddItem( new BMenuItem( _AddEllipsis(_("Messages")),
306                                        new BMessage( OPEN_MESSAGES ), 'M' ) );
307     fShowMenu->AddItem( new BMenuItem( _AddEllipsis(_("Preferences")),
308                                        new BMessage( OPEN_PREFERENCES ), 'S' ) );
309     fMenuBar->AddItem( fShowMenu );
310
311         // add the media control view after the menubar is complete
312         // because it will set the window size limits in AttachedToWindow()
313         // and the menubar needs to report the correct PreferredSize()
314     AddChild( p_mediaControl );
315
316     /* Prepare fow showing */
317     _SetMenusEnabled( false );
318     p_mediaControl->SetEnabled( false );
319
320     _RestoreSettings();
321
322     Show();
323 }
324
325 InterfaceWindow::~InterfaceWindow()
326 {
327     if( fPlaylistWindow )
328         fPlaylistWindow->ReallyQuit();
329     fPlaylistWindow = NULL;
330     if( fMessagesWindow )
331         fMessagesWindow->ReallyQuit();
332     fMessagesWindow = NULL;
333     if( fPreferencesWindow )
334         fPreferencesWindow->ReallyQuit();
335     fPreferencesWindow = NULL;
336         delete fFilePanel;
337         delete fSettings;
338 }
339
340 /*****************************************************************************
341  * InterfaceWindow::FrameResized
342  *****************************************************************************/
343 void
344 InterfaceWindow::FrameResized(float width, float height)
345 {
346     BRect r(Bounds());
347     fMenuBar->MoveTo(r.LeftTop());
348     fMenuBar->ResizeTo(r.Width(), fMenuBar->Bounds().Height());
349     r.top += fMenuBar->Bounds().Height() + 1.0;
350     p_mediaControl->MoveTo(r.LeftTop());
351     p_mediaControl->ResizeTo(r.Width(), r.Height());
352 }
353
354 /*****************************************************************************
355  * InterfaceWindow::MessageReceived
356  *****************************************************************************/
357 void InterfaceWindow::MessageReceived( BMessage * p_message )
358 {
359     int playback_status;      // remember playback state
360     playback_status = p_wrapper->InputStatus();
361
362     switch( p_message->what )
363     {
364         case B_ABOUT_REQUESTED:
365         {
366             BAlert* alert = new BAlert( "VLC " PACKAGE_VERSION,
367                                         "VLC " PACKAGE_VERSION " for BeOS"
368                                         "\n\n<www.videolan.org>", _("OK"));
369             alert->Go();
370             break;
371         }
372         case TOGGLE_ON_TOP:
373             break;
374
375         case OPEN_FILE:
376                 _ShowFilePanel( B_REFS_RECEIVED, _("VLC media player: Open Media Files") );
377             break;
378
379         case LOAD_SUBFILE:
380                 _ShowFilePanel( SUBFILE_RECEIVED, _("VLC media player: Open Subtitle File") );
381             break;
382
383         case OPEN_PLAYLIST:
384             if (fPlaylistWindow->Lock())
385             {
386                 if (fPlaylistWindow->IsHidden())
387                     fPlaylistWindow->Show();
388                 else
389                     fPlaylistWindow->Activate();
390                 fPlaylistWindow->Unlock();
391             }
392             break;
393         case OPEN_DVD:
394             {
395                 const char *psz_device;
396                 BString type( "dvd" );
397                 if( p_message->FindString( "device", &psz_device ) == B_OK )
398                 {
399                     BString device( psz_device );
400                     p_wrapper->OpenDisc( type, device, 0, 0 );
401                 }
402                 _UpdatePlaylist();
403             }
404             break;
405
406         case SUBFILE_RECEIVED:
407         {
408             entry_ref ref;
409             if( p_message->FindRef( "refs", 0, &ref ) == B_OK )
410             {
411                 BPath path( &ref );
412                 if ( path.InitCheck() == B_OK )
413                     p_wrapper->LoadSubFile( path.Path() );
414             }
415             break;
416         }
417
418         case STOP_PLAYBACK:
419             // this currently stops playback not nicely
420             if (playback_status > UNDEF_S)
421             {
422                 p_wrapper->PlaylistStop();
423                 p_mediaControl->SetStatus(UNDEF_S, DEFAULT_RATE);
424             }
425             break;
426     
427         case START_PLAYBACK:
428             /*  starts playing in normal mode */
429     
430         case PAUSE_PLAYBACK:
431             /* toggle between pause and play */
432             if (playback_status > UNDEF_S)
433             {
434                 /* pause if currently playing */
435                 if ( playback_status == PLAYING_S )
436                 {
437                     p_wrapper->PlaylistPause();
438                 }
439                 else
440                 {
441                     p_wrapper->PlaylistPlay();
442                 }
443             }
444             else
445             {
446                 /* Play a new file */
447                 p_wrapper->PlaylistPlay();
448             }    
449             break;
450     
451         case HEIGHTH_PLAY:
452             p_wrapper->InputSetRate( DEFAULT_RATE * 8 );
453             break;
454
455         case QUARTER_PLAY:
456             p_wrapper->InputSetRate( DEFAULT_RATE * 4 );
457             break;
458
459         case HALF_PLAY:
460             p_wrapper->InputSetRate( DEFAULT_RATE * 2 );
461             break;
462
463         case NORMAL_PLAY:
464             p_wrapper->InputSetRate( DEFAULT_RATE );
465             break;
466
467         case TWICE_PLAY:
468             p_wrapper->InputSetRate( DEFAULT_RATE / 2 );
469             break;
470
471         case FOUR_PLAY:
472             p_wrapper->InputSetRate( DEFAULT_RATE / 4 );
473             break;
474
475         case HEIGHT_PLAY:
476             p_wrapper->InputSetRate( DEFAULT_RATE / 8 );
477             break;
478
479         case SEEK_PLAYBACK:
480             /* handled by semaphores */
481             break;
482         // volume related messages
483         case VOLUME_CHG:
484             /* adjust the volume */
485             if (playback_status > UNDEF_S)
486             {
487                 p_wrapper->SetVolume( p_mediaControl->GetVolume() );
488                 p_mediaControl->SetMuted( p_wrapper->IsMuted() );
489             }
490             break;
491     
492         case VOLUME_MUTE:
493             // toggle muting
494             if( p_wrapper->IsMuted() )
495                 p_wrapper->VolumeRestore();
496             else
497                 p_wrapper->VolumeMute();
498             p_mediaControl->SetMuted( p_wrapper->IsMuted() );
499             break;
500     
501         case SELECT_CHANNEL:
502             if ( playback_status > UNDEF_S )
503             {
504                 int32 channel;
505                 if ( p_message->FindInt32( "channel", &channel ) == B_OK )
506                 {
507                     p_wrapper->ToggleLanguage( channel );
508                 }
509             }
510             break;
511     
512         case SELECT_SUBTITLE:
513             if ( playback_status > UNDEF_S )
514             {
515                 int32 subtitle;
516                 if ( p_message->FindInt32( "subtitle", &subtitle ) == B_OK )
517                      p_wrapper->ToggleSubtitle( subtitle );
518             }
519             break;
520     
521         // specific navigation messages
522         case PREV_TITLE:
523         {
524             p_wrapper->PrevTitle();
525             break;
526         }
527         case NEXT_TITLE:
528         {
529             p_wrapper->NextTitle();
530             break;
531         }
532         case NAVIGATE_MENU:
533                 p_wrapper->ToggleTitle( 0 );
534                 break;
535         case TOGGLE_TITLE:
536             if ( playback_status > UNDEF_S )
537             {
538                 int32 index;
539                 if( p_message->FindInt32( "index", &index ) == B_OK )
540                     p_wrapper->ToggleTitle( index );
541             }
542             break;
543         case PREV_CHAPTER:
544         {
545             p_wrapper->PrevChapter();
546             break;
547         }
548         case NEXT_CHAPTER:
549         {
550             p_wrapper->NextChapter();
551             break;
552         }
553         case TOGGLE_CHAPTER:
554             if ( playback_status > UNDEF_S )
555             {
556                 int32 index;
557                 if( p_message->FindInt32( "index", &index ) == B_OK )
558                     p_wrapper->ToggleChapter( index );
559             }
560             break;
561         case PREV_FILE:
562             p_wrapper->PlaylistPrev();
563             break;
564         case NEXT_FILE:
565             p_wrapper->PlaylistNext();
566             break;
567         // general next/prev functionality (skips to whatever makes most sense)
568         case NAVIGATE_PREV:
569             p_wrapper->NavigatePrev();
570             break;
571         case NAVIGATE_NEXT:
572             p_wrapper->NavigateNext();
573             break;
574         // drag'n'drop and system messages
575         case MSG_SOUNDPLAY:
576                 // convert soundplay drag'n'drop message (containing paths)
577                 // to normal message (containing refs)
578                 {
579                         const char* path;
580                         for ( int32 i = 0; p_message->FindString( "path", i, &path ) == B_OK; i++ )
581                         {
582                                 entry_ref ref;
583                                 if ( get_ref_for_path( path, &ref ) == B_OK )
584                                         p_message->AddRef( "refs", &ref );
585                         }
586                 }
587                 // fall through
588         case B_REFS_RECEIVED:
589         case B_SIMPLE_DATA:
590             {
591                 /* file(s) opened by the File menu -> append to the playlist;
592                  * file(s) opened by drag & drop -> replace playlist;
593                  * file(s) opened by 'shift' + drag & drop -> append */
594                 bool replace = false;
595                 bool reverse = false;
596                 if ( p_message->WasDropped() )
597                 {
598                     replace = !( modifiers() & B_SHIFT_KEY );
599                     reverse = true;
600                 }
601                     
602                 // build list of files to be played from message contents
603                 entry_ref ref;
604                 BList files;
605                 
606                 // if we should parse sub-folders as well
607                         bool askedAlready = false;
608                         bool parseSubFolders = askedAlready;
609                         // traverse refs in reverse order
610                         int32 count;
611                         type_code dummy;
612                         if ( p_message->GetInfo( "refs", &dummy, &count ) == B_OK && count > 0 )
613                         {
614                                 int32 i = reverse ? count - 1 : 0;
615                                 int32 increment = reverse ? -1 : 1;
616                         for ( ; p_message->FindRef( "refs", i, &ref ) == B_OK; i += increment )
617                         {
618                             BPath path( &ref );
619                             if ( path.InitCheck() == B_OK )
620                             {
621                                 bool add = true;
622                                 // has the user dropped a folder?
623                                 BDirectory dir( &ref );
624                                 if ( dir.InitCheck() == B_OK)
625                                 {
626                                         // has the user dropped a dvd disk icon?
627                                                                 if ( dir.IsRootDirectory() )
628                                                                 {
629                                                                         BVolumeRoster volRoster;
630                                                                         BVolume vol;
631                                                                         BDirectory volumeRoot;
632                                                                         status_t status = volRoster.GetNextVolume( &vol );
633                                                                         while ( status == B_NO_ERROR )
634                                                                         {
635                                                                                 if ( vol.GetRootDirectory( &volumeRoot ) == B_OK
636                                                                                          && dir == volumeRoot )
637                                                                                 {
638                                                                                         BString volumeName;
639                                                                                         BString deviceName;
640                                                                                         bool isCDROM;
641                                                                                         if ( get_volume_info( vol, volumeName, isCDROM, deviceName )
642                                                                                                  && isCDROM )
643                                                                                         {
644                                                                                                 BMessage msg( OPEN_DVD );
645                                                                                                 msg.AddString( "device", deviceName.String() );
646                                                                                                 PostMessage( &msg );
647                                                                                                 add = false;
648                                                                                         }
649                                                                                         break;
650                                                                                 }
651                                                                                 else
652                                                                                 {
653                                                                                         vol.Unset();
654                                                                                         status = volRoster.GetNextVolume( &vol );
655                                                                                 }
656                                                                         }
657                                                                 }
658                                         if ( add )
659                                         {
660                                                 add = false;
661                                                 dir.Rewind();   // defensive programming
662                                                 BEntry entry;
663                                                                         collect_folder_contents( dir, files,
664                                                                                                                          parseSubFolders,
665                                                                                                                          askedAlready,
666                                                                                                                          entry );
667                                         }
668                                 }
669                                 if ( add )
670                                 {
671                                         BString* string = new BString( path.Path() );
672                                         if ( !files.AddItem( string, 0 ) )
673                                                 delete string;  // at least don't leak
674                                 }
675                             }
676                         }
677                         // give the list to VLC
678                         // BString objects allocated here will be deleted there
679                         int32 index;
680                         if ( p_message->FindInt32("drop index", &index) != B_OK )
681                                 index = -1;
682                         p_wrapper->OpenFiles( &files, replace, index );
683                         _UpdatePlaylist();
684                         }
685             }
686             break;
687
688         case OPEN_PREFERENCES:
689         {
690             if( fPreferencesWindow->Lock() )
691             {
692                 if (fPreferencesWindow->IsHidden())
693                     fPreferencesWindow->Show();
694                 else
695                     fPreferencesWindow->Activate();
696                 fPreferencesWindow->Unlock();
697             }
698             break;
699         }
700
701         case OPEN_MESSAGES:
702         {
703             if( fMessagesWindow->Lock() )
704             {
705                 if (fMessagesWindow->IsHidden())
706                     fMessagesWindow->Show();
707                 else
708                     fMessagesWindow->Activate();
709                 fMessagesWindow->Unlock();
710             }
711             break;
712         }
713         case MSG_UPDATE:
714                 UpdateInterface();
715                 break;
716         default:
717             BWindow::MessageReceived( p_message );
718             break;
719     }
720
721 }
722
723 /*****************************************************************************
724  * InterfaceWindow::QuitRequested
725  *****************************************************************************/
726 bool InterfaceWindow::QuitRequested()
727 {
728     p_wrapper->PlaylistStop();
729     p_mediaControl->SetStatus(UNDEF_S, DEFAULT_RATE);
730
731         _StoreSettings();
732    
733     p_intf->b_die = 1;
734
735     return( true );
736 }
737
738 /*****************************************************************************
739  * InterfaceWindow::UpdateInterface
740  *****************************************************************************/
741 void InterfaceWindow::UpdateInterface()
742 {
743     if( p_wrapper->HasInput() )
744     {
745         if ( acquire_sem( p_mediaControl->fScrubSem ) == B_OK )
746         {
747             p_wrapper->SetTimeAsFloat( p_mediaControl->GetSeekTo() );
748         }
749         else if ( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) == B_OK )
750         {
751             p_mediaControl->SetEnabled( true );
752             bool hasTitles = p_wrapper->HasTitles();
753             bool hasChapters = p_wrapper->HasChapters();
754             p_mediaControl->SetStatus( p_wrapper->InputStatus(), 
755                                        p_wrapper->InputRate() );
756             p_mediaControl->SetProgress( p_wrapper->GetTimeAsFloat() );
757             _SetMenusEnabled( true, hasChapters, hasTitles );
758
759             _UpdateSpeedMenu( p_wrapper->InputRate() );
760
761             // enable/disable skip buttons
762             bool canSkipPrev;
763             bool canSkipNext;
764             p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
765             p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
766
767             if ( p_wrapper->HasInput() )
768             {
769                 p_mediaControl->SetAudioEnabled( true );
770                 p_mediaControl->SetMuted( p_wrapper->IsMuted() );
771             } else
772                 p_mediaControl->SetAudioEnabled( false );
773
774             Unlock();
775         }
776         // update playlist as well
777         if ( fPlaylistWindow->LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) == B_OK )
778         {
779             fPlaylistWindow->UpdatePlaylist();
780             fPlaylistWindow->Unlock();
781         }
782     }
783     else
784     {
785                 if ( LockWithTimeout(INTERFACE_LOCKING_TIMEOUT) == B_OK )
786                 {
787                 _SetMenusEnabled( false );
788                 if( !( p_wrapper->PlaylistSize() > 0 ) )
789                     p_mediaControl->SetEnabled( false );
790                 else
791                 {
792                     p_mediaControl->SetProgress( 0 );
793                     // enable/disable skip buttons
794                     bool canSkipPrev;
795                     bool canSkipNext;
796                     p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
797                     p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
798                         }
799             Unlock();
800         }
801     }
802
803     fLastUpdateTime = system_time();
804 }
805
806 /*****************************************************************************
807  * InterfaceWindow::IsStopped
808  *****************************************************************************/
809 bool
810 InterfaceWindow::IsStopped() const
811 {
812     return (system_time() - fLastUpdateTime > INTERFACE_UPDATE_TIMEOUT);
813 }
814
815 /*****************************************************************************
816  * InterfaceWindow::_UpdatePlaylist
817  *****************************************************************************/
818 void
819 InterfaceWindow::_UpdatePlaylist()
820 {
821     if ( fPlaylistWindow->Lock() )
822     {
823         fPlaylistWindow->UpdatePlaylist( true );
824         fPlaylistWindow->Unlock();
825         p_mediaControl->SetEnabled( p_wrapper->PlaylistSize() );
826     }
827 }
828
829 /*****************************************************************************
830  * InterfaceWindow::_SetMenusEnabled
831  *****************************************************************************/
832 void
833 InterfaceWindow::_SetMenusEnabled(bool hasFile, bool hasChapters, bool hasTitles)
834 {
835     if (!hasFile)
836     {
837         hasChapters = false;
838         hasTitles = false;
839     }
840     if ( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) == B_OK)
841     {
842         if ( fNextChapterMI->IsEnabled() != hasChapters )
843              fNextChapterMI->SetEnabled( hasChapters );
844         if ( fPrevChapterMI->IsEnabled() != hasChapters )
845              fPrevChapterMI->SetEnabled( hasChapters );
846         if ( fChapterMenu->IsEnabled() != hasChapters )
847              fChapterMenu->SetEnabled( hasChapters );
848         if ( fNextTitleMI->IsEnabled() != hasTitles )
849              fNextTitleMI->SetEnabled( hasTitles );
850         if ( fPrevTitleMI->IsEnabled() != hasTitles )
851              fPrevTitleMI->SetEnabled( hasTitles );
852         if ( fTitleMenu->IsEnabled() != hasTitles )
853              fTitleMenu->SetEnabled( hasTitles );
854         if ( fAudioMenu->IsEnabled() != hasFile )
855              fAudioMenu->SetEnabled( hasFile );
856         if ( fNavigationMenu->IsEnabled() != hasFile )
857              fNavigationMenu->SetEnabled( hasFile );
858         if ( fLanguageMenu->IsEnabled() != hasFile )
859              fLanguageMenu->SetEnabled( hasFile );
860         if ( fSubtitlesMenu->IsEnabled() != hasFile )
861              fSubtitlesMenu->SetEnabled( hasFile );
862         if ( fSpeedMenu->IsEnabled() != hasFile )
863              fSpeedMenu->SetEnabled( hasFile );
864         // "goto menu" menu item
865         bool hasMenu = p_wrapper->IsUsingMenus();
866         if ( fGotoMenuMI->IsEnabled() != hasMenu )
867              fGotoMenuMI->SetEnabled( hasMenu );
868         Unlock();
869     }
870 }
871
872 /*****************************************************************************
873  * InterfaceWindow::_UpdateSpeedMenu
874  *****************************************************************************/
875 void
876 InterfaceWindow::_UpdateSpeedMenu( int rate )
877 {
878     BMenuItem * toMark = NULL;
879     
880     switch( rate )
881     {
882         case ( DEFAULT_RATE * 8 ):
883             toMark = fHeighthMI;
884             break;
885             
886         case ( DEFAULT_RATE * 4 ):
887             toMark = fQuarterMI;
888             break;
889             
890         case ( DEFAULT_RATE * 2 ):
891             toMark = fHalfMI;
892             break;
893             
894         case ( DEFAULT_RATE ):
895             toMark = fNormalMI;
896             break;
897             
898         case ( DEFAULT_RATE / 2 ):
899             toMark = fTwiceMI;
900             break;
901             
902         case ( DEFAULT_RATE / 4 ):
903             toMark = fFourMI;
904             break;
905             
906         case ( DEFAULT_RATE / 8 ):
907             toMark = fHeightMI;
908             break;
909     }
910
911     if ( !toMark->IsMarked() )
912         toMark->SetMarked( true );
913 }
914
915 /*****************************************************************************
916  * InterfaceWindow::_ShowFilePanel
917  *****************************************************************************/
918 void
919 InterfaceWindow::_ShowFilePanel( uint32 command, const char* windowTitle )
920 {
921         if( !fFilePanel )
922         {
923                 fFilePanel = new BFilePanel( B_OPEN_PANEL, NULL, NULL,
924                                                                          B_FILE_NODE | B_DIRECTORY_NODE );
925                 fFilePanel->SetTarget( this );
926         }
927         fFilePanel->Window()->SetTitle( windowTitle );
928         BMessage message( command );
929         fFilePanel->SetMessage( &message );
930         if ( !fFilePanel->IsShowing() )
931         {
932                 fFilePanel->Refresh();
933                 fFilePanel->Show();
934         }
935 }
936
937 // set_window_pos
938 void
939 set_window_pos( BWindow* window, BRect frame )
940 {
941         // sanity checks: make sure window is not too big/small
942         // and that it's not off-screen
943         float minWidth, maxWidth, minHeight, maxHeight;
944         window->GetSizeLimits( &minWidth, &maxWidth, &minHeight, &maxHeight );
945
946         make_sure_frame_is_within_limits( frame,
947                                                                           minWidth, minHeight, maxWidth, maxHeight );
948         if ( make_sure_frame_is_on_screen( frame ) )
949         {
950                 window->MoveTo( frame.LeftTop() );
951                 window->ResizeTo( frame.Width(), frame.Height() );
952         }
953 }
954
955 // set_window_pos
956 void
957 launch_window( BWindow* window, bool showing )
958 {
959         if ( window->Lock() )
960         {
961                 if ( showing )
962                 {
963                         if ( window->IsHidden() )
964                                 window->Show();
965                 }
966                 else
967                 {
968                         if ( !window->IsHidden() )
969                                 window->Hide();
970                 }
971                 window->Unlock();
972         }
973 }
974
975 /*****************************************************************************
976  * InterfaceWindow::_RestoreSettings
977  *****************************************************************************/
978 void
979 InterfaceWindow::_RestoreSettings()
980 {
981         if ( load_settings( fSettings, "interface_settings", "VideoLAN Client" ) == B_OK )
982         {
983                 BRect frame;
984                 if ( fSettings->FindRect( "main frame", &frame ) == B_OK )
985                         set_window_pos( this, frame );
986                 if (fSettings->FindRect( "playlist frame", &frame ) == B_OK )
987                         set_window_pos( fPlaylistWindow, frame );
988                 if (fSettings->FindRect( "messages frame", &frame ) == B_OK )
989                         set_window_pos( fMessagesWindow, frame );
990                 if (fSettings->FindRect( "settings frame", &frame ) == B_OK )
991                 {
992                     /* FIXME: Preferences resizing doesn't work correctly yet */
993                     frame.right = frame.left + fPreferencesWindow->Frame().Width();
994                     frame.bottom = frame.top + fPreferencesWindow->Frame().Height();
995                         set_window_pos( fPreferencesWindow, frame );
996                 }
997                 
998                 bool showing;
999                 if ( fSettings->FindBool( "playlist showing", &showing ) == B_OK )
1000                         launch_window( fPlaylistWindow, showing );
1001                 if ( fSettings->FindBool( "messages showing", &showing ) == B_OK )
1002                         launch_window( fMessagesWindow, showing );
1003                 if ( fSettings->FindBool( "settings showing", &showing ) == B_OK )
1004                         launch_window( fPreferencesWindow, showing );
1005
1006                 uint32 displayMode;
1007                 if ( fSettings->FindInt32( "playlist display mode", (int32*)&displayMode ) == B_OK )
1008                         fPlaylistWindow->SetDisplayMode( displayMode );
1009         }
1010 }
1011
1012 /*****************************************************************************
1013  * InterfaceWindow::_StoreSettings
1014  *****************************************************************************/
1015 void
1016 InterfaceWindow::_StoreSettings()
1017 {
1018     /* Save the volume */
1019     config_PutInt( p_intf, "volume", p_mediaControl->GetVolume() );
1020     config_SaveConfigFile( p_intf, "main" );
1021
1022     /* Save the windows positions */
1023         if ( fSettings->ReplaceRect( "main frame", Frame() ) != B_OK )
1024                 fSettings->AddRect( "main frame", Frame() );
1025         if ( fPlaylistWindow->Lock() )
1026         {
1027                 if (fSettings->ReplaceRect( "playlist frame", fPlaylistWindow->Frame() ) != B_OK)
1028                         fSettings->AddRect( "playlist frame", fPlaylistWindow->Frame() );
1029                 if (fSettings->ReplaceBool( "playlist showing", !fPlaylistWindow->IsHidden() ) != B_OK)
1030                         fSettings->AddBool( "playlist showing", !fPlaylistWindow->IsHidden() );
1031                 fPlaylistWindow->Unlock();
1032         }
1033         if ( fMessagesWindow->Lock() )
1034         {
1035                 if (fSettings->ReplaceRect( "messages frame", fMessagesWindow->Frame() ) != B_OK)
1036                         fSettings->AddRect( "messages frame", fMessagesWindow->Frame() );
1037                 if (fSettings->ReplaceBool( "messages showing", !fMessagesWindow->IsHidden() ) != B_OK)
1038                         fSettings->AddBool( "messages showing", !fMessagesWindow->IsHidden() );
1039                 fMessagesWindow->Unlock();
1040         }
1041         if ( fPreferencesWindow->Lock() )
1042         {
1043                 if (fSettings->ReplaceRect( "settings frame", fPreferencesWindow->Frame() ) != B_OK)
1044                         fSettings->AddRect( "settings frame", fPreferencesWindow->Frame() );
1045                 if (fSettings->ReplaceBool( "settings showing", !fPreferencesWindow->IsHidden() ) != B_OK)
1046                         fSettings->AddBool( "settings showing", !fPreferencesWindow->IsHidden() );
1047                 fPreferencesWindow->Unlock();
1048         }
1049         uint32 displayMode = fPlaylistWindow->DisplayMode();
1050         if (fSettings->ReplaceInt32( "playlist display mode", displayMode ) != B_OK )
1051                 fSettings->AddInt32( "playlist display mode", displayMode );
1052
1053         save_settings( fSettings, "interface_settings", "VideoLAN Client" );
1054 }
1055
1056
1057 /*****************************************************************************
1058  * CDMenu::CDMenu
1059  *****************************************************************************/
1060 CDMenu::CDMenu(const char *name)
1061       : BMenu(name)
1062 {
1063 }
1064
1065 /*****************************************************************************
1066  * CDMenu::~CDMenu
1067  *****************************************************************************/
1068 CDMenu::~CDMenu()
1069 {
1070 }
1071
1072 /*****************************************************************************
1073  * CDMenu::AttachedToWindow
1074  *****************************************************************************/
1075 void CDMenu::AttachedToWindow(void)
1076 {
1077     // remove all items
1078     while ( BMenuItem* item = RemoveItem( 0L ) )
1079         delete item;
1080     GetCD( "/dev/disk" );
1081     BMenu::AttachedToWindow();
1082 }
1083
1084 /*****************************************************************************
1085  * CDMenu::GetCD
1086  *****************************************************************************/
1087 int CDMenu::GetCD( const char *directory )
1088 {
1089         BVolumeRoster volRoster;
1090         BVolume vol;
1091         BDirectory dir;
1092         status_t status = volRoster.GetNextVolume( &vol );
1093         while ( status ==  B_NO_ERROR )
1094         {
1095                 BString deviceName;
1096                 BString volumeName;
1097                 bool isCDROM;
1098                 if ( get_volume_info( vol, volumeName, isCDROM, deviceName )
1099                          && isCDROM )
1100                 {
1101                         BMessage* msg = new BMessage( OPEN_DVD );
1102                         msg->AddString( "device", deviceName.String() );
1103                         BMenuItem* item = new BMenuItem( volumeName.String(), msg );
1104                         AddItem( item );
1105                 }
1106                 vol.Unset();
1107                 status = volRoster.GetNextVolume( &vol );
1108         }
1109         return 0;
1110 }
1111
1112 /*****************************************************************************
1113  * LanguageMenu::LanguageMenu
1114  *****************************************************************************/
1115 LanguageMenu::LanguageMenu( const char *name, int menu_kind,
1116                             VlcWrapper *p_wrapper )
1117     :BMenu(name)
1118 {
1119     kind = menu_kind;
1120     this->p_wrapper = p_wrapper;
1121 }
1122
1123 /*****************************************************************************
1124  * LanguageMenu::~LanguageMenu
1125  *****************************************************************************/
1126 LanguageMenu::~LanguageMenu()
1127 {
1128 }
1129
1130 /*****************************************************************************
1131  * LanguageMenu::AttachedToWindow
1132  *****************************************************************************/
1133 void LanguageMenu::AttachedToWindow()
1134 {
1135     // remove all items
1136     while ( BMenuItem* item = RemoveItem( 0L ) )
1137         delete item;
1138
1139     SetRadioMode( true );
1140         if ( BList *list = p_wrapper->GetChannels( kind ) )
1141         {
1142             for ( int32 i = 0; BMenuItem* item = (BMenuItem*)list->ItemAt( i ); i++ )
1143                 AddItem( item );
1144             
1145             if ( list->CountItems() > 1 )
1146                 AddItem( new BSeparatorItem(), 1 );
1147         }
1148     BMenu::AttachedToWindow();
1149 }
1150
1151 /*****************************************************************************
1152  * TitleMenu::TitleMenu
1153  *****************************************************************************/
1154 TitleMenu::TitleMenu( const char *name, intf_thread_t  *p_interface )
1155     : BMenu(name),
1156     p_intf( p_interface )
1157 {
1158 }
1159
1160 /*****************************************************************************
1161  * TitleMenu::~TitleMenu
1162  *****************************************************************************/
1163 TitleMenu::~TitleMenu()
1164 {
1165 }
1166
1167 /*****************************************************************************
1168  * TitleMenu::AttachedToWindow
1169  *****************************************************************************/
1170 void TitleMenu::AttachedToWindow()
1171 {
1172     while( BMenuItem* item = RemoveItem( 0L ) )
1173         delete item;
1174
1175     if ( BList *list = p_intf->p_sys->p_wrapper->GetTitles() )
1176         {    
1177                 for( int i = 0; BMenuItem* item = (BMenuItem*)list->ItemAt( i ); i++ )
1178                 AddItem( item );
1179         }
1180     BMenu::AttachedToWindow();
1181 }
1182
1183
1184 /*****************************************************************************
1185  * ChapterMenu::ChapterMenu
1186  *****************************************************************************/
1187 ChapterMenu::ChapterMenu( const char *name, intf_thread_t  *p_interface )
1188     : BMenu(name),
1189     p_intf( p_interface )
1190 {
1191 }
1192
1193 /*****************************************************************************
1194  * ChapterMenu::~ChapterMenu
1195  *****************************************************************************/
1196 ChapterMenu::~ChapterMenu()
1197 {
1198 }
1199
1200 /*****************************************************************************
1201  * ChapterMenu::AttachedToWindow
1202  *****************************************************************************/
1203 void ChapterMenu::AttachedToWindow()
1204 {
1205     while( BMenuItem* item = RemoveItem( 0L ) )
1206         delete item;
1207
1208     if ( BList* list = p_intf->p_sys->p_wrapper->GetChapters() )
1209         {    
1210             for( int i = 0; BMenuItem* item = (BMenuItem*)list->ItemAt( i ); i++ )
1211                 AddItem( item );
1212         }
1213     
1214     BMenu::AttachedToWindow();
1215 }
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225 /*****************************************************************************
1226  * load_settings
1227  *****************************************************************************/
1228 status_t
1229 load_settings( BMessage* message, const char* fileName, const char* folder )
1230 {
1231         status_t ret = B_BAD_VALUE;
1232         if ( message )
1233         {
1234                 BPath path;
1235                 if ( ( ret = find_directory( B_USER_SETTINGS_DIRECTORY, &path ) ) == B_OK )
1236                 {
1237                         // passing folder is optional
1238                         if ( folder )
1239                                 ret = path.Append( folder );
1240                         if ( ret == B_OK && ( ret = path.Append( fileName ) ) == B_OK )
1241                         {
1242                                 BFile file( path.Path(), B_READ_ONLY );
1243                                 if ( ( ret = file.InitCheck() ) == B_OK )
1244                                 {
1245                                         ret = message->Unflatten( &file );
1246                                         file.Unset();
1247                                 }
1248                         }
1249                 }
1250         }
1251         return ret;
1252 }
1253
1254 /*****************************************************************************
1255  * save_settings
1256  *****************************************************************************/
1257 status_t
1258 save_settings( BMessage* message, const char* fileName, const char* folder )
1259 {
1260         status_t ret = B_BAD_VALUE;
1261         if ( message )
1262         {
1263                 BPath path;
1264                 if ( ( ret = find_directory( B_USER_SETTINGS_DIRECTORY, &path ) ) == B_OK )
1265                 {
1266                         // passing folder is optional
1267                         if ( folder && ( ret = path.Append( folder ) ) == B_OK )
1268                                 ret = create_directory( path.Path(), 0777 );
1269                         if ( ret == B_OK && ( ret = path.Append( fileName ) ) == B_OK )
1270                         {
1271                                 BFile file( path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE );
1272                                 if ( ( ret = file.InitCheck() ) == B_OK )
1273                                 {
1274                                         ret = message->Flatten( &file );
1275                                         file.Unset();
1276                                 }
1277                         }
1278                 }
1279         }
1280         return ret;
1281 }