1 /*****************************************************************************
2 * vout_beos.cpp: beos video output display method
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: VideoOutput.cpp,v 1.20 2003/06/03 12:06:29 titer Exp $
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>
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.
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.
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 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #include <errno.h> /* ENOMEM */
32 #include <stdlib.h> /* free() */
34 #include <string.h> /* strerror() */
36 #include <Application.h>
37 #include <BitmapStream.h>
39 #include <Directory.h>
40 #include <DirectWindow.h>
42 #include <InterfaceKit.h>
45 #include <TranslatorRoster.h>
46 #include <WindowScreen.h>
53 #include "InterfaceWindow.h" // for load/save_settings()
54 #include "DrawingTidbits.h"
57 #include "VideoWindow.h"
59 /*****************************************************************************
60 * vout_sys_t: BeOS video output method descriptor
61 *****************************************************************************
62 * This structure is part of the video output thread descriptor.
63 * It describes the BeOS specific properties of an output thread.
64 *****************************************************************************/
67 VideoWindow * p_window;
78 #define MOUSE_IDLE_TIMEOUT 2000000 // two seconds
79 #define MIN_AUTO_VSYNC_REFRESH 61 // Hz
80 #define DEFAULT_SCREEN_SHOT_FORMAT 'PNG '
81 #define DEFAULT_SCREEN_SHOT_PATH "/boot/home/vlc screenshot"
83 /*****************************************************************************
84 * beos_GetAppWindow : retrieve a BWindow pointer from the window name
85 *****************************************************************************/
87 beos_GetAppWindow(char *name)
92 for (index = 0 ; ; index++)
94 window = be_app->WindowAt(index);
97 if (window->LockWithTimeout(20000) == B_OK)
99 if (strcmp(window->Name(), name) == 0)
110 /*****************************************************************************
111 * get_interface_window
112 *****************************************************************************/
114 get_interface_window()
116 return beos_GetAppWindow( "VLC " PACKAGE_VERSION );
119 class BackgroundView : public BView
122 BackgroundView(BRect frame, VLCView* view)
123 : BView(frame, "background",
124 B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE),
127 SetViewColor(kBlack);
129 virtual ~BackgroundView() {}
131 virtual void MouseDown(BPoint where)
133 // convert coordinates
134 where = fVideoView->ConvertFromParent(where);
136 fVideoView->MouseDown(where);
138 virtual void MouseMoved(BPoint where, uint32 transit,
139 const BMessage* dragMessage)
141 // convert coordinates
142 where = fVideoView->ConvertFromParent(where);
144 fVideoView->MouseMoved(where, transit, dragMessage);
145 // notice: It might look like transit should be
146 // B_OUTSIDE_VIEW regardless, but leave it like this,
147 // otherwise, unwanted things will happen!
155 /*****************************************************************************
156 * VideoSettings constructor and destructor
157 *****************************************************************************/
158 VideoSettings::VideoSettings()
159 : fVideoSize( SIZE_100 ),
160 fFlags( FLAG_CORRECT_RATIO ),
161 fSettings( new BMessage( 'sett' ) )
163 // read settings from disk
164 status_t ret = load_settings( fSettings, "video_settings", "VideoLAN Client" );
168 if ( fSettings->FindInt32( "flags", (int32*)&flags ) == B_OK )
171 if ( fSettings->FindInt32( "video size", (int32*)&size ) == B_OK )
172 SetVideoSize( size );
176 fprintf( stderr, "error loading video settings: %s\n", strerror( ret ) );
178 // figure out if we should use vertical sync by default
179 BScreen screen(B_MAIN_SCREEN_ID);
180 if (screen.IsValid())
183 screen.GetMode(&mode);
184 float refresh = (mode.timing.pixel_clock * 1000)
185 / ((mode.timing.h_total)* (mode.timing.v_total));
186 if (refresh < MIN_AUTO_VSYNC_REFRESH)
187 AddFlags(FLAG_SYNC_RETRACE);
192 VideoSettings::VideoSettings( const VideoSettings& clone )
193 : fVideoSize( clone.VideoSize() ),
194 fFlags( clone.Flags() ),
200 VideoSettings::~VideoSettings()
204 // we are the default settings
205 // and write our settings to disk
206 if (fSettings->ReplaceInt32( "video size", VideoSize() ) != B_OK)
207 fSettings->AddInt32( "video size", VideoSize() );
208 if (fSettings->ReplaceInt32( "flags", Flags() ) != B_OK)
209 fSettings->AddInt32( "flags", Flags() );
211 status_t ret = save_settings( fSettings, "video_settings", "VideoLAN Client" );
213 fprintf( stderr, "error saving video settings: %s\n", strerror( ret ) );
218 // we are just a clone of the default settings
219 fDefaultSettings.SetVideoSize( VideoSize() );
220 fDefaultSettings.SetFlags( Flags() );
224 /*****************************************************************************
225 * VideoSettings::DefaultSettings
226 *****************************************************************************/
228 VideoSettings::DefaultSettings()
230 return &fDefaultSettings;
233 /*****************************************************************************
234 * VideoSettings::SetVideoSize
235 *****************************************************************************/
237 VideoSettings::SetVideoSize( uint32 mode )
242 // static variable initialization
244 VideoSettings::fDefaultSettings;
247 /*****************************************************************************
248 * VideoWindow constructor and destructor
249 *****************************************************************************/
250 VideoWindow::VideoWindow(int v_width, int v_height, BRect frame,
251 vout_thread_t *p_videoout)
252 : BWindow(frame, NULL, B_TITLED_WINDOW, B_NOT_CLOSABLE | B_NOT_MINIMIZABLE),
253 i_width(frame.IntegerWidth()),
254 i_height(frame.IntegerHeight()),
257 teardownwindow(false),
259 fTrueHeight(v_height),
260 fCachedFeel(B_NORMAL_WINDOW_FEEL),
261 fInterfaceShowing(false),
262 fInitStatus(B_ERROR),
263 fSettings(new VideoSettings(*VideoSettings::DefaultSettings()))
267 // create the view to do the display
268 view = new VLCView( Bounds(), p_vout );
270 // create background view
271 BView *mainView = new BackgroundView( Bounds(), view );
273 mainView->AddChild(view);
275 // allocate bitmap buffers
276 for (int32 i = 0; i < 3; i++)
278 fInitStatus = _AllocateBuffers(v_width, v_height, &mode);
280 // make sure we layout the view correctly
281 FrameResized(i_width, i_height);
283 if (fInitStatus >= B_OK && mode == OVERLAY)
285 overlay_restrictions r;
287 bitmap[1]->GetOverlayRestrictions(&r);
288 SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
289 (i_height * r.min_height_scale), i_height * r.max_height_scale);
292 // vlc settings override settings from disk
293 if (config_GetInt(p_vout, "fullscreen"))
294 fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
296 // add a few useful shortcuts
297 AddShortcut( 'f', 0, new BMessage( TOGGLE_FULL_SCREEN ) );
298 AddShortcut( '1', 0, new BMessage( RESIZE_50 ) );
299 AddShortcut( '2', 0, new BMessage( RESIZE_100 ) );
300 AddShortcut( '3', 0, new BMessage( RESIZE_200 ) );
302 // workaround for french keyboards
303 AddShortcut( '&', 0, new BMessage( RESIZE_50 ) );
304 AddShortcut( 'é', 0, new BMessage( RESIZE_100 ) );
305 // FIXME - this one doesn't work because 'é' is a multi-byte character
306 AddShortcut( '"', 0, new BMessage( RESIZE_200 ) );
311 VideoWindow::~VideoWindow()
315 teardownwindow = true;
316 wait_for_thread(fDrawThreadID, &result);
321 /*****************************************************************************
322 * VideoWindow::MessageReceived
323 *****************************************************************************/
325 VideoWindow::MessageReceived( BMessage *p_message )
327 switch( p_message->what )
330 SetInterfaceShowing( true );
332 case TOGGLE_FULL_SCREEN:
340 _SetVideoSize(p_message->what);
343 SetSyncToRetrace(!IsSyncedToRetrace());
348 if (p_message->FindInt32("WinFeel", (int32*)&winFeel) == B_OK)
351 fCachedFeel = winFeel;
352 if (winFeel == B_FLOATING_ALL_WINDOW_FEEL)
353 fSettings->AddFlags(VideoSettings::FLAG_ON_TOP_ALL);
355 fSettings->ClearFlags(VideoSettings::FLAG_ON_TOP_ALL);
360 SetCorrectAspectRatio(!CorrectAspectRatio());
363 // save a screen shot
364 if ( BBitmap* current = bitmap[i_buffer] )
366 // the following line might be tempting, but does not work for some overlay bitmaps!!!
367 // BBitmap* temp = new BBitmap( current );
368 // so we clone the bitmap ourselves
369 // however, we need to take care of potentially different padding!
370 // memcpy() is slow when reading from grafix memory, but what the heck...
371 BBitmap* temp = new BBitmap( current->Bounds(), current->ColorSpace() );
372 if ( temp && temp->IsValid() )
374 int32 height = (int32)current->Bounds().Height();
375 uint8* dst = (uint8*)temp->Bits();
376 uint8* src = (uint8*)current->Bits();
377 int32 dstBpr = temp->BytesPerRow();
378 int32 srcBpr = current->BytesPerRow();
379 int32 validBytes = dstBpr > srcBpr ? srcBpr : dstBpr;
380 for ( int32 y = 0; y < height; y++ )
382 memcpy( dst, src, validBytes );
386 char * path = config_GetPsz( p_vout, "beos-screenshotpath" );
388 path = strdup( DEFAULT_SCREEN_SHOT_PATH );
390 /* FIXME - we should check which translators are
391 actually available */
392 char * psz_format = config_GetPsz( p_vout, "beos-screenshotformat" );
393 int32 format = DEFAULT_SCREEN_SHOT_FORMAT;
394 if( !strcmp( psz_format, "TGA" ) )
396 else if( !strcmp( psz_format, "PPM" ) )
398 else if( !strcmp( psz_format, "JPEG" ) )
400 else if( !strcmp( psz_format, "BMP" ) )
403 _SaveScreenShot( temp, path, format );
412 BWindow::MessageReceived( p_message );
417 /*****************************************************************************
419 *****************************************************************************/
421 VideoWindow::Zoom(BPoint origin, float width, float height )
426 /*****************************************************************************
427 * VideoWindow::FrameMoved
428 *****************************************************************************/
430 VideoWindow::FrameMoved(BPoint origin)
437 /*****************************************************************************
438 * VideoWindow::FrameResized
439 *****************************************************************************/
441 VideoWindow::FrameResized( float width, float height )
443 int32 useWidth = CorrectAspectRatio() ? i_width : fTrueWidth;
444 int32 useHeight = CorrectAspectRatio() ? i_height : fTrueHeight;
445 float out_width, out_height;
446 float out_left, out_top;
447 float width_scale = width / useWidth;
448 float height_scale = height / useHeight;
450 if (width_scale <= height_scale)
452 out_width = (useWidth * width_scale);
453 out_height = (useHeight * width_scale);
455 out_top = (height - out_height) / 2;
457 else /* if the height is proportionally smaller */
459 out_width = (useWidth * height_scale);
460 out_height = (useHeight * height_scale);
462 out_left = (width - out_width) / 2;
464 view->MoveTo(out_left,out_top);
465 view->ResizeTo(out_width, out_height);
471 /*****************************************************************************
472 * VideoWindow::ScreenChanged
473 *****************************************************************************/
475 VideoWindow::ScreenChanged(BRect frame, color_space format)
477 BScreen screen(this);
479 screen.GetMode(&mode);
480 float refresh = (mode.timing.pixel_clock * 1000)
481 / ((mode.timing.h_total) * (mode.timing.v_total));
482 SetSyncToRetrace(refresh < MIN_AUTO_VSYNC_REFRESH);
485 /*****************************************************************************
486 * VideoWindow::Activate
487 *****************************************************************************/
489 VideoWindow::WindowActivated(bool active)
493 /*****************************************************************************
494 * VideoWindow::drawBuffer
495 *****************************************************************************/
497 VideoWindow::drawBuffer(int bufferIndex)
499 i_buffer = bufferIndex;
501 // sync to the screen if required
502 if (IsSyncedToRetrace())
504 BScreen screen(this);
505 screen.WaitForRetrace(22000);
507 if (fInitStatus >= B_OK && LockLooper())
509 // switch the overlay bitmap
513 view->SetViewOverlay(bitmap[i_buffer],
514 bitmap[i_buffer]->Bounds() ,
517 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
518 B_OVERLAY_TRANSFER_CHANNEL);
519 view->SetViewColor(key);
524 view->DrawBitmap(bitmap[i_buffer], view->Bounds() );
530 /*****************************************************************************
531 * VideoWindow::SetInterfaceShowing
532 *****************************************************************************/
534 VideoWindow::ToggleInterfaceShowing()
536 SetInterfaceShowing(!fInterfaceShowing);
539 /*****************************************************************************
540 * VideoWindow::SetInterfaceShowing
541 *****************************************************************************/
543 VideoWindow::SetInterfaceShowing(bool showIt)
545 BWindow* window = get_interface_window();
550 if (fCachedFeel != B_NORMAL_WINDOW_FEEL)
551 SetFeel(B_NORMAL_WINDOW_FEEL);
552 window->Activate(true);
557 SetFeel(fCachedFeel);
559 window->SendBehind(this);
561 fInterfaceShowing = showIt;
565 /*****************************************************************************
566 * VideoWindow::SetCorrectAspectRatio
567 *****************************************************************************/
569 VideoWindow::SetCorrectAspectRatio(bool doIt)
571 if (CorrectAspectRatio() != doIt)
574 fSettings->AddFlags(VideoSettings::FLAG_CORRECT_RATIO);
576 fSettings->ClearFlags(VideoSettings::FLAG_CORRECT_RATIO);
577 FrameResized(Bounds().Width(), Bounds().Height());
581 /*****************************************************************************
582 * VideoWindow::CorrectAspectRatio
583 *****************************************************************************/
585 VideoWindow::CorrectAspectRatio() const
587 return fSettings->HasFlags(VideoSettings::FLAG_CORRECT_RATIO);
590 /*****************************************************************************
591 * VideoWindow::ToggleFullScreen
592 *****************************************************************************/
594 VideoWindow::ToggleFullScreen()
596 SetFullScreen(!IsFullScreen());
599 /*****************************************************************************
600 * VideoWindow::SetFullScreen
601 *****************************************************************************/
603 VideoWindow::SetFullScreen(bool doIt)
607 BScreen screen(this);
608 BRect rect = screen.Frame();
611 ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
612 be_app->ObscureCursor();
613 fInterfaceShowing = false;
614 fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
618 MoveTo(winSize.left, winSize.top);
619 ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
620 be_app->ShowCursor();
621 fInterfaceShowing = true;
622 fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
626 /*****************************************************************************
627 * VideoWindow::IsFullScreen
628 *****************************************************************************/
630 VideoWindow::IsFullScreen() const
632 return fSettings->HasFlags(VideoSettings::FLAG_FULL_SCREEN);
635 /*****************************************************************************
636 * VideoWindow::SetSyncToRetrace
637 *****************************************************************************/
639 VideoWindow::SetSyncToRetrace(bool doIt)
642 fSettings->AddFlags(VideoSettings::FLAG_SYNC_RETRACE);
644 fSettings->ClearFlags(VideoSettings::FLAG_SYNC_RETRACE);
647 /*****************************************************************************
648 * VideoWindow::IsSyncedToRetrace
649 *****************************************************************************/
651 VideoWindow::IsSyncedToRetrace() const
653 return fSettings->HasFlags(VideoSettings::FLAG_SYNC_RETRACE);
657 /*****************************************************************************
658 * VideoWindow::_AllocateBuffers
659 *****************************************************************************/
661 VideoWindow::_AllocateBuffers(int width, int height, int* mode)
663 // clear any old buffers
668 BRect bitmapFrame( 0, 0, width, height );
669 // read from config, if we are supposed to use overlay at all
670 int noOverlay = !config_GetInt( p_vout, "overlay" );
671 // test for overlay capability
672 for (int i = 0; i < COLOR_COUNT; i++)
674 if (noOverlay) break;
675 bitmap[0] = new BBitmap ( bitmapFrame,
676 B_BITMAP_WILL_OVERLAY |
677 B_BITMAP_RESERVE_OVERLAY_CHANNEL,
678 colspace[i].colspace);
680 if(bitmap[0] && bitmap[0]->InitCheck() == B_OK)
684 bitmap[1] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
685 colspace[colspace_index].colspace);
686 bitmap[2] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
687 colspace[colspace_index].colspace);
688 if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) )
692 view->SetViewOverlay(bitmap[0],
693 bitmap[0]->Bounds() ,
696 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
697 view->SetViewColor(key);
698 SetTitle("VLC " PACKAGE_VERSION " (Overlay)");
704 *mode = BITMAP; // might want to try again with normal bitmaps
714 colspace_index = DEFAULT_COL; // B_RGB32
715 SetTitle( "VLC " PACKAGE_VERSION " (Bitmap)" );
716 bitmap[0] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
717 bitmap[1] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
718 bitmap[2] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
720 // see if everything went well
721 status_t status = B_ERROR;
722 for (int32 i = 0; i < 3; i++)
725 status = bitmap[i]->InitCheck();
731 // clear bitmaps to black
732 for (int32 i = 0; i < 3; i++)
733 _BlankBitmap(bitmap[i]);
738 /*****************************************************************************
739 * VideoWindow::_FreeBuffers
740 *****************************************************************************/
742 VideoWindow::_FreeBuffers()
750 fInitStatus = B_ERROR;
753 /*****************************************************************************
754 * VideoWindow::_BlankBitmap
755 *****************************************************************************/
757 VideoWindow::_BlankBitmap(BBitmap* bitmap) const
759 // no error checking (we do that earlier on and since it's a private function...
762 // Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128)
765 // Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128)
767 // we only handle weird colorspaces with special care
768 switch (bitmap->ColorSpace()) {
770 // Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0] Y2[7:0] Cb2[7:0] Y3[7:0] Cr2[7:0]
771 int32 height = bitmap->Bounds().IntegerHeight() + 1;
772 uint8* bits = (uint8*)bitmap->Bits();
773 int32 bpr = bitmap->BytesPerRow();
774 for (int32 y = 0; y < height; y++) {
775 // handle 2 bytes at a time
776 for (int32 i = 0; i < bpr; i += 2) {
788 // Non-interlaced only, Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ...
789 // Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines
790 int32 height = bitmap->Bounds().IntegerHeight() + 1;
791 uint8* bits = (uint8*)bitmap->Bits();
792 int32 bpr = bitmap->BytesPerRow();
793 for (int32 y = 0; y < height; y += 1) {
794 // handle 3 bytes at a time
795 for (int32 i = 0; i < bpr; i += 3) {
808 // U0[7:0] Y0[7:0] V0[7:0] Y1[7:0] U2[7:0] Y2[7:0] V2[7:0] Y3[7:0]
809 int32 height = bitmap->Bounds().IntegerHeight() + 1;
810 uint8* bits = (uint8*)bitmap->Bits();
811 int32 bpr = bitmap->BytesPerRow();
812 for (int32 y = 0; y < height; y += 1) {
813 // handle 2 bytes at a time
814 for (int32 i = 0; i < bpr; i += 2) {
825 memset(bitmap->Bits(), 0, bitmap->BitsLength());
830 /*****************************************************************************
831 * VideoWindow::_SetVideoSize
832 *****************************************************************************/
834 VideoWindow::_SetVideoSize(uint32 mode)
836 // let size depend on aspect correction
837 int32 width = CorrectAspectRatio() ? i_width : fTrueWidth;
838 int32 height = CorrectAspectRatio() ? i_height : fTrueHeight;
853 fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
854 ResizeTo(width, height);
857 /*****************************************************************************
858 * VideoWindow::_SetToSettings
859 *****************************************************************************/
861 VideoWindow::_SetToSettings()
864 uint32 mode = RESIZE_100;
865 switch (fSettings->VideoSize())
867 case VideoSettings::SIZE_50:
870 case VideoSettings::SIZE_200:
873 case VideoSettings::SIZE_100:
874 case VideoSettings::SIZE_OTHER:
878 bool fullscreen = IsFullScreen(); // remember settings
879 _SetVideoSize(mode); // because this will reset settings
880 // the fullscreen status is reflected in the settings,
881 // but not yet in the windows state
884 if (fSettings->HasFlags(VideoSettings::FLAG_ON_TOP_ALL))
885 fCachedFeel = B_FLOATING_ALL_WINDOW_FEEL;
887 fCachedFeel = B_NORMAL_WINDOW_FEEL;
888 SetFeel(fCachedFeel);
891 /*****************************************************************************
892 * VideoWindow::_SaveScreenShot
893 *****************************************************************************/
895 VideoWindow::_SaveScreenShot( BBitmap* bitmap, char* path,
896 uint32 translatorID ) const
898 // make the info object from the parameters
899 screen_shot_info* info = new screen_shot_info;
900 info->bitmap = bitmap;
902 info->translatorID = translatorID;
903 info->width = CorrectAspectRatio() ? i_width : fTrueWidth;
904 info->height = CorrectAspectRatio() ? i_height : fTrueHeight;
905 // spawn a new thread to take care of the actual saving to disk
906 thread_id thread = spawn_thread( _save_screen_shot,
908 B_LOW_PRIORITY, (void*)info );
909 // start thread or do the job ourself if something went wrong
910 if ( thread < B_OK || resume_thread( thread ) < B_OK )
911 _save_screen_shot( (void*)info );
914 /*****************************************************************************
915 * VideoWindow::_save_screen_shot
916 *****************************************************************************/
918 VideoWindow::_save_screen_shot( void* cookie )
920 screen_shot_info* info = (screen_shot_info*)cookie;
921 if ( info && info->bitmap && info->bitmap->IsValid() && info->path )
923 // try to be as quick as possible creating the file (the user might have
924 // taken the next screen shot already!)
925 // make sure we have a unique name for the screen shot
926 BString path( info->path );
927 // create the folder if it doesn't exist
928 BString folder( info->path );
929 create_directory( folder.String(), 0777 );
930 path << "/vlc screenshot";
931 BEntry entry( path.String() );
932 int32 appendedNumber = 0;
933 if ( entry.Exists() && !entry.IsSymLink() )
935 // we would clobber an existing entry
936 bool foundUniqueName = false;
938 while ( !foundUniqueName ) {
939 BString newName( path.String() );
940 newName << " " << appendedNumber;
941 BEntry possiblyClobberedEntry( newName.String() );
942 if ( possiblyClobberedEntry.Exists()
943 && !possiblyClobberedEntry.IsSymLink() )
946 foundUniqueName = true;
949 if ( appendedNumber > 0 )
950 path << " " << appendedNumber;
951 // there is still a slight chance to clobber an existing
952 // file (if it was created in the "meantime"), but we take it...
953 BFile outFile( path.String(),
954 B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE );
956 // make colorspace converted copy of bitmap
957 BBitmap* converted = new BBitmap( BRect( 0.0, 0.0, info->width, info->height ),
959 status_t status = convert_bitmap( info->bitmap, converted );
960 if ( status == B_OK )
962 BTranslatorRoster* roster = BTranslatorRoster::Default();
963 uint32 imageFormat = 0;
964 translator_id translator = 0;
967 // find suitable translator
968 translator_id* ids = NULL;
971 status = roster->GetAllTranslators( &ids, &count );
972 if ( status >= B_OK )
974 for ( int tix = 0; tix < count; tix++ )
976 const translation_format *formats = NULL;
977 int32 num_formats = 0;
979 status = roster->GetInputFormats( ids[tix],
980 &formats, &num_formats );
983 for ( int iix = 0; iix < num_formats; iix++ )
985 if ( formats[iix].type == B_TRANSLATOR_BITMAP )
994 status = roster->GetOutputFormats( ids[tix],
995 &formats, &num_formats);
996 if ( status >= B_OK )
998 for ( int32 oix = 0; oix < num_formats; oix++ )
1000 if ( formats[oix].type != B_TRANSLATOR_BITMAP )
1002 if ( formats[oix].type == info->translatorID )
1005 imageFormat = formats[oix].type;
1006 translator = ids[tix];
1017 // make bitmap stream
1018 BBitmapStream outStream( converted );
1020 status = outFile.InitCheck();
1021 if (status == B_OK) {
1022 status = roster->Translate( &outStream, NULL, NULL,
1023 &outFile, imageFormat );
1024 if ( status == B_OK )
1026 BNodeInfo nodeInfo( &outFile );
1027 if ( nodeInfo.InitCheck() == B_OK )
1029 translation_format* formats;
1031 status = roster->GetOutputFormats( translator,
1032 (const translation_format **) &formats,
1034 if ( status >= B_OK )
1036 const char * mime = NULL;
1037 for ( int ix = 0; ix < count; ix++ ) {
1038 if ( formats[ix].type == imageFormat ) {
1039 mime = formats[ix].MIME;
1044 nodeInfo.SetType( mime );
1049 outStream.DetachBitmap( &converted );
1057 delete info->bitmap;
1065 /*****************************************************************************
1067 *****************************************************************************/
1068 VLCView::VLCView(BRect bounds, vout_thread_t *p_vout_instance )
1069 : BView(bounds, "video view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED),
1070 fLastMouseMovedTime(system_time()),
1071 fCursorHidden(false),
1072 fCursorInside(false),
1073 fIgnoreDoubleClick(false)
1075 p_vout = p_vout_instance;
1076 SetViewColor(B_TRANSPARENT_32_BIT);
1079 /*****************************************************************************
1081 *****************************************************************************/
1086 /*****************************************************************************
1087 * VLCVIew::AttachedToWindow
1088 *****************************************************************************/
1090 VLCView::AttachedToWindow()
1092 // in order to get keyboard events
1094 // periodically check if we want to hide the pointer
1095 Window()->SetPulseRate(1000000);
1098 /*****************************************************************************
1099 * VLCVIew::MouseDown
1100 *****************************************************************************/
1102 VLCView::MouseDown(BPoint where)
1104 VideoWindow* videoWindow = dynamic_cast<VideoWindow*>(Window());
1105 BMessage* msg = Window()->CurrentMessage();
1108 msg->FindInt32("clicks", &clicks);
1109 msg->FindInt32("buttons", (int32*)&buttons);
1113 if (buttons & B_PRIMARY_MOUSE_BUTTON)
1115 if (clicks == 2 && !fIgnoreDoubleClick)
1118 videoWindow->ToggleInterfaceShowing(); */
1119 fIgnoreDoubleClick = false;
1123 if (buttons & B_SECONDARY_MOUSE_BUTTON)
1125 // clicks will be 2 next time (if interval short enough)
1126 // even if the first click and the second
1127 // have not been made with the same mouse button
1128 fIgnoreDoubleClick = true;
1129 // launch popup menu
1130 BPopUpMenu *menu = new BPopUpMenu("context menu");
1131 menu->SetRadioMode(false);
1132 // In full screen, add an item to show/hide the interface
1133 if( videoWindow->IsFullScreen() )
1135 BMenuItem *intfItem =
1136 new BMenuItem( _("Show Interface"), new BMessage(SHOW_INTERFACE) );
1137 menu->AddItem( intfItem );
1140 BMenuItem *halfItem = new BMenuItem(_("50%"), new BMessage(RESIZE_50));
1141 menu->AddItem(halfItem);
1143 BMenuItem *origItem = new BMenuItem(_("100%"), new BMessage(RESIZE_100));
1144 menu->AddItem(origItem);
1146 BMenuItem *doubleItem = new BMenuItem(_("200%"), new BMessage(RESIZE_200));
1147 menu->AddItem(doubleItem);
1148 // Toggle FullScreen
1149 BMenuItem *zoomItem = new BMenuItem(_("Fullscreen"), new BMessage(TOGGLE_FULL_SCREEN));
1150 zoomItem->SetMarked(videoWindow->IsFullScreen());
1151 menu->AddItem(zoomItem);
1153 menu->AddSeparatorItem();
1156 BMenuItem *vsyncItem = new BMenuItem(_("Vertical Sync"), new BMessage(VERT_SYNC));
1157 vsyncItem->SetMarked(videoWindow->IsSyncedToRetrace());
1158 menu->AddItem(vsyncItem);
1159 // Correct Aspect Ratio
1160 BMenuItem *aspectItem = new BMenuItem(_("Correct Aspect Ratio"), new BMessage(ASPECT_CORRECT));
1161 aspectItem->SetMarked(videoWindow->CorrectAspectRatio());
1162 menu->AddItem(aspectItem);
1164 menu->AddSeparatorItem();
1166 // Windwo Feel Items
1167 /* BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
1168 winNormFeel->AddInt32("WinFeel", (int32)B_NORMAL_WINDOW_FEEL);
1169 BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
1170 normWindItem->SetMarked(videoWindow->Feel() == B_NORMAL_WINDOW_FEEL);
1171 menu->AddItem(normWindItem);
1173 BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
1174 winFloatFeel->AddInt32("WinFeel", (int32)B_FLOATING_APP_WINDOW_FEEL);
1175 BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
1176 onTopWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
1177 menu->AddItem(onTopWindItem);
1179 BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
1180 winAllFeel->AddInt32("WinFeel", (int32)B_FLOATING_ALL_WINDOW_FEEL);
1181 BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
1182 allSpacesWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
1183 menu->AddItem(allSpacesWindItem);*/
1185 BMessage *windowFeelMsg = new BMessage( WINDOW_FEEL );
1186 bool onTop = videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
1187 window_feel feel = onTop ? B_NORMAL_WINDOW_FEEL : B_FLOATING_ALL_WINDOW_FEEL;
1188 windowFeelMsg->AddInt32( "WinFeel", (int32)feel );
1189 BMenuItem *windowFeelItem = new BMenuItem( _("Stay On Top"), windowFeelMsg );
1190 windowFeelItem->SetMarked( onTop );
1191 menu->AddItem( windowFeelItem );
1193 menu->AddSeparatorItem();
1195 BMenuItem* screenShotItem = new BMenuItem( _("Take Screen Shot"),
1196 new BMessage( SCREEN_SHOT ) );
1197 menu->AddItem( screenShotItem );
1199 menu->SetTargetForItems( this );
1200 ConvertToScreen( &where );
1201 menu->Go( where, true, false, true );
1205 fLastMouseMovedTime = system_time();
1206 fCursorHidden = false;
1209 /*****************************************************************************
1211 *****************************************************************************/
1213 VLCView::MouseUp( BPoint where )
1216 val.b_bool = VLC_TRUE;
1217 var_Set( p_vout, "mouse-clicked", val );
1220 /*****************************************************************************
1221 * VLCVIew::MouseMoved
1222 *****************************************************************************/
1224 VLCView::MouseMoved(BPoint point, uint32 transit, const BMessage* dragMessage)
1226 fLastMouseMovedTime = system_time();
1227 fCursorHidden = false;
1228 fCursorInside = (transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW);
1229 /* DVD navigation */
1230 unsigned int i_width, i_height, i_x, i_y;
1231 vout_PlacePicture( p_vout, (unsigned int)Bounds().Width(),
1232 (unsigned int)Bounds().Height(),
1233 &i_x, &i_y, &i_width, &i_height );
1235 val.i_int = ( (int)point.x - i_x ) * p_vout->render.i_width / i_width;
1236 var_Set( p_vout, "mouse-x", val );
1237 val.i_int = ( (int)point.y - i_y ) * p_vout->render.i_height / i_height;
1238 var_Set( p_vout, "mouse-y", val );
1239 val.b_bool = VLC_TRUE;
1240 var_Set( p_vout, "mouse-moved", val );
1243 /*****************************************************************************
1245 *****************************************************************************/
1249 // We are getting the pulse messages no matter if the mouse is over
1250 // this view. If we are in full screen mode, we want to hide the cursor
1251 // even if it is not.
1252 VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1256 && system_time() - fLastMouseMovedTime > MOUSE_IDLE_TIMEOUT)
1258 be_app->ObscureCursor();
1259 fCursorHidden = true;
1261 // hide the interface window as well if full screen
1262 if (videoWindow && videoWindow->IsFullScreen())
1263 videoWindow->SetInterfaceShowing(false);
1267 // Workaround to disable the screensaver in full screen:
1268 // we simulate an activity every 29 seconds
1269 if( videoWindow && videoWindow->IsFullScreen() &&
1270 system_time() - fLastMouseMovedTime > 29000000 )
1274 GetMouse(&where, &buttons, false);
1275 ConvertToScreen(&where);
1276 set_mouse_position((int32) where.x, (int32) where.y);
1280 /*****************************************************************************
1282 *****************************************************************************/
1284 VLCView::KeyDown(const char *bytes, int32 numBytes)
1286 VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1287 BWindow* interfaceWindow = get_interface_window();
1288 if (videoWindow && numBytes > 0) {
1289 uint32 mods = modifiers();
1294 // toggle window and full screen mode
1295 // not passing on the tab key to the default KeyDown()
1296 // implementation also avoids loosing the keyboard focus
1297 videoWindow->PostMessage(TOGGLE_FULL_SCREEN);
1300 // go back to window mode
1301 if (videoWindow->IsFullScreen())
1302 videoWindow->PostMessage(TOGGLE_FULL_SCREEN);
1306 if (interfaceWindow)
1307 interfaceWindow->PostMessage(PAUSE_PLAYBACK);
1310 if (interfaceWindow)
1312 if (mods & B_SHIFT_KEY)
1314 interfaceWindow->PostMessage(NEXT_TITLE);
1317 interfaceWindow->PostMessage(NEXT_CHAPTER);
1321 if (interfaceWindow)
1323 if (mods & B_SHIFT_KEY)
1325 interfaceWindow->PostMessage(PREV_TITLE);
1328 interfaceWindow->PostMessage(PREV_CHAPTER);
1332 // previous file in playlist
1333 interfaceWindow->PostMessage(PREV_FILE);
1336 // next file in playlist
1337 interfaceWindow->PostMessage(NEXT_FILE);
1342 videoWindow->PostMessage( SCREEN_SHOT );
1345 BView::KeyDown(bytes, numBytes);
1351 /*****************************************************************************
1353 *****************************************************************************/
1355 VLCView::Draw(BRect updateRect)
1357 VideoWindow* window = dynamic_cast<VideoWindow*>( Window() );
1358 if ( window && window->mode == BITMAP )
1359 FillRect( updateRect );
1362 /*****************************************************************************
1364 *****************************************************************************/
1365 static int Init ( vout_thread_t * );
1366 static void End ( vout_thread_t * );
1367 // static int Manage ( vout_thread_t * );
1368 static void Display ( vout_thread_t *, picture_t * );
1370 static int BeosOpenDisplay ( vout_thread_t *p_vout );
1371 static void BeosCloseDisplay( vout_thread_t *p_vout );
1373 /*****************************************************************************
1374 * OpenVideo: allocates BeOS video thread output method
1375 *****************************************************************************
1376 * This function allocates and initializes a BeOS vout method.
1377 *****************************************************************************/
1378 int E_(OpenVideo) ( vlc_object_t *p_this )
1380 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1382 /* Allocate structure */
1383 p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
1384 if( p_vout->p_sys == NULL )
1386 msg_Err( p_vout, "out of memory" );
1389 p_vout->p_sys->i_width = p_vout->render.i_width;
1390 p_vout->p_sys->i_height = p_vout->render.i_height;
1391 p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
1393 p_vout->pf_init = Init;
1394 p_vout->pf_end = End;
1395 p_vout->pf_manage = NULL;
1396 p_vout->pf_render = NULL;
1397 p_vout->pf_display = Display;
1402 /*****************************************************************************
1403 * Init: initialize BeOS video thread output method
1404 *****************************************************************************/
1405 int Init( vout_thread_t *p_vout )
1410 I_OUTPUTPICTURES = 0;
1412 /* Open and initialize device */
1413 if( BeosOpenDisplay( p_vout ) )
1415 msg_Err(p_vout, "vout error: can't open display");
1418 p_vout->output.i_width = p_vout->render.i_width;
1419 p_vout->output.i_height = p_vout->render.i_height;
1421 /* Assume we have square pixels */
1422 p_vout->output.i_aspect = p_vout->p_sys->i_width
1423 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
1424 p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
1425 p_vout->p_sys->i_index = 0;
1427 p_vout->b_direct = 1;
1429 p_vout->output.i_rmask = 0x00ff0000;
1430 p_vout->output.i_gmask = 0x0000ff00;
1431 p_vout->output.i_bmask = 0x000000ff;
1433 for (int buffer_index = 0 ; buffer_index < 3; buffer_index++)
1436 /* Find an empty picture slot */
1437 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
1440 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
1442 p_pic = p_vout->p_picture + i_index;
1451 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
1452 p_pic->p->i_lines = p_vout->p_sys->i_height;
1454 p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
1455 p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
1456 p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow();
1457 p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 );
1459 p_pic->i_status = DESTROYED_PICTURE;
1460 p_pic->i_type = DIRECT_PICTURE;
1462 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
1470 /*****************************************************************************
1471 * End: terminate BeOS video thread output method
1472 *****************************************************************************/
1473 void End( vout_thread_t *p_vout )
1475 BeosCloseDisplay( p_vout );
1478 /*****************************************************************************
1479 * CloseVideo: destroy BeOS video thread output method
1480 *****************************************************************************
1481 * Terminate an output method created by DummyCreateOutputMethod
1482 *****************************************************************************/
1483 void E_(CloseVideo) ( vlc_object_t *p_this )
1485 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1487 free( p_vout->p_sys );
1490 /*****************************************************************************
1491 * Display: displays previously rendered output
1492 *****************************************************************************
1493 * This function send the currently rendered image to BeOS image, waits until
1494 * it is displayed and switch the two rendering buffers, preparing next frame.
1495 *****************************************************************************/
1496 void Display( vout_thread_t *p_vout, picture_t *p_pic )
1498 VideoWindow * p_win = p_vout->p_sys->p_window;
1500 /* draw buffer if required */
1501 if (!p_win->teardownwindow)
1503 p_win->drawBuffer(p_vout->p_sys->i_index);
1506 p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3;
1507 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
1510 /* following functions are local */
1512 /*****************************************************************************
1513 * BeosOpenDisplay: open and initialize BeOS device
1514 *****************************************************************************/
1515 static int BeosOpenDisplay( vout_thread_t *p_vout )
1518 p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
1519 p_vout->p_sys->i_height - 1,
1521 20 + p_vout->i_window_width - 1,
1522 50 + p_vout->i_window_height - 1 ),
1524 if( p_vout->p_sys->p_window == NULL )
1526 msg_Err( p_vout, "cannot allocate VideoWindow" );
1531 p_vout->p_sys->p_window->Show();
1537 /*****************************************************************************
1538 * BeosDisplay: close and reset BeOS device
1539 *****************************************************************************
1540 * Returns all resources allocated by BeosOpenDisplay and restore the original
1541 * state of the device.
1542 *****************************************************************************/
1543 static void BeosCloseDisplay( vout_thread_t *p_vout )
1545 VideoWindow * p_win = p_vout->p_sys->p_window;
1546 /* Destroy the video window */
1547 if( p_win != NULL && !p_win->teardownwindow)
1550 p_win->teardownwindow = true;