]> git.sesse.net Git - vlc/blob - modules/gui/beos/VideoOutput.cpp
Remove E_()
[vlc] / modules / gui / beos / VideoOutput.cpp
1 /*****************************************************************************
2  * vout_beos.cpp: beos video output display method
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Tony Castley <tcastley@mail.powerup.com.au>
10  *          Richard Shepherd <richard@rshepherd.demon.co.uk>
11  *          Stephan Aßmus <stippi@yellowbites.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <errno.h>                                                 /* ENOMEM */
32
33 #include <Application.h>
34 #include <BitmapStream.h>
35 #include <Bitmap.h>
36 #include <Directory.h>
37 #include <DirectWindow.h>
38 #include <File.h>
39 #include <InterfaceKit.h>
40 #include <NodeInfo.h>
41 #include <String.h>
42 #include <TranslatorRoster.h>
43 #include <WindowScreen.h>
44
45 /* VLC headers */
46 #ifdef HAVE_CONFIG_H
47 # include "config.h"
48 #endif
49
50 #include <vlc/vlc.h>
51 #include <vlc_interface.h>
52 #include <vlc_vout.h>
53 #include <vlc_keys.h>
54
55 #include "InterfaceWindow.h"    // for load/save_settings()
56 #include "DrawingTidbits.h"
57 #include "MsgVals.h"
58
59 #include "VideoWindow.h"
60
61 /*****************************************************************************
62  * vout_sys_t: BeOS video output method descriptor
63  *****************************************************************************
64  * This structure is part of the video output thread descriptor.
65  * It describes the BeOS specific properties of an output thread.
66  *****************************************************************************/
67 struct vout_sys_t
68 {
69     VideoWindow *  p_window;
70
71     int32_t i_width;
72     int32_t i_height;
73
74 //    uint8_t *pp_buffer[3];
75     uint32_t source_chroma;
76     int i_index;
77
78 };
79
80 #define MIN_AUTO_VSYNC_REFRESH 61    // Hz
81
82 /*****************************************************************************
83  * beos_GetAppWindow : retrieve a BWindow pointer from the window name
84  *****************************************************************************/
85 BWindow*
86 beos_GetAppWindow(char *name)
87 {
88     int32_t     index;
89     BWindow     *window;
90
91     for (index = 0 ; ; index++)
92     {
93         window = be_app->WindowAt(index);
94         if (window == NULL)
95             break;
96         if (window->LockWithTimeout(20000) == B_OK)
97         {
98             if (strcmp(window->Name(), name) == 0)
99             {
100                 window->Unlock();
101                 break;
102             }
103             window->Unlock();
104         }
105     }
106     return window;
107 }
108
109 static const int beos_keys[][2] =
110 {
111     { B_LEFT_ARROW,  KEY_LEFT },
112     { B_RIGHT_ARROW, KEY_RIGHT },
113     { B_UP_ARROW,    KEY_UP },
114     { B_DOWN_ARROW,  KEY_DOWN },
115     { B_SPACE,       KEY_SPACE },
116     { B_ENTER,       KEY_ENTER },
117     { B_F1_KEY,      KEY_F1 },
118     { B_F2_KEY,      KEY_F2 },
119     { B_F3_KEY,      KEY_F3 },
120     { B_F4_KEY,      KEY_F4 },
121     { B_F5_KEY,      KEY_F5 },
122     { B_F6_KEY,      KEY_F6 },
123     { B_F7_KEY,      KEY_F7 },
124     { B_F8_KEY,      KEY_F8 },
125     { B_F9_KEY,      KEY_F9 },
126     { B_F10_KEY,     KEY_F10 },
127     { B_F11_KEY,     KEY_F11 },
128     { B_F12_KEY,     KEY_F12 },
129     { B_HOME,        KEY_HOME },
130     { B_END,         KEY_END },
131     { B_ESCAPE,      KEY_ESC },
132     { B_PAGE_UP,     KEY_PAGEUP },
133     { B_PAGE_DOWN,   KEY_PAGEDOWN },
134     { B_TAB,         KEY_TAB },
135     { B_BACKSPACE,   KEY_BACKSPACE }
136 };
137
138 static int ConvertKeyFromVLC( int key )
139 {
140     for( unsigned i = 0; i < sizeof( beos_keys ) / sizeof( int ) / 2; i++ )
141     {
142         if( beos_keys[i][1] == key )
143         {
144             return beos_keys[i][0];
145         }
146     }
147     return key;
148 }
149
150 static int ConvertKeyToVLC( int key )
151 {
152     for( unsigned i = 0; i < sizeof( beos_keys ) / sizeof( int ) / 2; i++ )
153     {
154         if( beos_keys[i][0] == key )
155         {
156             return beos_keys[i][1];
157         }
158     }
159     return key;
160 }
161
162 /*****************************************************************************
163  * get_interface_window
164  *****************************************************************************/
165 BWindow*
166 get_interface_window()
167 {
168     return beos_GetAppWindow( "VLC " PACKAGE_VERSION );
169 }
170
171 class BackgroundView : public BView
172 {
173  public:
174                             BackgroundView(BRect frame, VLCView* view)
175                             : BView(frame, "background",
176                                     B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE),
177                               fVideoView(view)
178                             {
179                                 SetViewColor(kBlack);
180                             }
181     virtual                    ~BackgroundView() {}
182
183     virtual    void            MouseDown(BPoint where)
184                             {
185                                 // convert coordinates
186                                 where = fVideoView->ConvertFromParent(where);
187                                 // let him handle it
188                                 fVideoView->MouseDown(where);
189                             }
190     virtual    void            MouseMoved(BPoint where, uint32_t transit,
191                                        const BMessage* dragMessage)
192                             {
193                                 // convert coordinates
194                                 where = fVideoView->ConvertFromParent(where);
195                                 // let him handle it
196                                 fVideoView->MouseMoved(where, transit, dragMessage);
197                                 // notice: It might look like transit should be
198                                 // B_OUTSIDE_VIEW regardless, but leave it like this,
199                                 // otherwise, unwanted things will happen!
200                             }
201
202  private:
203     VLCView*                fVideoView;
204 };
205
206
207 /*****************************************************************************
208  * VideoSettings constructor and destructor
209  *****************************************************************************/
210 VideoSettings::VideoSettings()
211     : fVideoSize( SIZE_100 ),
212       fFlags( FLAG_CORRECT_RATIO ),
213       fSettings( new BMessage( 'sett' ) )
214 {
215     // read settings from disk
216     status_t ret = load_settings( fSettings, "video_settings", "VideoLAN Client" );
217     if ( ret == B_OK )
218     {
219         uint32_t flags;
220         if ( fSettings->FindInt32( "flags", (int32*)&flags ) == B_OK )
221             SetFlags( flags );
222         uint32_t size;
223         if ( fSettings->FindInt32( "video size", (int32*)&size ) == B_OK )
224             SetVideoSize( size );
225     }
226     else
227     {
228         // figure out if we should use vertical sync by default
229         BScreen screen(B_MAIN_SCREEN_ID);
230         if (screen.IsValid())
231         {
232             display_mode mode;
233             screen.GetMode(&mode);
234             float refresh = (mode.timing.pixel_clock * 1000)
235                             / ((mode.timing.h_total)* (mode.timing.v_total));
236             if (refresh < MIN_AUTO_VSYNC_REFRESH)
237                 AddFlags(FLAG_SYNC_RETRACE);
238         }
239     }
240 }
241
242 VideoSettings::VideoSettings( const VideoSettings& clone )
243     : fVideoSize( clone.VideoSize() ),
244       fFlags( clone.Flags() ),
245       fSettings( NULL )
246 {
247 }
248
249
250 VideoSettings::~VideoSettings()
251 {
252     if ( fSettings )
253     {
254         // we are the default settings
255         // and write our settings to disk
256         if (fSettings->ReplaceInt32( "video size", VideoSize() ) != B_OK)
257             fSettings->AddInt32( "video size", VideoSize() );
258         if (fSettings->ReplaceInt32( "flags", Flags() ) != B_OK)
259             fSettings->AddInt32( "flags", Flags() );
260
261         save_settings( fSettings, "video_settings", "VideoLAN Client" );
262         delete fSettings;
263     }
264     else
265     {
266         // we are just a clone of the default settings
267         fDefaultSettings.SetVideoSize( VideoSize() );
268         fDefaultSettings.SetFlags( Flags() );
269     }
270 }
271
272 /*****************************************************************************
273  * VideoSettings::DefaultSettings
274  *****************************************************************************/
275 VideoSettings*
276 VideoSettings::DefaultSettings()
277 {
278     return &fDefaultSettings;
279 }
280
281 /*****************************************************************************
282  * VideoSettings::SetVideoSize
283  *****************************************************************************/
284 void
285 VideoSettings::SetVideoSize( uint32_t mode )
286 {
287     fVideoSize = mode;
288 }
289
290 // static variable initialization
291 VideoSettings
292 VideoSettings::fDefaultSettings;
293
294
295 /*****************************************************************************
296  * VideoWindow constructor and destructor
297  *****************************************************************************/
298 VideoWindow::VideoWindow(int v_width, int v_height, BRect frame,
299                          vout_thread_t *p_videoout)
300     : BWindow(frame, NULL, B_TITLED_WINDOW, B_NOT_CLOSABLE | B_NOT_MINIMIZABLE),
301       i_width(frame.IntegerWidth()),
302       i_height(frame.IntegerHeight()),
303       winSize(frame),
304       i_buffer(0),
305       teardownwindow(false),
306       fTrueWidth(v_width),
307       fTrueHeight(v_height),
308       fCachedFeel(B_NORMAL_WINDOW_FEEL),
309       fInterfaceShowing(false),
310       fInitStatus(B_ERROR),
311       fSettings(new VideoSettings(*VideoSettings::DefaultSettings()))
312 {
313     p_vout = p_videoout;
314
315     // create the view to do the display
316     view = new VLCView( Bounds(), p_vout );
317
318     // create background view
319     BView *mainView =  new BackgroundView( Bounds(), view );
320     AddChild(mainView);
321     mainView->AddChild(view);
322
323     // allocate bitmap buffers
324     for (int32_t i = 0; i < 3; i++)
325         bitmap[i] = NULL;
326     fInitStatus = _AllocateBuffers(v_width, v_height, &mode);
327
328     // make sure we layout the view correctly
329     FrameResized(i_width, i_height);
330
331     if (fInitStatus >= B_OK && mode == OVERLAY)
332     {
333        overlay_restrictions r;
334
335        bitmap[0]->GetOverlayRestrictions(&r);
336        SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
337                      (i_height * r.min_height_scale), i_height * r.max_height_scale);
338     }
339
340     // vlc settings override settings from disk
341     if (config_GetInt(p_vout, "fullscreen"))
342         fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
343
344     _SetToSettings();
345 }
346
347 VideoWindow::~VideoWindow()
348 {
349     int32 result;
350
351     teardownwindow = true;
352     wait_for_thread(fDrawThreadID, &result);
353     _FreeBuffers();
354     delete fSettings;
355 }
356
357 /*****************************************************************************
358  * VideoWindow::MessageReceived
359  *****************************************************************************/
360 void
361 VideoWindow::MessageReceived( BMessage *p_message )
362 {
363     switch( p_message->what )
364     {
365         case SHOW_INTERFACE:
366             SetInterfaceShowing( true );
367             break;
368         case TOGGLE_FULL_SCREEN:
369             BWindow::Zoom();
370             break;
371         case RESIZE_50:
372         case RESIZE_100:
373         case RESIZE_200:
374             if (IsFullScreen())
375                 BWindow::Zoom();
376             _SetVideoSize(p_message->what);
377             break;
378         case VERT_SYNC:
379             SetSyncToRetrace(!IsSyncedToRetrace());
380             break;
381         case WINDOW_FEEL:
382             {
383                 window_feel winFeel;
384                 if (p_message->FindInt32("WinFeel", (int32*)&winFeel) == B_OK)
385                 {
386                     SetFeel(winFeel);
387                     fCachedFeel = winFeel;
388                     if (winFeel == B_FLOATING_ALL_WINDOW_FEEL)
389                         fSettings->AddFlags(VideoSettings::FLAG_ON_TOP_ALL);
390                     else
391                         fSettings->ClearFlags(VideoSettings::FLAG_ON_TOP_ALL);
392                 }
393             }
394             break;
395         case ASPECT_CORRECT:
396             SetCorrectAspectRatio(!CorrectAspectRatio());
397             break;
398
399         case B_KEY_DOWN:
400         case B_UNMAPPED_KEY_DOWN:
401         case B_KEY_UP:
402         case B_UNMAPPED_KEY_UP:
403         {
404             key_map * keys;
405             char    * chars;
406             int32     key, modifiers;
407
408             if( p_message->FindInt32( "key", &key ) != B_OK ||
409                 p_message->FindInt32( "modifiers", &modifiers ) != B_OK )
410             {
411                 /* Shouldn't happen */
412                 break;
413             }
414
415             if( ( p_message->what == B_KEY_UP ||
416                   p_message->what == B_UNMAPPED_KEY_UP ) &&
417                 !( modifiers & B_COMMAND_KEY ) )
418             {
419                 /* We only use the KEY_UP messages to detect Alt+X
420                    shortcuts (because the KEY_DOWN messages aren't
421                    sent when Alt is pressed) */
422                 break;
423             }
424
425             /* Special case for Alt+1, Alt+2 and Alt+3 shortcuts: since
426                the character depends on the keymap, we use the key codes
427                directly (18, 19, 20) */
428             if( ( modifiers & B_COMMAND_KEY ) &&
429                 key >= 18 && key <= 20 )
430             {
431                 if( key == 18 )
432                     PostMessage( RESIZE_50 );
433                 else if( key == 19 )
434                     PostMessage( RESIZE_100 );
435                 else
436                     PostMessage( RESIZE_200 );
437
438                 break;
439             }
440
441             /* Get the current keymap */
442             get_key_map( &keys, &chars );
443
444             if( key >= 128 || chars[keys->normal_map[key]] != 1 )
445             {
446                 /* Weird key or Unicode character */
447                 free( keys );
448                 free( chars );
449                 break;
450             }
451
452             vlc_value_t val;
453             val.i_int = ConvertKeyToVLC( chars[keys->normal_map[key]+1] );
454
455             if( modifiers & B_COMMAND_KEY )
456             {
457                 val.i_int |= KEY_MODIFIER_ALT;
458             }
459             if( modifiers & B_SHIFT_KEY )
460             {
461                 val.i_int |= KEY_MODIFIER_SHIFT;
462             }
463             if( modifiers & B_CONTROL_KEY )
464             {
465                 val.i_int |= KEY_MODIFIER_CTRL;
466             }
467             var_Set( p_vout->p_libvlc, "key-pressed", val );
468
469             free( keys );
470             free( chars );
471             break;
472         }
473
474         default:
475             BWindow::MessageReceived( p_message );
476             break;
477     }
478 }
479
480 /*****************************************************************************
481  * VideoWindow::Zoom
482  *****************************************************************************/
483 void
484 VideoWindow::Zoom(BPoint origin, float width, float height )
485 {
486     ToggleFullScreen();
487 }
488
489 /*****************************************************************************
490  * VideoWindow::FrameMoved
491  *****************************************************************************/
492 void
493 VideoWindow::FrameMoved(BPoint origin)
494 {
495     if (IsFullScreen())
496         return ;
497     winSize = Frame();
498 }
499
500 /*****************************************************************************
501  * VideoWindow::FrameResized
502  *****************************************************************************/
503 void
504 VideoWindow::FrameResized( float width, float height )
505 {
506     int32_t useWidth = CorrectAspectRatio() ? i_width : fTrueWidth;
507     int32_t useHeight = CorrectAspectRatio() ? i_height : fTrueHeight;
508     float out_width, out_height;
509     float out_left, out_top;
510     float width_scale = width / useWidth;
511     float height_scale = height / useHeight;
512
513     if (width_scale <= height_scale)
514     {
515         out_width = (useWidth * width_scale);
516         out_height = (useHeight * width_scale);
517         out_left = 0;
518         out_top = (height - out_height) / 2;
519     }
520     else   /* if the height is proportionally smaller */
521     {
522         out_width = (useWidth * height_scale);
523         out_height = (useHeight * height_scale);
524         out_top = 0;
525         out_left = (width - out_width) / 2;
526     }
527     view->MoveTo(out_left,out_top);
528     view->ResizeTo(out_width, out_height);
529
530     if (!IsFullScreen())
531         winSize = Frame();
532 }
533
534 /*****************************************************************************
535  * VideoWindow::ScreenChanged
536  *****************************************************************************/
537 void
538 VideoWindow::ScreenChanged(BRect frame, color_space format)
539 {
540     BScreen screen(this);
541     display_mode mode;
542     screen.GetMode(&mode);
543     float refresh = (mode.timing.pixel_clock * 1000)
544                     / ((mode.timing.h_total) * (mode.timing.v_total));
545     SetSyncToRetrace(refresh < MIN_AUTO_VSYNC_REFRESH);
546 }
547
548 /*****************************************************************************
549  * VideoWindow::Activate
550  *****************************************************************************/
551 void
552 VideoWindow::WindowActivated(bool active)
553 {
554 }
555
556 /*****************************************************************************
557  * VideoWindow::drawBuffer
558  *****************************************************************************/
559 void
560 VideoWindow::drawBuffer(int bufferIndex)
561 {
562     i_buffer = bufferIndex;
563
564     // sync to the screen if required
565     if (IsSyncedToRetrace())
566     {
567         BScreen screen(this);
568         screen.WaitForRetrace(22000);
569     }
570     if (fInitStatus >= B_OK && LockLooper())
571     {
572        // switch the overlay bitmap
573        if (mode == OVERLAY)
574        {
575           rgb_color key;
576           view->SetViewOverlay(bitmap[i_buffer],
577                             bitmap[i_buffer]->Bounds() ,
578                             view->Bounds(),
579                             &key, B_FOLLOW_ALL,
580                             B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
581                             B_OVERLAY_TRANSFER_CHANNEL);
582            view->SetViewColor(key);
583        }
584        else
585        {
586          // switch the bitmap
587          view->DrawBitmap(bitmap[i_buffer], view->Bounds() );
588        }
589        UnlockLooper();
590     }
591 }
592
593 /*****************************************************************************
594  * VideoWindow::SetInterfaceShowing
595  *****************************************************************************/
596 void
597 VideoWindow::ToggleInterfaceShowing()
598 {
599     SetInterfaceShowing(!fInterfaceShowing);
600 }
601
602 /*****************************************************************************
603  * VideoWindow::SetInterfaceShowing
604  *****************************************************************************/
605 void
606 VideoWindow::SetInterfaceShowing(bool showIt)
607 {
608     BWindow* window = get_interface_window();
609     if (window)
610     {
611         if (showIt)
612         {
613             if (fCachedFeel != B_NORMAL_WINDOW_FEEL)
614                 SetFeel(B_NORMAL_WINDOW_FEEL);
615             window->Activate(true);
616             SendBehind(window);
617         }
618         else
619         {
620             SetFeel(fCachedFeel);
621             Activate(true);
622             window->SendBehind(this);
623         }
624         fInterfaceShowing = showIt;
625     }
626 }
627
628 /*****************************************************************************
629  * VideoWindow::SetCorrectAspectRatio
630  *****************************************************************************/
631 void
632 VideoWindow::SetCorrectAspectRatio(bool doIt)
633 {
634     if (CorrectAspectRatio() != doIt)
635     {
636         if (doIt)
637             fSettings->AddFlags(VideoSettings::FLAG_CORRECT_RATIO);
638         else
639             fSettings->ClearFlags(VideoSettings::FLAG_CORRECT_RATIO);
640         FrameResized(Bounds().Width(), Bounds().Height());
641     }
642 }
643
644 /*****************************************************************************
645  * VideoWindow::CorrectAspectRatio
646  *****************************************************************************/
647 bool
648 VideoWindow::CorrectAspectRatio() const
649 {
650     return fSettings->HasFlags(VideoSettings::FLAG_CORRECT_RATIO);
651 }
652
653 /*****************************************************************************
654  * VideoWindow::ToggleFullScreen
655  *****************************************************************************/
656 void
657 VideoWindow::ToggleFullScreen()
658 {
659     SetFullScreen(!IsFullScreen());
660 }
661
662 /*****************************************************************************
663  * VideoWindow::SetFullScreen
664  *****************************************************************************/
665 void
666 VideoWindow::SetFullScreen(bool doIt)
667 {
668     if (doIt)
669     {
670         SetLook( B_NO_BORDER_WINDOW_LOOK );
671         BScreen screen( this );
672         BRect rect = screen.Frame();
673         Activate();
674         MoveTo(0.0, 0.0);
675         ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
676         be_app->ObscureCursor();
677         fInterfaceShowing = false;
678         fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
679     }
680     else
681     {
682         SetLook( B_TITLED_WINDOW_LOOK );
683         MoveTo(winSize.left, winSize.top);
684         ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
685         be_app->ShowCursor();
686         fInterfaceShowing = true;
687         fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
688     }
689 }
690
691 /*****************************************************************************
692  * VideoWindow::IsFullScreen
693  *****************************************************************************/
694 bool
695 VideoWindow::IsFullScreen() const
696 {
697     return fSettings->HasFlags(VideoSettings::FLAG_FULL_SCREEN);
698 }
699
700 /*****************************************************************************
701  * VideoWindow::SetSyncToRetrace
702  *****************************************************************************/
703 void
704 VideoWindow::SetSyncToRetrace(bool doIt)
705 {
706     if (doIt)
707         fSettings->AddFlags(VideoSettings::FLAG_SYNC_RETRACE);
708     else
709         fSettings->ClearFlags(VideoSettings::FLAG_SYNC_RETRACE);
710 }
711
712 /*****************************************************************************
713  * VideoWindow::IsSyncedToRetrace
714  *****************************************************************************/
715 bool
716 VideoWindow::IsSyncedToRetrace() const
717 {
718     return fSettings->HasFlags(VideoSettings::FLAG_SYNC_RETRACE);
719 }
720
721
722 /*****************************************************************************
723  * VideoWindow::_AllocateBuffers
724  *****************************************************************************/
725 status_t
726 VideoWindow::_AllocateBuffers(int width, int height, int* mode)
727 {
728     // clear any old buffers
729     _FreeBuffers();
730     // set default mode
731     *mode = BITMAP;
732     bitmap_count = 3;
733
734     BRect bitmapFrame( 0, 0, width, height );
735     // read from config, if we are supposed to use overlay at all
736     int noOverlay = !config_GetInt( p_vout, "overlay" );
737
738     /* Test for overlay capability: for every chroma in colspace,
739        we try to do double-buffered overlay, single-buffered overlay
740        or basic overlay. If nothing worked, we then have to work with
741        a non-overlay BBitmap. */
742     for( int i = 0; i < COLOR_COUNT; i++ )
743     {
744         if( noOverlay )
745             break;
746
747         bitmap[0] = new BBitmap( bitmapFrame,
748                                  B_BITMAP_WILL_OVERLAY |
749                                  B_BITMAP_RESERVE_OVERLAY_CHANNEL,
750                                  colspace[i].colspace );
751         if( bitmap[0] && bitmap[0]->InitCheck() == B_OK )
752         {
753             colspace_index = i;
754
755             *mode = OVERLAY;
756             rgb_color key;
757             view->SetViewOverlay( bitmap[0], bitmap[0]->Bounds(),
758                                   view->Bounds(), &key, B_FOLLOW_ALL,
759                                   B_OVERLAY_FILTER_HORIZONTAL |
760                                   B_OVERLAY_FILTER_VERTICAL );
761             view->SetViewColor( key );
762             SetTitle( "VLC " PACKAGE_VERSION " (Overlay)" );
763
764             bitmap[1] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
765                                      colspace[colspace_index].colspace);
766             if( bitmap[1] && bitmap[1]->InitCheck() == B_OK )
767             {
768
769                 bitmap[2] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
770                                          colspace[colspace_index].colspace);
771                 if( bitmap[2] && bitmap[2]->InitCheck() == B_OK )
772                 {
773                     msg_Dbg( p_vout, "using double-buffered overlay" );
774                 }
775                 else
776                 {
777                     msg_Dbg( p_vout, "using single-buffered overlay" );
778                     bitmap_count = 2;
779                     delete bitmap[2]; bitmap[2] = NULL;
780                 }
781             }
782             else
783             {
784                 msg_Dbg( p_vout, "using simple overlay" );
785                 bitmap_count = 1;
786                 delete bitmap[1]; bitmap[1] = NULL;
787             }
788             break;
789         }
790         else
791         {
792             delete bitmap[0]; bitmap[0] = NULL;
793         }
794     }
795
796     if (*mode == BITMAP)
797     {
798         msg_Warn( p_vout, "no possible overlay" );
799
800         // fallback to RGB
801         colspace_index = DEFAULT_COL;    // B_RGB32
802         bitmap[0] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
803         bitmap[1] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
804         bitmap[2] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
805         SetTitle( "VLC " PACKAGE_VERSION " (Bitmap)" );
806     }
807     // see if everything went well
808     status_t status = B_ERROR;
809     for (int32_t i = 0; i < bitmap_count; i++)
810     {
811         if (bitmap[i])
812             status = bitmap[i]->InitCheck();
813         if (status < B_OK)
814             break;
815     }
816     if (status >= B_OK)
817     {
818         // clear bitmaps to black
819         for (int32_t i = 0; i < bitmap_count; i++)
820             _BlankBitmap(bitmap[i]);
821     }
822     return status;
823 }
824
825 /*****************************************************************************
826  * VideoWindow::_FreeBuffers
827  *****************************************************************************/
828 void
829 VideoWindow::_FreeBuffers()
830 {
831     delete bitmap[0]; bitmap[0] = NULL;
832     delete bitmap[1]; bitmap[1] = NULL;
833     delete bitmap[2]; bitmap[2] = NULL;
834     fInitStatus = B_ERROR;
835 }
836
837 /*****************************************************************************
838  * VideoWindow::_BlankBitmap
839  *****************************************************************************/
840 void
841 VideoWindow::_BlankBitmap(BBitmap* bitmap) const
842 {
843     // no error checking (we do that earlier on and since it's a private function...
844
845     // YCbCr:
846     // Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128)
847
848     // YUV:
849     // Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128)
850
851     // we only handle weird colorspaces with special care
852     switch (bitmap->ColorSpace()) {
853         case B_YCbCr422: {
854             // Y0[7:0]  Cb0[7:0]  Y1[7:0]  Cr0[7:0]  Y2[7:0]  Cb2[7:0]  Y3[7:0]  Cr2[7:0]
855             int32_t height = bitmap->Bounds().IntegerHeight() + 1;
856             uint8_t* bits = (uint8_t*)bitmap->Bits();
857             int32_t bpr = bitmap->BytesPerRow();
858             for (int32_t y = 0; y < height; y++) {
859                 // handle 2 bytes at a time
860                 for (int32_t i = 0; i < bpr; i += 2) {
861                     // offset into line
862                     bits[i] = 16;
863                     bits[i + 1] = 128;
864                 }
865                 // next line
866                 bits += bpr;
867             }
868             break;
869         }
870         case B_YCbCr420: {
871 // TODO: untested!!
872             // Non-interlaced only, Cb0  Y0  Y1  Cb2 Y2  Y3  on even scan lines ...
873             // Cr0  Y0  Y1  Cr2 Y2  Y3  on odd scan lines
874             int32_t height = bitmap->Bounds().IntegerHeight() + 1;
875             uint8_t* bits = (uint8_t*)bitmap->Bits();
876             int32_t bpr = bitmap->BytesPerRow();
877             for (int32_t y = 0; y < height; y += 1) {
878                 // handle 3 bytes at a time
879                 for (int32_t i = 0; i < bpr; i += 3) {
880                     // offset into line
881                     bits[i] = 128;
882                     bits[i + 1] = 16;
883                     bits[i + 2] = 16;
884                 }
885                 // next line
886                 bits += bpr;
887             }
888             break;
889         }
890         case B_YUV422: {
891 // TODO: untested!!
892             // U0[7:0]  Y0[7:0]   V0[7:0]  Y1[7:0]  U2[7:0]  Y2[7:0]   V2[7:0]  Y3[7:0]
893             int32_t height = bitmap->Bounds().IntegerHeight() + 1;
894             uint8_t* bits = (uint8_t*)bitmap->Bits();
895             int32_t bpr = bitmap->BytesPerRow();
896             for (int32_t y = 0; y < height; y += 1) {
897                 // handle 2 bytes at a time
898                 for (int32_t i = 0; i < bpr; i += 2) {
899                     // offset into line
900                     bits[i] = 128;
901                     bits[i + 1] = 0;
902                 }
903                 // next line
904                 bits += bpr;
905             }
906             break;
907         }
908         default:
909             memset(bitmap->Bits(), 0, bitmap->BitsLength());
910             break;
911     }
912 }
913
914 /*****************************************************************************
915  * VideoWindow::_SetVideoSize
916  *****************************************************************************/
917 void
918 VideoWindow::_SetVideoSize(uint32_t mode)
919 {
920     // let size depend on aspect correction
921     int32_t width = CorrectAspectRatio() ? i_width : fTrueWidth;
922     int32_t height = CorrectAspectRatio() ? i_height : fTrueHeight;
923     switch (mode)
924     {
925         case RESIZE_50:
926             width /= 2;
927             height /= 2;
928             break;
929         case RESIZE_200:
930             width *= 2;
931             height *= 2;
932             break;
933         case RESIZE_100:
934         default:
935             break;
936     }
937     fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
938     ResizeTo(width, height);
939 }
940
941 /*****************************************************************************
942  * VideoWindow::_SetToSettings
943  *****************************************************************************/
944 void
945 VideoWindow::_SetToSettings()
946 {
947     // adjust dimensions
948     uint32_t mode = RESIZE_100;
949     switch (fSettings->VideoSize())
950     {
951         case VideoSettings::SIZE_50:
952             mode = RESIZE_50;
953             break;
954         case VideoSettings::SIZE_200:
955             mode = RESIZE_200;
956             break;
957         case VideoSettings::SIZE_100:
958         case VideoSettings::SIZE_OTHER:
959         default:
960             break;
961     }
962     bool fullscreen = IsFullScreen();    // remember settings
963     _SetVideoSize(mode);                // because this will reset settings
964     // the fullscreen status is reflected in the settings,
965     // but not yet in the windows state
966     if (fullscreen)
967         SetFullScreen(true);
968     if (fSettings->HasFlags(VideoSettings::FLAG_ON_TOP_ALL))
969         fCachedFeel = B_FLOATING_ALL_WINDOW_FEEL;
970     else
971         fCachedFeel = B_NORMAL_WINDOW_FEEL;
972     SetFeel(fCachedFeel);
973 }
974
975 /*****************************************************************************
976  * VLCView::VLCView
977  *****************************************************************************/
978 VLCView::VLCView(BRect bounds, vout_thread_t *p_vout_instance )
979     : BView(bounds, "video view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED),
980       fLastMouseMovedTime(mdate()),
981       fCursorHidden(false),
982       fCursorInside(false),
983       fIgnoreDoubleClick(false)
984 {
985     p_vout = p_vout_instance;
986     fMouseHideTimeout = var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
987     SetViewColor(B_TRANSPARENT_32_BIT);
988 }
989
990 /*****************************************************************************
991  * VLCView::~VLCView
992  *****************************************************************************/
993 VLCView::~VLCView()
994 {
995 }
996
997 /*****************************************************************************
998  * VLCVIew::AttachedToWindow
999  *****************************************************************************/
1000 void
1001 VLCView::AttachedToWindow()
1002 {
1003     // periodically check if we want to hide the pointer
1004     Window()->SetPulseRate(1000000);
1005 }
1006
1007 /*****************************************************************************
1008  * VLCVIew::MouseDown
1009  *****************************************************************************/
1010 void
1011 VLCView::MouseDown(BPoint where)
1012 {
1013     VideoWindow* videoWindow = dynamic_cast<VideoWindow*>(Window());
1014     BMessage* msg = Window()->CurrentMessage();
1015     int32 clicks;
1016     uint32_t buttons;
1017     msg->FindInt32("clicks", &clicks);
1018     msg->FindInt32("buttons", (int32*)&buttons);
1019
1020     if (videoWindow)
1021     {
1022         if (buttons & B_PRIMARY_MOUSE_BUTTON)
1023         {
1024             if (clicks == 2 && !fIgnoreDoubleClick)
1025                 Window()->Zoom();
1026             /* else
1027                 videoWindow->ToggleInterfaceShowing(); */
1028             fIgnoreDoubleClick = false;
1029         }
1030         else
1031         {
1032             if (buttons & B_SECONDARY_MOUSE_BUTTON)
1033             {
1034                 // clicks will be 2 next time (if interval short enough)
1035                 // even if the first click and the second
1036                 // have not been made with the same mouse button
1037                 fIgnoreDoubleClick = true;
1038                 // launch popup menu
1039                 BPopUpMenu *menu = new BPopUpMenu("context menu");
1040                 menu->SetRadioMode(false);
1041                 // In full screen, add an item to show/hide the interface
1042                 if( videoWindow->IsFullScreen() )
1043                 {
1044                     BMenuItem *intfItem =
1045                         new BMenuItem( _("Show Interface"), new BMessage(SHOW_INTERFACE) );
1046                     menu->AddItem( intfItem );
1047                 }
1048                 // Resize to 50%
1049                 BMenuItem *halfItem = new BMenuItem(_("50%"), new BMessage(RESIZE_50));
1050                 menu->AddItem(halfItem);
1051                 // Resize to 100%
1052                 BMenuItem *origItem = new BMenuItem(_("100%"), new BMessage(RESIZE_100));
1053                 menu->AddItem(origItem);
1054                 // Resize to 200%
1055                 BMenuItem *doubleItem = new BMenuItem(_("200%"), new BMessage(RESIZE_200));
1056                 menu->AddItem(doubleItem);
1057                 // Toggle FullScreen
1058                 BMenuItem *zoomItem = new BMenuItem(_("Fullscreen"), new BMessage(TOGGLE_FULL_SCREEN));
1059                 zoomItem->SetMarked(videoWindow->IsFullScreen());
1060                 menu->AddItem(zoomItem);
1061  
1062                 menu->AddSeparatorItem();
1063  
1064                 // Toggle vSync
1065                 BMenuItem *vsyncItem = new BMenuItem(_("Vertical Sync"), new BMessage(VERT_SYNC));
1066                 vsyncItem->SetMarked(videoWindow->IsSyncedToRetrace());
1067                 menu->AddItem(vsyncItem);
1068                 // Correct Aspect Ratio
1069                 BMenuItem *aspectItem = new BMenuItem(_("Correct Aspect Ratio"), new BMessage(ASPECT_CORRECT));
1070                 aspectItem->SetMarked(videoWindow->CorrectAspectRatio());
1071                 menu->AddItem(aspectItem);
1072  
1073                 menu->AddSeparatorItem();
1074  
1075                 // Window Feel Items
1076 /*                BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
1077                 winNormFeel->AddInt32("WinFeel", (int32_t)B_NORMAL_WINDOW_FEEL);
1078                 BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
1079                 normWindItem->SetMarked(videoWindow->Feel() == B_NORMAL_WINDOW_FEEL);
1080                 menu->AddItem(normWindItem);
1081  
1082                 BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
1083                 winFloatFeel->AddInt32("WinFeel", (int32_t)B_FLOATING_APP_WINDOW_FEEL);
1084                 BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
1085                 onTopWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
1086                 menu->AddItem(onTopWindItem);
1087  
1088                 BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
1089                 winAllFeel->AddInt32("WinFeel", (int32_t)B_FLOATING_ALL_WINDOW_FEEL);
1090                 BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
1091                 allSpacesWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
1092                 menu->AddItem(allSpacesWindItem);*/
1093
1094                 BMessage *windowFeelMsg = new BMessage( WINDOW_FEEL );
1095                 bool onTop = videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
1096                 window_feel feel = onTop ? B_NORMAL_WINDOW_FEEL : B_FLOATING_ALL_WINDOW_FEEL;
1097                 windowFeelMsg->AddInt32( "WinFeel", (int32_t)feel );
1098                 BMenuItem *windowFeelItem = new BMenuItem( _("Stay On Top"), windowFeelMsg );
1099                 windowFeelItem->SetMarked( onTop );
1100                 menu->AddItem( windowFeelItem );
1101
1102                 menu->AddSeparatorItem();
1103
1104                 BMenuItem* screenShotItem = new BMenuItem( _("Take Screen Shot"),
1105                                                            new BMessage( SCREEN_SHOT ) );
1106                 menu->AddItem( screenShotItem );
1107
1108                 menu->SetTargetForItems( this );
1109                 ConvertToScreen( &where );
1110                 BRect mouseRect( where.x - 5, where.y - 5,
1111                                  where.x + 5, where.y + 5 );
1112                 menu->Go( where, true, false, mouseRect, true );
1113             }
1114         }
1115     }
1116     fLastMouseMovedTime = mdate();
1117     fCursorHidden = false;
1118 }
1119
1120 /*****************************************************************************
1121  * VLCVIew::MouseUp
1122  *****************************************************************************/
1123 void
1124 VLCView::MouseUp( BPoint where )
1125 {
1126     vlc_value_t val;
1127     val.b_bool = true;
1128     var_Set( p_vout, "mouse-clicked", val );
1129 }
1130
1131 /*****************************************************************************
1132  * VLCVIew::MouseMoved
1133  *****************************************************************************/
1134 void
1135 VLCView::MouseMoved(BPoint point, uint32 transit, const BMessage* dragMessage)
1136 {
1137     fLastMouseMovedTime = mdate();
1138     fCursorHidden = false;
1139     fCursorInside = ( transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW );
1140
1141     if( !fCursorInside )
1142     {
1143         return;
1144     }
1145
1146     vlc_value_t val;
1147     unsigned int i_width, i_height, i_x, i_y;
1148     vout_PlacePicture( p_vout, (unsigned int)Bounds().Width(),
1149                        (unsigned int)Bounds().Height(),
1150                        &i_x, &i_y, &i_width, &i_height );
1151     val.i_int = ( (int)point.x - i_x ) * p_vout->render.i_width / i_width;
1152     var_Set( p_vout, "mouse-x", val );
1153     val.i_int = ( (int)point.y - i_y ) * p_vout->render.i_height / i_height;
1154     var_Set( p_vout, "mouse-y", val );
1155     val.b_bool = true;
1156     var_Set( p_vout, "mouse-moved", val );
1157 }
1158
1159 /*****************************************************************************
1160  * VLCVIew::Pulse
1161  *****************************************************************************/
1162 void
1163 VLCView::Pulse()
1164 {
1165     // We are getting the pulse messages no matter if the mouse is over
1166     // this view. If we are in full screen mode, we want to hide the cursor
1167     // even if it is not.
1168     VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1169     if (!fCursorHidden)
1170     {
1171         if (fCursorInside
1172             && mdate() - fLastMouseMovedTime > fMouseHideTimeout)
1173         {
1174             be_app->ObscureCursor();
1175             fCursorHidden = true;
1176  
1177             // hide the interface window as well if full screen
1178             if (videoWindow && videoWindow->IsFullScreen())
1179                 videoWindow->SetInterfaceShowing(false);
1180         }
1181     }
1182
1183     // Workaround to disable the screensaver in full screen:
1184     // we simulate an activity every 29 seconds
1185     if( videoWindow && videoWindow->IsFullScreen() &&
1186         mdate() - fLastMouseMovedTime > 29000000 )
1187     {
1188         BPoint where;
1189         uint32 buttons;
1190         GetMouse(&where, &buttons, false);
1191         ConvertToScreen(&where);
1192         set_mouse_position((int32_t) where.x, (int32_t) where.y);
1193     }
1194 }
1195
1196 /*****************************************************************************
1197  * VLCVIew::Draw
1198  *****************************************************************************/
1199 void
1200 VLCView::Draw(BRect updateRect)
1201 {
1202     VideoWindow* window = dynamic_cast<VideoWindow*>( Window() );
1203     if ( window && window->mode == BITMAP )
1204         FillRect( updateRect );
1205 }
1206
1207 /*****************************************************************************
1208  * Local prototypes
1209  *****************************************************************************/
1210 static int  Init       ( vout_thread_t * );
1211 static void End        ( vout_thread_t * );
1212 static int  Manage     ( vout_thread_t * );
1213 static void Display    ( vout_thread_t *, picture_t * );
1214 static int  Control    ( vout_thread_t *, int, va_list );
1215
1216 static int  BeosOpenDisplay ( vout_thread_t *p_vout );
1217 static void BeosCloseDisplay( vout_thread_t *p_vout );
1218
1219 /*****************************************************************************
1220  * OpenVideo: allocates BeOS video thread output method
1221  *****************************************************************************
1222  * This function allocates and initializes a BeOS vout method.
1223  *****************************************************************************/
1224 int OpenVideo ( vlc_object_t *p_this )
1225 {
1226     vout_thread_t * p_vout = (vout_thread_t *)p_this;
1227
1228     /* Allocate structure */
1229     p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
1230     if( p_vout->p_sys == NULL )
1231     {
1232         msg_Err( p_vout, "out of memory" );
1233         return( 1 );
1234     }
1235     p_vout->p_sys->i_width = p_vout->render.i_width;
1236     p_vout->p_sys->i_height = p_vout->render.i_height;
1237     p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
1238
1239     p_vout->pf_init = Init;
1240     p_vout->pf_end = End;
1241     p_vout->pf_manage = Manage;
1242     p_vout->pf_render = NULL;
1243     p_vout->pf_display = Display;
1244     p_vout->pf_control = Control;
1245
1246     return( 0 );
1247 }
1248
1249 /*****************************************************************************
1250  * Init: initialize BeOS video thread output method
1251  *****************************************************************************/
1252 int Init( vout_thread_t *p_vout )
1253 {
1254     int i_index;
1255     picture_t *p_pic;
1256
1257     I_OUTPUTPICTURES = 0;
1258
1259     /* Open and initialize device */
1260     if( BeosOpenDisplay( p_vout ) )
1261     {
1262         msg_Err(p_vout, "vout error: can't open display");
1263         return 0;
1264     }
1265     p_vout->output.i_width  = p_vout->render.i_width;
1266     p_vout->output.i_height = p_vout->render.i_height;
1267
1268     /* Assume we have square pixels */
1269     p_vout->output.i_aspect = p_vout->p_sys->i_width
1270                                * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
1271     p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
1272     p_vout->p_sys->i_index = 0;
1273
1274     p_vout->b_direct = 1;
1275
1276     p_vout->output.i_rmask  = 0x00ff0000;
1277     p_vout->output.i_gmask  = 0x0000ff00;
1278     p_vout->output.i_bmask  = 0x000000ff;
1279
1280     for( int buffer_index = 0 ;
1281          buffer_index < p_vout->p_sys->p_window->bitmap_count;
1282          buffer_index++ )
1283     {
1284        p_pic = NULL;
1285        /* Find an empty picture slot */
1286        for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
1287        {
1288            p_pic = NULL;
1289            if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
1290            {
1291                p_pic = p_vout->p_picture + i_index;
1292                break;
1293            }
1294        }
1295
1296        if( p_pic == NULL )
1297        {
1298            return 0;
1299        }
1300        p_pic->p->p_pixels = (uint8_t*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
1301        p_pic->p->i_lines = p_vout->p_sys->i_height;
1302        p_pic->p->i_visible_lines = p_vout->p_sys->i_height;
1303
1304        p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
1305        p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
1306        p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow();
1307        p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 );
1308
1309        p_pic->i_status = DESTROYED_PICTURE;
1310        p_pic->i_type   = DIRECT_PICTURE;
1311
1312        PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
1313
1314        I_OUTPUTPICTURES++;
1315     }
1316
1317     return( 0 );
1318 }
1319
1320 /*****************************************************************************
1321  * End: terminate BeOS video thread output method
1322  *****************************************************************************/
1323 void End( vout_thread_t *p_vout )
1324 {
1325     BeosCloseDisplay( p_vout );
1326 }
1327
1328 /*****************************************************************************
1329  * Manage
1330  *****************************************************************************/
1331 static int Manage( vout_thread_t * p_vout )
1332 {
1333     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
1334     {
1335         p_vout->p_sys->p_window->PostMessage( TOGGLE_FULL_SCREEN );
1336         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
1337     }
1338
1339     return 0;
1340 }
1341
1342 /*****************************************************************************
1343  * CloseVideo: destroy BeOS video thread output method
1344  *****************************************************************************
1345  * Terminate an output method created by DummyCreateOutputMethod
1346  *****************************************************************************/
1347 void CloseVideo ( vlc_object_t *p_this )
1348 {
1349     vout_thread_t * p_vout = (vout_thread_t *)p_this;
1350
1351     free( p_vout->p_sys );
1352 }
1353
1354 /*****************************************************************************
1355  * Display: displays previously rendered output
1356  *****************************************************************************
1357  * This function send the currently rendered image to BeOS image, waits until
1358  * it is displayed and switch the two rendering buffers, preparing next frame.
1359  *****************************************************************************/
1360 void Display( vout_thread_t *p_vout, picture_t *p_pic )
1361 {
1362     VideoWindow * p_win = p_vout->p_sys->p_window;
1363
1364     /* draw buffer if required */
1365     if (!p_win->teardownwindow)
1366     {
1367        p_win->drawBuffer(p_vout->p_sys->i_index);
1368     }
1369     /* change buffer */
1370     p_vout->p_sys->i_index = ++p_vout->p_sys->i_index %
1371         p_vout->p_sys->p_window->bitmap_count;
1372     p_pic->p->p_pixels = (uint8_t*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
1373 }
1374
1375 static int Control( vout_thread_t * p_vout, int i_query, va_list args )
1376 {
1377     return vout_vaControlDefault( p_vout, i_query, args );
1378 }
1379
1380 /* following functions are local */
1381
1382 /*****************************************************************************
1383  * BeosOpenDisplay: open and initialize BeOS device
1384  *****************************************************************************/
1385 static int BeosOpenDisplay( vout_thread_t *p_vout )
1386 {
1387
1388     p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
1389                                                p_vout->p_sys->i_height - 1,
1390                                                BRect( 20, 50,
1391                                                       20 + p_vout->i_window_width - 1,
1392                                                       50 + p_vout->i_window_height - 1 ),
1393                                                p_vout );
1394     if( p_vout->p_sys->p_window == NULL )
1395     {
1396         msg_Err( p_vout, "cannot allocate VideoWindow" );
1397         return( 1 );
1398     }
1399     else
1400     {
1401         p_vout->p_sys->p_window->Show();
1402     }
1403
1404     return( 0 );
1405 }
1406
1407 /*****************************************************************************
1408  * BeosDisplay: close and reset BeOS device
1409  *****************************************************************************
1410  * Returns all resources allocated by BeosOpenDisplay and restore the original
1411  * state of the device.
1412  *****************************************************************************/
1413 static void BeosCloseDisplay( vout_thread_t *p_vout )
1414 {
1415     VideoWindow * p_win = p_vout->p_sys->p_window;
1416     /* Destroy the video window */
1417     if( p_win != NULL && !p_win->teardownwindow)
1418     {
1419         p_win->Lock();
1420         p_win->teardownwindow = true;
1421         p_win->Hide();
1422         p_win->Quit();
1423     }
1424     p_win = NULL;
1425 }