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