]> git.sesse.net Git - vlc/blob - plugins/beos/intf_beos.cpp
* Beginning of the built-in modules support.
[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.25 2001/04/15 04:19:57 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 , 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)
107 {
108     file_panel = NULL;
109     p_intf = p_interface;
110         BRect ButtonRect;
111         float xStart = 5.0;
112         float yStart = 20.0;
113
114     SetName( "interface" );
115     SetTitle(VOUT_TITLE " (BeOS interface)");
116     BRect rect(0, 0, 0, 0);
117     
118     BMenuBar *menu_bar; 
119     menu_bar = new BMenuBar(rect, "main menu");
120     AddChild( menu_bar );
121
122         BMenu *m; 
123         BMenu *am;
124         CDMenu *cd_menu;
125
126         menu_bar->AddItem( m = new BMenu("File") );
127         menu_bar->ResizeToPreferred();
128         m->AddItem( new BMenuItem("Open File" B_UTF8_ELLIPSIS, new BMessage(OPEN_FILE), 'O'));
129         cd_menu = new CDMenu("Open Disc");
130         m->AddItem(cd_menu);
131         m->AddSeparatorItem();
132         m->AddItem( new BMenuItem("About" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED), 'A'));
133         m->AddItem( new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'));
134
135         menu_bar->AddItem (am = new BMenu("Audio") );
136         menu_bar->ResizeToPreferred();
137         am->AddItem( new LanguageMenu("Language", AUDIO_ES, p_intf) );
138         am->AddItem( new LanguageMenu("Subtitles", SPU_ES, p_intf) );
139         
140
141     rect = Bounds();
142     rect.top += menu_bar->Bounds().IntegerHeight()+1;
143
144     BBox* p_view;
145         p_view = new BBox( rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW, B_PLAIN_BORDER );
146         p_view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
147     
148         /* Buttons */
149         /* Slow play */
150         ButtonRect.SetLeftTop(BPoint(xStart, yStart));
151         ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSkipButtonSize);
152         xStart += kRewindBitmapWidth;
153         TransportButton* p_slow = new TransportButton(ButtonRect, B_EMPTY_STRING,
154                                                                                         kSkipBackBitmapBits,
155                                                                                         kPressedSkipBackBitmapBits,
156                                                                                         kDisabledSkipBackBitmapBits,
157                                                                                         new BMessage(SLOWER_PLAY));
158         p_view->AddChild( p_slow );
159
160         /* Play Pause */
161         ButtonRect.SetLeftTop(BPoint(xStart, yStart));
162         ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kPlayButtonSize);
163         xStart += kPlayPauseBitmapWidth + 1.0;
164         PlayPauseButton* p_play = new PlayPauseButton(ButtonRect, B_EMPTY_STRING,
165                                                                                         kPlayButtonBitmapBits,
166                                                                                         kPressedPlayButtonBitmapBits,
167                                                                                         kDisabledPlayButtonBitmapBits,
168                                                                                         kPlayingPlayButtonBitmapBits,
169                                                                                         kPressedPlayingPlayButtonBitmapBits,
170                                                                                         kPausedPlayButtonBitmapBits,
171                                                                                         kPressedPausedPlayButtonBitmapBits,
172                                                                                         new BMessage(START_PLAYBACK));
173    
174         p_view->AddChild( p_play );
175         p_play->SetPlaying();
176
177         /* Fast Foward */
178         ButtonRect.SetLeftTop(BPoint(xStart, yStart));
179         ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSkipButtonSize);
180         xStart += kRewindBitmapWidth;
181         TransportButton* p_fast = new TransportButton(ButtonRect, B_EMPTY_STRING,
182                                                                                         kSkipForwardBitmapBits,
183                                                                                         kPressedSkipForwardBitmapBits,
184                                                                                         kDisabledSkipForwardBitmapBits,
185                                                                                         new BMessage(FASTER_PLAY));
186         p_view->AddChild( p_fast );
187
188         /* Stop */
189         ButtonRect.SetLeftTop(BPoint(xStart, yStart));
190         ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kStopButtonSize);
191         xStart += kStopBitmapWidth;
192         TransportButton* p_stop = new TransportButton(ButtonRect, B_EMPTY_STRING,
193                                                                                         kStopButtonBitmapBits,
194                                                                                         kPressedStopButtonBitmapBits,
195                                                                                         kDisabledStopButtonBitmapBits,
196                                                                                         new BMessage(STOP_PLAYBACK));
197         p_view->AddChild( p_stop );
198
199         ButtonRect.SetLeftTop(BPoint(xStart + 5, yStart + 6));
200         ButtonRect.SetRightBottom(ButtonRect.LeftTop() + kSpeakerButtonSize);
201         xStart += kSpeakerIconBitmapWidth;
202  
203         TransportButton* p_mute = new TransportButton(ButtonRect, B_EMPTY_STRING,
204                                                                                         kSpeakerIconBits,
205                                                                                         kPressedSpeakerIconBits,
206                                                                                         kSpeakerIconBits,
207                                                                                         new BMessage(VOLUME_MUTE));
208
209         p_view->AddChild( p_mute );
210  
211         /* Seek Status */       
212     rgb_color fill_color = {0,255,0};
213         p_seek = new SeekSlider(BRect(5,2,255,15), this, 0, 100,
214                                                 B_TRIANGLE_THUMB);
215         p_seek->SetValue(0);
216         p_seek->UseFillColor(true, &fill_color);
217     p_view->AddChild( p_seek );
218
219         /* Volume Slider */     
220         p_vol = new MediaSlider(BRect(xStart,20,255,30), new BMessage(VOLUME_CHG),
221                                                         0, VOLUME_MAX);
222         p_vol->SetValue(VOLUME_DEFAULT);
223         p_vol->UseFillColor(true, &fill_color);
224     p_view->AddChild( p_vol );
225     
226         /* Set size and Show */
227     AddChild( p_view );
228         ResizeTo(260,50 + menu_bar->Bounds().IntegerHeight()+1);
229     Show();
230 }
231
232 InterfaceWindow::~InterfaceWindow()
233 {
234 }
235
236 /*****************************************************************************
237  * InterfaceWindow::MessageReceived
238  *****************************************************************************/
239 void InterfaceWindow::MessageReceived( BMessage * p_message )
240 {
241         int vol_val = p_vol->Value();   // remember the current volume
242         static int playback_status;             // remember playback state
243         
244         BAlert *alert;
245         Activate();
246     switch( p_message->what )
247     {
248     case B_ABOUT_REQUESTED:
249                 alert = new BAlert(VOUT_TITLE, "BeOS " VOUT_TITLE "\n\n<www.videolan.org>", "Ok");
250             alert->Go();
251             break;      
252     
253     case OPEN_FILE:
254         if(file_panel)
255                 {
256                 file_panel->Show();
257                 break;
258                 }
259         file_panel = new BFilePanel();
260         file_panel->SetTarget(this);
261         file_panel->Show();
262         break;
263
264     case OPEN_DVD:
265             const char **device;
266             char device_method_and_name[B_FILE_NAME_LENGTH + 4];
267             if(p_message->FindString("device", device) != B_ERROR)
268                 {
269                 sprintf(device_method_and_name, "dvd:%s", *device); 
270                 intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, device_method_and_name );
271                 }
272         break;
273
274     case STOP_PLAYBACK:
275         // this currently stops playback not nicely
276                 if (p_intf->p_input != NULL )
277                 {
278                         // silence the sound, otherwise very horrible
279                         if (p_main->p_aout != NULL)
280                         {
281                                 p_main->p_aout->vol = 0;
282                         }
283                         snooze(400000);
284                         input_SetStatus(p_intf->p_input, INPUT_STATUS_END);
285                 }
286         break;
287         case START_PLAYBACK:
288                 // starts playing in normal mode
289 //              if (p_intf->p_input != NULL )
290 //              {                       
291 //                      if (p_main->p_aout != NULL)
292 //                      {
293 //                              p_main->p_aout->vol = vol_val;
294 //                      }
295 //                      snooze(400000);
296 //                      input_SetStatus(p_intf->p_input, INPUT_STATUS_PLAY);
297 //                      playback_status = PLAYING;
298 //              } 
299 //              break;
300         case PAUSE_PLAYBACK:
301                 // pause the playback
302                 if (p_intf->p_input != NULL )
303                 {
304                         // mute the volume if currently playing
305                         if (playback_status == PLAYING)
306                         {
307                                 if (p_main->p_aout != NULL)
308                                 {
309                                         p_main->p_aout->vol = 0;
310                                 }
311                                 playback_status = PAUSED;
312                         }
313                         else
314                         // restore the volume
315                         {
316                                 if (p_main->p_aout != NULL)
317                                 {
318                                         p_main->p_aout->vol = vol_val;
319                                 }
320                                 playback_status = PLAYING;
321                         }
322                         snooze(400000);
323                         input_SetStatus(p_intf->p_input, INPUT_STATUS_PAUSE);
324                 }
325                 break;
326         case FASTER_PLAY:
327                 // cycle the fast playback modes
328                 if (p_intf->p_input != NULL )
329                 {
330                         if (p_main->p_aout != NULL)
331                         {
332                                 p_main->p_aout->vol = 0;
333                         }
334                         snooze(400000);
335                         input_SetStatus(p_intf->p_input, INPUT_STATUS_FASTER);
336                 }
337                 break;
338         case SLOWER_PLAY:
339                 // cycle the slow playback modes
340                 if (p_intf->p_input != NULL )
341                 {
342                         if (p_main->p_aout != NULL)
343                         {
344                                 p_main->p_aout->vol = 0;
345                         }
346                         snooze(400000);
347                         input_SetStatus(p_intf->p_input, INPUT_STATUS_SLOWER);
348                 }
349                 break;
350         case SEEK_PLAYBACK:
351                 // handled by semaphores;
352                 break;
353         case VOLUME_CHG:
354                 // adjust the volume
355         if (p_main->p_aout != NULL) 
356         {
357                         p_main->p_aout->vol = vol_val;
358                 }
359                 break;
360         case VOLUME_MUTE:
361                 // mute
362         if (p_main->p_aout != NULL) 
363             {
364                         if (p_main->p_aout->vol == 0)
365                         {
366                                 p_vol->SetEnabled(true);
367                                 p_main->p_aout->vol = vol_val;
368                         }       
369                         else
370                         {
371                                 p_vol->SetEnabled(false);
372                                 p_main->p_aout->vol = 0;
373                         }
374                 }
375                 break;
376         case SELECT_CHANNEL:
377                 {
378                         int32 i = p_message->FindInt32("channel");
379                         input_ChangeES(p_intf->p_input, 
380                                         p_intf->p_input->stream.pp_es[i], 1);
381                 }
382                 break;
383         case SELECT_SUBTITLE:
384                 {
385                         int32 i = p_message->FindInt32("subtitle");
386                         input_ChangeES(p_intf->p_input, 
387                                         p_intf->p_input->stream.pp_es[i], 2);
388                 }
389                 break;
390         case B_REFS_RECEIVED:
391     case B_SIMPLE_DATA:
392         {
393             entry_ref ref;
394             if( p_message->FindRef( "refs", &ref ) == B_OK )
395             {
396                 BPath path( &ref );
397                 intf_PlaylistAdd( p_main->p_playlist,
398                                   PLAYLIST_END, path.Path() );
399             }
400
401         }
402         break;
403     default:
404         BWindow::MessageReceived( p_message );
405         break;
406     }
407 }
408
409 /*****************************************************************************
410  * InterfaceWindow::QuitRequested
411  *****************************************************************************/
412 bool InterfaceWindow::QuitRequested()
413 {
414     p_intf->b_die = 1;
415
416     return( false );
417 }
418
419 /*****************************************************************************
420  * CDMenu::CDMenu
421  *****************************************************************************/
422 CDMenu::CDMenu(const char *name)
423         : BMenu(name)
424 {
425 }
426
427 /*****************************************************************************
428  * CDMenu::~CDMenu
429  *****************************************************************************/
430 CDMenu::~CDMenu()
431 {
432 }
433
434 /*****************************************************************************
435  * CDMenu::AttachedToWindow
436  *****************************************************************************/
437 void CDMenu::AttachedToWindow(void)
438 {
439         while (RemoveItem((long int)0) != NULL);  // remove all items
440         GetCD("/dev/disk");
441         BMenu::AttachedToWindow();
442 }
443
444 /*****************************************************************************
445  * CDMenu::GetCD
446  *****************************************************************************/
447 int CDMenu::GetCD(const char *directory)
448
449         BDirectory dir; 
450         dir.SetTo(directory); 
451         if(dir.InitCheck() != B_NO_ERROR) { 
452                 return B_ERROR; 
453         } 
454         dir.Rewind(); 
455         BEntry entry; 
456         while(dir.GetNextEntry(&entry) >= 0) { 
457                 BPath path; 
458                 const char *name; 
459                 entry_ref e; 
460                 
461                 if(entry.GetPath(&path) != B_NO_ERROR) 
462                         continue; 
463                 name = path.Path(); 
464                 
465                 
466                 if(entry.GetRef(&e) != B_NO_ERROR) 
467                         continue; 
468
469                 if(entry.IsDirectory()) { 
470                         if(strcmp(e.name, "floppy") == 0) 
471                                 continue; // ignore floppy (it is not silent) 
472                         int devfd = GetCD(name);
473                         if(devfd >= 0)
474                                 {
475                                 return devfd;
476                                 }
477                 } 
478                 else { 
479                         int devfd; 
480                         device_geometry g;
481                         status_t m;
482
483                         if(strcmp(e.name, "raw") != 0) 
484                                 continue; // ignore partitions 
485
486                         devfd = open(name, O_RDONLY); 
487                         if(devfd < 0) 
488                                 continue; 
489
490                         if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
491                                 if(g.device_type == B_CD) //ensure the drive is a CD-ROM
492                                 { 
493                                         if(ioctl(devfd, B_GET_MEDIA_STATUS, &m, sizeof(m)) >= 0 )
494                                                 if(m == B_NO_ERROR) //ensure media is present
495                                                         {
496                                                         BMessage *msg;
497                                                         msg = new BMessage(OPEN_DVD);
498                                                         msg->AddString("device", name);
499                                                         BMenuItem *menu_item;
500                                                         menu_item = new BMenuItem(name, msg);
501                                                         AddItem(menu_item);
502                                                         continue;
503                                                         }
504                                 }
505                         }
506                         close(devfd);
507                 } 
508         }
509         return B_ERROR;
510 }
511
512 /*****************************************************************************
513  * LanguageMenu::LanguageMenu
514  *****************************************************************************/
515 LanguageMenu::LanguageMenu(const char *name, int menu_kind, intf_thread_t  *p_interface)
516         :BMenu(name)
517 {
518         kind = menu_kind;
519         p_intf = p_interface;
520 }
521
522 /*****************************************************************************
523  * LanguageMenu::~LanguageMenu
524  *****************************************************************************/
525 LanguageMenu::~LanguageMenu()
526 {
527 }
528
529 /*****************************************************************************
530  * LanguageMenu::AttachedToWindow
531  *****************************************************************************/
532 void LanguageMenu::AttachedToWindow(void)
533 {
534         while (RemoveItem((long int)0) != NULL); // remove all items
535         SetRadioMode(true);
536         GetChannels();
537         BMenu::AttachedToWindow();
538 }
539
540 /*****************************************************************************
541  * LanguageMenu::GetChannels
542  *****************************************************************************/
543 int LanguageMenu::GetChannels()
544
545         char*   psz_name;
546         bool    b_active;
547         bool    b_found;
548         int32   i;
549         es_descriptor_t *p_es;
550         
551         if (p_intf->p_input == NULL)
552                 return 1;
553                 
554         for (i = 0; i < p_intf->p_input->stream.i_selected_es_number; i++)
555         {
556                 if (kind ==
557                         p_intf->p_input->stream.pp_selected_es[i]->i_cat)
558                 {
559                         p_es = p_intf->p_input->stream.pp_selected_es[i];
560                 }
561         }               
562         for (i = 0; i < p_intf->p_input->stream.i_es_number; i++)
563         {
564                 if (kind == p_intf->p_input->stream.pp_es[i]->i_cat)
565                 {
566                         psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
567                         BMessage *msg;
568                         if (kind == AUDIO_ES) //audio
569                         {
570                                 msg = new BMessage(SELECT_CHANNEL);
571                                 msg->AddInt32("channel", i);
572                         }
573                         else
574                         {
575                                 msg = new BMessage(SELECT_SUBTITLE);
576                                 msg->AddInt32("subtitle", i);
577                         }
578                         BMenuItem *menu_item;
579                         menu_item = new BMenuItem(psz_name, msg);
580                         AddItem(menu_item);
581                         b_active = (p_es == p_intf->p_input->stream.pp_es[i]);
582                         menu_item->SetMarked(b_active);
583                 }
584         }
585 }
586
587
588 /*****************************************************************************
589  * MediaSlider
590  *****************************************************************************/
591 MediaSlider::MediaSlider(BRect frame,
592                                                 BMessage *message,
593                                                 int32 minValue,
594                                                 int32 maxValue)
595                                         :BSlider(frame, NULL, NULL, message, minValue, maxValue)
596 {
597
598 }
599
600 MediaSlider::~MediaSlider()
601 {
602
603 }
604
605 void MediaSlider::DrawThumb(void)
606 {
607         BRect r;
608         BView *v;
609
610         rgb_color black = {0,0,0};
611         r = ThumbFrame();
612         v = OffscreenView();
613         if(IsEnabled())
614                 v->SetHighColor(black);
615         else
616                 v->SetHighColor(tint_color(black, B_LIGHTEN_2_TINT));
617         r.InsetBy(r.IntegerWidth()/4, r.IntegerHeight()/(4 * r.IntegerWidth() / r.IntegerHeight()));
618         v->StrokeEllipse(r);
619         if(IsEnabled())
620                 v->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
621         else
622                 v->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT));
623         r.InsetBy(1,1);
624         v->FillEllipse(r);
625 }
626
627 /*****************************************************************************
628  * SeekSlider
629  *****************************************************************************/
630 SeekSlider::SeekSlider(BRect frame,
631                                 InterfaceWindow *owner,
632                                 int32 minValue,
633                                 int32 maxValue,
634                                 thumb_style thumbType = B_TRIANGLE_THUMB)
635                         :MediaSlider(frame, NULL, minValue, maxValue)
636 {
637         fOwner = owner;
638         fMouseDown = false;
639 }
640
641 SeekSlider::~SeekSlider()
642 {
643 }
644
645 /*****************************************************************************
646  * SeekSlider::MouseDown
647  *****************************************************************************/
648 void SeekSlider::MouseDown(BPoint where)
649 {
650         BSlider::MouseDown(where);
651         fOwner->fScrubSem = create_sem(1, "Vlc::fScrubSem");
652         fMouseDown = true;                                      
653 }
654
655 /*****************************************************************************
656  * SeekSlider::MouseUp
657  *****************************************************************************/
658 void SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage *message)
659 {
660         BSlider::MouseMoved(where, code, message);
661         if (!fMouseDown)
662                 return;
663         release_sem(fOwner->fScrubSem);
664 }
665
666 /*****************************************************************************
667  * SeekSlider::MouseUp
668  *****************************************************************************/
669 void SeekSlider::MouseUp(BPoint where)
670 {
671         BSlider::MouseUp(where);
672         delete_sem(fOwner->fScrubSem);
673         fOwner->fScrubSem = B_ERROR;
674         fMouseDown = false;                                     
675 }
676         
677
678 extern "C"
679 {
680
681 /*****************************************************************************
682  * Local prototypes.
683  *****************************************************************************/
684 static int  intf_Probe     ( probedata_t *p_data );
685 static int  intf_Open      ( intf_thread_t *p_intf );
686 static void intf_Close     ( intf_thread_t *p_intf );
687 static void intf_Run       ( intf_thread_t *p_intf );
688
689 /*****************************************************************************
690  * Functions exported as capabilities. They are declared as static so that
691  * we don't pollute the namespace too much.
692  *****************************************************************************/
693 void _M( intf_getfunctions )( function_list_t * p_function_list )
694 {
695     p_function_list->pf_probe = intf_Probe;
696     p_function_list->functions.intf.pf_open  = intf_Open;
697     p_function_list->functions.intf.pf_close = intf_Close;
698     p_function_list->functions.intf.pf_run   = intf_Run;
699 }
700
701 /*****************************************************************************
702  * intf_Probe: probe the interface and return a score
703  *****************************************************************************
704  * This function tries to initialize Gnome and returns a score to the
705  * plugin manager so that it can select the best plugin.
706  *****************************************************************************/
707 static int intf_Probe( probedata_t *p_data )
708 {
709     if( TestMethod( INTF_METHOD_VAR, "beos" ) )
710     {
711         return( 999 );
712     }
713
714     return( 100 );
715 }
716
717 /*****************************************************************************
718  * intf_Open: initialize interface
719  *****************************************************************************/
720 static int intf_Open( intf_thread_t *p_intf )
721 {
722     BScreen *screen;
723     screen = new BScreen();
724     BRect rect = screen->Frame();
725     rect.top = rect.bottom-100;
726     rect.bottom -= 50;
727     rect.left += 50;
728     rect.right = rect.left + 350;
729     delete screen;
730     
731     /* Allocate instance and initialize some members */
732     p_intf->p_sys = (intf_sys_t*) malloc( sizeof( intf_sys_t ) );
733     if( p_intf->p_sys == NULL )
734     {
735         intf_ErrMsg("error: %s", strerror(ENOMEM));
736         return( 1 );
737     }
738     p_intf->p_sys->i_key = -1;
739     
740     /* Create the interface window */
741     p_intf->p_sys->p_window =
742         new InterfaceWindow( rect,
743                              VOUT_TITLE " (BeOS interface)", p_intf );
744     if( p_intf->p_sys->p_window == 0 )
745     {
746         free( p_intf->p_sys );
747         intf_ErrMsg( "error: cannot allocate memory for InterfaceWindow" );
748         return( 1 );
749     }
750     
751     return( 0 );
752 }
753
754 /*****************************************************************************
755  * intf_Close: destroy dummy interface
756  *****************************************************************************/
757 static void intf_Close( intf_thread_t *p_intf )
758 {
759     /* Destroy the interface window */
760     p_intf->p_sys->p_window->Lock();
761     p_intf->p_sys->p_window->Quit();    
762
763     /* Destroy structure */
764     free( p_intf->p_sys );
765 }
766
767
768 /*****************************************************************************
769  * intf_Run: event loop
770  *****************************************************************************/
771 static void intf_Run( intf_thread_t *p_intf )
772 {
773         
774         float progress;
775         bool seekNeeded = false;
776         
777     while( !p_intf->b_die )
778     {
779
780         /* Manage core vlc functions through the callback */
781         p_intf->pf_manage( p_intf );
782
783             /* Manage the slider */
784             if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL)
785         {
786             if (acquire_sem(p_intf->p_sys->p_window->fScrubSem) == B_OK)
787                         {
788                                 seekNeeded = true;
789                         }               
790
791                         if (seekNeeded)
792             {
793                 uint32 seekTo = (p_intf->p_sys->p_window->p_seek->Value() * 
794                                 p_intf->p_input->stream.p_selected_area->i_size) / 100;
795                                 input_Seek( p_intf->p_input, seekTo );
796                                 seekNeeded = false;             
797             }
798                         else if (p_intf->p_sys->p_window->Lock())
799             {
800                     progress = (100. * p_intf->p_input->stream.p_selected_area->i_tell) /
801                                         p_intf->p_input->stream.p_selected_area->i_size;
802                     p_intf->p_sys->p_window->p_seek->SetValue(progress);
803                     p_intf->p_sys->p_window->Unlock();
804                 }
805          }
806
807         /* Wait a bit */
808         msleep( INTF_IDLE_SLEEP );
809     }
810 }
811
812 } /* extern "C" */