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