1 /*****************************************************************************
2 * intf_beos.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: intf_beos.cpp,v 1.28 2001/05/07 04:42:42 sam Exp $
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>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 *****************************************************************************/
27 #define MODULE_NAME beos
28 #include "modules_inner.h"
30 /*****************************************************************************
32 *****************************************************************************/
36 #include <stdlib.h> /* malloc(), free() */
38 #include <kernel/OS.h>
39 #include <storage/Path.h>
45 #include <StatusBar.h>
46 #include <Application.h>
50 #include <DirectWindow.h>
55 #include <FilePanel.h>
59 #include <Directory.h>
62 #include <StorageDefs.h>
64 #include <scsiprobe_driver.h>
75 #include "stream_control.h"
76 #include "input_ext-intf.h"
78 #include "interface.h"
79 #include "intf_playlist.h"
81 #include "audio_output.h"
87 #include "InterfaceWindow.h"
89 #include "TransportButton.h"
91 /*****************************************************************************
92 * intf_sys_t: description and status of FB interface
93 *****************************************************************************/
94 typedef struct intf_sys_s
96 InterfaceWindow * p_window;
100 /*****************************************************************************
102 *****************************************************************************/
104 InterfaceWindow::InterfaceWindow( BRect frame, const char *name,
105 intf_thread_t *p_interface )
106 : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
107 B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK
108 | B_ASYNCHRONOUS_CONTROLS )
111 p_intf = p_interface;
116 SetName( "interface" );
117 SetTitle(VOUT_TITLE " (BeOS interface)");
118 BRect rect(0, 0, 0, 0);
121 menu_bar = new BMenuBar(rect, "main menu");
122 AddChild( menu_bar );
130 menu_bar->AddItem( mFile = new BMenu( "File" ) );
131 menu_bar->ResizeToPreferred();
132 mFile->AddItem( mItem = new BMenuItem( "Open File" B_UTF8_ELLIPSIS,
133 new BMessage(OPEN_FILE), 'O') );
134 cd_menu = new CDMenu( "Open Disc" );
135 mFile->AddItem( cd_menu );
136 mFile->AddSeparatorItem();
137 mFile->AddItem( mItem = new BMenuItem( "About" B_UTF8_ELLIPSIS,
138 new BMessage(B_ABOUT_REQUESTED), 'A') );
139 mItem->SetTarget( be_app );
140 mFile->AddItem(mItem = new BMenuItem( "Quit",
141 new BMessage(B_QUIT_REQUESTED), 'Q') );
143 menu_bar->AddItem ( mAudio = new BMenu( "Audio" ) );
144 menu_bar->ResizeToPreferred();
145 mAudio->AddItem( new LanguageMenu( "Language", AUDIO_ES, p_intf ) );
146 mAudio->AddItem( new LanguageMenu( "Subtitles", SPU_ES, p_intf ) );
150 rect.top += menu_bar->Bounds().IntegerHeight() + 1;
153 p_view = new BBox( rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW, B_PLAIN_BORDER );
154 p_view->SetViewColor( ui_color(B_PANEL_BACKGROUND_COLOR) );
158 ButtonRect.SetLeftTop(BPoint(xStart, yStart));
159 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSkipButtonSize);
160 xStart += kRewindBitmapWidth;
161 TransportButton* p_slow = new TransportButton(ButtonRect, B_EMPTY_STRING,
163 kPressedSkipBackBitmapBits,
164 kDisabledSkipBackBitmapBits,
165 new BMessage(SLOWER_PLAY));
166 p_view->AddChild( p_slow );
169 ButtonRect.SetLeftTop(BPoint(xStart, yStart));
170 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kPlayButtonSize);
171 xStart += kPlayPauseBitmapWidth + 1.0;
172 PlayPauseButton* p_play = new PlayPauseButton(ButtonRect, B_EMPTY_STRING,
173 kPlayButtonBitmapBits,
174 kPressedPlayButtonBitmapBits,
175 kDisabledPlayButtonBitmapBits,
176 kPlayingPlayButtonBitmapBits,
177 kPressedPlayingPlayButtonBitmapBits,
178 kPausedPlayButtonBitmapBits,
179 kPressedPausedPlayButtonBitmapBits,
180 new BMessage(START_PLAYBACK));
182 p_view->AddChild( p_play );
183 p_play->SetPlaying();
186 ButtonRect.SetLeftTop(BPoint(xStart, yStart));
187 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSkipButtonSize);
188 xStart += kRewindBitmapWidth;
189 TransportButton* p_fast = new TransportButton(ButtonRect, B_EMPTY_STRING,
190 kSkipForwardBitmapBits,
191 kPressedSkipForwardBitmapBits,
192 kDisabledSkipForwardBitmapBits,
193 new BMessage(FASTER_PLAY));
194 p_view->AddChild( p_fast );
197 ButtonRect.SetLeftTop(BPoint(xStart, yStart));
198 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kStopButtonSize);
199 xStart += kStopBitmapWidth;
200 TransportButton* p_stop = new TransportButton(ButtonRect, B_EMPTY_STRING,
201 kStopButtonBitmapBits,
202 kPressedStopButtonBitmapBits,
203 kDisabledStopButtonBitmapBits,
204 new BMessage(STOP_PLAYBACK));
205 p_view->AddChild( p_stop );
207 ButtonRect.SetLeftTop(BPoint(xStart + 5, yStart + 6));
208 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSpeakerButtonSize);
209 xStart += kSpeakerIconBitmapWidth;
211 TransportButton* p_mute = new TransportButton(ButtonRect, B_EMPTY_STRING,
213 kPressedSpeakerIconBits,
215 new BMessage(VOLUME_MUTE));
217 p_view->AddChild( p_mute );
220 rgb_color fill_color = {0,255,0};
221 p_seek = new SeekSlider(BRect(5,2,255,15), this, 0, 100,
224 p_seek->UseFillColor(true, &fill_color);
225 p_view->AddChild( p_seek );
228 p_vol = new MediaSlider(BRect(xStart,20,255,30), new BMessage(VOLUME_CHG),
230 p_vol->SetValue(VOLUME_DEFAULT);
231 p_vol->UseFillColor(true, &fill_color);
232 p_view->AddChild( p_vol );
234 /* Set size and Show */
236 ResizeTo(260,50 + menu_bar->Bounds().IntegerHeight()+1);
240 InterfaceWindow::~InterfaceWindow()
244 /*****************************************************************************
245 * InterfaceWindow::MessageReceived
246 *****************************************************************************/
247 void InterfaceWindow::MessageReceived( BMessage * p_message )
249 int vol_val = p_vol->Value(); // remember the current volume
250 static int playback_status; // remember playback state
256 switch( p_message->what )
258 // case B_ABOUT_REQUESTED:
259 // alert = new BAlert(VOUT_TITLE, "BeOS " VOUT_TITLE "\n\n<www.videolan.org>", "Ok");
269 file_panel = new BFilePanel();
270 file_panel->SetTarget( this );
275 const char **ppsz_device;
276 char psz_method[ B_FILE_NAME_LENGTH + 4 ];
278 if( p_message->FindString("device", ppsz_device) != B_ERROR )
280 snprintf( psz_method, B_FILE_NAME_LENGTH + 4,
281 "dvd:%s", *ppsz_device );
282 psz_method[ B_FILE_NAME_LENGTH + 4 - 1 ] = '\0';
284 intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, psz_method );
289 // this currently stops playback not nicely
290 if( p_intf->p_input != NULL )
292 // silence the sound, otherwise very horrible
293 vlc_mutex_lock( &p_aout_bank->lock );
294 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
296 p_aout_bank->pp_aout[i_index]->i_savedvolume = p_aout_bank->pp_aout[i_index]->i_volume;
297 p_aout_bank->pp_aout[i_index]->i_volume = 0;
299 vlc_mutex_unlock( &p_aout_bank->lock );
302 input_SetStatus( p_intf->p_input, INPUT_STATUS_END );
307 // starts playing in normal mode
308 // if (p_intf->p_input != NULL )
310 // if (p_main->p_aout != NULL)
312 // p_main->p_aout->i_vol = vol_val;
315 // input_SetStatus(p_intf->p_input, INPUT_STATUS_PLAY);
316 // playback_status = PLAYING;
321 // pause the playback
322 if( p_intf->p_input != NULL )
324 // mute the volume if currently playing
325 if( playback_status == PLAYING )
327 vlc_mutex_lock( &p_aout_bank->lock );
328 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
330 p_aout_bank->pp_aout[i_index]->i_savedvolume =
331 p_aout_bank->pp_aout[i_index]->i_volume;
332 p_aout_bank->pp_aout[i_index]->i_volume = 0;
334 vlc_mutex_unlock( &p_aout_bank->lock );
335 playback_status = PAUSED;
338 // restore the volume
340 vlc_mutex_lock( &p_aout_bank->lock );
341 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
343 p_aout_bank->pp_aout[i_index]->i_volume =
344 p_aout_bank->pp_aout[i_index]->i_savedvolume;
345 p_aout_bank->pp_aout[i_index]->i_savedvolume = 0;
347 vlc_mutex_unlock( &p_aout_bank->lock );
348 playback_status = PLAYING;
352 input_SetStatus( p_intf->p_input, INPUT_STATUS_PAUSE );
357 // cycle the fast playback modes
358 if( p_intf->p_input != NULL )
360 vlc_mutex_lock( &p_aout_bank->lock );
361 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
363 p_aout_bank->pp_aout[i_index]->i_savedvolume =
364 p_aout_bank->pp_aout[i_index]->i_volume;
365 p_aout_bank->pp_aout[i_index]->i_volume = 0;
367 vlc_mutex_unlock( &p_aout_bank->lock );
370 input_SetStatus( p_intf->p_input, INPUT_STATUS_FASTER );
375 // cycle the slow playback modes
376 if (p_intf->p_input != NULL )
378 vlc_mutex_lock( &p_aout_bank->lock );
379 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
381 p_aout_bank->pp_aout[i_index]->i_savedvolume =
382 p_aout_bank->pp_aout[i_index]->i_volume;
383 p_aout_bank->pp_aout[i_index]->i_volume = 0;
385 vlc_mutex_unlock( &p_aout_bank->lock );
388 input_SetStatus( p_intf->p_input, INPUT_STATUS_SLOWER );
393 // handled by semaphores;
398 vlc_mutex_lock( &p_aout_bank->lock );
399 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
401 if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
403 p_aout_bank->pp_aout[i_index]->i_savedvolume = vol_val;
407 p_aout_bank->pp_aout[i_index]->i_volume = vol_val;
410 vlc_mutex_unlock( &p_aout_bank->lock );
415 vlc_mutex_lock( &p_aout_bank->lock );
416 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
418 if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
420 p_aout_bank->pp_aout[i_index]->i_volume =
421 p_aout_bank->pp_aout[i_index]->i_savedvolume;
422 p_aout_bank->pp_aout[i_index]->i_savedvolume = 0;
426 p_aout_bank->pp_aout[i_index]->i_savedvolume =
427 p_aout_bank->pp_aout[i_index]->i_volume;
428 p_aout_bank->pp_aout[i_index]->i_volume = 0;
431 vlc_mutex_unlock( &p_aout_bank->lock );
436 int32 i = p_message->FindInt32( "channel" );
437 input_ChangeES( p_intf->p_input,
438 p_intf->p_input->stream.pp_es[i], 1 );
442 case SELECT_SUBTITLE:
444 int32 i = p_message->FindInt32( "subtitle" );
445 input_ChangeES( p_intf->p_input,
446 p_intf->p_input->stream.pp_es[i], 2 );
450 case B_REFS_RECEIVED:
454 if( p_message->FindRef( "refs", &ref ) == B_OK )
457 intf_PlaylistAdd( p_main->p_playlist,
458 PLAYLIST_END, path.Path() );
465 BWindow::MessageReceived( p_message );
470 /*****************************************************************************
471 * InterfaceWindow::QuitRequested
472 *****************************************************************************/
473 bool InterfaceWindow::QuitRequested()
480 /*****************************************************************************
482 *****************************************************************************/
483 CDMenu::CDMenu(const char *name)
488 /*****************************************************************************
490 *****************************************************************************/
495 /*****************************************************************************
496 * CDMenu::AttachedToWindow
497 *****************************************************************************/
498 void CDMenu::AttachedToWindow(void)
500 while (RemoveItem((long int)0) != NULL); // remove all items
502 BMenu::AttachedToWindow();
505 /*****************************************************************************
507 *****************************************************************************/
508 int CDMenu::GetCD( const char *directory )
512 dir.SetTo( directory );
514 if( dir.InitCheck() != B_NO_ERROR )
522 while( dir.GetNextEntry(&entry) >= 0 )
528 if( entry.GetPath(&path) != B_NO_ERROR )
535 if( entry.GetRef(&e) != B_NO_ERROR )
540 if( entry.IsDirectory() )
542 if( strcmp(e.name, "floppy") == 0 )
544 continue; // ignore floppy (it is not silent)
547 i_dev = GetCD( name );
559 if( strcmp(e.name, "raw") != 0 )
561 continue; // ignore partitions
564 i_dev = open( name, O_RDONLY );
571 if( ioctl(i_dev, B_GET_GEOMETRY, &g, sizeof(g)) >= 0 )
573 if( g.device_type == B_CD ) //ensure the drive is a CD-ROM
575 if( ioctl(i_dev, B_GET_MEDIA_STATUS, &m, sizeof(m)) >= 0 )
577 if( m == B_NO_ERROR ) //ensure media is present
580 msg = new BMessage( OPEN_DVD );
581 msg->AddString( "device", name );
582 BMenuItem *menu_item;
583 menu_item = new BMenuItem( name, msg );
584 AddItem( menu_item );
596 /*****************************************************************************
597 * LanguageMenu::LanguageMenu
598 *****************************************************************************/
599 LanguageMenu::LanguageMenu(const char *name, int menu_kind, intf_thread_t *p_interface)
603 p_intf = p_interface;
606 /*****************************************************************************
607 * LanguageMenu::~LanguageMenu
608 *****************************************************************************/
609 LanguageMenu::~LanguageMenu()
613 /*****************************************************************************
614 * LanguageMenu::AttachedToWindow
615 *****************************************************************************/
616 void LanguageMenu::AttachedToWindow(void)
618 while( RemoveItem((long int)0) != NULL )
620 ; // remove all items
625 BMenu::AttachedToWindow();
628 /*****************************************************************************
629 * LanguageMenu::GetChannels
630 *****************************************************************************/
631 int LanguageMenu::GetChannels()
637 es_descriptor_t *p_es;
639 if( p_intf->p_input == NULL )
644 for( i = 0; i < p_intf->p_input->stream.i_selected_es_number; i++ )
646 if( kind == p_intf->p_input->stream.pp_selected_es[i]->i_cat )
648 p_es = p_intf->p_input->stream.pp_selected_es[i];
652 for( i = 0; i < p_intf->p_input->stream.i_es_number; i++ )
654 if( kind == p_intf->p_input->stream.pp_es[i]->i_cat )
656 psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
658 if( kind == AUDIO_ES ) //audio
660 msg = new BMessage(SELECT_CHANNEL);
661 msg->AddInt32("channel", i);
665 msg = new BMessage(SELECT_SUBTITLE);
666 msg->AddInt32("subtitle", i);
668 BMenuItem *menu_item;
669 menu_item = new BMenuItem(psz_name, msg);
671 b_active = (p_es == p_intf->p_input->stream.pp_es[i]);
672 menu_item->SetMarked(b_active);
677 /*****************************************************************************
679 *****************************************************************************/
680 MediaSlider::MediaSlider( BRect frame, BMessage *p_message,
681 int32 i_min, int32 i_max )
682 :BSlider(frame, NULL, NULL, p_message, i_min, i_max )
687 MediaSlider::~MediaSlider()
692 void MediaSlider::DrawThumb(void)
697 rgb_color black = {0,0,0};
703 v->SetHighColor(black);
707 v->SetHighColor(tint_color(black, B_LIGHTEN_2_TINT));
710 r.InsetBy(r.IntegerWidth()/4, r.IntegerHeight()/(4 * r.IntegerWidth() / r.IntegerHeight()));
715 v->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
719 v->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT));
726 /*****************************************************************************
728 *****************************************************************************/
729 SeekSlider::SeekSlider( BRect frame, InterfaceWindow *p_owner, int32 i_min,
730 int32 i_max, thumb_style thumbType = B_TRIANGLE_THUMB )
731 :MediaSlider( frame, NULL, i_min, i_max )
737 SeekSlider::~SeekSlider()
741 /*****************************************************************************
742 * SeekSlider::MouseDown
743 *****************************************************************************/
744 void SeekSlider::MouseDown(BPoint where)
746 BSlider::MouseDown(where);
747 fOwner->fScrubSem = create_sem(1, "Vlc::fScrubSem");
751 /*****************************************************************************
752 * SeekSlider::MouseUp
753 *****************************************************************************/
754 void SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage *message)
756 BSlider::MouseMoved(where, code, message);
759 release_sem(fOwner->fScrubSem);
762 /*****************************************************************************
763 * SeekSlider::MouseUp
764 *****************************************************************************/
765 void SeekSlider::MouseUp(BPoint where)
767 BSlider::MouseUp(where);
768 delete_sem(fOwner->fScrubSem);
769 fOwner->fScrubSem = B_ERROR;
777 /*****************************************************************************
779 *****************************************************************************/
780 static int intf_Probe ( probedata_t *p_data );
781 static int intf_Open ( intf_thread_t *p_intf );
782 static void intf_Close ( intf_thread_t *p_intf );
783 static void intf_Run ( intf_thread_t *p_intf );
785 /*****************************************************************************
786 * Functions exported as capabilities. They are declared as static so that
787 * we don't pollute the namespace too much.
788 *****************************************************************************/
789 void _M( intf_getfunctions )( function_list_t * p_function_list )
791 p_function_list->pf_probe = intf_Probe;
792 p_function_list->functions.intf.pf_open = intf_Open;
793 p_function_list->functions.intf.pf_close = intf_Close;
794 p_function_list->functions.intf.pf_run = intf_Run;
797 /*****************************************************************************
798 * intf_Probe: probe the interface and return a score
799 *****************************************************************************
800 * This function tries to initialize Gnome and returns a score to the
801 * plugin manager so that it can select the best plugin.
802 *****************************************************************************/
803 static int intf_Probe( probedata_t *p_data )
805 if( TestMethod( INTF_METHOD_VAR, "beos" ) )
813 /*****************************************************************************
814 * intf_Open: initialize interface
815 *****************************************************************************/
816 static int intf_Open( intf_thread_t *p_intf )
819 screen = new BScreen();
820 BRect rect = screen->Frame();
821 rect.top = rect.bottom-100;
824 rect.right = rect.left + 350;
827 /* Allocate instance and initialize some members */
828 p_intf->p_sys = (intf_sys_t*) malloc( sizeof( intf_sys_t ) );
829 if( p_intf->p_sys == NULL )
831 intf_ErrMsg("error: %s", strerror(ENOMEM));
834 p_intf->p_sys->i_key = -1;
836 /* Create the interface window */
837 p_intf->p_sys->p_window =
838 new InterfaceWindow( rect,
839 VOUT_TITLE " (BeOS interface)", p_intf );
840 if( p_intf->p_sys->p_window == 0 )
842 free( p_intf->p_sys );
843 intf_ErrMsg( "error: cannot allocate memory for InterfaceWindow" );
850 /*****************************************************************************
851 * intf_Close: destroy dummy interface
852 *****************************************************************************/
853 static void intf_Close( intf_thread_t *p_intf )
855 /* Destroy the interface window */
856 p_intf->p_sys->p_window->Lock();
857 p_intf->p_sys->p_window->Quit();
859 /* Destroy structure */
860 free( p_intf->p_sys );
864 /*****************************************************************************
865 * intf_Run: event loop
866 *****************************************************************************/
867 static void intf_Run( intf_thread_t *p_intf )
870 bool seekNeeded = false;
872 while( !p_intf->b_die )
874 /* Manage core vlc functions through the callback */
875 p_intf->pf_manage( p_intf );
877 /* Manage the slider */
878 if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL)
880 if( acquire_sem(p_intf->p_sys->p_window->fScrubSem) == B_OK )
887 uint32 seekTo = (p_intf->p_sys->p_window->p_seek->Value() *
888 p_intf->p_input->stream.p_selected_area->i_size) / 100;
889 input_Seek( p_intf->p_input, seekTo );
892 else if( p_intf->p_sys->p_window->Lock() )
894 progress = (100. * p_intf->p_input->stream.p_selected_area->i_tell) /
895 p_intf->p_input->stream.p_selected_area->i_size;
896 p_intf->p_sys->p_window->p_seek->SetValue(progress);
897 p_intf->p_sys->p_window->Unlock();
902 msleep( INTF_IDLE_SLEEP );