]> git.sesse.net Git - vlc/blob - plugins/beos/intf_beos.cpp
003b21a39daf3b3dfba92f0803884296ee7135ba
[vlc] / plugins / beos / intf_beos.cpp
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 $
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  *
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.
16  *
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.
21  *
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  *****************************************************************************/
26
27 #define MODULE_NAME beos
28 #include "modules_inner.h"
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include "defs.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>                                      /* malloc(), free() */
37
38 #include <kernel/OS.h>
39 #include <storage/Path.h>
40 #include <Alert.h>
41 #include <View.h>
42 #include <CheckBox.h>
43 #include <Button.h>
44 #include <Slider.h>
45 #include <StatusBar.h>
46 #include <Application.h>
47 #include <Message.h>
48 #include <NodeInfo.h>
49 #include <Locker.h>
50 #include <DirectWindow.h>
51 #include <Box.h>
52 #include <Alert.h>
53 #include <MenuBar.h>
54 #include <MenuItem.h>
55 #include <FilePanel.h>
56 #include <Screen.h>
57 #include <malloc.h>
58 #include <string.h>
59 #include <Directory.h>
60 #include <Entry.h>
61 #include <Path.h>
62 #include <StorageDefs.h>
63 #include <scsi.h>
64 #include <scsiprobe_driver.h>
65
66 extern "C"
67 {
68 #include "config.h"
69 #include "common.h"
70 #include "threads.h"
71 #include "mtime.h"
72 #include "tests.h"
73 #include "modules.h"
74
75 #include "stream_control.h"
76 #include "input_ext-intf.h"
77
78 #include "interface.h"
79 #include "intf_playlist.h"
80 #include "intf_msg.h"
81 #include "audio_output.h"
82 #include "MsgVals.h"
83
84 #include "main.h"
85 }
86
87 #include "InterfaceWindow.h"
88 #include "Bitmaps.h"
89 #include "TransportButton.h"
90
91 /*****************************************************************************
92  * intf_sys_t: description and status of FB interface
93  *****************************************************************************/
94 typedef struct intf_sys_s
95 {
96     InterfaceWindow * p_window;
97     char              i_key;
98 } intf_sys_t;
99
100 /*****************************************************************************
101  * InterfaceWindow
102  *****************************************************************************/
103
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 )
109 {
110     file_panel = NULL;
111     p_intf = p_interface;
112     BRect ButtonRect;
113     float xStart = 5.0;
114     float yStart = 20.0;
115
116     SetName( "interface" );
117     SetTitle(VOUT_TITLE " (BeOS interface)");
118     BRect rect(0, 0, 0, 0);
119
120     BMenuBar *menu_bar;
121     menu_bar = new BMenuBar(rect, "main menu");
122     AddChild( menu_bar );
123
124     BMenu *mFile;
125     BMenu *mAudio;
126     CDMenu *cd_menu;
127
128     BMenuItem *mItem;
129
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') );
142
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 ) );
147
148
149     rect = Bounds();
150     rect.top += menu_bar->Bounds().IntegerHeight() + 1;
151
152     BBox* p_view;
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) );
155
156     /* Buttons */
157     /* Slow play */
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,
162                                             kSkipBackBitmapBits,
163                                             kPressedSkipBackBitmapBits,
164                                             kDisabledSkipBackBitmapBits,
165                                             new BMessage(SLOWER_PLAY));
166     p_view->AddChild( p_slow );
167
168     /* Play Pause */
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));
181
182     p_view->AddChild( p_play );
183     p_play->SetPlaying();
184
185     /* Fast Foward */
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 );
195
196     /* Stop */
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 );
206
207     ButtonRect.SetLeftTop(BPoint(xStart + 5, yStart + 6));
208     ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSpeakerButtonSize);
209     xStart += kSpeakerIconBitmapWidth;
210
211     TransportButton* p_mute = new TransportButton(ButtonRect, B_EMPTY_STRING,
212                                             kSpeakerIconBits,
213                                             kPressedSpeakerIconBits,
214                                             kSpeakerIconBits,
215                                             new BMessage(VOLUME_MUTE));
216
217     p_view->AddChild( p_mute );
218
219     /* Seek Status */
220     rgb_color fill_color = {0,255,0};
221     p_seek = new SeekSlider(BRect(5,2,255,15), this, 0, 100,
222                         B_TRIANGLE_THUMB);
223     p_seek->SetValue(0);
224     p_seek->UseFillColor(true, &fill_color);
225     p_view->AddChild( p_seek );
226
227     /* Volume Slider */
228     p_vol = new MediaSlider(BRect(xStart,20,255,30), new BMessage(VOLUME_CHG),
229                             0, VOLUME_MAX);
230     p_vol->SetValue(VOLUME_DEFAULT);
231     p_vol->UseFillColor(true, &fill_color);
232     p_view->AddChild( p_vol );
233
234     /* Set size and Show */
235     AddChild( p_view );
236     ResizeTo(260,50 + menu_bar->Bounds().IntegerHeight()+1);
237     Show();
238 }
239
240 InterfaceWindow::~InterfaceWindow()
241 {
242 }
243
244 /*****************************************************************************
245  * InterfaceWindow::MessageReceived
246  *****************************************************************************/
247 void InterfaceWindow::MessageReceived( BMessage * p_message )
248 {
249     int vol_val = p_vol->Value();    // remember the current volume
250     static int playback_status;      // remember playback state
251     int     i_index;
252     BAlert *alert;
253
254     Activate();
255
256     switch( p_message->what )
257     {
258 //    case B_ABOUT_REQUESTED:
259 //        alert = new BAlert(VOUT_TITLE, "BeOS " VOUT_TITLE "\n\n<www.videolan.org>", "Ok");
260 //        alert->Go();
261 //        break;
262
263     case OPEN_FILE:
264         if( file_panel )
265         {
266             file_panel->Show();
267             break;
268         }
269         file_panel = new BFilePanel();
270         file_panel->SetTarget( this );
271         file_panel->Show();
272         break;
273
274     case OPEN_DVD:
275         const char **ppsz_device;
276         char psz_method[ B_FILE_NAME_LENGTH + 4 ];
277
278         if( p_message->FindString("device", ppsz_device) != B_ERROR )
279         {
280             snprintf( psz_method, B_FILE_NAME_LENGTH + 4,
281                       "dvd:%s", *ppsz_device );
282             psz_method[ B_FILE_NAME_LENGTH + 4 - 1 ] = '\0';
283
284             intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, psz_method );
285         }
286         break;
287
288     case STOP_PLAYBACK:
289         // this currently stops playback not nicely
290         if( p_intf->p_input != NULL )
291         {
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++ )
295             {
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;
298             }
299             vlc_mutex_unlock( &p_aout_bank->lock );
300
301             snooze( 400000 );
302             input_SetStatus( p_intf->p_input, INPUT_STATUS_END );
303         }
304         break;
305
306     case START_PLAYBACK:
307         // starts playing in normal mode
308 //        if (p_intf->p_input != NULL )
309 //
310 //            if (p_main->p_aout != NULL)
311 //            {
312 //                p_main->p_aout->i_vol = vol_val;
313 //            }
314 //            snooze(400000);
315 //            input_SetStatus(p_intf->p_input, INPUT_STATUS_PLAY);
316 //            playback_status = PLAYING;
317 //        }
318 //        break;
319
320     case PAUSE_PLAYBACK:
321         // pause the playback
322         if( p_intf->p_input != NULL )
323         {
324             // mute the volume if currently playing
325             if( playback_status == PLAYING )
326             {
327                 vlc_mutex_lock( &p_aout_bank->lock );
328                 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
329                 {
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;
333                 }
334                 vlc_mutex_unlock( &p_aout_bank->lock );
335                 playback_status = PAUSED;
336             }
337             else
338             // restore the volume
339             {
340                 vlc_mutex_lock( &p_aout_bank->lock );
341                 for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
342                 {
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;
346                 }
347                 vlc_mutex_unlock( &p_aout_bank->lock );
348                 playback_status = PLAYING;
349             }
350
351             snooze( 400000 );
352             input_SetStatus( p_intf->p_input, INPUT_STATUS_PAUSE );
353         }
354         break;
355
356     case FASTER_PLAY:
357         // cycle the fast playback modes
358         if( p_intf->p_input != NULL )
359         {
360             vlc_mutex_lock( &p_aout_bank->lock );
361             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
362             {
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;
366             }
367             vlc_mutex_unlock( &p_aout_bank->lock );
368
369             snooze( 400000 );
370             input_SetStatus( p_intf->p_input, INPUT_STATUS_FASTER );
371         }
372         break;
373
374     case SLOWER_PLAY:
375         // cycle the slow playback modes
376         if (p_intf->p_input != NULL )
377         {
378             vlc_mutex_lock( &p_aout_bank->lock );
379             for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
380             {
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;
384             }
385             vlc_mutex_unlock( &p_aout_bank->lock );
386
387             snooze( 400000 );
388             input_SetStatus( p_intf->p_input, INPUT_STATUS_SLOWER );
389         }
390         break;
391
392     case SEEK_PLAYBACK:
393         // handled by semaphores;
394         break;
395
396     case VOLUME_CHG:
397         // adjust the volume
398         vlc_mutex_lock( &p_aout_bank->lock );
399         for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
400         {
401             if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
402             {
403                 p_aout_bank->pp_aout[i_index]->i_savedvolume = vol_val;
404             }
405             else
406             {
407                 p_aout_bank->pp_aout[i_index]->i_volume = vol_val;
408             }
409         }
410         vlc_mutex_unlock( &p_aout_bank->lock );
411         break;
412
413     case VOLUME_MUTE:
414         // mute
415         vlc_mutex_lock( &p_aout_bank->lock );
416         for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ )
417         {
418             if( p_aout_bank->pp_aout[i_index]->i_savedvolume )
419             {
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;
423             }
424             else
425             {
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;
429             }
430         }
431         vlc_mutex_unlock( &p_aout_bank->lock );
432         break;
433
434     case SELECT_CHANNEL:
435         {
436             int32 i = p_message->FindInt32( "channel" );
437             input_ChangeES( p_intf->p_input,
438                             p_intf->p_input->stream.pp_es[i], 1 );
439         }
440         break;
441
442     case SELECT_SUBTITLE:
443         {
444             int32 i = p_message->FindInt32( "subtitle" );
445             input_ChangeES( p_intf->p_input,
446                             p_intf->p_input->stream.pp_es[i], 2 );
447         }
448         break;
449
450     case B_REFS_RECEIVED:
451     case B_SIMPLE_DATA:
452         {
453             entry_ref ref;
454             if( p_message->FindRef( "refs", &ref ) == B_OK )
455             {
456                 BPath path( &ref );
457                 intf_PlaylistAdd( p_main->p_playlist,
458                                   PLAYLIST_END, path.Path() );
459             }
460
461         }
462         break;
463
464     default:
465         BWindow::MessageReceived( p_message );
466         break;
467     }
468 }
469
470 /*****************************************************************************
471  * InterfaceWindow::QuitRequested
472  *****************************************************************************/
473 bool InterfaceWindow::QuitRequested()
474 {
475     p_intf->b_die = 1;
476
477     return( false );
478 }
479
480 /*****************************************************************************
481  * CDMenu::CDMenu
482  *****************************************************************************/
483 CDMenu::CDMenu(const char *name)
484       : BMenu(name)
485 {
486 }
487
488 /*****************************************************************************
489  * CDMenu::~CDMenu
490  *****************************************************************************/
491 CDMenu::~CDMenu()
492 {
493 }
494
495 /*****************************************************************************
496  * CDMenu::AttachedToWindow
497  *****************************************************************************/
498 void CDMenu::AttachedToWindow(void)
499 {
500     while (RemoveItem((long int)0) != NULL);  // remove all items
501     GetCD("/dev/disk");
502     BMenu::AttachedToWindow();
503 }
504
505 /*****************************************************************************
506  * CDMenu::GetCD
507  *****************************************************************************/
508 int CDMenu::GetCD( const char *directory )
509 {
510     int i_dev;
511     BDirectory dir;
512     dir.SetTo( directory );
513
514     if( dir.InitCheck() != B_NO_ERROR )
515     {
516         return B_ERROR;
517     }
518
519     dir.Rewind();
520     BEntry entry;
521
522     while( dir.GetNextEntry(&entry) >= 0 )
523     {
524         const char *name;
525         entry_ref e;
526         BPath path;
527
528         if( entry.GetPath(&path) != B_NO_ERROR )
529         {
530             continue;
531         }
532
533         name = path.Path();
534
535         if( entry.GetRef(&e) != B_NO_ERROR )
536         {
537             continue;
538         }
539
540         if( entry.IsDirectory() )
541         {
542             if( strcmp(e.name, "floppy") == 0 )
543             {
544                 continue; // ignore floppy (it is not silent)
545             }
546
547             i_dev = GetCD( name );
548
549             if( i_dev >= 0 )
550             {
551                 return i_dev;
552             }
553         }
554         else
555         {
556             device_geometry g;
557             status_t m;
558
559             if( strcmp(e.name, "raw") != 0 )
560             {
561                 continue; // ignore partitions
562             }
563
564             i_dev = open( name, O_RDONLY );
565
566             if( i_dev < 0 )
567             {
568                 continue;
569             }
570
571             if( ioctl(i_dev, B_GET_GEOMETRY, &g, sizeof(g)) >= 0 )
572             {
573                 if( g.device_type == B_CD ) //ensure the drive is a CD-ROM
574                 {
575                     if( ioctl(i_dev, B_GET_MEDIA_STATUS, &m, sizeof(m)) >= 0 )
576                     {
577                         if( m == B_NO_ERROR ) //ensure media is present
578                         {
579                             BMessage *msg;
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 );
585                             continue;
586                         }
587                     }
588                 }
589             }
590             close( i_dev );
591         }
592     }
593     return B_ERROR;
594 }
595
596 /*****************************************************************************
597  * LanguageMenu::LanguageMenu
598  *****************************************************************************/
599 LanguageMenu::LanguageMenu(const char *name, int menu_kind, intf_thread_t  *p_interface)
600     :BMenu(name)
601 {
602     kind = menu_kind;
603     p_intf = p_interface;
604 }
605
606 /*****************************************************************************
607  * LanguageMenu::~LanguageMenu
608  *****************************************************************************/
609 LanguageMenu::~LanguageMenu()
610 {
611 }
612
613 /*****************************************************************************
614  * LanguageMenu::AttachedToWindow
615  *****************************************************************************/
616 void LanguageMenu::AttachedToWindow(void)
617 {
618     while( RemoveItem((long int)0) != NULL )
619     {
620         ; // remove all items
621     }
622
623     SetRadioMode(true);
624     GetChannels();
625     BMenu::AttachedToWindow();
626 }
627
628 /*****************************************************************************
629  * LanguageMenu::GetChannels
630  *****************************************************************************/
631 int LanguageMenu::GetChannels()
632 {
633     char  *psz_name;
634     bool   b_active;
635     bool   b_found;
636     int    i;
637     es_descriptor_t *p_es;
638
639     if( p_intf->p_input == NULL )
640     {
641         return 1;
642     }
643
644     for( i = 0; i < p_intf->p_input->stream.i_selected_es_number; i++ )
645     {
646         if( kind == p_intf->p_input->stream.pp_selected_es[i]->i_cat )
647         {
648             p_es = p_intf->p_input->stream.pp_selected_es[i];
649         }
650     }
651
652     for( i = 0; i < p_intf->p_input->stream.i_es_number; i++ )
653     {
654         if( kind == p_intf->p_input->stream.pp_es[i]->i_cat )
655         {
656             psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
657             BMessage *msg;
658             if( kind == AUDIO_ES ) //audio
659             {
660                 msg = new BMessage(SELECT_CHANNEL);
661                 msg->AddInt32("channel", i);
662             }
663             else
664             {
665                 msg = new BMessage(SELECT_SUBTITLE);
666                 msg->AddInt32("subtitle", i);
667             }
668             BMenuItem *menu_item;
669             menu_item = new BMenuItem(psz_name, msg);
670             AddItem(menu_item);
671             b_active = (p_es == p_intf->p_input->stream.pp_es[i]);
672             menu_item->SetMarked(b_active);
673         }
674     }
675 }
676
677 /*****************************************************************************
678  * MediaSlider
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 )
683 {
684
685 }
686
687 MediaSlider::~MediaSlider()
688 {
689
690 }
691
692 void MediaSlider::DrawThumb(void)
693 {
694     BRect r;
695     BView *v;
696
697     rgb_color black = {0,0,0};
698     r = ThumbFrame();
699     v = OffscreenView();
700
701     if(IsEnabled())
702     {
703         v->SetHighColor(black);
704     }
705     else
706     {
707         v->SetHighColor(tint_color(black, B_LIGHTEN_2_TINT));
708     }
709
710     r.InsetBy(r.IntegerWidth()/4, r.IntegerHeight()/(4 * r.IntegerWidth() / r.IntegerHeight()));
711     v->StrokeEllipse(r);
712
713     if(IsEnabled())
714     {
715         v->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
716     }
717     else
718     {
719         v->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT));
720     }
721
722     r.InsetBy(1,1);
723     v->FillEllipse(r);
724 }
725
726 /*****************************************************************************
727  * SeekSlider
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 )
732 {
733     fOwner = p_owner;
734     fMouseDown = false;
735 }
736
737 SeekSlider::~SeekSlider()
738 {
739 }
740
741 /*****************************************************************************
742  * SeekSlider::MouseDown
743  *****************************************************************************/
744 void SeekSlider::MouseDown(BPoint where)
745 {
746     BSlider::MouseDown(where);
747     fOwner->fScrubSem = create_sem(1, "Vlc::fScrubSem");
748     fMouseDown = true;
749 }
750
751 /*****************************************************************************
752  * SeekSlider::MouseUp
753  *****************************************************************************/
754 void SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage *message)
755 {
756     BSlider::MouseMoved(where, code, message);
757     if (!fMouseDown)
758         return;
759     release_sem(fOwner->fScrubSem);
760 }
761
762 /*****************************************************************************
763  * SeekSlider::MouseUp
764  *****************************************************************************/
765 void SeekSlider::MouseUp(BPoint where)
766 {
767     BSlider::MouseUp(where);
768     delete_sem(fOwner->fScrubSem);
769     fOwner->fScrubSem = B_ERROR;
770     fMouseDown = false;
771 }
772
773
774 extern "C"
775 {
776
777 /*****************************************************************************
778  * Local prototypes.
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 );
784
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 )
790 {
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;
795 }
796
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 )
804 {
805     if( TestMethod( INTF_METHOD_VAR, "beos" ) )
806     {
807         return( 999 );
808     }
809
810     return( 100 );
811 }
812
813 /*****************************************************************************
814  * intf_Open: initialize interface
815  *****************************************************************************/
816 static int intf_Open( intf_thread_t *p_intf )
817 {
818     BScreen *screen;
819     screen = new BScreen();
820     BRect rect = screen->Frame();
821     rect.top = rect.bottom-100;
822     rect.bottom -= 50;
823     rect.left += 50;
824     rect.right = rect.left + 350;
825     delete screen;
826
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 )
830     {
831         intf_ErrMsg("error: %s", strerror(ENOMEM));
832         return( 1 );
833     }
834     p_intf->p_sys->i_key = -1;
835
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 )
841     {
842         free( p_intf->p_sys );
843         intf_ErrMsg( "error: cannot allocate memory for InterfaceWindow" );
844         return( 1 );
845     }
846
847     return( 0 );
848 }
849
850 /*****************************************************************************
851  * intf_Close: destroy dummy interface
852  *****************************************************************************/
853 static void intf_Close( intf_thread_t *p_intf )
854 {
855     /* Destroy the interface window */
856     p_intf->p_sys->p_window->Lock();
857     p_intf->p_sys->p_window->Quit();
858
859     /* Destroy structure */
860     free( p_intf->p_sys );
861 }
862
863
864 /*****************************************************************************
865  * intf_Run: event loop
866  *****************************************************************************/
867 static void intf_Run( intf_thread_t *p_intf )
868 {
869     float progress;
870     bool seekNeeded = false;
871
872     while( !p_intf->b_die )
873     {
874         /* Manage core vlc functions through the callback */
875         p_intf->pf_manage( p_intf );
876
877         /* Manage the slider */
878         if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL)
879         {
880             if( acquire_sem(p_intf->p_sys->p_window->fScrubSem) == B_OK )
881             {
882                 seekNeeded = true;
883             }
884
885             if( seekNeeded )
886             {
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 );
890                 seekNeeded = false;
891             }
892             else if( p_intf->p_sys->p_window->Lock() )
893             {
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();
898             }
899         }
900
901         /* Wait a bit */
902         msleep( INTF_IDLE_SLEEP );
903     }
904 }
905
906 } /* extern "C" */
907