1 /*****************************************************************************
2 * vout_beos.cpp: beos video output display method
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: VideoOutput.cpp,v 1.10 2003/01/24 06:31:56 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 <DirectWindow.h>
41 #include <InterfaceKit.h>
44 #include <TranslatorRoster.h>
51 #include "VideoWindow.h"
52 #include "DrawingTidbits.h"
55 /*****************************************************************************
56 * vout_sys_t: BeOS video output method descriptor
57 *****************************************************************************
58 * This structure is part of the video output thread descriptor.
59 * It describes the BeOS specific properties of an output thread.
60 *****************************************************************************/
63 VideoWindow * p_window;
74 #define MOUSE_IDLE_TIMEOUT 2000000 // two seconds
75 #define MIN_AUTO_VSYNC_REFRESH 61 // Hz
76 #define DEFAULT_SCREEN_SHOT_FORMAT 'PNG '
77 #define DEFAULT_SCREEN_SHOT_PATH "/boot/home/vlc screenshot"
79 /*****************************************************************************
80 * beos_GetAppWindow : retrieve a BWindow pointer from the window name
81 *****************************************************************************/
83 beos_GetAppWindow(char *name)
88 for (index = 0 ; ; index++)
90 window = be_app->WindowAt(index);
93 if (window->LockWithTimeout(20000) == B_OK)
95 if (strcmp(window->Name(), name) == 0)
106 /*****************************************************************************
107 * get_interface_window
108 *****************************************************************************/
110 get_interface_window()
112 return beos_GetAppWindow(VOUT_TITLE);
115 class BackgroundView : public BView
118 BackgroundView(BRect frame, VLCView* view)
119 : BView(frame, "background",
120 B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE),
123 SetViewColor(kBlack);
125 virtual ~BackgroundView() {}
127 virtual void MouseDown(BPoint where)
129 // convert coordinates
130 where = fVideoView->ConvertFromParent(where);
132 fVideoView->MouseDown(where);
134 virtual void MouseMoved(BPoint where, uint32 transit,
135 const BMessage* dragMessage)
137 // convert coordinates
138 where = fVideoView->ConvertFromParent(where);
140 fVideoView->MouseMoved(where, transit, dragMessage);
141 // notice: It might look like transit should be
142 // B_OUTSIDE_VIEW regardless, but leave it like this,
143 // otherwise, unwanted things will happen!
150 /*****************************************************************************
151 * VideoWindow constructor and destructor
152 *****************************************************************************/
153 VideoWindow::VideoWindow(int v_width, int v_height, BRect frame,
154 vout_thread_t *p_videoout)
155 : BWindow(frame, NULL, B_TITLED_WINDOW, B_NOT_CLOSABLE | B_NOT_MINIMIZABLE),
156 i_width(frame.IntegerWidth()),
157 i_height(frame.IntegerHeight()),
161 teardownwindow(false),
163 fTrueHeight(v_height),
164 fCorrectAspect(true),
165 fCachedFeel(B_NORMAL_WINDOW_FEEL),
166 fInterfaceShowing(false),
171 // create the view to do the display
172 view = new VLCView( Bounds(), p_vout );
174 // create background view
175 BView *mainView = new BackgroundView( Bounds(), view );
177 mainView->AddChild(view);
179 // figure out if we should use vertical sync by default
180 BScreen screen(this);
181 if (screen.IsValid())
184 screen.GetMode(&mode);
185 float refresh = (mode.timing.pixel_clock * 1000)
186 / ((mode.timing.h_total)* (mode.timing.v_total));
187 vsync = (refresh < MIN_AUTO_VSYNC_REFRESH);
190 // allocate bitmap buffers
191 for (int32 i = 0; i < 3; i++)
193 fInitStatus = _AllocateBuffers(v_width, v_height, &mode);
195 // make sure we layout the view correctly
196 FrameResized(i_width, i_height);
198 if (fInitStatus >= B_OK && mode == OVERLAY)
200 overlay_restrictions r;
202 bitmap[1]->GetOverlayRestrictions(&r);
203 SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
204 (i_height * r.min_height_scale), i_height * r.max_height_scale);
207 if( config_GetInt( p_vout, "fullscreen" ) )
213 VideoWindow::~VideoWindow()
217 teardownwindow = true;
218 wait_for_thread(fDrawThreadID, &result);
222 /*****************************************************************************
223 * VideoWindow::MessageReceived
224 *****************************************************************************/
226 VideoWindow::MessageReceived( BMessage *p_message )
228 switch( p_message->what )
230 case TOGGLE_FULL_SCREEN:
238 _SetVideoSize(p_message->what);
246 if (p_message->FindInt32("WinFeel", (int32*)&winFeel) == B_OK)
249 fCachedFeel = winFeel;
254 SetCorrectAspectRatio(!fCorrectAspect);
257 // save a screen shot
258 if ( BBitmap* current = bitmap[i_buffer] )
260 // the following line might be tempting, but does not work for some overlay bitmaps!!!
261 // BBitmap* temp = new BBitmap( current );
262 // so we clone the bitmap ourselves
263 // however, we need to take care of potentially different padding!
264 // memcpy() is slow when reading from grafix memory, but what the heck...
265 BBitmap* temp = new BBitmap( current->Bounds(), current->ColorSpace() );
266 if ( temp && temp->IsValid() )
268 int32 height = (int32)current->Bounds().Height();
269 uint8* dst = (uint8*)temp->Bits();
270 uint8* src = (uint8*)current->Bits();
271 int32 dstBpr = temp->BytesPerRow();
272 int32 srcBpr = current->BytesPerRow();
273 int32 validBytes = dstBpr > srcBpr ? srcBpr : dstBpr;
274 for ( int32 y = 0; y < height; y++ )
276 memcpy( dst, src, validBytes );
280 _SaveScreenShot( temp,
281 strdup( DEFAULT_SCREEN_SHOT_PATH ),
282 DEFAULT_SCREEN_SHOT_FORMAT );
291 BWindow::MessageReceived( p_message );
296 /*****************************************************************************
298 *****************************************************************************/
300 VideoWindow::Zoom(BPoint origin, float width, float height )
304 MoveTo(winSize.left, winSize.top);
305 ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
306 be_app->ShowCursor();
307 fInterfaceShowing = true;
311 BScreen screen(this);
312 BRect rect = screen.Frame();
315 ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
316 be_app->ObscureCursor();
317 fInterfaceShowing = false;
319 is_zoomed = !is_zoomed;
322 /*****************************************************************************
323 * VideoWindow::FrameMoved
324 *****************************************************************************/
326 VideoWindow::FrameMoved(BPoint origin)
328 if (is_zoomed) return ;
332 /*****************************************************************************
333 * VideoWindow::FrameResized
334 *****************************************************************************/
336 VideoWindow::FrameResized( float width, float height )
338 int32 useWidth = fCorrectAspect ? i_width : fTrueWidth;
339 int32 useHeight = fCorrectAspect ? i_height : fTrueHeight;
340 float out_width, out_height;
341 float out_left, out_top;
342 float width_scale = width / useWidth;
343 float height_scale = height / useHeight;
345 if (width_scale <= height_scale)
347 out_width = (useWidth * width_scale);
348 out_height = (useHeight * width_scale);
350 out_top = (height - out_height) / 2;
352 else /* if the height is proportionally smaller */
354 out_width = (useWidth * height_scale);
355 out_height = (useHeight * height_scale);
357 out_left = (width - out_width) / 2;
359 view->MoveTo(out_left,out_top);
360 view->ResizeTo(out_width, out_height);
366 /*****************************************************************************
367 * VideoWindow::ScreenChanged
368 *****************************************************************************/
370 VideoWindow::ScreenChanged(BRect frame, color_space format)
372 BScreen screen(this);
374 screen.GetMode(&mode);
375 float refresh = (mode.timing.pixel_clock * 1000)
376 / ((mode.timing.h_total) * (mode.timing.v_total));
377 if (refresh < MIN_AUTO_VSYNC_REFRESH)
381 /*****************************************************************************
382 * VideoWindow::Activate
383 *****************************************************************************/
385 VideoWindow::WindowActivated(bool active)
389 /*****************************************************************************
390 * VideoWindow::drawBuffer
391 *****************************************************************************/
393 VideoWindow::drawBuffer(int bufferIndex)
395 i_buffer = bufferIndex;
397 // sync to the screen if required
400 BScreen screen(this);
401 screen.WaitForRetrace(22000);
403 if (fInitStatus >= B_OK && LockLooper())
405 // switch the overlay bitmap
409 view->SetViewOverlay(bitmap[i_buffer],
410 bitmap[i_buffer]->Bounds() ,
413 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
414 B_OVERLAY_TRANSFER_CHANNEL);
415 view->SetViewColor(key);
420 view->DrawBitmap(bitmap[i_buffer], view->Bounds() );
426 /*****************************************************************************
427 * VideoWindow::SetInterfaceShowing
428 *****************************************************************************/
430 VideoWindow::ToggleInterfaceShowing()
432 SetInterfaceShowing(!fInterfaceShowing);
435 /*****************************************************************************
436 * VideoWindow::SetInterfaceShowing
437 *****************************************************************************/
439 VideoWindow::SetInterfaceShowing(bool showIt)
441 BWindow* window = get_interface_window();
446 if (fCachedFeel != B_NORMAL_WINDOW_FEEL)
447 SetFeel(B_NORMAL_WINDOW_FEEL);
448 window->Activate(true);
453 SetFeel(fCachedFeel);
455 window->SendBehind(this);
457 fInterfaceShowing = showIt;
461 /*****************************************************************************
462 * VideoWindow::SetCorrectAspectRatio
463 *****************************************************************************/
465 VideoWindow::SetCorrectAspectRatio(bool doIt)
467 if (fCorrectAspect != doIt)
469 fCorrectAspect = doIt;
470 FrameResized(Bounds().Width(), Bounds().Height());
474 /*****************************************************************************
475 * VideoWindow::_AllocateBuffers
476 *****************************************************************************/
478 VideoWindow::_AllocateBuffers(int width, int height, int* mode)
480 // clear any old buffers
485 BRect bitmapFrame( 0, 0, width, height );
486 // read from config, if we are supposed to use overlay at all
487 int noOverlay = !config_GetInt( p_vout, "overlay" );
488 // test for overlay capability
489 for (int i = 0; i < COLOR_COUNT; i++)
491 if (noOverlay) break;
492 bitmap[0] = new BBitmap ( bitmapFrame,
493 B_BITMAP_WILL_OVERLAY |
494 B_BITMAP_RESERVE_OVERLAY_CHANNEL,
495 colspace[i].colspace);
497 if(bitmap[0] && bitmap[0]->InitCheck() == B_OK)
501 bitmap[1] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
502 colspace[colspace_index].colspace);
503 bitmap[2] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
504 colspace[colspace_index].colspace);
505 if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) )
509 view->SetViewOverlay(bitmap[0],
510 bitmap[0]->Bounds() ,
513 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
514 view->SetViewColor(key);
515 SetTitle(VOUT_TITLE " (Overlay)");
521 *mode = BITMAP; // might want to try again with normal bitmaps
531 colspace_index = DEFAULT_COL; // B_RGB32
532 SetTitle( VOUT_TITLE " (Bitmap)" );
533 bitmap[0] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
534 bitmap[1] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
535 bitmap[2] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
537 // see if everything went well
538 status_t status = B_ERROR;
539 for (int32 i = 0; i < 3; i++)
542 status = bitmap[i]->InitCheck();
548 // clear bitmaps to black
549 for (int32 i = 0; i < 3; i++)
550 _BlankBitmap(bitmap[i]);
555 /*****************************************************************************
556 * VideoWindow::_FreeBuffers
557 *****************************************************************************/
559 VideoWindow::_FreeBuffers()
567 fInitStatus = B_ERROR;
570 /*****************************************************************************
571 * VideoWindow::_BlankBitmap
572 *****************************************************************************/
574 VideoWindow::_BlankBitmap(BBitmap* bitmap) const
576 // no error checking (we do that earlier on and since it's a private function...
579 // Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128)
582 // Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128)
584 // we only handle weird colorspaces with special care
585 switch (bitmap->ColorSpace()) {
587 // Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0] Y2[7:0] Cb2[7:0] Y3[7:0] Cr2[7:0]
588 int32 height = bitmap->Bounds().IntegerHeight() + 1;
589 uint8* bits = (uint8*)bitmap->Bits();
590 int32 bpr = bitmap->BytesPerRow();
591 for (int32 y = 0; y < height; y++) {
592 // handle 2 bytes at a time
593 for (int32 i = 0; i < bpr; i += 2) {
605 // Non-interlaced only, Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ...
606 // Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines
607 int32 height = bitmap->Bounds().IntegerHeight() + 1;
608 uint8* bits = (uint8*)bitmap->Bits();
609 int32 bpr = bitmap->BytesPerRow();
610 for (int32 y = 0; y < height; y += 1) {
611 // handle 3 bytes at a time
612 for (int32 i = 0; i < bpr; i += 3) {
625 // U0[7:0] Y0[7:0] V0[7:0] Y1[7:0] U2[7:0] Y2[7:0] V2[7:0] Y3[7:0]
626 int32 height = bitmap->Bounds().IntegerHeight() + 1;
627 uint8* bits = (uint8*)bitmap->Bits();
628 int32 bpr = bitmap->BytesPerRow();
629 for (int32 y = 0; y < height; y += 1) {
630 // handle 2 bytes at a time
631 for (int32 i = 0; i < bpr; i += 2) {
642 memset(bitmap->Bits(), 0, bitmap->BitsLength());
647 /*****************************************************************************
648 * VideoWindow::_SetVideoSize
649 *****************************************************************************/
651 VideoWindow::_SetVideoSize(uint32 mode)
653 // let size depend on aspect correction
654 int32 width = fCorrectAspect ? i_width : fTrueWidth;
655 int32 height = fCorrectAspect ? i_height : fTrueHeight;
670 ResizeTo(width, height);
674 /*****************************************************************************
675 * VideoWindow::_SaveScreenShot
676 *****************************************************************************/
678 VideoWindow::_SaveScreenShot( BBitmap* bitmap, char* path,
679 uint32 translatorID ) const
681 // make the info object from the parameters
682 screen_shot_info* info = new screen_shot_info;
683 info->bitmap = bitmap;
685 info->translatorID = translatorID;
686 info->width = fCorrectAspect ? i_width : fTrueWidth;
687 info->height = fCorrectAspect ? i_height : fTrueHeight;
688 // spawn a new thread to take care of the actual saving to disk
689 thread_id thread = spawn_thread( _save_screen_shot,
691 B_LOW_PRIORITY, (void*)info );
692 // start thread or do the job ourself if something went wrong
693 if ( thread < B_OK || resume_thread( thread ) < B_OK )
694 _save_screen_shot( (void*)info );
697 /*****************************************************************************
698 * VideoWindow::_save_screen_shot
699 *****************************************************************************/
701 VideoWindow::_save_screen_shot( void* cookie )
703 screen_shot_info* info = (screen_shot_info*)cookie;
704 if ( info && info->bitmap && info->bitmap->IsValid() && info->path )
706 // try to be as quick as possible creating the file (the user might have
707 // taken the next screen shot already!)
708 // make sure we have a unique name for the screen shot
709 BString path( info->path );
710 BEntry entry( path.String() );
711 int32 appendedNumber = 0;
712 if ( entry.Exists() && !entry.IsSymLink() )
714 // we would clobber an existing entry
715 bool foundUniqueName = false;
717 while ( !foundUniqueName ) {
718 BString newName( info->path );
719 newName << " " << appendedNumber;
720 BEntry possiblyClobberedEntry( newName.String() );
721 if ( possiblyClobberedEntry.Exists()
722 && !possiblyClobberedEntry.IsSymLink() )
725 foundUniqueName = true;
728 if ( appendedNumber > 0 )
729 path << " " << appendedNumber;
730 // there is still a slight chance to clobber an existing
731 // file (if it was created in the "meantime"), but we take it...
732 BFile outFile( path.String(),
733 B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE );
735 // make colorspace converted copy of bitmap
736 BBitmap* converted = new BBitmap( BRect( 0.0, 0.0, info->width, info->height ),
738 // if ( converted->IsValid() )
739 // memset( converted->Bits(), 0, converted->BitsLength() );
740 status_t status = convert_bitmap( info->bitmap, converted );
741 if ( status == B_OK )
743 BTranslatorRoster* roster = BTranslatorRoster::Default();
744 uint32 imageFormat = 0;
745 translator_id translator = 0;
748 // find suitable translator
749 translator_id* ids = NULL;
752 status = roster->GetAllTranslators( &ids, &count );
753 if ( status >= B_OK )
755 for ( int tix = 0; tix < count; tix++ )
757 const translation_format *formats = NULL;
758 int32 num_formats = 0;
760 status = roster->GetInputFormats( ids[tix],
761 &formats, &num_formats );
764 for ( int iix = 0; iix < num_formats; iix++ )
766 if ( formats[iix].type == B_TRANSLATOR_BITMAP )
775 status = roster->GetOutputFormats( ids[tix],
776 &formats, &num_formats);
777 if ( status >= B_OK )
779 for ( int32 oix = 0; oix < num_formats; oix++ )
781 if ( formats[oix].type != B_TRANSLATOR_BITMAP )
783 if ( formats[oix].type == info->translatorID )
786 imageFormat = formats[oix].type;
787 translator = ids[tix];
798 // make bitmap stream
799 BBitmapStream outStream( converted );
801 status = outFile.InitCheck();
802 if (status == B_OK) {
803 status = roster->Translate( &outStream, NULL, NULL,
804 &outFile, imageFormat );
805 if ( status == B_OK )
807 BNodeInfo nodeInfo( &outFile );
808 if ( nodeInfo.InitCheck() == B_OK )
810 translation_format* formats;
812 status = roster->GetOutputFormats( translator,
813 (const translation_format **) &formats,
815 if ( status >= B_OK )
817 const char * mime = NULL;
818 for ( int ix = 0; ix < count; ix++ ) {
819 if ( formats[ix].type == imageFormat ) {
820 mime = formats[ix].MIME;
825 nodeInfo.SetType( mime );
830 outStream.DetachBitmap( &converted );
846 /*****************************************************************************
848 *****************************************************************************/
849 VLCView::VLCView(BRect bounds, vout_thread_t *p_vout_instance )
850 : BView(bounds, "video view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED),
851 fLastMouseMovedTime(system_time()),
852 fCursorHidden(false),
853 fCursorInside(false),
854 fIgnoreDoubleClick(false)
856 p_vout = p_vout_instance;
857 SetViewColor(B_TRANSPARENT_32_BIT);
860 /*****************************************************************************
862 *****************************************************************************/
867 /*****************************************************************************
868 * VLCVIew::AttachedToWindow
869 *****************************************************************************/
871 VLCView::AttachedToWindow()
873 // in order to get keyboard events
875 // periodically check if we want to hide the pointer
876 Window()->SetPulseRate(1000000);
879 /*****************************************************************************
881 *****************************************************************************/
883 VLCView::MouseDown(BPoint where)
885 VideoWindow* videoWindow = dynamic_cast<VideoWindow*>(Window());
886 BMessage* msg = Window()->CurrentMessage();
889 msg->FindInt32("clicks", &clicks);
890 msg->FindInt32("buttons", (int32*)&buttons);
894 if (buttons & B_PRIMARY_MOUSE_BUTTON)
896 if (clicks == 2 && !fIgnoreDoubleClick)
899 videoWindow->ToggleInterfaceShowing();
900 fIgnoreDoubleClick = false;
904 if (buttons & B_SECONDARY_MOUSE_BUTTON)
906 // clicks will be 2 next time (if interval short enough)
907 // even if the first click and the second
908 // have not been made with the same mouse button
909 fIgnoreDoubleClick = true;
911 BPopUpMenu *menu = new BPopUpMenu("context menu");
912 menu->SetRadioMode(false);
914 BMenuItem *halfItem = new BMenuItem("50%", new BMessage(RESIZE_50));
915 menu->AddItem(halfItem);
917 BMenuItem *origItem = new BMenuItem("100%", new BMessage(RESIZE_100));
918 menu->AddItem(origItem);
920 BMenuItem *doubleItem = new BMenuItem("200%", new BMessage(RESIZE_200));
921 menu->AddItem(doubleItem);
923 BMenuItem *zoomItem = new BMenuItem("Fullscreen", new BMessage(TOGGLE_FULL_SCREEN));
924 zoomItem->SetMarked(videoWindow->is_zoomed);
925 menu->AddItem(zoomItem);
927 menu->AddSeparatorItem();
930 BMenuItem *vsyncItem = new BMenuItem("Vertical Sync", new BMessage(VERT_SYNC));
931 vsyncItem->SetMarked(videoWindow->vsync);
932 menu->AddItem(vsyncItem);
933 // Correct Aspect Ratio
934 BMenuItem *aspectItem = new BMenuItem("Correct Aspect Ratio", new BMessage(ASPECT_CORRECT));
935 aspectItem->SetMarked(videoWindow->CorrectAspectRatio());
936 menu->AddItem(aspectItem);
938 menu->AddSeparatorItem();
941 /* BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
942 winNormFeel->AddInt32("WinFeel", (int32)B_NORMAL_WINDOW_FEEL);
943 BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
944 normWindItem->SetMarked(videoWindow->Feel() == B_NORMAL_WINDOW_FEEL);
945 menu->AddItem(normWindItem);
947 BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
948 winFloatFeel->AddInt32("WinFeel", (int32)B_FLOATING_APP_WINDOW_FEEL);
949 BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
950 onTopWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
951 menu->AddItem(onTopWindItem);
953 BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
954 winAllFeel->AddInt32("WinFeel", (int32)B_FLOATING_ALL_WINDOW_FEEL);
955 BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
956 allSpacesWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
957 menu->AddItem(allSpacesWindItem);*/
959 BMessage *windowFeelMsg = new BMessage( WINDOW_FEEL );
960 bool onTop = videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
961 window_feel feel = onTop ? B_NORMAL_WINDOW_FEEL : B_FLOATING_ALL_WINDOW_FEEL;
962 windowFeelMsg->AddInt32( "WinFeel", (int32)feel );
963 BMenuItem *windowFeelItem = new BMenuItem( "Stay On Top", windowFeelMsg );
964 windowFeelItem->SetMarked( onTop );
965 menu->AddItem( windowFeelItem );
967 menu->AddSeparatorItem();
969 BMenuItem* screenShotItem = new BMenuItem( "Take Screen Shot",
970 new BMessage( SCREEN_SHOT ) );
971 menu->AddItem( screenShotItem );
973 menu->SetTargetForItems( this );
974 ConvertToScreen( &where );
975 menu->Go( where, true, false, true );
979 fLastMouseMovedTime = system_time();
980 fCursorHidden = false;
983 /*****************************************************************************
985 *****************************************************************************/
987 VLCView::MouseUp( BPoint where )
990 val.b_bool = VLC_TRUE;
991 var_Set( p_vout, "mouse-clicked", val );
994 /*****************************************************************************
995 * VLCVIew::MouseMoved
996 *****************************************************************************/
998 VLCView::MouseMoved(BPoint point, uint32 transit, const BMessage* dragMessage)
1000 fLastMouseMovedTime = system_time();
1001 fCursorHidden = false;
1002 fCursorInside = (transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW);
1003 /* DVD navigation */
1004 unsigned int i_width, i_height, i_x, i_y;
1005 vout_PlacePicture( p_vout, (unsigned int)Bounds().Width(),
1006 (unsigned int)Bounds().Height(),
1007 &i_x, &i_y, &i_width, &i_height );
1009 val.i_int = ( (int)point.x - i_x ) * p_vout->render.i_width / i_width;
1010 var_Set( p_vout, "mouse-x", val );
1011 val.i_int = ( (int)point.y - i_y ) * p_vout->render.i_height / i_height;
1012 var_Set( p_vout, "mouse-y", val );
1013 val.b_bool = VLC_TRUE;
1014 var_Set( p_vout, "mouse-moved", val );
1017 /*****************************************************************************
1019 *****************************************************************************/
1023 // We are getting the pulse messages no matter if the mouse is over
1024 // this view. If we are in full screen mode, we want to hide the cursor
1025 // even if it is not.
1029 && system_time() - fLastMouseMovedTime > MOUSE_IDLE_TIMEOUT)
1031 be_app->ObscureCursor();
1032 fCursorHidden = true;
1033 VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1034 // hide the interface window as well if full screen
1035 if (videoWindow && videoWindow->is_zoomed)
1036 videoWindow->SetInterfaceShowing(false);
1041 /*****************************************************************************
1043 *****************************************************************************/
1045 VLCView::KeyDown(const char *bytes, int32 numBytes)
1047 VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1048 BWindow* interfaceWindow = get_interface_window();
1049 if (videoWindow && numBytes > 0) {
1050 uint32 mods = modifiers();
1053 // toggle window and full screen mode
1054 // not passing on the tab key to the default KeyDown()
1055 // implementation also avoids loosing the keyboard focus
1056 videoWindow->PostMessage(TOGGLE_FULL_SCREEN);
1059 // go back to window mode
1060 if (videoWindow->is_zoomed)
1061 videoWindow->PostMessage(TOGGLE_FULL_SCREEN);
1065 if (interfaceWindow)
1066 interfaceWindow->PostMessage(PAUSE_PLAYBACK);
1069 if (interfaceWindow)
1071 if (mods & B_SHIFT_KEY)
1073 interfaceWindow->PostMessage(NEXT_TITLE);
1076 interfaceWindow->PostMessage(NEXT_CHAPTER);
1080 if (interfaceWindow)
1082 if (mods & B_SHIFT_KEY)
1084 interfaceWindow->PostMessage(PREV_TITLE);
1087 interfaceWindow->PostMessage(PREV_CHAPTER);
1091 // previous file in playlist
1092 interfaceWindow->PostMessage(PREV_FILE);
1095 // next file in playlist
1096 interfaceWindow->PostMessage(NEXT_FILE);
1101 videoWindow->PostMessage( SCREEN_SHOT );
1104 BView::KeyDown(bytes, numBytes);
1110 /*****************************************************************************
1112 *****************************************************************************/
1114 VLCView::Draw(BRect updateRect)
1116 VideoWindow* window = dynamic_cast<VideoWindow*>( Window() );
1117 if ( window && window->mode == BITMAP )
1118 FillRect( updateRect );
1121 /*****************************************************************************
1123 *****************************************************************************/
1124 static int Init ( vout_thread_t * );
1125 static void End ( vout_thread_t * );
1126 // static int Manage ( vout_thread_t * );
1127 static void Display ( vout_thread_t *, picture_t * );
1129 static int BeosOpenDisplay ( vout_thread_t *p_vout );
1130 static void BeosCloseDisplay( vout_thread_t *p_vout );
1132 /*****************************************************************************
1133 * OpenVideo: allocates BeOS video thread output method
1134 *****************************************************************************
1135 * This function allocates and initializes a BeOS vout method.
1136 *****************************************************************************/
1137 int E_(OpenVideo) ( vlc_object_t *p_this )
1139 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1141 /* Allocate structure */
1142 p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
1143 if( p_vout->p_sys == NULL )
1145 msg_Err( p_vout, "out of memory" );
1148 p_vout->p_sys->i_width = p_vout->render.i_width;
1149 p_vout->p_sys->i_height = p_vout->render.i_height;
1150 p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
1152 p_vout->pf_init = Init;
1153 p_vout->pf_end = End;
1154 p_vout->pf_manage = NULL;
1155 p_vout->pf_render = NULL;
1156 p_vout->pf_display = Display;
1161 /*****************************************************************************
1162 * Init: initialize BeOS video thread output method
1163 *****************************************************************************/
1164 int Init( vout_thread_t *p_vout )
1169 I_OUTPUTPICTURES = 0;
1171 /* Open and initialize device */
1172 if( BeosOpenDisplay( p_vout ) )
1174 msg_Err(p_vout, "vout error: can't open display");
1177 p_vout->output.i_width = p_vout->render.i_width;
1178 p_vout->output.i_height = p_vout->render.i_height;
1180 /* Assume we have square pixels */
1181 p_vout->output.i_aspect = p_vout->p_sys->i_width
1182 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
1183 p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
1184 p_vout->p_sys->i_index = 0;
1186 p_vout->b_direct = 1;
1188 p_vout->output.i_rmask = 0x00ff0000;
1189 p_vout->output.i_gmask = 0x0000ff00;
1190 p_vout->output.i_bmask = 0x000000ff;
1192 for (int buffer_index = 0 ; buffer_index < 3; buffer_index++)
1195 /* Find an empty picture slot */
1196 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
1199 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
1201 p_pic = p_vout->p_picture + i_index;
1210 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
1211 p_pic->p->i_lines = p_vout->p_sys->i_height;
1213 p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
1214 p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
1215 p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow();
1216 p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 );
1218 p_pic->i_status = DESTROYED_PICTURE;
1219 p_pic->i_type = DIRECT_PICTURE;
1221 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
1229 /*****************************************************************************
1230 * End: terminate BeOS video thread output method
1231 *****************************************************************************/
1232 void End( vout_thread_t *p_vout )
1234 BeosCloseDisplay( p_vout );
1237 /*****************************************************************************
1238 * CloseVideo: destroy BeOS video thread output method
1239 *****************************************************************************
1240 * Terminate an output method created by DummyCreateOutputMethod
1241 *****************************************************************************/
1242 void E_(CloseVideo) ( vlc_object_t *p_this )
1244 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1246 free( p_vout->p_sys );
1249 /*****************************************************************************
1250 * Display: displays previously rendered output
1251 *****************************************************************************
1252 * This function send the currently rendered image to BeOS image, waits until
1253 * it is displayed and switch the two rendering buffers, preparing next frame.
1254 *****************************************************************************/
1255 void Display( vout_thread_t *p_vout, picture_t *p_pic )
1257 VideoWindow * p_win = p_vout->p_sys->p_window;
1259 /* draw buffer if required */
1260 if (!p_win->teardownwindow)
1262 p_win->drawBuffer(p_vout->p_sys->i_index);
1265 p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3;
1266 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
1269 /* following functions are local */
1271 /*****************************************************************************
1272 * BeosOpenDisplay: open and initialize BeOS device
1273 *****************************************************************************/
1274 static int BeosOpenDisplay( vout_thread_t *p_vout )
1277 p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
1278 p_vout->p_sys->i_height - 1,
1280 20 + p_vout->i_window_width - 1,
1281 50 + p_vout->i_window_height - 1 ),
1283 if( p_vout->p_sys->p_window == NULL )
1285 msg_Err( p_vout, "cannot allocate VideoWindow" );
1290 p_vout->p_sys->p_window->Show();
1296 /*****************************************************************************
1297 * BeosDisplay: close and reset BeOS device
1298 *****************************************************************************
1299 * Returns all resources allocated by BeosOpenDisplay and restore the original
1300 * state of the device.
1301 *****************************************************************************/
1302 static void BeosCloseDisplay( vout_thread_t *p_vout )
1304 VideoWindow * p_win = p_vout->p_sys->p_window;
1305 /* Destroy the video window */
1306 if( p_win != NULL && !p_win->teardownwindow)
1309 p_win->teardownwindow = true;