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