1 /*****************************************************************************
2 * intf_beos.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: intf_beos.cpp,v 1.26 2001/04/29 17:03:20 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 , intf_thread_t *p_interface )
105 : BWindow(frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
106 B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK |B_ASYNCHRONOUS_CONTROLS)
109 p_intf = p_interface;
114 SetName( "interface" );
115 SetTitle(VOUT_TITLE " (BeOS interface)");
116 BRect rect(0, 0, 0, 0);
119 menu_bar = new BMenuBar(rect, "main menu");
120 AddChild( menu_bar );
128 menu_bar->AddItem( mFile = new BMenu("File") );
129 menu_bar->ResizeToPreferred();
130 mFile->AddItem(mItem = new BMenuItem("Open File" B_UTF8_ELLIPSIS, new BMessage(OPEN_FILE), 'O'));
131 cd_menu = new CDMenu("Open Disc");
132 mFile->AddItem(cd_menu);
133 mFile->AddSeparatorItem();
134 mFile->AddItem(mItem = new BMenuItem("About" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED), 'A'));
135 mItem->SetTarget( be_app );
136 mFile->AddItem(mItem = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'));
138 menu_bar->AddItem ( mAudio = new BMenu("Audio") );
139 menu_bar->ResizeToPreferred();
140 mAudio->AddItem( new LanguageMenu("Language", AUDIO_ES, p_intf) );
141 mAudio->AddItem( new LanguageMenu("Subtitles", SPU_ES, p_intf) );
145 rect.top += menu_bar->Bounds().IntegerHeight()+1;
148 p_view = new BBox( rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW, B_PLAIN_BORDER );
149 p_view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
153 ButtonRect.SetLeftTop(BPoint(xStart, yStart));
154 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSkipButtonSize);
155 xStart += kRewindBitmapWidth;
156 TransportButton* p_slow = new TransportButton(ButtonRect, B_EMPTY_STRING,
158 kPressedSkipBackBitmapBits,
159 kDisabledSkipBackBitmapBits,
160 new BMessage(SLOWER_PLAY));
161 p_view->AddChild( p_slow );
164 ButtonRect.SetLeftTop(BPoint(xStart, yStart));
165 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kPlayButtonSize);
166 xStart += kPlayPauseBitmapWidth + 1.0;
167 PlayPauseButton* p_play = new PlayPauseButton(ButtonRect, B_EMPTY_STRING,
168 kPlayButtonBitmapBits,
169 kPressedPlayButtonBitmapBits,
170 kDisabledPlayButtonBitmapBits,
171 kPlayingPlayButtonBitmapBits,
172 kPressedPlayingPlayButtonBitmapBits,
173 kPausedPlayButtonBitmapBits,
174 kPressedPausedPlayButtonBitmapBits,
175 new BMessage(START_PLAYBACK));
177 p_view->AddChild( p_play );
178 p_play->SetPlaying();
181 ButtonRect.SetLeftTop(BPoint(xStart, yStart));
182 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSkipButtonSize);
183 xStart += kRewindBitmapWidth;
184 TransportButton* p_fast = new TransportButton(ButtonRect, B_EMPTY_STRING,
185 kSkipForwardBitmapBits,
186 kPressedSkipForwardBitmapBits,
187 kDisabledSkipForwardBitmapBits,
188 new BMessage(FASTER_PLAY));
189 p_view->AddChild( p_fast );
192 ButtonRect.SetLeftTop(BPoint(xStart, yStart));
193 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kStopButtonSize);
194 xStart += kStopBitmapWidth;
195 TransportButton* p_stop = new TransportButton(ButtonRect, B_EMPTY_STRING,
196 kStopButtonBitmapBits,
197 kPressedStopButtonBitmapBits,
198 kDisabledStopButtonBitmapBits,
199 new BMessage(STOP_PLAYBACK));
200 p_view->AddChild( p_stop );
202 ButtonRect.SetLeftTop(BPoint(xStart + 5, yStart + 6));
203 ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSpeakerButtonSize);
204 xStart += kSpeakerIconBitmapWidth;
206 TransportButton* p_mute = new TransportButton(ButtonRect, B_EMPTY_STRING,
208 kPressedSpeakerIconBits,
210 new BMessage(VOLUME_MUTE));
212 p_view->AddChild( p_mute );
215 rgb_color fill_color = {0,255,0};
216 p_seek = new SeekSlider(BRect(5,2,255,15), this, 0, 100,
219 p_seek->UseFillColor(true, &fill_color);
220 p_view->AddChild( p_seek );
223 p_vol = new MediaSlider(BRect(xStart,20,255,30), new BMessage(VOLUME_CHG),
225 p_vol->SetValue(VOLUME_DEFAULT);
226 p_vol->UseFillColor(true, &fill_color);
227 p_view->AddChild( p_vol );
229 /* Set size and Show */
231 ResizeTo(260,50 + menu_bar->Bounds().IntegerHeight()+1);
235 InterfaceWindow::~InterfaceWindow()
239 /*****************************************************************************
240 * InterfaceWindow::MessageReceived
241 *****************************************************************************/
242 void InterfaceWindow::MessageReceived( BMessage * p_message )
244 int vol_val = p_vol->Value(); // remember the current volume
245 static int playback_status; // remember playback state
249 switch( p_message->what )
251 // case B_ABOUT_REQUESTED:
252 // alert = new BAlert(VOUT_TITLE, "BeOS " VOUT_TITLE "\n\n<www.videolan.org>", "Ok");
262 file_panel = new BFilePanel();
263 file_panel->SetTarget(this);
269 char device_method_and_name[B_FILE_NAME_LENGTH + 4];
270 if(p_message->FindString("device", device) != B_ERROR)
272 sprintf(device_method_and_name, "dvd:%s", *device);
273 intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, device_method_and_name );
278 // this currently stops playback not nicely
279 if (p_intf->p_input != NULL )
281 // silence the sound, otherwise very horrible
282 if (p_main->p_aout != NULL)
284 p_main->p_aout->vol = 0;
287 input_SetStatus(p_intf->p_input, INPUT_STATUS_END);
291 // starts playing in normal mode
292 // if (p_intf->p_input != NULL )
294 // if (p_main->p_aout != NULL)
296 // p_main->p_aout->vol = vol_val;
299 // input_SetStatus(p_intf->p_input, INPUT_STATUS_PLAY);
300 // playback_status = PLAYING;
304 // pause the playback
305 if (p_intf->p_input != NULL )
307 // mute the volume if currently playing
308 if (playback_status == PLAYING)
310 if (p_main->p_aout != NULL)
312 p_main->p_aout->vol = 0;
314 playback_status = PAUSED;
317 // restore the volume
319 if (p_main->p_aout != NULL)
321 p_main->p_aout->vol = vol_val;
323 playback_status = PLAYING;
326 input_SetStatus(p_intf->p_input, INPUT_STATUS_PAUSE);
330 // cycle the fast playback modes
331 if (p_intf->p_input != NULL )
333 if (p_main->p_aout != NULL)
335 p_main->p_aout->vol = 0;
338 input_SetStatus(p_intf->p_input, INPUT_STATUS_FASTER);
342 // cycle the slow playback modes
343 if (p_intf->p_input != NULL )
345 if (p_main->p_aout != NULL)
347 p_main->p_aout->vol = 0;
350 input_SetStatus(p_intf->p_input, INPUT_STATUS_SLOWER);
354 // handled by semaphores;
358 if (p_main->p_aout != NULL)
360 p_main->p_aout->vol = vol_val;
365 if (p_main->p_aout != NULL)
367 if (p_main->p_aout->vol == 0)
369 p_vol->SetEnabled(true);
370 p_main->p_aout->vol = vol_val;
374 p_vol->SetEnabled(false);
375 p_main->p_aout->vol = 0;
381 int32 i = p_message->FindInt32("channel");
382 input_ChangeES(p_intf->p_input,
383 p_intf->p_input->stream.pp_es[i], 1);
386 case SELECT_SUBTITLE:
388 int32 i = p_message->FindInt32("subtitle");
389 input_ChangeES(p_intf->p_input,
390 p_intf->p_input->stream.pp_es[i], 2);
393 case B_REFS_RECEIVED:
397 if( p_message->FindRef( "refs", &ref ) == B_OK )
400 intf_PlaylistAdd( p_main->p_playlist,
401 PLAYLIST_END, path.Path() );
407 BWindow::MessageReceived( p_message );
412 /*****************************************************************************
413 * InterfaceWindow::QuitRequested
414 *****************************************************************************/
415 bool InterfaceWindow::QuitRequested()
422 /*****************************************************************************
424 *****************************************************************************/
425 CDMenu::CDMenu(const char *name)
430 /*****************************************************************************
432 *****************************************************************************/
437 /*****************************************************************************
438 * CDMenu::AttachedToWindow
439 *****************************************************************************/
440 void CDMenu::AttachedToWindow(void)
442 while (RemoveItem((long int)0) != NULL); // remove all items
444 BMenu::AttachedToWindow();
447 /*****************************************************************************
449 *****************************************************************************/
450 int CDMenu::GetCD(const char *directory)
453 dir.SetTo(directory);
454 if(dir.InitCheck() != B_NO_ERROR) {
459 while(dir.GetNextEntry(&entry) >= 0) {
464 if(entry.GetPath(&path) != B_NO_ERROR)
469 if(entry.GetRef(&e) != B_NO_ERROR)
472 if(entry.IsDirectory()) {
473 if(strcmp(e.name, "floppy") == 0)
474 continue; // ignore floppy (it is not silent)
475 int devfd = GetCD(name);
486 if(strcmp(e.name, "raw") != 0)
487 continue; // ignore partitions
489 devfd = open(name, O_RDONLY);
493 if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
494 if(g.device_type == B_CD) //ensure the drive is a CD-ROM
496 if(ioctl(devfd, B_GET_MEDIA_STATUS, &m, sizeof(m)) >= 0 )
497 if(m == B_NO_ERROR) //ensure media is present
500 msg = new BMessage(OPEN_DVD);
501 msg->AddString("device", name);
502 BMenuItem *menu_item;
503 menu_item = new BMenuItem(name, msg);
515 /*****************************************************************************
516 * LanguageMenu::LanguageMenu
517 *****************************************************************************/
518 LanguageMenu::LanguageMenu(const char *name, int menu_kind, intf_thread_t *p_interface)
522 p_intf = p_interface;
525 /*****************************************************************************
526 * LanguageMenu::~LanguageMenu
527 *****************************************************************************/
528 LanguageMenu::~LanguageMenu()
532 /*****************************************************************************
533 * LanguageMenu::AttachedToWindow
534 *****************************************************************************/
535 void LanguageMenu::AttachedToWindow(void)
537 while (RemoveItem((long int)0) != NULL); // remove all items
540 BMenu::AttachedToWindow();
543 /*****************************************************************************
544 * LanguageMenu::GetChannels
545 *****************************************************************************/
546 int LanguageMenu::GetChannels()
552 es_descriptor_t *p_es;
554 if (p_intf->p_input == NULL)
557 for (i = 0; i < p_intf->p_input->stream.i_selected_es_number; i++)
560 p_intf->p_input->stream.pp_selected_es[i]->i_cat)
562 p_es = p_intf->p_input->stream.pp_selected_es[i];
565 for (i = 0; i < p_intf->p_input->stream.i_es_number; i++)
567 if (kind == p_intf->p_input->stream.pp_es[i]->i_cat)
569 psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
571 if (kind == AUDIO_ES) //audio
573 msg = new BMessage(SELECT_CHANNEL);
574 msg->AddInt32("channel", i);
578 msg = new BMessage(SELECT_SUBTITLE);
579 msg->AddInt32("subtitle", i);
581 BMenuItem *menu_item;
582 menu_item = new BMenuItem(psz_name, msg);
584 b_active = (p_es == p_intf->p_input->stream.pp_es[i]);
585 menu_item->SetMarked(b_active);
591 /*****************************************************************************
593 *****************************************************************************/
594 MediaSlider::MediaSlider(BRect frame,
598 :BSlider(frame, NULL, NULL, message, minValue, maxValue)
603 MediaSlider::~MediaSlider()
608 void MediaSlider::DrawThumb(void)
613 rgb_color black = {0,0,0};
617 v->SetHighColor(black);
619 v->SetHighColor(tint_color(black, B_LIGHTEN_2_TINT));
620 r.InsetBy(r.IntegerWidth()/4, r.IntegerHeight()/(4 * r.IntegerWidth() / r.IntegerHeight()));
623 v->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
625 v->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT));
630 /*****************************************************************************
632 *****************************************************************************/
633 SeekSlider::SeekSlider(BRect frame,
634 InterfaceWindow *owner,
637 thumb_style thumbType = B_TRIANGLE_THUMB)
638 :MediaSlider(frame, NULL, minValue, maxValue)
644 SeekSlider::~SeekSlider()
648 /*****************************************************************************
649 * SeekSlider::MouseDown
650 *****************************************************************************/
651 void SeekSlider::MouseDown(BPoint where)
653 BSlider::MouseDown(where);
654 fOwner->fScrubSem = create_sem(1, "Vlc::fScrubSem");
658 /*****************************************************************************
659 * SeekSlider::MouseUp
660 *****************************************************************************/
661 void SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage *message)
663 BSlider::MouseMoved(where, code, message);
666 release_sem(fOwner->fScrubSem);
669 /*****************************************************************************
670 * SeekSlider::MouseUp
671 *****************************************************************************/
672 void SeekSlider::MouseUp(BPoint where)
674 BSlider::MouseUp(where);
675 delete_sem(fOwner->fScrubSem);
676 fOwner->fScrubSem = B_ERROR;
684 /*****************************************************************************
686 *****************************************************************************/
687 static int intf_Probe ( probedata_t *p_data );
688 static int intf_Open ( intf_thread_t *p_intf );
689 static void intf_Close ( intf_thread_t *p_intf );
690 static void intf_Run ( intf_thread_t *p_intf );
692 /*****************************************************************************
693 * Functions exported as capabilities. They are declared as static so that
694 * we don't pollute the namespace too much.
695 *****************************************************************************/
696 void _M( intf_getfunctions )( function_list_t * p_function_list )
698 p_function_list->pf_probe = intf_Probe;
699 p_function_list->functions.intf.pf_open = intf_Open;
700 p_function_list->functions.intf.pf_close = intf_Close;
701 p_function_list->functions.intf.pf_run = intf_Run;
704 /*****************************************************************************
705 * intf_Probe: probe the interface and return a score
706 *****************************************************************************
707 * This function tries to initialize Gnome and returns a score to the
708 * plugin manager so that it can select the best plugin.
709 *****************************************************************************/
710 static int intf_Probe( probedata_t *p_data )
712 if( TestMethod( INTF_METHOD_VAR, "beos" ) )
720 /*****************************************************************************
721 * intf_Open: initialize interface
722 *****************************************************************************/
723 static int intf_Open( intf_thread_t *p_intf )
726 screen = new BScreen();
727 BRect rect = screen->Frame();
728 rect.top = rect.bottom-100;
731 rect.right = rect.left + 350;
734 /* Allocate instance and initialize some members */
735 p_intf->p_sys = (intf_sys_t*) malloc( sizeof( intf_sys_t ) );
736 if( p_intf->p_sys == NULL )
738 intf_ErrMsg("error: %s", strerror(ENOMEM));
741 p_intf->p_sys->i_key = -1;
743 /* Create the interface window */
744 p_intf->p_sys->p_window =
745 new InterfaceWindow( rect,
746 VOUT_TITLE " (BeOS interface)", p_intf );
747 if( p_intf->p_sys->p_window == 0 )
749 free( p_intf->p_sys );
750 intf_ErrMsg( "error: cannot allocate memory for InterfaceWindow" );
757 /*****************************************************************************
758 * intf_Close: destroy dummy interface
759 *****************************************************************************/
760 static void intf_Close( intf_thread_t *p_intf )
762 /* Destroy the interface window */
763 p_intf->p_sys->p_window->Lock();
764 p_intf->p_sys->p_window->Quit();
766 /* Destroy structure */
767 free( p_intf->p_sys );
771 /*****************************************************************************
772 * intf_Run: event loop
773 *****************************************************************************/
774 static void intf_Run( intf_thread_t *p_intf )
778 bool seekNeeded = false;
780 while( !p_intf->b_die )
783 /* Manage core vlc functions through the callback */
784 p_intf->pf_manage( p_intf );
786 /* Manage the slider */
787 if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL)
789 if (acquire_sem(p_intf->p_sys->p_window->fScrubSem) == B_OK)
796 uint32 seekTo = (p_intf->p_sys->p_window->p_seek->Value() *
797 p_intf->p_input->stream.p_selected_area->i_size) / 100;
798 input_Seek( p_intf->p_input, seekTo );
801 else if (p_intf->p_sys->p_window->Lock())
803 progress = (100. * p_intf->p_input->stream.p_selected_area->i_tell) /
804 p_intf->p_input->stream.p_selected_area->i_size;
805 p_intf->p_sys->p_window->p_seek->SetValue(progress);
806 p_intf->p_sys->p_window->Unlock();
811 msleep( INTF_IDLE_SLEEP );