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