]> git.sesse.net Git - vlc/blob - modules/gui/beos/InterfaceWindow.cpp
beos/*: fixed title/chapter navigation
[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 #include <vlc/input.h>
45
46 /* BeOS interface headers */
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( intf_thread_t * _p_intf, BRect frame,
183                                   const char * name )
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       
187       /* Initializations */
188       p_intf( _p_intf ),
189       p_input( NULL ),
190       p_playlist( NULL ),
191       
192       fFilePanel( NULL ),
193       fLastUpdateTime( system_time() ),
194       fSettings( new BMessage( 'sett' ) )
195 {
196     char psz_tmp[1024];
197 #define ADD_ELLIPSIS( a ) \
198     memset( psz_tmp, 0, 1024 ); \
199     snprintf( psz_tmp, 1024, "%s%s", a, B_UTF8_ELLIPSIS );
200
201     BScreen screen;
202     BRect screen_rect = screen.Frame();
203     BRect window_rect;
204     window_rect.Set( ( screen_rect.right - PREFS_WINDOW_WIDTH ) / 2,
205                      ( screen_rect.bottom - PREFS_WINDOW_HEIGHT ) / 2,
206                      ( screen_rect.right + PREFS_WINDOW_WIDTH ) / 2,
207                      ( screen_rect.bottom + PREFS_WINDOW_HEIGHT ) / 2 );
208     fPreferencesWindow = new PreferencesWindow( p_intf, window_rect, _("Preferences") );
209     window_rect.Set( screen_rect.right - 500,
210                      screen_rect.top + 50,
211                      screen_rect.right - 150,
212                      screen_rect.top + 250 );
213     fPlaylistWindow = new PlayListWindow( window_rect, _("Playlist"), this, p_intf );
214     window_rect.Set( screen_rect.right - 550,
215                      screen_rect.top + 300,
216                      screen_rect.right - 150,
217                      screen_rect.top + 500 );
218     fMessagesWindow = new MessagesWindow( p_intf, window_rect, _("Messages") );
219
220     // the media control view
221     p_mediaControl = new MediaControlView( p_intf, BRect( 0.0, 0.0, 250.0, 50.0 ) );
222     p_mediaControl->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
223
224     float width, height;
225     p_mediaControl->GetPreferredSize( &width, &height );
226
227     // set up the main menu
228     fMenuBar = new BMenuBar( BRect(0.0, 0.0, width, 15.0), "main menu",
229                              B_FOLLOW_NONE, B_ITEMS_IN_ROW, false );
230
231     // make menu bar resize to correct height
232     float menuWidth, menuHeight;
233     fMenuBar->GetPreferredSize( &menuWidth, &menuHeight );
234     fMenuBar->ResizeTo( width, menuHeight );    // don't change! it's a workarround!
235     // take care of proper size for ourself
236     height += fMenuBar->Bounds().Height();
237     ResizeTo( width, height );
238
239     p_mediaControl->MoveTo( fMenuBar->Bounds().LeftBottom() + BPoint(0.0, 1.0) );
240     AddChild( fMenuBar );
241
242
243     // Add the file Menu
244     BMenu* fileMenu = new BMenu( _("File") );
245     fMenuBar->AddItem( fileMenu );
246     ADD_ELLIPSIS( _("Open File") );
247     fileMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( OPEN_FILE ), 'O') );
248     fileMenu->AddItem( new CDMenu( _("Open Disc") ) );
249     ADD_ELLIPSIS( _("Open Subtitles") );
250     fileMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( LOAD_SUBFILE ) ) );
251
252     fileMenu->AddSeparatorItem();
253     ADD_ELLIPSIS( _("About") );
254     BMenuItem* item = new BMenuItem( psz_tmp, new BMessage( B_ABOUT_REQUESTED ), 'A');
255     item->SetTarget( be_app );
256     fileMenu->AddItem( item );
257     fileMenu->AddItem( new BMenuItem( _("Quit"), new BMessage( B_QUIT_REQUESTED ), 'Q') );
258
259     fLanguageMenu = new LanguageMenu( p_intf, _("Language"), "audio-es" );
260     fSubtitlesMenu = new LanguageMenu( p_intf, _("Subtitles"), "spu-es" );
261
262     /* Add the Audio menu */
263     fAudioMenu = new BMenu( _("Audio") );
264     fMenuBar->AddItem ( fAudioMenu );
265     fAudioMenu->AddItem( fLanguageMenu );
266     fAudioMenu->AddItem( fSubtitlesMenu );
267
268     fPrevTitleMI = new BMenuItem( _("Prev Title"), new BMessage( PREV_TITLE ) );
269     fNextTitleMI = new BMenuItem( _("Next Title"), new BMessage( NEXT_TITLE ) );
270     fPrevChapterMI = new BMenuItem( _("Previous chapter"), new BMessage( PREV_CHAPTER ) );
271     fNextChapterMI = new BMenuItem( _("Next chapter"), new BMessage( NEXT_CHAPTER ) );
272
273     /* Add the Navigation menu */
274     fNavigationMenu = new BMenu( _("Navigation") );
275     fMenuBar->AddItem( fNavigationMenu );
276     fNavigationMenu->AddItem( fPrevTitleMI );
277     fNavigationMenu->AddItem( fNextTitleMI );
278     fNavigationMenu->AddItem( fTitleMenu = new TitleMenu( _("Go to Title"), p_intf ) );
279     fNavigationMenu->AddSeparatorItem();
280     fNavigationMenu->AddItem( fPrevChapterMI );
281     fNavigationMenu->AddItem( fNextChapterMI );
282     fNavigationMenu->AddItem( fChapterMenu = new ChapterMenu( _("Go to Chapter"), p_intf ) );
283
284     /* Add the Speed menu */
285     fSpeedMenu = new BMenu( _("Speed") );
286     fSpeedMenu->SetRadioMode( true );
287     fSpeedMenu->AddItem(
288         fHeighthMI = new BMenuItem( "1/8x", new BMessage( HEIGHTH_PLAY ) ) );
289     fSpeedMenu->AddItem(
290         fQuarterMI = new BMenuItem( "1/4x", new BMessage( QUARTER_PLAY ) ) );
291     fSpeedMenu->AddItem(
292         fHalfMI = new BMenuItem( "1/2x", new BMessage( HALF_PLAY ) ) );
293     fSpeedMenu->AddItem(
294         fNormalMI = new BMenuItem( "1x", new BMessage( NORMAL_PLAY ) ) );
295     fSpeedMenu->AddItem(
296         fTwiceMI = new BMenuItem( "2x", new BMessage( TWICE_PLAY ) ) );
297     fSpeedMenu->AddItem(
298         fFourMI = new BMenuItem( "4x", new BMessage( FOUR_PLAY ) ) );
299     fSpeedMenu->AddItem(
300         fHeightMI = new BMenuItem( "8x", new BMessage( HEIGHT_PLAY ) ) );
301     fMenuBar->AddItem( fSpeedMenu );
302
303     /* Add the Show menu */
304     fShowMenu = new BMenu( _("Window") );
305     ADD_ELLIPSIS( _("Playlist") );
306     fShowMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( OPEN_PLAYLIST ), 'P') );
307     ADD_ELLIPSIS( _("Messages") );
308     fShowMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( OPEN_MESSAGES ), 'M' ) );
309     ADD_ELLIPSIS( _("Preferences") );
310     fShowMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( OPEN_PREFERENCES ), 'S' ) );
311     fMenuBar->AddItem( fShowMenu );
312
313     // add the media control view after the menubar is complete
314     // because it will set the window size limits in AttachedToWindow()
315     // and the menubar needs to report the correct PreferredSize()
316     AddChild( p_mediaControl );
317
318     /* Prepare fow showing */
319     _SetMenusEnabled( false );
320     p_mediaControl->SetEnabled( false );
321
322     _RestoreSettings();
323
324     Show();
325 }
326
327 InterfaceWindow::~InterfaceWindow()
328 {
329     if( p_input )
330     {
331         vlc_object_release( p_input );
332     }
333     if( p_playlist )
334     {
335         vlc_object_release( p_playlist );
336     }
337     if( fPlaylistWindow )
338     {
339         fPlaylistWindow->ReallyQuit();
340     }
341     if( fMessagesWindow )
342     {
343         fMessagesWindow->ReallyQuit();
344     }
345     if( fPreferencesWindow )
346     {
347         fPreferencesWindow->ReallyQuit();
348     }
349     delete fFilePanel;
350     delete fSettings;
351 }
352
353 /*****************************************************************************
354  * InterfaceWindow::FrameResized
355  *****************************************************************************/
356 void
357 InterfaceWindow::FrameResized(float width, float height)
358 {
359     BRect r(Bounds());
360     fMenuBar->MoveTo(r.LeftTop());
361     fMenuBar->ResizeTo(r.Width(), fMenuBar->Bounds().Height());
362     r.top += fMenuBar->Bounds().Height() + 1.0;
363     p_mediaControl->MoveTo(r.LeftTop());
364     p_mediaControl->ResizeTo(r.Width(), r.Height());
365 }
366
367 /*****************************************************************************
368  * InterfaceWindow::MessageReceived
369  *****************************************************************************/
370 void InterfaceWindow::MessageReceived( BMessage * p_message )
371 {
372     switch( p_message->what )
373     {
374         case B_ABOUT_REQUESTED:
375         {
376             BAlert * alert;
377             
378             alert = new BAlert( "VLC media player" VERSION,
379                                 "VLC media player" VERSION " (BeOS interface)\n\n"
380                                 "The VideoLAN team <videolan@videolan.org>\n"
381                                 "http://www.videolan.org/", _("OK") );
382             alert->Go();
383             break;
384         }
385         case TOGGLE_ON_TOP:
386             break;
387
388         case OPEN_FILE:
389             _ShowFilePanel( B_REFS_RECEIVED, _("VLC media player: Open Media Files") );
390             break;
391
392         case LOAD_SUBFILE:
393             _ShowFilePanel( SUBFILE_RECEIVED, _("VLC media player: Open Subtitle File") );
394             break;
395
396         case OPEN_PLAYLIST:
397             if (fPlaylistWindow->Lock())
398             {
399                 if (fPlaylistWindow->IsHidden())
400                     fPlaylistWindow->Show();
401                 else
402                     fPlaylistWindow->Activate();
403                 fPlaylistWindow->Unlock();
404             }
405             break;
406
407         case OPEN_DVD:
408             {
409                 const char * psz_device;
410                 if( p_playlist &&
411                     p_message->FindString( "device", &psz_device ) == B_OK )
412                 {
413                     char psz_uri[1024];
414                     memset( psz_uri, 0, 1024 );
415                     snprintf( psz_uri, 1024, "dvdnav:%s", psz_device );
416                     playlist_Add( p_playlist, psz_uri, psz_device,
417                                   PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
418                 }
419                 _UpdatePlaylist();
420             }
421             break;
422
423         case SUBFILE_RECEIVED:
424         {
425             entry_ref ref;
426             if( p_message->FindRef( "refs", 0, &ref ) == B_OK )
427             {
428                 BPath path( &ref );
429                 if ( path.InitCheck() == B_OK )
430                     config_PutPsz( p_intf, "sub-file", path.Path() );
431             }
432             break;
433         }
434
435         case STOP_PLAYBACK:
436             if( p_playlist )
437             {
438                 playlist_Stop( p_playlist );
439             }
440             p_mediaControl->SetStatus(-1, INPUT_RATE_DEFAULT);
441             break;
442     
443         case START_PLAYBACK:
444             /*  starts playing in normal mode */
445     
446         case PAUSE_PLAYBACK:
447             if( p_input )
448             {
449                 if( var_GetInteger( p_input, "state" ) == PAUSE_S )
450                 {
451                     if( p_playlist )
452                     {
453                         playlist_Play( p_playlist );
454                     }
455                 }
456                 else
457                 {
458                     var_SetInteger( p_input, "state", PAUSE_S );
459                 }
460             }
461             break;
462     
463         case HEIGHTH_PLAY:
464             if( p_input )
465             {
466                 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT * 8 );
467             }
468             break;
469
470         case QUARTER_PLAY:
471             if( p_input )
472             {
473                 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT * 4 );
474             }
475             break;
476
477         case HALF_PLAY:
478             if( p_input )
479             {
480                 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT * 2 );
481             }
482             break;
483
484         case NORMAL_PLAY:
485             if( p_input )
486             {
487                 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT );
488             }
489             break;
490
491         case TWICE_PLAY:
492             if( p_input )
493             {
494                 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT / 2 );
495             }
496             break;
497
498         case FOUR_PLAY:
499             if( p_input )
500             {
501                 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT / 4 );
502             }
503             break;
504
505         case HEIGHT_PLAY:
506             if( p_input )
507             {
508                 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT / 8 );
509             }
510             break;
511
512         case SEEK_PLAYBACK:
513             /* handled by semaphores */
514             break;
515
516         case VOLUME_CHG:
517             aout_VolumeSet( p_intf, p_mediaControl->GetVolume() );
518             break;
519     
520         case VOLUME_MUTE:
521             aout_VolumeMute( p_intf, NULL );
522             break;
523     
524         case SELECT_CHANNEL:
525         {
526             int32 channel;
527             if( p_input )
528             {
529                 if( p_message->FindInt32( "audio-es", &channel ) == B_OK )
530                 {
531                     var_SetInteger( p_input, "audio-es", channel );
532                 }
533                 else if( p_message->FindInt32( "spu-es", &channel ) == B_OK )
534                 {
535                     var_SetInteger( p_input, "spu-es", channel );
536                 }
537             }
538             break;
539         }
540     
541         case PREV_TITLE:
542             if( p_input )
543             {
544                 var_SetVoid( p_input, "prev-title" );
545             }
546             break;
547
548         case NEXT_TITLE:
549             if( p_input )
550             {
551                 var_SetVoid( p_input, "next-title" );
552             }
553             break;
554
555         case TOGGLE_TITLE:
556         {
557             int32 index;
558             if( p_input &&
559                 p_message->FindInt32( "index", &index ) == B_OK )
560             {
561                 var_SetInteger( p_input, "title", index );
562             }
563             break;
564         }
565
566         case PREV_CHAPTER:
567             if( p_input )
568             {
569                 var_SetVoid( p_input, "prev-chapter" );
570             }
571             break;
572
573         case NEXT_CHAPTER:
574             if( p_input )
575             {
576                 var_SetVoid( p_input, "next-chapter" );
577             }
578             break;
579
580         case TOGGLE_CHAPTER:
581         {
582             int32 index;
583             if( p_input &&
584                 p_message->FindInt32( "index", &index ) == B_OK )
585             {
586                 var_SetInteger( p_input, "chapter", index );
587             }
588             break;
589         }
590
591         case PREV_FILE:
592             if( p_playlist )
593             {
594                 playlist_Prev( p_playlist );
595             }
596             break;
597
598         case NEXT_FILE:
599             if( p_playlist )
600             {
601                 playlist_Next( p_playlist );
602             }
603             break;
604
605         case NAVIGATE_PREV:
606             if( p_input )
607             {
608                 vlc_value_t val;
609
610                 /* First try to go to previous chapter */
611                 if( !var_Get( p_input, "chapter", &val ) )
612                 {
613                     if( val.i_int > 1 )
614                     {
615                         var_SetVoid( p_input, "prev-chapter" );
616                         break;
617                     }
618                 }
619
620                 /* Try to go to previous title */
621                 if( !var_Get( p_input, "title", &val ) )
622                 {
623                     if( val.i_int > 1 )
624                     {
625                         var_SetVoid( p_input, "prev-title" );
626                         break;
627                     }
628                 }
629
630                 /* Try to go to previous file */
631                 if( p_playlist )
632                 {
633                     playlist_Prev( p_playlist );
634                 }
635             }
636             break;
637
638         case NAVIGATE_NEXT:
639             if( p_input )
640             {
641                 vlc_value_t val, val_list;
642
643                 /* First try to go to next chapter */
644                 if( !var_Get( p_input, "chapter", &val ) )
645                 {
646                     var_Change( p_input, "chapter", VLC_VAR_GETCHOICES,
647                                 &val_list, NULL );
648                     if( val_list.p_list->i_count > val.i_int )
649                     {
650                         var_Change( p_input, "chapter", VLC_VAR_FREELIST,
651                                     &val_list, NULL );
652                         var_SetVoid( p_input, "next-chapter" );
653                         break;
654                     }
655                     var_Change( p_input, "chapter", VLC_VAR_FREELIST,
656                                 &val_list, NULL );
657                 }
658
659                 /* Try to go to next title */
660                 if( !var_Get( p_input, "title", &val ) )
661                 {
662                     var_Change( p_input, "title", VLC_VAR_GETCHOICES,
663                                 &val_list, NULL );
664                     if( val_list.p_list->i_count > val.i_int )
665                     {
666                         var_Change( p_input, "title", VLC_VAR_FREELIST,
667                                     &val_list, NULL );
668                         var_SetVoid( p_input, "next-title" );
669                         break;
670                     }
671                     var_Change( p_input, "title", VLC_VAR_FREELIST,
672                                 &val_list, NULL );
673                 }
674
675                 /* Try to go to next file */
676                 if( p_playlist )
677                 {
678                     playlist_Next( p_playlist );
679                 }
680             }
681             break;
682
683         // drag'n'drop and system messages
684         case MSG_SOUNDPLAY:
685             // convert soundplay drag'n'drop message (containing paths)
686             // to normal message (containing refs)
687             {
688                 const char* path;
689                 for ( int32 i = 0; p_message->FindString( "path", i, &path ) == B_OK; i++ )
690                 {
691                     entry_ref ref;
692                     if ( get_ref_for_path( path, &ref ) == B_OK )
693                         p_message->AddRef( "refs", &ref );
694                 }
695             }
696             // fall through
697         case B_REFS_RECEIVED:
698         case B_SIMPLE_DATA:
699         {
700             /* file(s) opened by the File menu -> append to the playlist;
701                file(s) opened by drag & drop -> replace playlist;
702                file(s) opened by 'shift' + drag & drop -> append */
703
704             int32 count;
705             type_code dummy;
706             if( p_message->GetInfo( "refs", &dummy, &count ) != B_OK ||
707                 count < 1 )
708             {
709                 break;
710             }
711             
712             vlc_bool_t b_remove = ( p_message->WasDropped() &&
713                                     !( modifiers() & B_SHIFT_KEY ) ); 
714
715             if( b_remove && p_playlist )
716             {
717                 /* Empty playlist */
718                 while( p_playlist->i_size > 0 )
719                 {
720                     playlist_Delete( p_playlist, 0 );
721                 }
722             }
723
724             entry_ref ref;
725             for( int i = 0; p_message->FindRef( "refs", i, &ref ) == B_OK; i++ )
726             {
727                 BPath path( &ref );
728
729                 /* TODO: find out if this is a DVD icon */
730
731                 if( p_playlist )
732                 {
733                     playlist_Add( p_playlist, path.Path(), path.Path(),
734                                   PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
735                 }
736             }
737
738             _UpdatePlaylist();
739             break;
740         }
741
742         case OPEN_PREFERENCES:
743         {
744             if( fPreferencesWindow->Lock() )
745             {
746                 if (fPreferencesWindow->IsHidden())
747                     fPreferencesWindow->Show();
748                 else
749                     fPreferencesWindow->Activate();
750                 fPreferencesWindow->Unlock();
751             }
752             break;
753         }
754
755         case OPEN_MESSAGES:
756         {
757             if( fMessagesWindow->Lock() )
758             {
759                 if (fMessagesWindow->IsHidden())
760                     fMessagesWindow->Show();
761                 else
762                     fMessagesWindow->Activate();
763                 fMessagesWindow->Unlock();
764             }
765             break;
766         }
767         case MSG_UPDATE:
768             UpdateInterface();
769             break;
770         default:
771             BWindow::MessageReceived( p_message );
772             break;
773     }
774 }
775
776 /*****************************************************************************
777  * InterfaceWindow::QuitRequested
778  *****************************************************************************/
779 bool InterfaceWindow::QuitRequested()
780 {
781     if( p_playlist )
782     {
783         playlist_Stop( p_playlist );
784     }
785     p_mediaControl->SetStatus(-1, INPUT_RATE_DEFAULT);
786
787      _StoreSettings();
788    
789     p_intf->b_die = 1;
790
791     return( true );
792 }
793
794 /*****************************************************************************
795  * InterfaceWindow::UpdateInterface
796  *****************************************************************************/
797 void InterfaceWindow::UpdateInterface()
798 {
799     /* Manage the input part */
800     if( !p_playlist )
801     {
802         p_playlist = (playlist_t *)
803             vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
804     }
805     if( !p_input )
806     {
807         p_input = (input_thread_t *)
808             vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
809     }
810     else if( p_input->b_dead )
811     {
812         vlc_object_release( p_input );
813         p_input = NULL;
814     }
815
816     /* Get ready to update the interface */
817     if( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) != B_OK )
818     {
819         return;
820     }
821     
822     if( p_input )
823     {
824         vlc_value_t val;
825         p_mediaControl->SetEnabled( true );
826         bool hasTitles   = !var_Get( p_input, "title", &val );
827         bool hasChapters = !var_Get( p_input, "chapter", &val );
828         p_mediaControl->SetStatus( var_GetInteger( p_input, "state" ), 
829                                    var_GetInteger( p_input, "rate" ) );
830         var_Get( p_input, "position", &val );
831         p_mediaControl->SetProgress( val.f_float );
832         _SetMenusEnabled( true, hasChapters, hasTitles );
833         _UpdateSpeedMenu( var_GetInteger( p_input, "rate" ) );
834
835         // enable/disable skip buttons
836 #if 0
837         bool canSkipPrev;
838         bool canSkipNext;
839         p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
840         p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
841 #endif
842
843         audio_volume_t i_volume;
844         aout_VolumeGet( p_intf, &i_volume );
845         p_mediaControl->SetAudioEnabled( true );
846         p_mediaControl->SetMuted( i_volume );
847
848         // update playlist as well
849         if( fPlaylistWindow->LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) == B_OK )
850         {
851             fPlaylistWindow->UpdatePlaylist();
852             fPlaylistWindow->Unlock();
853         }
854     }
855     else
856     {
857         p_mediaControl->SetAudioEnabled( false );
858
859         _SetMenusEnabled( false );
860         
861         if( !p_playlist || p_playlist->i_size <= 0 )
862         {
863             p_mediaControl->SetProgress( 0 );
864             
865 #if 0
866             // enable/disable skip buttons
867             bool canSkipPrev;
868             bool canSkipNext;
869             p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
870             p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
871 #endif
872         }
873         else
874         {
875             p_mediaControl->SetEnabled( false );
876         }
877     }
878     
879     Unlock();
880     fLastUpdateTime = system_time();
881 }
882
883 /*****************************************************************************
884  * InterfaceWindow::IsStopped
885  *****************************************************************************/
886 bool
887 InterfaceWindow::IsStopped() const
888 {
889     return (system_time() - fLastUpdateTime > INTERFACE_UPDATE_TIMEOUT);
890 }
891
892 /*****************************************************************************
893  * InterfaceWindow::_UpdatePlaylist
894  *****************************************************************************/
895 void
896 InterfaceWindow::_UpdatePlaylist()
897 {
898     if( fPlaylistWindow->Lock() )
899     {
900         fPlaylistWindow->UpdatePlaylist( true );
901         fPlaylistWindow->Unlock();
902     }
903     p_mediaControl->SetEnabled( p_playlist->i_size );
904 }
905
906 /*****************************************************************************
907  * InterfaceWindow::_SetMenusEnabled
908  *****************************************************************************/
909 void
910 InterfaceWindow::_SetMenusEnabled(bool hasFile, bool hasChapters, bool hasTitles)
911 {
912     if (!hasFile)
913     {
914         hasChapters = false;
915         hasTitles = false;
916     }
917     if ( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) == B_OK)
918     {
919         if ( fNextChapterMI->IsEnabled() != hasChapters )
920              fNextChapterMI->SetEnabled( hasChapters );
921         if ( fPrevChapterMI->IsEnabled() != hasChapters )
922              fPrevChapterMI->SetEnabled( hasChapters );
923         if ( fChapterMenu->IsEnabled() != hasChapters )
924              fChapterMenu->SetEnabled( hasChapters );
925         if ( fNextTitleMI->IsEnabled() != hasTitles )
926              fNextTitleMI->SetEnabled( hasTitles );
927         if ( fPrevTitleMI->IsEnabled() != hasTitles )
928              fPrevTitleMI->SetEnabled( hasTitles );
929         if ( fTitleMenu->IsEnabled() != hasTitles )
930              fTitleMenu->SetEnabled( hasTitles );
931         if ( fAudioMenu->IsEnabled() != hasFile )
932              fAudioMenu->SetEnabled( hasFile );
933         if ( fNavigationMenu->IsEnabled() != hasFile )
934              fNavigationMenu->SetEnabled( hasFile );
935         if ( fLanguageMenu->IsEnabled() != hasFile )
936              fLanguageMenu->SetEnabled( hasFile );
937         if ( fSubtitlesMenu->IsEnabled() != hasFile )
938              fSubtitlesMenu->SetEnabled( hasFile );
939         if ( fSpeedMenu->IsEnabled() != hasFile )
940              fSpeedMenu->SetEnabled( hasFile );
941         Unlock();
942     }
943 }
944
945 /*****************************************************************************
946  * InterfaceWindow::_UpdateSpeedMenu
947  *****************************************************************************/
948 void
949 InterfaceWindow::_UpdateSpeedMenu( int rate )
950 {
951     BMenuItem * toMark = NULL;
952     
953     switch( rate )
954     {
955         case ( INPUT_RATE_DEFAULT * 8 ):
956             toMark = fHeighthMI;
957             break;
958             
959         case ( INPUT_RATE_DEFAULT * 4 ):
960             toMark = fQuarterMI;
961             break;
962             
963         case ( INPUT_RATE_DEFAULT * 2 ):
964             toMark = fHalfMI;
965             break;
966             
967         case ( INPUT_RATE_DEFAULT ):
968             toMark = fNormalMI;
969             break;
970             
971         case ( INPUT_RATE_DEFAULT / 2 ):
972             toMark = fTwiceMI;
973             break;
974             
975         case ( INPUT_RATE_DEFAULT / 4 ):
976             toMark = fFourMI;
977             break;
978             
979         case ( INPUT_RATE_DEFAULT / 8 ):
980             toMark = fHeightMI;
981             break;
982     }
983
984     if ( toMark && !toMark->IsMarked() )
985     {
986         toMark->SetMarked( true );
987     }
988 }
989
990 /*****************************************************************************
991  * InterfaceWindow::_ShowFilePanel
992  *****************************************************************************/
993 void
994 InterfaceWindow::_ShowFilePanel( uint32 command, const char* windowTitle )
995 {
996     if( !fFilePanel )
997     {
998         fFilePanel = new BFilePanel( B_OPEN_PANEL, NULL, NULL,
999                                      B_FILE_NODE | B_DIRECTORY_NODE );
1000         fFilePanel->SetTarget( this );
1001     }
1002     fFilePanel->Window()->SetTitle( windowTitle );
1003     BMessage message( command );
1004     fFilePanel->SetMessage( &message );
1005     if ( !fFilePanel->IsShowing() )
1006     {
1007         fFilePanel->Refresh();
1008         fFilePanel->Show();
1009     }
1010 }
1011
1012 // set_window_pos
1013 void
1014 set_window_pos( BWindow* window, BRect frame )
1015 {
1016     // sanity checks: make sure window is not too big/small
1017     // and that it's not off-screen
1018     float minWidth, maxWidth, minHeight, maxHeight;
1019     window->GetSizeLimits( &minWidth, &maxWidth, &minHeight, &maxHeight );
1020
1021     make_sure_frame_is_within_limits( frame,
1022                                       minWidth, minHeight, maxWidth, maxHeight );
1023     if ( make_sure_frame_is_on_screen( frame ) )
1024     {
1025         window->MoveTo( frame.LeftTop() );
1026         window->ResizeTo( frame.Width(), frame.Height() );
1027     }
1028 }
1029
1030 // set_window_pos
1031 void
1032 launch_window( BWindow* window, bool showing )
1033 {
1034     if ( window->Lock() )
1035     {
1036         if ( showing )
1037         {
1038             if ( window->IsHidden() )
1039                 window->Show();
1040         }
1041         else
1042         {
1043             if ( !window->IsHidden() )
1044                 window->Hide();
1045         }
1046         window->Unlock();
1047     }
1048 }
1049
1050 /*****************************************************************************
1051  * InterfaceWindow::_RestoreSettings
1052  *****************************************************************************/
1053 void
1054 InterfaceWindow::_RestoreSettings()
1055 {
1056     if ( load_settings( fSettings, "interface_settings", "VideoLAN Client" ) == B_OK )
1057     {
1058         BRect frame;
1059         if ( fSettings->FindRect( "main frame", &frame ) == B_OK )
1060             set_window_pos( this, frame );
1061         if (fSettings->FindRect( "playlist frame", &frame ) == B_OK )
1062             set_window_pos( fPlaylistWindow, frame );
1063         if (fSettings->FindRect( "messages frame", &frame ) == B_OK )
1064             set_window_pos( fMessagesWindow, frame );
1065         if (fSettings->FindRect( "settings frame", &frame ) == B_OK )
1066         {
1067             /* FIXME: Preferences resizing doesn't work correctly yet */
1068             frame.right = frame.left + fPreferencesWindow->Frame().Width();
1069             frame.bottom = frame.top + fPreferencesWindow->Frame().Height();
1070             set_window_pos( fPreferencesWindow, frame );
1071         }
1072         
1073         bool showing;
1074         if ( fSettings->FindBool( "playlist showing", &showing ) == B_OK )
1075             launch_window( fPlaylistWindow, showing );
1076         if ( fSettings->FindBool( "messages showing", &showing ) == B_OK )
1077             launch_window( fMessagesWindow, showing );
1078         if ( fSettings->FindBool( "settings showing", &showing ) == B_OK )
1079             launch_window( fPreferencesWindow, showing );
1080
1081         uint32 displayMode;
1082         if ( fSettings->FindInt32( "playlist display mode", (int32*)&displayMode ) == B_OK )
1083             fPlaylistWindow->SetDisplayMode( displayMode );
1084     }
1085 }
1086
1087 /*****************************************************************************
1088  * InterfaceWindow::_StoreSettings
1089  *****************************************************************************/
1090 void
1091 InterfaceWindow::_StoreSettings()
1092 {
1093     /* Save the volume */
1094     config_PutInt( p_intf, "volume", p_mediaControl->GetVolume() );
1095     config_SaveConfigFile( p_intf, "main" );
1096
1097     /* Save the windows positions */
1098     if ( fSettings->ReplaceRect( "main frame", Frame() ) != B_OK )
1099         fSettings->AddRect( "main frame", Frame() );
1100     if ( fPlaylistWindow->Lock() )
1101     {
1102         if (fSettings->ReplaceRect( "playlist frame", fPlaylistWindow->Frame() ) != B_OK)
1103             fSettings->AddRect( "playlist frame", fPlaylistWindow->Frame() );
1104         if (fSettings->ReplaceBool( "playlist showing", !fPlaylistWindow->IsHidden() ) != B_OK)
1105             fSettings->AddBool( "playlist showing", !fPlaylistWindow->IsHidden() );
1106         fPlaylistWindow->Unlock();
1107     }
1108     if ( fMessagesWindow->Lock() )
1109     {
1110         if (fSettings->ReplaceRect( "messages frame", fMessagesWindow->Frame() ) != B_OK)
1111             fSettings->AddRect( "messages frame", fMessagesWindow->Frame() );
1112         if (fSettings->ReplaceBool( "messages showing", !fMessagesWindow->IsHidden() ) != B_OK)
1113             fSettings->AddBool( "messages showing", !fMessagesWindow->IsHidden() );
1114         fMessagesWindow->Unlock();
1115     }
1116     if ( fPreferencesWindow->Lock() )
1117     {
1118         if (fSettings->ReplaceRect( "settings frame", fPreferencesWindow->Frame() ) != B_OK)
1119             fSettings->AddRect( "settings frame", fPreferencesWindow->Frame() );
1120         if (fSettings->ReplaceBool( "settings showing", !fPreferencesWindow->IsHidden() ) != B_OK)
1121             fSettings->AddBool( "settings showing", !fPreferencesWindow->IsHidden() );
1122         fPreferencesWindow->Unlock();
1123     }
1124     uint32 displayMode = fPlaylistWindow->DisplayMode();
1125     if (fSettings->ReplaceInt32( "playlist display mode", displayMode ) != B_OK )
1126         fSettings->AddInt32( "playlist display mode", displayMode );
1127
1128     save_settings( fSettings, "interface_settings", "VideoLAN Client" );
1129 }
1130
1131
1132 /*****************************************************************************
1133  * CDMenu::CDMenu
1134  *****************************************************************************/
1135 CDMenu::CDMenu(const char *name)
1136       : BMenu(name)
1137 {
1138 }
1139
1140 /*****************************************************************************
1141  * CDMenu::~CDMenu
1142  *****************************************************************************/
1143 CDMenu::~CDMenu()
1144 {
1145 }
1146
1147 /*****************************************************************************
1148  * CDMenu::AttachedToWindow
1149  *****************************************************************************/
1150 void CDMenu::AttachedToWindow(void)
1151 {
1152     // remove all items
1153     while ( BMenuItem* item = RemoveItem( 0L ) )
1154         delete item;
1155     GetCD( "/dev/disk" );
1156     BMenu::AttachedToWindow();
1157 }
1158
1159 /*****************************************************************************
1160  * CDMenu::GetCD
1161  *****************************************************************************/
1162 int CDMenu::GetCD( const char *directory )
1163 {
1164     BVolumeRoster volRoster;
1165     BVolume vol;
1166     BDirectory dir;
1167     status_t status = volRoster.GetNextVolume( &vol );
1168     while ( status ==  B_NO_ERROR )
1169     {
1170         BString deviceName;
1171         BString volumeName;
1172         bool isCDROM;
1173         if ( get_volume_info( vol, volumeName, isCDROM, deviceName )
1174              && isCDROM )
1175         {
1176             BMessage* msg = new BMessage( OPEN_DVD );
1177             msg->AddString( "device", deviceName.String() );
1178             BMenuItem* item = new BMenuItem( volumeName.String(), msg );
1179             AddItem( item );
1180         }
1181          vol.Unset();
1182         status = volRoster.GetNextVolume( &vol );
1183     }
1184     return 0;
1185 }
1186
1187 /*****************************************************************************
1188  * LanguageMenu::LanguageMenu
1189  *****************************************************************************/
1190 LanguageMenu::LanguageMenu( intf_thread_t * _p_intf, const char * psz_name,
1191                             char * _psz_variable )
1192     : BMenu( psz_name )
1193 {
1194     p_intf       = _p_intf;
1195     psz_variable = strdup( _psz_variable );
1196 }
1197
1198 /*****************************************************************************
1199  * LanguageMenu::~LanguageMenu
1200  *****************************************************************************/
1201 LanguageMenu::~LanguageMenu()
1202 {
1203     free( psz_variable );
1204 }
1205
1206 /*****************************************************************************
1207  * LanguageMenu::AttachedToWindow
1208  *****************************************************************************/
1209 void LanguageMenu::AttachedToWindow()
1210 {
1211     BMenuItem * item;
1212
1213     // remove all items
1214     while( ( item = RemoveItem( 0L ) ) )
1215     {
1216         delete item;
1217     }
1218
1219     SetRadioMode( true );
1220
1221     input_thread_t * p_input = (input_thread_t *)
1222             vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1223     if( !p_input )
1224     {
1225         return;
1226     }
1227     
1228     vlc_value_t val_list, text_list;
1229     BMessage * message;
1230     int i_current;
1231     
1232     i_current = var_GetInteger( p_input, psz_variable );
1233     var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list );
1234     for( int i = 0; i < val_list.p_list->i_count; i++ )
1235     {
1236         message = new BMessage( SELECT_CHANNEL );
1237         message->AddInt32( psz_variable, val_list.p_list->p_values[i].i_int );
1238         item = new BMenuItem( text_list.p_list->p_values[i].psz_string, message );
1239         if( val_list.p_list->p_values[i].i_int == i_current )
1240         {
1241             item->SetMarked( true );
1242         }
1243         AddItem( item );
1244     }
1245     var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list );
1246     
1247     vlc_object_release( p_input );
1248     
1249     BMenu::AttachedToWindow();
1250 }
1251
1252 /*****************************************************************************
1253  * TitleMenu::TitleMenu
1254  *****************************************************************************/
1255 TitleMenu::TitleMenu( const char *name, intf_thread_t  *p_interface )
1256     : BMenu(name),
1257     p_intf( p_interface )
1258 {
1259 }
1260
1261 /*****************************************************************************
1262  * TitleMenu::~TitleMenu
1263  *****************************************************************************/
1264 TitleMenu::~TitleMenu()
1265 {
1266 }
1267
1268 /*****************************************************************************
1269  * TitleMenu::AttachedToWindow
1270  *****************************************************************************/
1271 void TitleMenu::AttachedToWindow()
1272 {
1273     BMenuItem * item;
1274     while( ( item = RemoveItem( 0L ) ) )
1275     {
1276         delete item;
1277     }
1278
1279     input_thread_t * p_input;
1280     p_input = (input_thread_t *)
1281         vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1282     if( !p_input )
1283     {
1284         return;
1285     }
1286
1287     vlc_value_t val;
1288     BMessage * message;
1289     if( !var_Get( p_input, "title", &val ) )
1290     {
1291         vlc_value_t val_list, text_list;
1292         var_Change( p_input, "title", VLC_VAR_GETCHOICES,
1293                     &val_list, &text_list );
1294         
1295         for( int i = 0; i < val_list.p_list->i_count; i++ )
1296         {
1297             message = new BMessage( TOGGLE_TITLE );
1298             message->AddInt32( "index", val_list.p_list->p_values[i].i_int );
1299             item = new BMenuItem( text_list.p_list->p_values[i].psz_string,
1300                                   message );
1301             if( val_list.p_list->p_values[i].i_int == val.i_int )
1302             {
1303                 item->SetMarked( true );
1304             }
1305             AddItem( item );
1306         }
1307
1308         var_Change( p_input, "title", VLC_VAR_FREELIST,
1309                     &val_list, &text_list );
1310     }
1311     BMenu::AttachedToWindow();
1312 }
1313
1314
1315 /*****************************************************************************
1316  * ChapterMenu::ChapterMenu
1317  *****************************************************************************/
1318 ChapterMenu::ChapterMenu( const char *name, intf_thread_t  *p_interface )
1319     : BMenu(name),
1320     p_intf( p_interface )
1321 {
1322 }
1323
1324 /*****************************************************************************
1325  * ChapterMenu::~ChapterMenu
1326  *****************************************************************************/
1327 ChapterMenu::~ChapterMenu()
1328 {
1329 }
1330
1331 /*****************************************************************************
1332  * ChapterMenu::AttachedToWindow
1333  *****************************************************************************/
1334 void ChapterMenu::AttachedToWindow()
1335 {
1336     BMenuItem * item;
1337     while( ( item = RemoveItem( 0L ) ) )
1338     {
1339         delete item;
1340     }
1341
1342     input_thread_t * p_input;
1343     p_input = (input_thread_t *)
1344         vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1345     if( !p_input )
1346     {
1347         return;
1348     }
1349
1350     vlc_value_t val;
1351     BMessage * message;
1352     if( !var_Get( p_input, "chapter", &val ) )
1353     {
1354         vlc_value_t val_list, text_list;
1355         var_Change( p_input, "chapter", VLC_VAR_GETCHOICES,
1356                     &val_list, &text_list );
1357         
1358         for( int i = 0; i < val_list.p_list->i_count; i++ )
1359         {
1360             message = new BMessage( TOGGLE_CHAPTER );
1361             message->AddInt32( "index", val_list.p_list->p_values[i].i_int );
1362             item = new BMenuItem( text_list.p_list->p_values[i].psz_string,
1363                                   message );
1364             if( val_list.p_list->p_values[i].i_int == val.i_int )
1365             {
1366                 item->SetMarked( true );
1367             }
1368             AddItem( item );
1369         }
1370
1371         var_Change( p_input, "chapter", VLC_VAR_FREELIST,
1372                     &val_list, &text_list );
1373     }
1374     BMenu::AttachedToWindow();
1375 }
1376
1377
1378 /*****************************************************************************
1379  * load_settings
1380  *****************************************************************************/
1381 status_t
1382 load_settings( BMessage* message, const char* fileName, const char* folder )
1383 {
1384     status_t ret = B_BAD_VALUE;
1385     if ( message )
1386     {
1387         BPath path;
1388         if ( ( ret = find_directory( B_USER_SETTINGS_DIRECTORY, &path ) ) == B_OK )
1389         {
1390             // passing folder is optional
1391             if ( folder )
1392                 ret = path.Append( folder );
1393             if ( ret == B_OK && ( ret = path.Append( fileName ) ) == B_OK )
1394             {
1395                 BFile file( path.Path(), B_READ_ONLY );
1396                 if ( ( ret = file.InitCheck() ) == B_OK )
1397                 {
1398                     ret = message->Unflatten( &file );
1399                     file.Unset();
1400                 }
1401             }
1402         }
1403     }
1404     return ret;
1405 }
1406
1407 /*****************************************************************************
1408  * save_settings
1409  *****************************************************************************/
1410 status_t
1411 save_settings( BMessage* message, const char* fileName, const char* folder )
1412 {
1413     status_t ret = B_BAD_VALUE;
1414     if ( message )
1415     {
1416         BPath path;
1417         if ( ( ret = find_directory( B_USER_SETTINGS_DIRECTORY, &path ) ) == B_OK )
1418         {
1419             // passing folder is optional
1420             if ( folder && ( ret = path.Append( folder ) ) == B_OK )
1421                 ret = create_directory( path.Path(), 0777 );
1422             if ( ret == B_OK && ( ret = path.Append( fileName ) ) == B_OK )
1423             {
1424                 BFile file( path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE );
1425                 if ( ( ret = file.InitCheck() ) == B_OK )
1426                 {
1427                     ret = message->Flatten( &file );
1428                     file.Unset();
1429                 }
1430             }
1431         }
1432     }
1433     return ret;
1434 }