]> git.sesse.net Git - vlc/blob - modules/gui/beos/InterfaceWindow.cpp
beos/InterfaceWindow.cpp: fixed a couple of missing vlc_object_release()s
[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         case PAUSE_PLAYBACK:
445         {
446             vlc_value_t val;
447             val.i_int = PLAYING_S;
448             if( p_input )
449             {
450                 var_Get( p_input, "state", &val );
451             }
452             if( p_input && val.i_int != PAUSE_S )
453             {
454                 val.i_int = PAUSE_S;
455                 var_Set( p_input, "state", val );
456             }
457             else
458             {
459                 playlist_Play( p_playlist );
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                 playlist_Clear( p_playlist );
718             }
719
720             entry_ref ref;
721             for( int i = 0; p_message->FindRef( "refs", i, &ref ) == B_OK; i++ )
722             {
723                 BPath path( &ref );
724
725                 /* TODO: find out if this is a DVD icon */
726
727                 if( p_playlist )
728                 {
729                     playlist_Add( p_playlist, path.Path(), path.Path(),
730                                   PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
731                 }
732             }
733
734             _UpdatePlaylist();
735             break;
736         }
737
738         case OPEN_PREFERENCES:
739         {
740             if( fPreferencesWindow->Lock() )
741             {
742                 if (fPreferencesWindow->IsHidden())
743                     fPreferencesWindow->Show();
744                 else
745                     fPreferencesWindow->Activate();
746                 fPreferencesWindow->Unlock();
747             }
748             break;
749         }
750
751         case OPEN_MESSAGES:
752         {
753             if( fMessagesWindow->Lock() )
754             {
755                 if (fMessagesWindow->IsHidden())
756                     fMessagesWindow->Show();
757                 else
758                     fMessagesWindow->Activate();
759                 fMessagesWindow->Unlock();
760             }
761             break;
762         }
763         case MSG_UPDATE:
764             UpdateInterface();
765             break;
766         default:
767             BWindow::MessageReceived( p_message );
768             break;
769     }
770 }
771
772 /*****************************************************************************
773  * InterfaceWindow::QuitRequested
774  *****************************************************************************/
775 bool InterfaceWindow::QuitRequested()
776 {
777     if( p_playlist )
778     {
779         playlist_Stop( p_playlist );
780     }
781     p_mediaControl->SetStatus(-1, INPUT_RATE_DEFAULT);
782
783      _StoreSettings();
784
785     p_intf->b_die = 1;
786
787     return( true );
788 }
789
790 /*****************************************************************************
791  * InterfaceWindow::UpdateInterface
792  *****************************************************************************/
793 void InterfaceWindow::UpdateInterface()
794 {
795     /* Manage the input part */
796     if( !p_playlist )
797     {
798         p_playlist = (playlist_t *)
799             vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
800     }
801     if( !p_input )
802     {
803         p_input = (input_thread_t *)
804             vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
805     }
806     else if( p_input->b_dead )
807     {
808         vlc_object_release( p_input );
809         p_input = NULL;
810     }
811
812     /* Get ready to update the interface */
813     if( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) != B_OK )
814     {
815         return;
816     }
817
818     if( p_input )
819     {
820         vlc_value_t val;
821         p_mediaControl->SetEnabled( true );
822         bool hasTitles   = !var_Get( p_input, "title", &val );
823         bool hasChapters = !var_Get( p_input, "chapter", &val );
824         p_mediaControl->SetStatus( var_GetInteger( p_input, "state" ),
825                                    var_GetInteger( p_input, "rate" ) );
826         var_Get( p_input, "position", &val );
827         p_mediaControl->SetProgress( val.f_float );
828         _SetMenusEnabled( true, hasChapters, hasTitles );
829         _UpdateSpeedMenu( var_GetInteger( p_input, "rate" ) );
830
831         // enable/disable skip buttons
832 #if 0
833         bool canSkipPrev;
834         bool canSkipNext;
835         p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
836         p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
837 #endif
838
839         audio_volume_t i_volume;
840         aout_VolumeGet( p_intf, &i_volume );
841         p_mediaControl->SetAudioEnabled( true );
842         p_mediaControl->SetMuted( i_volume );
843
844         // update playlist as well
845         if( fPlaylistWindow->LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) == B_OK )
846         {
847             fPlaylistWindow->UpdatePlaylist();
848             fPlaylistWindow->Unlock();
849         }
850     }
851     else
852     {
853         p_mediaControl->SetAudioEnabled( false );
854
855         _SetMenusEnabled( false );
856
857         if( !playlist_IsEmpty( p_playlist ) )
858         {
859             p_mediaControl->SetProgress( 0 );
860
861 #if 0
862             // enable/disable skip buttons
863             bool canSkipPrev;
864             bool canSkipNext;
865             p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
866             p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
867 #endif
868         }
869         else
870         {
871             p_mediaControl->SetEnabled( false );
872         }
873     }
874
875     Unlock();
876     fLastUpdateTime = system_time();
877 }
878
879 /*****************************************************************************
880  * InterfaceWindow::IsStopped
881  *****************************************************************************/
882 bool
883 InterfaceWindow::IsStopped() const
884 {
885     return (system_time() - fLastUpdateTime > INTERFACE_UPDATE_TIMEOUT);
886 }
887
888 /*****************************************************************************
889  * InterfaceWindow::_UpdatePlaylist
890  *****************************************************************************/
891 void
892 InterfaceWindow::_UpdatePlaylist()
893 {
894     if( fPlaylistWindow->Lock() )
895     {
896         fPlaylistWindow->UpdatePlaylist( true );
897         fPlaylistWindow->Unlock();
898     }
899     p_mediaControl->SetEnabled( p_playlist->i_size );
900 }
901
902 /*****************************************************************************
903  * InterfaceWindow::_SetMenusEnabled
904  *****************************************************************************/
905 void
906 InterfaceWindow::_SetMenusEnabled(bool hasFile, bool hasChapters, bool hasTitles)
907 {
908     if (!hasFile)
909     {
910         hasChapters = false;
911         hasTitles = false;
912     }
913     if ( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) == B_OK)
914     {
915         if ( fNextChapterMI->IsEnabled() != hasChapters )
916              fNextChapterMI->SetEnabled( hasChapters );
917         if ( fPrevChapterMI->IsEnabled() != hasChapters )
918              fPrevChapterMI->SetEnabled( hasChapters );
919         if ( fChapterMenu->IsEnabled() != hasChapters )
920              fChapterMenu->SetEnabled( hasChapters );
921         if ( fNextTitleMI->IsEnabled() != hasTitles )
922              fNextTitleMI->SetEnabled( hasTitles );
923         if ( fPrevTitleMI->IsEnabled() != hasTitles )
924              fPrevTitleMI->SetEnabled( hasTitles );
925         if ( fTitleMenu->IsEnabled() != hasTitles )
926              fTitleMenu->SetEnabled( hasTitles );
927         if ( fAudioMenu->IsEnabled() != hasFile )
928              fAudioMenu->SetEnabled( hasFile );
929         if ( fNavigationMenu->IsEnabled() != hasFile )
930              fNavigationMenu->SetEnabled( hasFile );
931         if ( fLanguageMenu->IsEnabled() != hasFile )
932              fLanguageMenu->SetEnabled( hasFile );
933         if ( fSubtitlesMenu->IsEnabled() != hasFile )
934              fSubtitlesMenu->SetEnabled( hasFile );
935         if ( fSpeedMenu->IsEnabled() != hasFile )
936              fSpeedMenu->SetEnabled( hasFile );
937         Unlock();
938     }
939 }
940
941 /*****************************************************************************
942  * InterfaceWindow::_UpdateSpeedMenu
943  *****************************************************************************/
944 void
945 InterfaceWindow::_UpdateSpeedMenu( int rate )
946 {
947     BMenuItem * toMark = NULL;
948
949     switch( rate )
950     {
951         case ( INPUT_RATE_DEFAULT * 8 ):
952             toMark = fHeighthMI;
953             break;
954
955         case ( INPUT_RATE_DEFAULT * 4 ):
956             toMark = fQuarterMI;
957             break;
958
959         case ( INPUT_RATE_DEFAULT * 2 ):
960             toMark = fHalfMI;
961             break;
962
963         case ( INPUT_RATE_DEFAULT ):
964             toMark = fNormalMI;
965             break;
966
967         case ( INPUT_RATE_DEFAULT / 2 ):
968             toMark = fTwiceMI;
969             break;
970
971         case ( INPUT_RATE_DEFAULT / 4 ):
972             toMark = fFourMI;
973             break;
974
975         case ( INPUT_RATE_DEFAULT / 8 ):
976             toMark = fHeightMI;
977             break;
978     }
979
980     if ( toMark && !toMark->IsMarked() )
981     {
982         toMark->SetMarked( true );
983     }
984 }
985
986 /*****************************************************************************
987  * InterfaceWindow::_ShowFilePanel
988  *****************************************************************************/
989 void
990 InterfaceWindow::_ShowFilePanel( uint32 command, const char* windowTitle )
991 {
992     if( !fFilePanel )
993     {
994         fFilePanel = new BFilePanel( B_OPEN_PANEL, NULL, NULL,
995                                      B_FILE_NODE | B_DIRECTORY_NODE );
996         fFilePanel->SetTarget( this );
997     }
998     fFilePanel->Window()->SetTitle( windowTitle );
999     BMessage message( command );
1000     fFilePanel->SetMessage( &message );
1001     if ( !fFilePanel->IsShowing() )
1002     {
1003         fFilePanel->Refresh();
1004         fFilePanel->Show();
1005     }
1006 }
1007
1008 // set_window_pos
1009 void
1010 set_window_pos( BWindow* window, BRect frame )
1011 {
1012     // sanity checks: make sure window is not too big/small
1013     // and that it's not off-screen
1014     float minWidth, maxWidth, minHeight, maxHeight;
1015     window->GetSizeLimits( &minWidth, &maxWidth, &minHeight, &maxHeight );
1016
1017     make_sure_frame_is_within_limits( frame,
1018                                       minWidth, minHeight, maxWidth, maxHeight );
1019     if ( make_sure_frame_is_on_screen( frame ) )
1020     {
1021         window->MoveTo( frame.LeftTop() );
1022         window->ResizeTo( frame.Width(), frame.Height() );
1023     }
1024 }
1025
1026 // set_window_pos
1027 void
1028 launch_window( BWindow* window, bool showing )
1029 {
1030     if ( window->Lock() )
1031     {
1032         if ( showing )
1033         {
1034             if ( window->IsHidden() )
1035                 window->Show();
1036         }
1037         else
1038         {
1039             if ( !window->IsHidden() )
1040                 window->Hide();
1041         }
1042         window->Unlock();
1043     }
1044 }
1045
1046 /*****************************************************************************
1047  * InterfaceWindow::_RestoreSettings
1048  *****************************************************************************/
1049 void
1050 InterfaceWindow::_RestoreSettings()
1051 {
1052     if ( load_settings( fSettings, "interface_settings", "VideoLAN Client" ) == B_OK )
1053     {
1054         BRect frame;
1055         if ( fSettings->FindRect( "main frame", &frame ) == B_OK )
1056             set_window_pos( this, frame );
1057         if (fSettings->FindRect( "playlist frame", &frame ) == B_OK )
1058             set_window_pos( fPlaylistWindow, frame );
1059         if (fSettings->FindRect( "messages frame", &frame ) == B_OK )
1060             set_window_pos( fMessagesWindow, frame );
1061         if (fSettings->FindRect( "settings frame", &frame ) == B_OK )
1062         {
1063             /* FIXME: Preferences resizing doesn't work correctly yet */
1064             frame.right = frame.left + fPreferencesWindow->Frame().Width();
1065             frame.bottom = frame.top + fPreferencesWindow->Frame().Height();
1066             set_window_pos( fPreferencesWindow, frame );
1067         }
1068
1069         bool showing;
1070         if ( fSettings->FindBool( "playlist showing", &showing ) == B_OK )
1071             launch_window( fPlaylistWindow, showing );
1072         if ( fSettings->FindBool( "messages showing", &showing ) == B_OK )
1073             launch_window( fMessagesWindow, showing );
1074         if ( fSettings->FindBool( "settings showing", &showing ) == B_OK )
1075             launch_window( fPreferencesWindow, showing );
1076
1077         uint32 displayMode;
1078         if ( fSettings->FindInt32( "playlist display mode", (int32*)&displayMode ) == B_OK )
1079             fPlaylistWindow->SetDisplayMode( displayMode );
1080     }
1081 }
1082
1083 /*****************************************************************************
1084  * InterfaceWindow::_StoreSettings
1085  *****************************************************************************/
1086 void
1087 InterfaceWindow::_StoreSettings()
1088 {
1089     /* Save the volume */
1090     config_PutInt( p_intf, "volume", p_mediaControl->GetVolume() );
1091     config_SaveConfigFile( p_intf, "main" );
1092
1093     /* Save the windows positions */
1094     if ( fSettings->ReplaceRect( "main frame", Frame() ) != B_OK )
1095         fSettings->AddRect( "main frame", Frame() );
1096     if ( fPlaylistWindow->Lock() )
1097     {
1098         if (fSettings->ReplaceRect( "playlist frame", fPlaylistWindow->Frame() ) != B_OK)
1099             fSettings->AddRect( "playlist frame", fPlaylistWindow->Frame() );
1100         if (fSettings->ReplaceBool( "playlist showing", !fPlaylistWindow->IsHidden() ) != B_OK)
1101             fSettings->AddBool( "playlist showing", !fPlaylistWindow->IsHidden() );
1102         fPlaylistWindow->Unlock();
1103     }
1104     if ( fMessagesWindow->Lock() )
1105     {
1106         if (fSettings->ReplaceRect( "messages frame", fMessagesWindow->Frame() ) != B_OK)
1107             fSettings->AddRect( "messages frame", fMessagesWindow->Frame() );
1108         if (fSettings->ReplaceBool( "messages showing", !fMessagesWindow->IsHidden() ) != B_OK)
1109             fSettings->AddBool( "messages showing", !fMessagesWindow->IsHidden() );
1110         fMessagesWindow->Unlock();
1111     }
1112     if ( fPreferencesWindow->Lock() )
1113     {
1114         if (fSettings->ReplaceRect( "settings frame", fPreferencesWindow->Frame() ) != B_OK)
1115             fSettings->AddRect( "settings frame", fPreferencesWindow->Frame() );
1116         if (fSettings->ReplaceBool( "settings showing", !fPreferencesWindow->IsHidden() ) != B_OK)
1117             fSettings->AddBool( "settings showing", !fPreferencesWindow->IsHidden() );
1118         fPreferencesWindow->Unlock();
1119     }
1120     uint32 displayMode = fPlaylistWindow->DisplayMode();
1121     if (fSettings->ReplaceInt32( "playlist display mode", displayMode ) != B_OK )
1122         fSettings->AddInt32( "playlist display mode", displayMode );
1123
1124     save_settings( fSettings, "interface_settings", "VideoLAN Client" );
1125 }
1126
1127
1128 /*****************************************************************************
1129  * CDMenu::CDMenu
1130  *****************************************************************************/
1131 CDMenu::CDMenu(const char *name)
1132       : BMenu(name)
1133 {
1134 }
1135
1136 /*****************************************************************************
1137  * CDMenu::~CDMenu
1138  *****************************************************************************/
1139 CDMenu::~CDMenu()
1140 {
1141 }
1142
1143 /*****************************************************************************
1144  * CDMenu::AttachedToWindow
1145  *****************************************************************************/
1146 void CDMenu::AttachedToWindow(void)
1147 {
1148     // remove all items
1149     while ( BMenuItem* item = RemoveItem( 0L ) )
1150         delete item;
1151     GetCD( "/dev/disk" );
1152     BMenu::AttachedToWindow();
1153 }
1154
1155 /*****************************************************************************
1156  * CDMenu::GetCD
1157  *****************************************************************************/
1158 int CDMenu::GetCD( const char *directory )
1159 {
1160     BVolumeRoster volRoster;
1161     BVolume vol;
1162     BDirectory dir;
1163     status_t status = volRoster.GetNextVolume( &vol );
1164     while ( status ==  B_NO_ERROR )
1165     {
1166         BString deviceName;
1167         BString volumeName;
1168         bool isCDROM;
1169         if ( get_volume_info( vol, volumeName, isCDROM, deviceName )
1170              && isCDROM )
1171         {
1172             BMessage* msg = new BMessage( OPEN_DVD );
1173             msg->AddString( "device", deviceName.String() );
1174             BMenuItem* item = new BMenuItem( volumeName.String(), msg );
1175             AddItem( item );
1176         }
1177          vol.Unset();
1178         status = volRoster.GetNextVolume( &vol );
1179     }
1180     return 0;
1181 }
1182
1183 /*****************************************************************************
1184  * LanguageMenu::LanguageMenu
1185  *****************************************************************************/
1186 LanguageMenu::LanguageMenu( intf_thread_t * _p_intf, const char * psz_name,
1187                             char * _psz_variable )
1188     : BMenu( psz_name )
1189 {
1190     p_intf       = _p_intf;
1191     psz_variable = strdup( _psz_variable );
1192 }
1193
1194 /*****************************************************************************
1195  * LanguageMenu::~LanguageMenu
1196  *****************************************************************************/
1197 LanguageMenu::~LanguageMenu()
1198 {
1199     free( psz_variable );
1200 }
1201
1202 /*****************************************************************************
1203  * LanguageMenu::AttachedToWindow
1204  *****************************************************************************/
1205 void LanguageMenu::AttachedToWindow()
1206 {
1207     BMenuItem * item;
1208
1209     // remove all items
1210     while( ( item = RemoveItem( 0L ) ) )
1211     {
1212         delete item;
1213     }
1214
1215     SetRadioMode( true );
1216
1217     input_thread_t * p_input = (input_thread_t *)
1218             vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1219     if( !p_input )
1220     {
1221         return;
1222     }
1223
1224     vlc_value_t val_list, text_list;
1225     BMessage * message;
1226     int i_current;
1227
1228     i_current = var_GetInteger( p_input, psz_variable );
1229     var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list );
1230     for( int i = 0; i < val_list.p_list->i_count; i++ )
1231     {
1232         message = new BMessage( SELECT_CHANNEL );
1233         message->AddInt32( psz_variable, val_list.p_list->p_values[i].i_int );
1234         item = new BMenuItem( text_list.p_list->p_values[i].psz_string, message );
1235         if( val_list.p_list->p_values[i].i_int == i_current )
1236         {
1237             item->SetMarked( true );
1238         }
1239         AddItem( item );
1240     }
1241     var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list );
1242
1243     vlc_object_release( p_input );
1244
1245     BMenu::AttachedToWindow();
1246 }
1247
1248 /*****************************************************************************
1249  * TitleMenu::TitleMenu
1250  *****************************************************************************/
1251 TitleMenu::TitleMenu( const char *name, intf_thread_t  *p_interface )
1252     : BMenu(name),
1253     p_intf( p_interface )
1254 {
1255 }
1256
1257 /*****************************************************************************
1258  * TitleMenu::~TitleMenu
1259  *****************************************************************************/
1260 TitleMenu::~TitleMenu()
1261 {
1262 }
1263
1264 /*****************************************************************************
1265  * TitleMenu::AttachedToWindow
1266  *****************************************************************************/
1267 void TitleMenu::AttachedToWindow()
1268 {
1269     BMenuItem * item;
1270     while( ( item = RemoveItem( 0L ) ) )
1271     {
1272         delete item;
1273     }
1274
1275     input_thread_t * p_input;
1276     p_input = (input_thread_t *)
1277         vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1278     if( !p_input )
1279     {
1280         return;
1281     }
1282
1283     vlc_value_t val;
1284     BMessage * message;
1285     if( !var_Get( p_input, "title", &val ) )
1286     {
1287         vlc_value_t val_list, text_list;
1288         var_Change( p_input, "title", VLC_VAR_GETCHOICES,
1289                     &val_list, &text_list );
1290
1291         for( int i = 0; i < val_list.p_list->i_count; i++ )
1292         {
1293             message = new BMessage( TOGGLE_TITLE );
1294             message->AddInt32( "index", val_list.p_list->p_values[i].i_int );
1295             item = new BMenuItem( text_list.p_list->p_values[i].psz_string,
1296                                   message );
1297             if( val_list.p_list->p_values[i].i_int == val.i_int )
1298             {
1299                 item->SetMarked( true );
1300             }
1301             AddItem( item );
1302         }
1303
1304         var_Change( p_input, "title", VLC_VAR_FREELIST,
1305                     &val_list, &text_list );
1306     }
1307     vlc_object_release( p_input );
1308     BMenu::AttachedToWindow();
1309 }
1310
1311
1312 /*****************************************************************************
1313  * ChapterMenu::ChapterMenu
1314  *****************************************************************************/
1315 ChapterMenu::ChapterMenu( const char *name, intf_thread_t  *p_interface )
1316     : BMenu(name),
1317     p_intf( p_interface )
1318 {
1319 }
1320
1321 /*****************************************************************************
1322  * ChapterMenu::~ChapterMenu
1323  *****************************************************************************/
1324 ChapterMenu::~ChapterMenu()
1325 {
1326 }
1327
1328 /*****************************************************************************
1329  * ChapterMenu::AttachedToWindow
1330  *****************************************************************************/
1331 void ChapterMenu::AttachedToWindow()
1332 {
1333     BMenuItem * item;
1334     while( ( item = RemoveItem( 0L ) ) )
1335     {
1336         delete item;
1337     }
1338
1339     input_thread_t * p_input;
1340     p_input = (input_thread_t *)
1341         vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1342     if( !p_input )
1343     {
1344         return;
1345     }
1346
1347     vlc_value_t val;
1348     BMessage * message;
1349     if( !var_Get( p_input, "chapter", &val ) )
1350     {
1351         vlc_value_t val_list, text_list;
1352         var_Change( p_input, "chapter", VLC_VAR_GETCHOICES,
1353                     &val_list, &text_list );
1354
1355         for( int i = 0; i < val_list.p_list->i_count; i++ )
1356         {
1357             message = new BMessage( TOGGLE_CHAPTER );
1358             message->AddInt32( "index", val_list.p_list->p_values[i].i_int );
1359             item = new BMenuItem( text_list.p_list->p_values[i].psz_string,
1360                                   message );
1361             if( val_list.p_list->p_values[i].i_int == val.i_int )
1362             {
1363                 item->SetMarked( true );
1364             }
1365             AddItem( item );
1366         }
1367
1368         var_Change( p_input, "chapter", VLC_VAR_FREELIST,
1369                     &val_list, &text_list );
1370     }
1371     vlc_object_release( p_input );
1372     BMenu::AttachedToWindow();
1373 }
1374
1375
1376 /*****************************************************************************
1377  * load_settings
1378  *****************************************************************************/
1379 status_t
1380 load_settings( BMessage* message, const char* fileName, const char* folder )
1381 {
1382     status_t ret = B_BAD_VALUE;
1383     if ( message )
1384     {
1385         BPath path;
1386         if ( ( ret = find_directory( B_USER_SETTINGS_DIRECTORY, &path ) ) == B_OK )
1387         {
1388             // passing folder is optional
1389             if ( folder )
1390                 ret = path.Append( folder );
1391             if ( ret == B_OK && ( ret = path.Append( fileName ) ) == B_OK )
1392             {
1393                 BFile file( path.Path(), B_READ_ONLY );
1394                 if ( ( ret = file.InitCheck() ) == B_OK )
1395                 {
1396                     ret = message->Unflatten( &file );
1397                     file.Unset();
1398                 }
1399             }
1400         }
1401     }
1402     return ret;
1403 }
1404
1405 /*****************************************************************************
1406  * save_settings
1407  *****************************************************************************/
1408 status_t
1409 save_settings( BMessage* message, const char* fileName, const char* folder )
1410 {
1411     status_t ret = B_BAD_VALUE;
1412     if ( message )
1413     {
1414         BPath path;
1415         if ( ( ret = find_directory( B_USER_SETTINGS_DIRECTORY, &path ) ) == B_OK )
1416         {
1417             // passing folder is optional
1418             if ( folder && ( ret = path.Append( folder ) ) == B_OK )
1419                 ret = create_directory( path.Path(), 0777 );
1420             if ( ret == B_OK && ( ret = path.Append( fileName ) ) == B_OK )
1421             {
1422                 BFile file( path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE );
1423                 if ( ( ret = file.InitCheck() ) == B_OK )
1424                 {
1425                     ret = message->Flatten( &file );
1426                     file.Unset();
1427                 }
1428             }
1429         }
1430     }
1431     return ret;
1432 }