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