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