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