2 * MainWin.cpp - Media Player for the Haiku Operating System
4 * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5 * Copyright (C) 2007-2010 Stephan Aßmus <superstippi@gmx.de> (GPL->MIT ok)
6 * Copyright (C) 2007-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
31 #include <Application.h>
38 #include <MediaRoster.h>
42 #include <MessageRunner.h>
43 #include <Messenger.h>
44 #include <PopUpMenu.h>
45 #include <PropertyInfo.h>
46 #include <RecentItems.h>
50 #include <TypeConstants.h>
53 #include "AudioProducer.h"
54 #include "ControllerObserver.h"
55 #include "DurationToString.h"
56 #include "FilePlaylistItem.h"
59 #include "PlaylistItem.h"
60 #include "PlaylistObserver.h"
61 #include "PlaylistWindow.h"
65 #undef B_TRANSLATION_CONTEXT
66 #define B_TRANSLATION_CONTEXT "MediaPlayer-Main"
70 int MainWin::sNoVideoWidth
= MIN_WIDTH
;
73 // XXX TODO: why is lround not defined?
74 #define lround(a) ((int)(0.99999 + (a)))
85 M_TOGGLE_ALWAYS_ON_TOP
,
86 M_TOGGLE_NO_INTERFACE
,
93 // The common display aspect ratios
94 M_ASPECT_SAME_AS_SOURCE
,
95 M_ASPECT_NO_DISTORTION
,
103 M_SELECT_AUDIO_TRACK
= 0x00000800,
104 M_SELECT_AUDIO_TRACK_END
= 0x00000fff,
105 M_SELECT_VIDEO_TRACK
= 0x00010000,
106 M_SELECT_VIDEO_TRACK_END
= 0x00010fff,
107 M_SELECT_SUB_TITLE_TRACK
= 0x00020000,
108 M_SELECT_SUB_TITLE_TRACK_END
= 0x00020fff,
112 M_SET_PLAYLIST_POSITION
,
117 M_FINISH_SLIDING_CONTROLS
121 static property_info sPropertyInfo
[] = {
122 { B_TRANSLATE("Next"), { B_EXECUTE_PROPERTY
},
123 { B_DIRECT_SPECIFIER
, 0 },
124 B_TRANSLATE("Skip to the next track."), 0
126 { B_TRANSLATE("Prev"), { B_EXECUTE_PROPERTY
},
127 { B_DIRECT_SPECIFIER
, 0 },
128 B_TRANSLATE("Skip to the previous track."), 0
130 { B_TRANSLATE("Play"), { B_EXECUTE_PROPERTY
},
131 { B_DIRECT_SPECIFIER
, 0 },
132 B_TRANSLATE("Start playing."), 0
134 { B_TRANSLATE("Stop"), { B_EXECUTE_PROPERTY
},
135 { B_DIRECT_SPECIFIER
, 0 },
136 B_TRANSLATE("Stop playing."), 0
138 { B_TRANSLATE("Pause"), { B_EXECUTE_PROPERTY
},
139 { B_DIRECT_SPECIFIER
, 0 },
140 B_TRANSLATE("Pause playback."), 0
142 { B_TRANSLATE("TogglePlaying"), { B_EXECUTE_PROPERTY
},
143 { B_DIRECT_SPECIFIER
, 0 },
144 B_TRANSLATE("Toggle pause/play."), 0
146 { B_TRANSLATE("Mute"), { B_EXECUTE_PROPERTY
},
147 { B_DIRECT_SPECIFIER
, 0 },
148 B_TRANSLATE("Toggle mute."), 0
150 { B_TRANSLATE("Volume"), { B_GET_PROPERTY
, B_SET_PROPERTY
, 0 },
151 { B_DIRECT_SPECIFIER
, 0 },
152 B_TRANSLATE("Gets/sets the volume (0.0-2.0)."), 0,
155 { B_TRANSLATE("URI"), { B_GET_PROPERTY
, 0 },
156 { B_DIRECT_SPECIFIER
, 0 },
157 B_TRANSLATE("Gets the URI of the currently playing item."), 0,
160 { B_TRANSLATE("ToggleFullscreen"), { B_EXECUTE_PROPERTY
},
161 { B_DIRECT_SPECIFIER
, 0 },
162 B_TRANSLATE("Toggle fullscreen."), 0
164 { B_TRANSLATE("Duration"), { B_GET_PROPERTY
, 0 },
165 { B_DIRECT_SPECIFIER
, 0 },
166 B_TRANSLATE("Gets the duration of the currently playing item "
167 "in microseconds."), 0,
170 { B_TRANSLATE("Position"), { B_GET_PROPERTY
, B_SET_PROPERTY
, 0 },
171 { B_DIRECT_SPECIFIER
, 0 },
172 B_TRANSLATE("Gets/sets the current playing position in microseconds."),
175 { B_TRANSLATE("Seek"), { B_SET_PROPERTY
},
176 { B_DIRECT_SPECIFIER
, 0 },
177 B_TRANSLATE("Seek by the specified amounts of microseconds."), 0,
180 { 0, { 0 }, { 0 }, 0, 0 }
184 static const char* kRatingAttrName
= "Media:Rating";
186 static const char* kDisabledSeekMessage
= B_TRANSLATE("Drop files to play");
188 static const char* kApplicationName
= B_TRANSLATE_SYSTEM_NAME(NAME
);
191 MainWin::MainWin(bool isFirstWindow
, BMessage
* message
)
193 BWindow(BRect(100, 100, 400, 300), kApplicationName
, B_TITLED_WINDOW
,
194 B_ASYNCHRONOUS_CONTROLS
),
195 fCreationTime(system_time()),
197 fPlaylistWindow(NULL
),
201 fPlaylist(new Playlist
),
202 fPlaylistObserver(new PlaylistObserver(this)),
203 fController(new Controller
),
204 fControllerObserver(new ControllerObserver(this,
205 OBSERVE_FILE_CHANGES
| OBSERVE_TRACK_CHANGES
206 | OBSERVE_PLAYBACK_STATE_CHANGES
| OBSERVE_POSITION_CHANGES
207 | OBSERVE_VOLUME_CHANGES
)),
208 fIsFullscreen(false),
211 fShowsFullscreenControls(false),
219 fMouseDownTracking(false),
221 fLastMouseMovedTime(system_time()),
224 fGlobalSettingsListener(this),
225 fInitialSeekPosition(0),
228 // Handle window position and size depending on whether this is the
229 // first window or not. Use the window size from the window that was
230 // last resized by the user.
232 MoveBy(pos
* 25, pos
* 25);
233 pos
= (pos
+ 1) % 15;
235 BRect frame
= Settings::Default()->AudioPlayerWindowFrame();
236 if (frame
.IsValid()) {
238 if (message
== NULL
) {
239 MoveTo(frame
.LeftTop());
240 ResizeTo(frame
.Width(), frame
.Height());
242 // Delay moving to the initial position, since we don't
243 // know if we will be playing audio at all.
244 message
->AddRect("window frame", frame
);
247 if (sNoVideoWidth
== MIN_WIDTH
)
248 sNoVideoWidth
= frame
.IntegerWidth();
249 } else if (sNoVideoWidth
> MIN_WIDTH
) {
250 ResizeTo(sNoVideoWidth
, Bounds().Height());
252 fNoVideoWidth
= sNoVideoWidth
;
254 BRect rect
= Bounds();
257 fBackground
= new BView(rect
, "background", B_FOLLOW_ALL
,
258 B_WILL_DRAW
| B_FULL_UPDATE_ON_RESIZE
);
259 fBackground
->SetViewColor(0, 0, 0);
260 AddChild(fBackground
);
263 fMenuBar
= new BMenuBar(fBackground
->Bounds(), "menu");
265 fBackground
->AddChild(fMenuBar
);
266 fMenuBar
->SetResizingMode(B_FOLLOW_NONE
);
267 fMenuBar
->ResizeToPreferred();
268 fMenuBarWidth
= (int)fMenuBar
->Frame().Width() + 1;
269 fMenuBarHeight
= (int)fMenuBar
->Frame().Height() + 1;
272 rect
= BRect(0, fMenuBarHeight
, fBackground
->Bounds().right
,
273 fMenuBarHeight
+ 10);
274 fVideoView
= new VideoView(rect
, "video display", B_FOLLOW_NONE
);
275 fBackground
->AddChild(fVideoView
);
278 rect
= BRect(0, fMenuBarHeight
+ 11, fBackground
->Bounds().right
,
279 fBackground
->Bounds().bottom
);
280 fControls
= new ControllerView(rect
, fController
, fPlaylist
);
281 fBackground
->AddChild(fControls
);
282 fControls
->ResizeToPreferred();
283 fControlsHeight
= (int)fControls
->Frame().Height() + 1;
284 fControlsWidth
= (int)fControls
->Frame().Width() + 1;
285 fControls
->SetResizingMode(B_FOLLOW_BOTTOM
| B_FOLLOW_LEFT_RIGHT
);
286 fControls
->SetDisabledString(kDisabledSeekMessage
);
288 fPlaylist
->AddListener(fPlaylistObserver
);
289 fController
->SetVideoView(fVideoView
);
290 fController
->AddListener(fControllerObserver
);
291 PeakView
* peakView
= fControls
->GetPeakView();
292 peakView
->SetPeakNotificationWhat(MSG_PEAK_NOTIFICATION
);
293 fController
->SetPeakListener(peakView
);
297 // setup the playlist window now, we need to have it
298 // running for the undo/redo playlist editing
299 fPlaylistWindow
= new PlaylistWindow(BRect(150, 150, 500, 600), fPlaylist
,
301 fPlaylistWindow
->Hide();
302 fPlaylistWindow
->Show();
303 // this makes sure the window thread is running without
304 // showing the window just yet
306 Settings::Default()->AddListener(&fGlobalSettingsListener
);
307 _AdoptGlobalSettings();
309 AddShortcut('z', B_COMMAND_KEY
, new BMessage(B_UNDO
));
310 AddShortcut('y', B_COMMAND_KEY
, new BMessage(B_UNDO
));
311 AddShortcut('z', B_COMMAND_KEY
| B_SHIFT_KEY
, new BMessage(B_REDO
));
312 AddShortcut('y', B_COMMAND_KEY
| B_SHIFT_KEY
, new BMessage(B_REDO
));
318 PostMessage(message
);
320 BMediaRoster
* roster
= BMediaRoster::Roster();
321 roster
->StartWatching(BMessenger(this, this), B_MEDIA_SERVER_STARTED
);
322 roster
->StartWatching(BMessenger(this, this), B_MEDIA_SERVER_QUIT
);
328 // printf("MainWin::~MainWin\n");
330 BMediaRoster
* roster
= BMediaRoster::CurrentRoster();
331 roster
->StopWatching(BMessenger(this, this), B_MEDIA_SERVER_STARTED
);
332 roster
->StopWatching(BMessenger(this, this), B_MEDIA_SERVER_QUIT
);
334 Settings::Default()->RemoveListener(&fGlobalSettingsListener
);
335 fPlaylist
->RemoveListener(fPlaylistObserver
);
337 fController
->RemoveListener(fControllerObserver
);
338 fController
->SetPeakListener(NULL
);
339 fController
->SetVideoTarget(NULL
);
340 fController
->Unlock();
342 // give the views a chance to detach from any notifiers
343 // before we delete them
344 fBackground
->RemoveSelf();
347 if (fInfoWin
&& fInfoWin
->Lock())
350 if (fPlaylistWindow
&& fPlaylistWindow
->Lock())
351 fPlaylistWindow
->Quit();
356 // quit the Controller looper thread
357 thread_id controllerThread
= fController
->Thread();
358 fController
->PostMessage(B_QUIT_REQUESTED
);
360 wait_for_thread(controllerThread
, &exitValue
);
368 MainWin::FrameResized(float newWidth
, float newHeight
)
370 if (newWidth
!= Bounds().Width() || newHeight
!= Bounds().Height()) {
371 debugger("size wrong\n");
374 bool noMenu
= fNoInterface
|| fIsFullscreen
;
375 bool noControls
= fNoInterface
|| fIsFullscreen
;
377 // printf("FrameResized enter: newWidth %.0f, newHeight %.0f\n",
378 // newWidth, newHeight);
381 sNoVideoWidth
= fNoVideoWidth
= (int)newWidth
;
383 int maxVideoWidth
= int(newWidth
) + 1;
384 int maxVideoHeight
= int(newHeight
) + 1
385 - (noMenu
? 0 : fMenuBarHeight
)
386 - (noControls
? 0 : fControlsHeight
);
388 ASSERT(maxVideoHeight
>= 0);
393 if (!fMenuBar
->IsHidden(fMenuBar
))
396 fMenuBar
->MoveTo(0, y
);
397 fMenuBar
->ResizeTo(newWidth
, fMenuBarHeight
- 1);
398 if (fMenuBar
->IsHidden(fMenuBar
))
403 if (maxVideoHeight
== 0) {
404 if (!fVideoView
->IsHidden(fVideoView
))
407 _ResizeVideoView(0, y
, maxVideoWidth
, maxVideoHeight
);
408 if (fVideoView
->IsHidden(fVideoView
))
414 if (!fControls
->IsHidden(fControls
))
417 fControls
->MoveTo(0, y
);
418 fControls
->ResizeTo(newWidth
, fControlsHeight
- 1);
419 if (fControls
->IsHidden(fControls
))
421 // y += fControlsHeight;
424 // printf("FrameResized leave\n");
429 MainWin::Zoom(BPoint
/*position*/, float /*width*/, float /*height*/)
431 PostMessage(M_TOGGLE_FULLSCREEN
);
436 MainWin::DispatchMessage(BMessage
* msg
, BHandler
* handler
)
438 if ((msg
->what
== B_MOUSE_DOWN
)
439 && (handler
== fBackground
|| handler
== fVideoView
440 || handler
== fControls
)) {
441 _MouseDown(msg
, dynamic_cast<BView
*>(handler
));
444 if ((msg
->what
== B_MOUSE_MOVED
)
445 && (handler
== fBackground
|| handler
== fVideoView
446 || handler
== fControls
)) {
447 _MouseMoved(msg
, dynamic_cast<BView
*>(handler
));
450 if ((msg
->what
== B_MOUSE_UP
)
451 && (handler
== fBackground
|| handler
== fVideoView
)) {
455 if ((msg
->what
== B_KEY_DOWN
)
456 && (handler
== fBackground
|| handler
== fVideoView
)) {
457 // special case for PrintScreen key
458 if (msg
->FindInt32("key") == B_PRINT_KEY
) {
459 fVideoView
->OverlayScreenshotPrepare();
460 BWindow::DispatchMessage(msg
, handler
);
461 fVideoView
->OverlayScreenshotCleanup();
465 // every other key gets dispatched to our _KeyDown first
467 // it got handled, don't pass it on
472 BWindow::DispatchMessage(msg
, handler
);
477 MainWin::MessageReceived(BMessage
* msg
)
479 // msg->PrintToStream();
481 case B_EXECUTE_PROPERTY
:
485 BMessage
reply(B_REPLY
);
486 status_t result
= B_BAD_SCRIPT_SYNTAX
;
490 const char* property
;
492 if (msg
->GetCurrentSpecifier(&index
, &specifier
, &what
,
493 &property
) != B_OK
) {
494 return BWindow::MessageReceived(msg
);
497 BPropertyInfo
propertyInfo(sPropertyInfo
);
498 switch (propertyInfo
.FindMatch(msg
, index
, &specifier
, what
,
501 fControls
->SkipForward();
506 fControls
->SkipBackward();
521 fController
->Pause();
526 fController
->TogglePlaying();
531 fController
->ToggleMute();
537 if (msg
->what
== B_GET_PROPERTY
) {
538 result
= reply
.AddFloat("result",
539 fController
->Volume());
540 } else if (msg
->what
== B_SET_PROPERTY
) {
542 result
= msg
->FindFloat("data", &newVolume
);
544 fController
->SetVolume(newVolume
);
551 if (msg
->what
== B_GET_PROPERTY
) {
552 BAutolock
_(fPlaylist
);
553 const PlaylistItem
* item
= fController
->Item();
559 result
= reply
.AddString("result", item
->LocationURI());
565 PostMessage(M_TOGGLE_FULLSCREEN
);
569 if (msg
->what
!= B_GET_PROPERTY
)
572 result
= reply
.AddInt64("result",
573 fController
->TimeDuration());
578 if (msg
->what
== B_GET_PROPERTY
) {
579 result
= reply
.AddInt64("result",
580 fController
->TimePosition());
581 } else if (msg
->what
== B_SET_PROPERTY
) {
583 result
= msg
->FindInt64("data", &newTime
);
585 fController
->SetTimePosition(newTime
);
593 if (msg
->what
!= B_SET_PROPERTY
)
597 result
= msg
->FindInt64("data", &seekBy
);
606 return BWindow::MessageReceived(msg
);
609 if (result
!= B_OK
) {
610 reply
.what
= B_MESSAGE_NOT_UNDERSTOOD
;
611 reply
.AddString("message", strerror(result
));
612 reply
.AddInt32("error", result
);
615 msg
->SendReply(&reply
);
619 case B_REFS_RECEIVED
:
623 if (msg
->HasRef("refs"))
626 case M_OPEN_PREVIOUS_PLAYLIST
:
632 fPlaylistWindow
->PostMessage(msg
);
635 case B_MEDIA_SERVER_STARTED
:
637 printf("TODO: implement B_MEDIA_SERVER_STARTED\n");
639 // BAutolock _(fPlaylist);
640 // BMessage fakePlaylistMessage(MSG_PLAYLIST_CURRENT_ITEM_CHANGED);
641 // fakePlaylistMessage.AddInt32("index",
642 // fPlaylist->CurrentItemIndex());
643 // PostMessage(&fakePlaylistMessage);
647 case B_MEDIA_SERVER_QUIT
:
648 printf("TODO: implement B_MEDIA_SERVER_QUIT\n");
649 // if (fController->Lock()) {
650 // fController->CleanupNodes();
651 // fController->Unlock();
655 // PlaylistObserver messages
656 case MSG_PLAYLIST_ITEM_ADDED
:
660 if (msg
->FindPointer("item", (void**)&item
) == B_OK
661 && msg
->FindInt32("index", &index
) == B_OK
) {
662 _AddPlaylistItem(item
, index
);
666 case MSG_PLAYLIST_ITEM_REMOVED
:
669 if (msg
->FindInt32("index", &index
) == B_OK
)
670 _RemovePlaylistItem(index
);
673 case MSG_PLAYLIST_CURRENT_ITEM_CHANGED
:
675 BAutolock
_(fPlaylist
);
678 // if false, the message was meant to only update the GUI
680 if (msg
->FindBool("play", &play
) < B_OK
|| !play
)
682 if (msg
->FindInt32("index", &index
) < B_OK
683 || index
!= fPlaylist
->CurrentItemIndex())
685 PlaylistItemRef
item(fPlaylist
->ItemAt(index
));
686 if (item
.Get() != NULL
) {
687 printf("open playlist item: %s\n", item
->Name().String());
688 OpenPlaylistItem(item
);
689 _MarkPlaylistItem(index
);
693 case MSG_PLAYLIST_IMPORT_FAILED
:
695 BAlert
* alert
= new BAlert(B_TRANSLATE("Nothing to Play"),
696 B_TRANSLATE("None of the files you wanted to play appear "
697 "to be media files."), B_TRANSLATE("OK"));
698 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
700 fControls
->SetDisabledString(kDisabledSeekMessage
);
704 // ControllerObserver messages
705 case MSG_CONTROLLER_FILE_FINISHED
:
707 BAutolock
_(fPlaylist
);
709 bool hadNext
= fPlaylist
->SetCurrentItemIndex(
710 fPlaylist
->CurrentItemIndex() + 1);
712 // Reached end of playlist
713 // Handle "quit when done" settings
714 if ((fHasVideo
&& fCloseWhenDonePlayingMovie
)
715 || (!fHasVideo
&& fCloseWhenDonePlayingSound
))
716 PostMessage(B_QUIT_REQUESTED
);
717 // Handle "loop by default" settings
718 if ((fHasVideo
&& fLoopMovies
)
719 || (!fHasVideo
&& fLoopSounds
)) {
720 if (fPlaylist
->CountItems() > 1)
721 fPlaylist
->SetCurrentItemIndex(0);
728 case MSG_CONTROLLER_FILE_CHANGED
:
730 status_t result
= B_ERROR
;
731 msg
->FindInt32("result", &result
);
732 PlaylistItemRef itemRef
;
734 if (msg
->FindPointer("item", (void**)&item
) == B_OK
) {
735 itemRef
.SetTo(item
, true);
736 // The reference was passed along with the message.
738 BAutolock
_(fPlaylist
);
739 itemRef
.SetTo(fPlaylist
->ItemAt(
740 fPlaylist
->CurrentItemIndex()));
742 _PlaylistItemOpened(itemRef
, result
);
745 case MSG_CONTROLLER_VIDEO_TRACK_CHANGED
:
748 if (msg
->FindInt32("index", &index
) == B_OK
) {
750 while (BMenuItem
* item
= fVideoTrackMenu
->ItemAt(i
)) {
751 item
->SetMarked(i
== index
);
757 case MSG_CONTROLLER_AUDIO_TRACK_CHANGED
:
760 if (msg
->FindInt32("index", &index
) == B_OK
) {
762 while (BMenuItem
* item
= fAudioTrackMenu
->ItemAt(i
)) {
763 item
->SetMarked(i
== index
);
766 _UpdateAudioChannelCount(index
);
770 case MSG_CONTROLLER_SUB_TITLE_TRACK_CHANGED
:
773 if (msg
->FindInt32("index", &index
) == B_OK
) {
775 while (BMenuItem
* item
= fSubTitleTrackMenu
->ItemAt(i
)) {
776 BMessage
* message
= item
->Message();
777 if (message
!= NULL
) {
778 item
->SetMarked((int32
)message
->what
779 - M_SELECT_SUB_TITLE_TRACK
== index
);
786 case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED
:
789 if (msg
->FindInt32("state", (int32
*)&state
) == B_OK
)
790 fControls
->SetPlaybackState(state
);
793 case MSG_CONTROLLER_POSITION_CHANGED
:
796 if (msg
->FindFloat("position", &position
) == B_OK
) {
797 fControls
->SetPosition(position
, fController
->TimePosition(),
798 fController
->TimeDuration());
799 fAllowWinding
= true;
803 case MSG_CONTROLLER_SEEK_HANDLED
:
806 case MSG_CONTROLLER_VOLUME_CHANGED
:
809 if (msg
->FindFloat("volume", &volume
) == B_OK
)
810 fControls
->SetVolume(volume
);
813 case MSG_CONTROLLER_MUTED_CHANGED
:
816 if (msg
->FindBool("muted", &muted
) == B_OK
)
817 fControls
->SetMuted(muted
);
821 // menu item messages
824 BMessenger
target(this);
825 BMessage
result(B_REFS_RECEIVED
);
826 BMessage
appMessage(M_SHOW_OPEN_PANEL
);
827 appMessage
.AddMessenger("target", target
);
828 appMessage
.AddMessage("message", &result
);
829 appMessage
.AddString("title", B_TRANSLATE("Open clips"));
830 appMessage
.AddString("label", B_TRANSLATE("Open"));
831 be_app
->PostMessage(&appMessage
);
837 case M_FILE_PLAYLIST
:
838 ShowPlaylistWindow();
841 PostMessage(B_QUIT_REQUESTED
);
844 be_app
->PostMessage(B_QUIT_REQUESTED
);
847 case M_TOGGLE_FULLSCREEN
:
851 case M_TOGGLE_ALWAYS_ON_TOP
:
852 _ToggleAlwaysOnTop();
855 case M_TOGGLE_NO_INTERFACE
:
856 _ToggleNoInterface();
862 if (msg
->FindInt32("size", &size
) == B_OK
) {
873 case B_ACQUIRE_OVERLAY_LOCK:
874 printf("B_ACQUIRE_OVERLAY_LOCK\n");
875 fVideoView->OverlayLockAcquire();
878 case B_RELEASE_OVERLAY_LOCK:
879 printf("B_RELEASE_OVERLAY_LOCK\n");
880 fVideoView->OverlayLockRelease();
883 case B_MOUSE_WHEEL_CHANGED
:
885 float dx
= msg
->FindFloat("be:wheel_delta_x");
886 float dy
= msg
->FindFloat("be:wheel_delta_y");
887 bool inv
= modifiers() & B_COMMAND_KEY
;
889 PostMessage(inv
? M_VOLUME_DOWN
: M_SKIP_PREV
);
891 PostMessage(inv
? M_VOLUME_UP
: M_SKIP_NEXT
);
893 PostMessage(inv
? M_SKIP_PREV
: M_VOLUME_DOWN
);
895 PostMessage(inv
? M_SKIP_NEXT
: M_VOLUME_UP
);
900 fControls
->SkipForward();
904 fControls
->SkipBackward();
911 if (msg
->FindInt64("how much", &howMuch
) != B_OK
912 || msg
->FindInt64("frames", &frames
) != B_OK
) {
916 _Wind(howMuch
, frames
);
921 fController
->VolumeUp();
925 fController
->VolumeDown();
928 case M_ASPECT_SAME_AS_SOURCE
:
934 fController
->GetSize(&width
, &height
,
935 &widthAspect
, &heightAspect
);
936 VideoFormatChange(width
, height
, widthAspect
, heightAspect
);
940 case M_ASPECT_NO_DISTORTION
:
944 fController
->GetSize(&width
, &height
);
945 VideoFormatChange(width
, height
, width
, height
);
950 VideoAspectChange(4, 3);
953 case M_ASPECT_16_9
: // 1.77 : 1
954 VideoAspectChange(16, 9);
957 case M_ASPECT_83_50
: // 1.66 : 1
958 VideoAspectChange(83, 50);
961 case M_ASPECT_7_4
: // 1.75 : 1
962 VideoAspectChange(7, 4);
965 case M_ASPECT_37_20
: // 1.85 : 1
966 VideoAspectChange(37, 20);
969 case M_ASPECT_47_20
: // 2.35 : 1
970 VideoAspectChange(47, 20);
973 case M_SET_PLAYLIST_POSITION
:
975 BAutolock
_(fPlaylist
);
978 if (msg
->FindInt32("index", &index
) == B_OK
)
979 fPlaylist
->SetCurrentItemIndex(index
);
983 case MSG_OBJECT_CHANGED
:
984 // received from fGlobalSettingsListener
985 // TODO: find out which object, if we ever watch more than
986 // the global settings instance...
987 _AdoptGlobalSettings();
990 case M_SLIDE_CONTROLS
:
993 if (msg
->FindFloat("offset", &offset
) == B_OK
) {
994 fControls
->MoveBy(0, offset
);
995 fVideoView
->SetSubTitleMaxBottom(fControls
->Frame().top
- 1);
1001 case M_FINISH_SLIDING_CONTROLS
:
1005 if (msg
->FindFloat("offset", &offset
) == B_OK
1006 && msg
->FindBool("show", &show
) == B_OK
) {
1008 fControls
->MoveTo(fControls
->Frame().left
, offset
);
1009 fVideoView
->SetSubTitleMaxBottom(offset
- 1);
1011 fVideoView
->SetSubTitleMaxBottom(
1012 fVideoView
->Bounds().bottom
);
1013 fControls
->RemoveSelf();
1014 fControls
->MoveTo(fVideoView
->Frame().left
,
1015 fVideoView
->Frame().bottom
+ 1);
1016 fBackground
->AddChild(fControls
);
1017 fControls
->SetSymbolScale(1.0f
);
1018 while (!fControls
->IsHidden())
1024 case M_HIDE_FULL_SCREEN_CONTROLS
:
1025 if (fIsFullscreen
) {
1026 BPoint videoViewWhere
;
1027 if (msg
->FindPoint("where", &videoViewWhere
) == B_OK
) {
1028 if (msg
->FindBool("force")
1029 || !fControls
->Frame().Contains(videoViewWhere
)) {
1030 _ShowFullscreenControls(false);
1031 // hide the mouse cursor until the user moves it
1032 be_app
->ObscureCursor();
1041 if (msg
->FindInt32("rating", &rating
) == B_OK
)
1047 if (msg
->what
>= M_SELECT_AUDIO_TRACK
1048 && msg
->what
<= M_SELECT_AUDIO_TRACK_END
) {
1049 fController
->SelectAudioTrack(msg
->what
- M_SELECT_AUDIO_TRACK
);
1052 if (msg
->what
>= M_SELECT_VIDEO_TRACK
1053 && msg
->what
<= M_SELECT_VIDEO_TRACK_END
) {
1054 fController
->SelectVideoTrack(msg
->what
- M_SELECT_VIDEO_TRACK
);
1057 if ((int32
)msg
->what
>= M_SELECT_SUB_TITLE_TRACK
- 1
1058 && msg
->what
<= M_SELECT_SUB_TITLE_TRACK_END
) {
1059 fController
->SelectSubTitleTrack((int32
)msg
->what
1060 - M_SELECT_SUB_TITLE_TRACK
);
1063 // let BWindow handle the rest
1064 BWindow::MessageReceived(msg
);
1070 MainWin::WindowActivated(bool active
)
1072 fController
->PlayerActivated(active
);
1077 MainWin::QuitRequested()
1079 BMessage
message(M_PLAYER_QUIT
);
1080 GetQuitMessage(&message
);
1081 be_app
->PostMessage(&message
);
1087 MainWin::MenusBeginning()
1089 _SetupVideoAspectItems(fVideoAspectMenu
);
1097 MainWin::OpenPlaylist(const BMessage
* playlistArchive
)
1099 if (playlistArchive
== NULL
)
1103 BAutolock
playlistLocker(fPlaylist
);
1105 if (fPlaylist
->Unarchive(playlistArchive
) != B_OK
)
1109 if (playlistArchive
->FindInt32("index", ¤tIndex
) != B_OK
)
1111 fPlaylist
->SetCurrentItemIndex(currentIndex
);
1113 playlistLocker
.Unlock();
1115 if (currentIndex
!= -1) {
1116 // Restore the current play position only if we have something to play
1117 playlistArchive
->FindInt64("position", (int64
*)&fInitialSeekPosition
);
1126 MainWin::OpenPlaylistItem(const PlaylistItemRef
& item
)
1128 status_t ret
= fController
->SetToAsync(item
);
1130 fprintf(stderr
, "MainWin::OpenPlaylistItem() - Failed to send message "
1131 "to Controller.\n");
1132 BString message
= B_TRANSLATE("%app% encountered an internal error. "
1133 "The file could not be opened.");
1134 message
.ReplaceFirst("%app%", kApplicationName
);
1135 BAlert
* alert
= new BAlert(kApplicationName
, message
.String(),
1136 B_TRANSLATE("OK"), NULL
, NULL
, B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
1137 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
1139 _PlaylistItemOpened(item
, ret
);
1142 string
<< "Opening '" << item
->Name() << "'.";
1143 fControls
->SetDisabledString(string
.String());
1149 MainWin::ShowFileInfo()
1152 fInfoWin
= new InfoWin(Frame().LeftTop(), fController
);
1154 if (fInfoWin
->Lock()) {
1155 if (fInfoWin
->IsHidden())
1158 fInfoWin
->Activate();
1165 MainWin::ShowPlaylistWindow()
1167 if (fPlaylistWindow
->Lock()) {
1168 // make sure the window shows on the same workspace as ourself
1169 uint32 workspaces
= Workspaces();
1170 if (fPlaylistWindow
->Workspaces() != workspaces
)
1171 fPlaylistWindow
->SetWorkspaces(workspaces
);
1174 if (fPlaylistWindow
->IsHidden())
1175 fPlaylistWindow
->Show();
1177 fPlaylistWindow
->Activate();
1179 fPlaylistWindow
->Unlock();
1185 MainWin::VideoAspectChange(int forcedWidth
, int forcedHeight
, float widthScale
)
1187 // Force specific source size and pixel width scale.
1191 fController
->GetSize(&width
, &height
);
1192 VideoFormatChange(forcedWidth
, forcedHeight
,
1193 lround(width
* widthScale
), height
);
1199 MainWin::VideoAspectChange(float widthScale
)
1201 // Called when video aspect ratio changes and the original
1202 // width/height should be restored too, display aspect is not known,
1203 // only pixel width scale.
1207 fController
->GetSize(&width
, &height
);
1208 VideoFormatChange(width
, height
, lround(width
* widthScale
), height
);
1214 MainWin::VideoAspectChange(int widthAspect
, int heightAspect
)
1216 // Called when video aspect ratio changes and the original
1217 // width/height should be restored too.
1221 fController
->GetSize(&width
, &height
);
1222 VideoFormatChange(width
, height
, widthAspect
, heightAspect
);
1228 MainWin::VideoFormatChange(int width
, int height
, int widthAspect
,
1231 // Called when video format or aspect ratio changes.
1233 printf("VideoFormatChange enter: width %d, height %d, "
1234 "aspect ratio: %d:%d\n", width
, height
, widthAspect
, heightAspect
);
1236 // remember current view scale
1237 int percent
= _CurrentVideoSizeInPercent();
1239 fSourceWidth
= width
;
1240 fSourceHeight
= height
;
1241 fWidthAspect
= widthAspect
;
1242 fHeightAspect
= heightAspect
;
1247 FrameResized(Bounds().Width(), Bounds().Height());
1249 printf("VideoFormatChange leave\n");
1254 MainWin::GetQuitMessage(BMessage
* message
)
1256 message
->AddPointer("instance", this);
1257 message
->AddRect("window frame", Frame());
1258 message
->AddBool("audio only", !fHasVideo
);
1259 message
->AddInt64("creation time", fCreationTime
);
1261 if (!fHasVideo
&& fHasAudio
) {
1262 // store playlist, current index and position if this is audio
1263 BMessage playlistArchive
;
1265 BAutolock
controllerLocker(fController
);
1266 playlistArchive
.AddInt64("position", fController
->TimePosition());
1267 controllerLocker
.Unlock();
1272 BAutolock
playlistLocker(fPlaylist
);
1273 if (fPlaylist
->Archive(&playlistArchive
) != B_OK
1274 || playlistArchive
.AddInt32("index",
1275 fPlaylist
->CurrentItemIndex()) != B_OK
1276 || message
->AddMessage("playlist", &playlistArchive
) != B_OK
) {
1277 fprintf(stderr
, "Failed to store current playlist.\n");
1284 MainWin::ResolveSpecifier(BMessage
* message
, int32 index
, BMessage
* specifier
,
1285 int32 what
, const char* property
)
1287 BPropertyInfo
propertyInfo(sPropertyInfo
);
1288 switch (propertyInfo
.FindMatch(message
, index
, specifier
, what
, property
)) {
1305 return BWindow::ResolveSpecifier(message
, index
, specifier
, what
, property
);
1310 MainWin::GetSupportedSuites(BMessage
* data
)
1315 status_t status
= data
->AddString("suites", "suite/vnd.Haiku-MediaPlayer");
1319 BPropertyInfo
propertyInfo(sPropertyInfo
);
1320 status
= data
->AddFlat("messages", &propertyInfo
);
1324 return BWindow::GetSupportedSuites(data
);
1332 MainWin::_RefsReceived(BMessage
* message
)
1334 // the playlist is replaced by dropped files
1335 // or the dropped files are appended to the end
1336 // of the existing playlist if <shift> is pressed
1337 bool append
= false;
1338 if (message
->FindBool("append to playlist", &append
) != B_OK
)
1339 append
= modifiers() & B_SHIFT_KEY
;
1341 BAutolock
_(fPlaylist
);
1342 int32 appendIndex
= append
? APPEND_INDEX_APPEND_LAST
1343 : APPEND_INDEX_REPLACE_PLAYLIST
;
1344 message
->AddInt32("append_index", appendIndex
);
1346 // forward the message to the playlist window,
1347 // so that undo/redo is used for modifying the playlist
1348 fPlaylistWindow
->PostMessage(message
);
1350 if (message
->FindRect("window frame", &fNoVideoFrame
) != B_OK
)
1351 fNoVideoFrame
= BRect();
1356 MainWin::_PlaylistItemOpened(const PlaylistItemRef
& item
, status_t result
)
1358 if (result
!= B_OK
) {
1359 BAutolock
_(fPlaylist
);
1361 item
->SetPlaybackFailed();
1362 bool allItemsFailed
= true;
1363 int32 count
= fPlaylist
->CountItems();
1364 for (int32 i
= 0; i
< count
; i
++) {
1365 if (!fPlaylist
->ItemAtFast(i
)->PlaybackFailed()) {
1366 allItemsFailed
= false;
1371 if (allItemsFailed
) {
1372 // Display error if all files failed to play.
1373 BString
message(B_TRANSLATE(
1374 "The file '%filename' could not be opened.\n\n"));;
1375 message
.ReplaceAll("%filename", item
->Name());
1377 if (result
== B_MEDIA_NO_HANDLER
) {
1378 // give a more detailed message for the most likely of all
1380 message
<< B_TRANSLATE(
1381 "There is no decoder installed to handle the "
1382 "file format, or the decoder has trouble with the "
1383 "specific version of the format.");
1385 message
<< B_TRANSLATE("Error: ") << strerror(result
);
1387 BAlert
* alert
= new BAlert("error", message
.String(),
1388 B_TRANSLATE("OK"), NULL
, NULL
, B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
1389 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
1391 fControls
->SetDisabledString(kDisabledSeekMessage
);
1393 // Just go to the next file and don't bother user (yet)
1394 fPlaylist
->SetCurrentItemIndex(fPlaylist
->CurrentItemIndex() + 1);
1400 SetTitle(kApplicationName
);
1403 fHasVideo
= fController
->VideoTrackCount() != 0;
1404 fHasAudio
= fController
->AudioTrackCount() != 0;
1405 SetTitle(item
->Name().String());
1407 if (fInitialSeekPosition
< 0) {
1408 fInitialSeekPosition
1409 = fController
->TimeDuration() + fInitialSeekPosition
;
1411 fController
->SetTimePosition(fInitialSeekPosition
);
1412 fInitialSeekPosition
= 0;
1417 _UpdatePlaylistItemFile();
1422 MainWin::_SetupWindow()
1424 // printf("MainWin::_SetupWindow\n");
1425 // Populate the track menus
1426 _SetupTrackMenus(fAudioTrackMenu
, fVideoTrackMenu
, fSubTitleTrackMenu
);
1427 _UpdateAudioChannelCount(fController
->CurrentAudioTrack());
1429 fVideoMenu
->SetEnabled(fHasVideo
);
1430 fAudioMenu
->SetEnabled(fHasAudio
);
1431 int previousSourceWidth
= fSourceWidth
;
1432 int previousSourceHeight
= fSourceHeight
;
1433 int previousWidthAspect
= fWidthAspect
;
1434 int previousHeightAspect
= fHeightAspect
;
1436 fController
->GetSize(&fSourceWidth
, &fSourceHeight
,
1437 &fWidthAspect
, &fHeightAspect
);
1444 _UpdateControlsEnabledStatus();
1446 // Adopt the size and window layout if necessary
1447 if (previousSourceWidth
!= fSourceWidth
1448 || previousSourceHeight
!= fSourceHeight
1449 || previousWidthAspect
!= fWidthAspect
1450 || previousHeightAspect
!= fHeightAspect
) {
1452 _SetWindowSizeLimits();
1454 if (!fIsFullscreen
) {
1455 // Resize to 100% but stay on screen
1456 _ResizeWindow(100, !fHasVideo
, true);
1458 // Make sure we relayout the video view when in full screen mode
1459 FrameResized(Frame().Width(), Frame().Height());
1465 fVideoView
->MakeFocus();
1470 MainWin::_CreateMenu()
1472 fFileMenu
= new BMenu(kApplicationName
);
1473 fPlaylistMenu
= new BMenu(B_TRANSLATE("Playlist" B_UTF8_ELLIPSIS
));
1474 fAudioMenu
= new BMenu(B_TRANSLATE("Audio"));
1475 fVideoMenu
= new BMenu(B_TRANSLATE("Video"));
1476 fVideoAspectMenu
= new BMenu(B_TRANSLATE("Aspect ratio"));
1477 fAudioTrackMenu
= new BMenu(B_TRANSLATE_CONTEXT("Track",
1478 "Audio Track Menu"));
1479 fVideoTrackMenu
= new BMenu(B_TRANSLATE_CONTEXT("Track",
1480 "Video Track Menu"));
1481 fSubTitleTrackMenu
= new BMenu(B_TRANSLATE("Subtitles"));
1482 fAttributesMenu
= new BMenu(B_TRANSLATE("Attributes"));
1484 fMenuBar
->AddItem(fFileMenu
);
1485 fMenuBar
->AddItem(fAudioMenu
);
1486 fMenuBar
->AddItem(fVideoMenu
);
1487 fMenuBar
->AddItem(fAttributesMenu
);
1489 BMenuItem
* item
= new BMenuItem(B_TRANSLATE("New player" B_UTF8_ELLIPSIS
),
1490 new BMessage(M_NEW_PLAYER
), 'N');
1491 fFileMenu
->AddItem(item
);
1492 item
->SetTarget(be_app
);
1494 // Add recent files to "Open File" entry as sub-menu.
1495 BRecentFilesList
recentFiles(10, false, NULL
, kAppSig
);
1496 item
= new BMenuItem(recentFiles
.NewFileListMenu(
1497 B_TRANSLATE("Open file" B_UTF8_ELLIPSIS
), NULL
, NULL
, this, 10, true,
1498 NULL
, kAppSig
), new BMessage(M_FILE_OPEN
));
1499 item
->SetShortcut('O', 0);
1500 fFileMenu
->AddItem(item
);
1502 fFileMenu
->AddSeparatorItem();
1504 fFileMenu
->AddItem(new BMenuItem(B_TRANSLATE("File info" B_UTF8_ELLIPSIS
),
1505 new BMessage(M_FILE_INFO
), 'I'));
1506 fFileMenu
->AddItem(fPlaylistMenu
);
1507 fPlaylistMenu
->Superitem()->SetShortcut('P', B_COMMAND_KEY
);
1508 fPlaylistMenu
->Superitem()->SetMessage(new BMessage(M_FILE_PLAYLIST
));
1510 fFileMenu
->AddSeparatorItem();
1512 fNoInterfaceMenuItem
= new BMenuItem(B_TRANSLATE("Hide interface"),
1513 new BMessage(M_TOGGLE_NO_INTERFACE
), 'H');
1514 fFileMenu
->AddItem(fNoInterfaceMenuItem
);
1515 fFileMenu
->AddItem(new BMenuItem(B_TRANSLATE("Always on top"),
1516 new BMessage(M_TOGGLE_ALWAYS_ON_TOP
), 'A'));
1518 item
= new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS
),
1519 new BMessage(M_SETTINGS
), 'S');
1520 fFileMenu
->AddItem(item
);
1521 item
->SetTarget(be_app
);
1523 fFileMenu
->AddSeparatorItem();
1525 fFileMenu
->AddItem(new BMenuItem(B_TRANSLATE("Close"),
1526 new BMessage(M_FILE_CLOSE
), 'W'));
1527 fFileMenu
->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
1528 new BMessage(M_FILE_QUIT
), 'Q'));
1530 fPlaylistMenu
->SetRadioMode(true);
1532 fAudioMenu
->AddItem(fAudioTrackMenu
);
1534 fVideoMenu
->AddItem(fVideoTrackMenu
);
1535 fVideoMenu
->AddItem(fSubTitleTrackMenu
);
1536 fVideoMenu
->AddSeparatorItem();
1537 BMessage
* resizeMessage
= new BMessage(M_VIEW_SIZE
);
1538 resizeMessage
->AddInt32("size", 50);
1539 fVideoMenu
->AddItem(new BMenuItem(
1540 B_TRANSLATE("50% scale"), resizeMessage
, '0'));
1542 resizeMessage
= new BMessage(M_VIEW_SIZE
);
1543 resizeMessage
->AddInt32("size", 100);
1544 fVideoMenu
->AddItem(new BMenuItem(
1545 B_TRANSLATE("100% scale"), resizeMessage
, '1'));
1547 resizeMessage
= new BMessage(M_VIEW_SIZE
);
1548 resizeMessage
->AddInt32("size", 200);
1549 fVideoMenu
->AddItem(new BMenuItem(
1550 B_TRANSLATE("200% scale"), resizeMessage
, '2'));
1552 resizeMessage
= new BMessage(M_VIEW_SIZE
);
1553 resizeMessage
->AddInt32("size", 300);
1554 fVideoMenu
->AddItem(new BMenuItem(
1555 B_TRANSLATE("300% scale"), resizeMessage
, '3'));
1557 resizeMessage
= new BMessage(M_VIEW_SIZE
);
1558 resizeMessage
->AddInt32("size", 400);
1559 fVideoMenu
->AddItem(new BMenuItem(
1560 B_TRANSLATE("400% scale"), resizeMessage
, '4'));
1562 fVideoMenu
->AddSeparatorItem();
1564 fVideoMenu
->AddItem(new BMenuItem(B_TRANSLATE("Full screen"),
1565 new BMessage(M_TOGGLE_FULLSCREEN
), B_ENTER
));
1567 fVideoMenu
->AddSeparatorItem();
1569 _SetupVideoAspectItems(fVideoAspectMenu
);
1570 fVideoMenu
->AddItem(fVideoAspectMenu
);
1572 fRatingMenu
= new BMenu(B_TRANSLATE("Rating"));
1573 fAttributesMenu
->AddItem(fRatingMenu
);
1574 for (int32 i
= 1; i
<= 10; i
++) {
1576 snprintf(label
, sizeof(label
), "%" B_PRId32
, i
);
1577 BMessage
* setRatingMsg
= new BMessage(M_SET_RATING
);
1578 setRatingMsg
->AddInt32("rating", i
);
1579 fRatingMenu
->AddItem(new BMenuItem(label
, setRatingMsg
));
1585 MainWin::_SetupVideoAspectItems(BMenu
* menu
)
1588 while ((item
= menu
->RemoveItem((int32
)0)) != NULL
)
1595 fController
->GetSize(&width
, &height
, &widthAspect
, &heightAspect
);
1596 // We don't care if there is a video track at all. In that
1597 // case we should end up not marking any item.
1599 // NOTE: The item marking may end up marking for example both
1600 // "Stream Settings" and "16 : 9" if the stream settings happen to
1603 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Stream settings"),
1604 new BMessage(M_ASPECT_SAME_AS_SOURCE
), '1', B_SHIFT_KEY
));
1605 item
->SetMarked(widthAspect
== fWidthAspect
1606 && heightAspect
== fHeightAspect
);
1608 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("No aspect correction"),
1609 new BMessage(M_ASPECT_NO_DISTORTION
), '0', B_SHIFT_KEY
));
1610 item
->SetMarked(width
== fWidthAspect
&& height
== fHeightAspect
);
1612 menu
->AddSeparatorItem();
1614 menu
->AddItem(item
= new BMenuItem("4 : 3",
1615 new BMessage(M_ASPECT_4_3
), 2, B_SHIFT_KEY
));
1616 item
->SetMarked(fWidthAspect
== 4 && fHeightAspect
== 3);
1617 menu
->AddItem(item
= new BMenuItem("16 : 9",
1618 new BMessage(M_ASPECT_16_9
), 3, B_SHIFT_KEY
));
1619 item
->SetMarked(fWidthAspect
== 16 && fHeightAspect
== 9);
1621 menu
->AddSeparatorItem();
1623 menu
->AddItem(item
= new BMenuItem("1.66 : 1",
1624 new BMessage(M_ASPECT_83_50
)));
1625 item
->SetMarked(fWidthAspect
== 83 && fHeightAspect
== 50);
1626 menu
->AddItem(item
= new BMenuItem("1.75 : 1",
1627 new BMessage(M_ASPECT_7_4
)));
1628 item
->SetMarked(fWidthAspect
== 7 && fHeightAspect
== 4);
1629 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("1.85 : 1 (American)"),
1630 new BMessage(M_ASPECT_37_20
)));
1631 item
->SetMarked(fWidthAspect
== 37 && fHeightAspect
== 20);
1632 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("2.35 : 1 (Cinemascope)"),
1633 new BMessage(M_ASPECT_47_20
)));
1634 item
->SetMarked(fWidthAspect
== 47 && fHeightAspect
== 20);
1639 MainWin::_SetupTrackMenus(BMenu
* audioTrackMenu
, BMenu
* videoTrackMenu
,
1640 BMenu
* subTitleTrackMenu
)
1642 audioTrackMenu
->RemoveItems(0, audioTrackMenu
->CountItems(), true);
1643 videoTrackMenu
->RemoveItems(0, videoTrackMenu
->CountItems(), true);
1644 subTitleTrackMenu
->RemoveItems(0, subTitleTrackMenu
->CountItems(), true);
1648 int count
= fController
->AudioTrackCount();
1649 int current
= fController
->CurrentAudioTrack();
1650 for (int i
= 0; i
< count
; i
++) {
1652 const char* languageString
= NULL
;
1653 if (fController
->GetAudioMetaData(i
, &metaData
) == B_OK
)
1654 metaData
.FindString("language", &languageString
);
1655 if (languageString
!= NULL
) {
1656 BLanguage
language(languageString
);
1657 BString languageName
;
1658 if (language
.GetName(languageName
) == B_OK
)
1659 languageString
= languageName
.String();
1660 snprintf(s
, sizeof(s
), "%s", languageString
);
1662 snprintf(s
, sizeof(s
), B_TRANSLATE("Track %d"), i
+ 1);
1663 BMenuItem
* item
= new BMenuItem(s
,
1664 new BMessage(M_SELECT_AUDIO_TRACK
+ i
));
1665 item
->SetMarked(i
== current
);
1666 audioTrackMenu
->AddItem(item
);
1669 audioTrackMenu
->AddItem(new BMenuItem(B_TRANSLATE_CONTEXT("none",
1670 "Audio track menu"), new BMessage(M_DUMMY
)));
1671 audioTrackMenu
->ItemAt(0)->SetMarked(true);
1673 audioTrackMenu
->SetEnabled(count
> 1);
1675 count
= fController
->VideoTrackCount();
1676 current
= fController
->CurrentVideoTrack();
1677 for (int i
= 0; i
< count
; i
++) {
1678 snprintf(s
, sizeof(s
), B_TRANSLATE("Track %d"), i
+ 1);
1679 BMenuItem
* item
= new BMenuItem(s
,
1680 new BMessage(M_SELECT_VIDEO_TRACK
+ i
));
1681 item
->SetMarked(i
== current
);
1682 videoTrackMenu
->AddItem(item
);
1685 videoTrackMenu
->AddItem(new BMenuItem(B_TRANSLATE("none"),
1686 new BMessage(M_DUMMY
)));
1687 videoTrackMenu
->ItemAt(0)->SetMarked(true);
1689 videoTrackMenu
->SetEnabled(count
> 1);
1691 count
= fController
->SubTitleTrackCount();
1693 current
= fController
->CurrentSubTitleTrack();
1694 BMenuItem
* item
= new BMenuItem(
1695 B_TRANSLATE_CONTEXT("Off", "Subtitles menu"),
1696 new BMessage(M_SELECT_SUB_TITLE_TRACK
- 1));
1697 subTitleTrackMenu
->AddItem(item
);
1698 item
->SetMarked(current
== -1);
1700 subTitleTrackMenu
->AddSeparatorItem();
1702 for (int i
= 0; i
< count
; i
++) {
1703 const char* name
= fController
->SubTitleTrackName(i
);
1705 snprintf(s
, sizeof(s
), "%s", name
);
1707 snprintf(s
, sizeof(s
), B_TRANSLATE("Track %d"), i
+ 1);
1708 item
= new BMenuItem(s
,
1709 new BMessage(M_SELECT_SUB_TITLE_TRACK
+ i
));
1710 item
->SetMarked(i
== current
);
1711 subTitleTrackMenu
->AddItem(item
);
1714 subTitleTrackMenu
->AddItem(new BMenuItem(
1715 B_TRANSLATE_CONTEXT("none", "Subtitles menu"),
1716 new BMessage(M_DUMMY
)));
1717 subTitleTrackMenu
->ItemAt(0)->SetMarked(true);
1719 subTitleTrackMenu
->SetEnabled(count
> 0);
1724 MainWin::_UpdateAudioChannelCount(int32 audioTrackIndex
)
1726 fControls
->SetAudioChannelCount(fController
->AudioTrackChannelCount());
1731 MainWin::_GetMinimumWindowSize(int& width
, int& height
) const
1735 if (!fNoInterface
) {
1736 width
= max_c(width
, fMenuBarWidth
);
1737 width
= max_c(width
, fControlsWidth
);
1738 height
= fMenuBarHeight
+ fControlsHeight
;
1744 MainWin::_GetUnscaledVideoSize(int& videoWidth
, int& videoHeight
) const
1746 if (fWidthAspect
!= 0 && fHeightAspect
!= 0) {
1747 videoWidth
= fSourceHeight
* fWidthAspect
/ fHeightAspect
;
1748 videoHeight
= fSourceWidth
* fHeightAspect
/ fWidthAspect
;
1749 // Use the scaling which produces an enlarged view.
1750 if (videoWidth
> fSourceWidth
) {
1752 videoHeight
= fSourceHeight
;
1755 videoWidth
= fSourceWidth
;
1758 videoWidth
= fSourceWidth
;
1759 videoHeight
= fSourceHeight
;
1765 MainWin::_SetWindowSizeLimits()
1769 _GetMinimumWindowSize(minWidth
, minHeight
);
1770 SetSizeLimits(minWidth
- 1, 32000, minHeight
- 1,
1771 fHasVideo
? 32000 : minHeight
- 1);
1776 MainWin::_CurrentVideoSizeInPercent() const
1783 _GetUnscaledVideoSize(videoWidth
, videoHeight
);
1785 int viewWidth
= fVideoView
->Bounds().IntegerWidth() + 1;
1786 int viewHeight
= fVideoView
->Bounds().IntegerHeight() + 1;
1788 int widthPercent
= viewWidth
* 100 / videoWidth
;
1789 int heightPercent
= viewHeight
* 100 / videoHeight
;
1791 if (widthPercent
> heightPercent
)
1792 return widthPercent
;
1793 return heightPercent
;
1798 MainWin::_ZoomVideoView(int percentDiff
)
1803 int percent
= _CurrentVideoSizeInPercent();
1804 int newSize
= percent
* (100 + percentDiff
) / 100;
1810 if (newSize
!= percent
) {
1811 BMessage
message(M_VIEW_SIZE
);
1812 message
.AddInt32("size", newSize
);
1813 PostMessage(&message
);
1819 MainWin::_ResizeWindow(int percent
, bool useNoVideoWidth
, bool stayOnScreen
)
1821 // Get required window size
1824 _GetUnscaledVideoSize(videoWidth
, videoHeight
);
1826 videoWidth
= (videoWidth
* percent
) / 100;
1827 videoHeight
= (videoHeight
* percent
) / 100;
1829 // Calculate and set the minimum window size
1832 _GetMinimumWindowSize(width
, height
);
1834 width
= max_c(width
, videoWidth
) - 1;
1835 if (useNoVideoWidth
)
1836 width
= max_c(width
, fNoVideoWidth
);
1837 height
= height
+ videoHeight
- 1;
1840 BRect
screenFrame(BScreen(this).Frame());
1841 BRect
frame(Frame());
1842 BRect
decoratorFrame(DecoratorFrame());
1844 // Shrink the screen frame by the window border size
1845 screenFrame
.top
+= frame
.top
- decoratorFrame
.top
;
1846 screenFrame
.left
+= frame
.left
- decoratorFrame
.left
;
1847 screenFrame
.right
+= frame
.right
- decoratorFrame
.right
;
1848 screenFrame
.bottom
+= frame
.bottom
- decoratorFrame
.bottom
;
1850 // Update frame to what the new size would be
1851 frame
.right
= frame
.left
+ width
;
1852 frame
.bottom
= frame
.top
+ height
;
1854 if (!screenFrame
.Contains(frame
)) {
1855 // Resize the window so it doesn't extend outside the current
1857 if (frame
.Width() > screenFrame
.Width()
1858 || frame
.Height() > screenFrame
.Height()) {
1861 = frame
.IntegerWidth() - screenFrame
.IntegerWidth();
1863 = frame
.IntegerHeight() - screenFrame
.IntegerHeight();
1866 if (widthDiff
> heightDiff
)
1867 shrinkScale
= (float)(width
- widthDiff
) / width
;
1869 shrinkScale
= (float)(height
- heightDiff
) / height
;
1871 // Resize width/height and center window
1872 width
= lround(width
* shrinkScale
);
1873 height
= lround(height
* shrinkScale
);
1874 MoveTo((screenFrame
.left
+ screenFrame
.right
- width
) / 2,
1875 (screenFrame
.top
+ screenFrame
.bottom
- height
) / 2);
1877 // just off-screen on one or more sides
1880 if (frame
.left
< screenFrame
.left
)
1881 offsetX
= (int)(screenFrame
.left
- frame
.left
);
1882 else if (frame
.right
> screenFrame
.right
)
1883 offsetX
= (int)(screenFrame
.right
- frame
.right
);
1884 if (frame
.top
< screenFrame
.top
)
1885 offsetY
= (int)(screenFrame
.top
- frame
.top
);
1886 else if (frame
.bottom
> screenFrame
.bottom
)
1887 offsetY
= (int)(screenFrame
.bottom
- frame
.bottom
);
1888 MoveBy(offsetX
, offsetY
);
1893 ResizeTo(width
, height
);
1898 MainWin::_ResizeVideoView(int x
, int y
, int width
, int height
)
1900 // Keep aspect ratio, place video view inside
1901 // the background area (may create black bars).
1904 _GetUnscaledVideoSize(videoWidth
, videoHeight
);
1905 float scaledWidth
= videoWidth
;
1906 float scaledHeight
= videoHeight
;
1907 float factor
= min_c(width
/ scaledWidth
, height
/ scaledHeight
);
1908 int renderWidth
= lround(scaledWidth
* factor
);
1909 int renderHeight
= lround(scaledHeight
* factor
);
1910 if (renderWidth
> width
)
1911 renderWidth
= width
;
1912 if (renderHeight
> height
)
1913 renderHeight
= height
;
1915 int xOffset
= (width
- renderWidth
) / 2;
1916 int yOffset
= (height
- renderHeight
) / 2;
1918 fVideoView
->MoveTo(x
, y
);
1919 fVideoView
->ResizeTo(width
- 1, height
- 1);
1921 BRect
videoFrame(xOffset
, yOffset
,
1922 xOffset
+ renderWidth
- 1, yOffset
+ renderHeight
- 1);
1924 fVideoView
->SetVideoFrame(videoFrame
);
1925 fVideoView
->SetSubTitleMaxBottom(height
- 1);
1933 MainWin::_MouseDown(BMessage
* msg
, BView
* originalHandler
)
1935 uint32 buttons
= msg
->FindInt32("buttons");
1937 // On Zeta, only "screen_where" is reliable, "where" and "be:view_where"
1938 // seem to be broken
1940 if (msg
->FindPoint("screen_where", &screenWhere
) != B_OK
) {
1942 // Workaround for BeOS R5, it has no "screen_where"
1943 if (!originalHandler
|| msg
->FindPoint("where", &screenWhere
) < B_OK
)
1945 originalHandler
->ConvertToScreen(&screenWhere
);
1948 // double click handling
1950 if (msg
->FindInt32("clicks") % 2 == 0) {
1951 BRect
rect(screenWhere
.x
- 1, screenWhere
.y
- 1, screenWhere
.x
+ 1,
1953 if (rect
.Contains(fMouseDownMousePos
)) {
1954 if (buttons
== B_PRIMARY_MOUSE_BUTTON
)
1955 PostMessage(M_TOGGLE_FULLSCREEN
);
1956 else if (buttons
== B_SECONDARY_MOUSE_BUTTON
)
1957 PostMessage(M_TOGGLE_NO_INTERFACE
);
1963 fMouseDownMousePos
= screenWhere
;
1964 fMouseDownWindowPos
= Frame().LeftTop();
1966 if (buttons
== B_PRIMARY_MOUSE_BUTTON
&& !fIsFullscreen
) {
1967 // start mouse tracking
1968 fVideoView
->SetMouseEventMask(B_POINTER_EVENTS
| B_NO_POINTER_HISTORY
1969 /* | B_LOCK_WINDOW_FOCUS */);
1970 fMouseDownTracking
= true;
1973 // pop up a context menu if right mouse button is down
1975 if ((buttons
& B_SECONDARY_MOUSE_BUTTON
) != 0)
1976 _ShowContextMenu(screenWhere
);
1981 MainWin::_MouseMoved(BMessage
* msg
, BView
* originalHandler
)
1983 // msg->PrintToStream();
1986 uint32 buttons
= msg
->FindInt32("buttons");
1987 // On Zeta, only "screen_where" is reliable, "where"
1988 // and "be:view_where" seem to be broken
1989 if (msg
->FindPoint("screen_where", &mousePos
) != B_OK
) {
1991 // Workaround for BeOS R5, it has no "screen_where"
1992 if (!originalHandler
|| msg
->FindPoint("where", &mousePos
) < B_OK
)
1994 originalHandler
->ConvertToScreen(&mousePos
);
1997 if (buttons
== B_PRIMARY_MOUSE_BUTTON
&& fMouseDownTracking
1998 && !fIsFullscreen
) {
1999 // printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y);
2000 float delta_x
= mousePos
.x
- fMouseDownMousePos
.x
;
2001 float delta_y
= mousePos
.y
- fMouseDownMousePos
.y
;
2002 float x
= fMouseDownWindowPos
.x
+ delta_x
;
2003 float y
= fMouseDownWindowPos
.y
+ delta_y
;
2004 // printf("move window to %.0f, %.0f\n", x, y);
2008 bigtime_t eventTime
;
2009 if (msg
->FindInt64("when", &eventTime
) != B_OK
)
2010 eventTime
= system_time();
2012 if (buttons
== 0 && fIsFullscreen
) {
2013 BPoint moveDelta
= mousePos
- fLastMousePos
;
2015 = sqrtf(moveDelta
.x
* moveDelta
.x
+ moveDelta
.y
* moveDelta
.y
);
2016 if (eventTime
- fLastMouseMovedTime
< 200000)
2017 fMouseMoveDist
+= moveDeltaDist
;
2019 fMouseMoveDist
= moveDeltaDist
;
2020 if (fMouseMoveDist
> 5)
2021 _ShowFullscreenControls(true);
2024 fLastMousePos
= mousePos
;
2025 fLastMouseMovedTime
=eventTime
;
2030 MainWin::_MouseUp(BMessage
* msg
)
2032 fMouseDownTracking
= false;
2037 MainWin::_ShowContextMenu(const BPoint
& screenPoint
)
2039 printf("Show context menu\n");
2040 BPopUpMenu
* menu
= new BPopUpMenu("context menu", false, false);
2042 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Full screen"),
2043 new BMessage(M_TOGGLE_FULLSCREEN
), B_ENTER
));
2044 item
->SetMarked(fIsFullscreen
);
2045 item
->SetEnabled(fHasVideo
);
2047 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Hide interface"),
2048 new BMessage(M_TOGGLE_NO_INTERFACE
), 'H'));
2049 item
->SetMarked(fNoInterface
);
2050 item
->SetEnabled(fHasVideo
&& !fIsFullscreen
);
2052 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Always on top"),
2053 new BMessage(M_TOGGLE_ALWAYS_ON_TOP
), 'A'));
2054 item
->SetMarked(fAlwaysOnTop
);
2055 item
->SetEnabled(fHasVideo
);
2057 BMenu
* aspectSubMenu
= new BMenu(B_TRANSLATE("Aspect ratio"));
2058 _SetupVideoAspectItems(aspectSubMenu
);
2059 aspectSubMenu
->SetTargetForItems(this);
2060 menu
->AddItem(item
= new BMenuItem(aspectSubMenu
));
2061 item
->SetEnabled(fHasVideo
);
2063 menu
->AddSeparatorItem();
2065 // Add track selector menus
2066 BMenu
* audioTrackMenu
= new BMenu(B_TRANSLATE("Audio track"));
2067 BMenu
* videoTrackMenu
= new BMenu(B_TRANSLATE("Video track"));
2068 BMenu
* subTitleTrackMenu
= new BMenu(B_TRANSLATE("Subtitles"));
2069 _SetupTrackMenus(audioTrackMenu
, videoTrackMenu
, subTitleTrackMenu
);
2071 audioTrackMenu
->SetTargetForItems(this);
2072 videoTrackMenu
->SetTargetForItems(this);
2073 subTitleTrackMenu
->SetTargetForItems(this);
2075 menu
->AddItem(item
= new BMenuItem(audioTrackMenu
));
2076 item
->SetEnabled(fHasAudio
);
2078 menu
->AddItem(item
= new BMenuItem(videoTrackMenu
));
2079 item
->SetEnabled(fHasVideo
);
2081 menu
->AddItem(item
= new BMenuItem(subTitleTrackMenu
));
2082 item
->SetEnabled(fHasVideo
);
2084 menu
->AddSeparatorItem();
2085 menu
->AddItem(new BMenuItem(B_TRANSLATE("Quit"), new BMessage(M_FILE_QUIT
), 'Q'));
2087 menu
->SetTargetForItems(this);
2088 BRect
rect(screenPoint
.x
- 5, screenPoint
.y
- 5, screenPoint
.x
+ 5,
2090 menu
->Go(screenPoint
, true, true, rect
, true);
2094 /*! Trap keys that are about to be send to background or renderer view.
2095 Return true if it shouldn't be passed to the view.
2098 MainWin::_KeyDown(BMessage
* msg
)
2100 uint32 key
= msg
->FindInt32("key");
2101 uint32 rawChar
= msg
->FindInt32("raw_char");
2102 uint32 modifier
= msg
->FindInt32("modifiers");
2104 // printf("key 0x%lx, rawChar 0x%lx, modifiers 0x%lx\n", key, rawChar,
2107 // ignore the system modifier namespace
2108 if ((modifier
& (B_CONTROL_KEY
| B_COMMAND_KEY
))
2109 == (B_CONTROL_KEY
| B_COMMAND_KEY
))
2114 fController
->TogglePlaying();
2118 fController
->ToggleMute();
2125 PostMessage(M_TOGGLE_FULLSCREEN
);
2128 case B_ENTER
: // Enter / Return
2129 if ((modifier
& B_COMMAND_KEY
) != 0) {
2130 PostMessage(M_TOGGLE_FULLSCREEN
);
2137 if ((modifier
& (B_COMMAND_KEY
| B_CONTROL_KEY
| B_OPTION_KEY
2138 | B_MENU_KEY
)) == 0) {
2139 PostMessage(M_TOGGLE_FULLSCREEN
);
2145 if ((modifier
& B_COMMAND_KEY
) != 0)
2146 PostMessage(M_SKIP_NEXT
);
2148 PostMessage(M_VOLUME_UP
);
2152 if ((modifier
& B_COMMAND_KEY
) != 0)
2153 PostMessage(M_SKIP_PREV
);
2155 PostMessage(M_VOLUME_DOWN
);
2159 if ((modifier
& B_COMMAND_KEY
) != 0)
2160 PostMessage(M_SKIP_NEXT
);
2161 else if (fAllowWinding
) {
2162 BMessage
windMessage(M_WIND
);
2163 if ((modifier
& B_SHIFT_KEY
) != 0) {
2164 windMessage
.AddInt64("how much", 30000000LL);
2165 windMessage
.AddInt64("frames", 5);
2167 windMessage
.AddInt64("how much", 5000000LL);
2168 windMessage
.AddInt64("frames", 1);
2170 PostMessage(&windMessage
);
2175 if ((modifier
& B_COMMAND_KEY
) != 0)
2176 PostMessage(M_SKIP_PREV
);
2177 else if (fAllowWinding
) {
2178 BMessage
windMessage(M_WIND
);
2179 if ((modifier
& B_SHIFT_KEY
) != 0) {
2180 windMessage
.AddInt64("how much", -30000000LL);
2181 windMessage
.AddInt64("frames", -5);
2183 windMessage
.AddInt64("how much", -5000000LL);
2184 windMessage
.AddInt64("frames", -1);
2186 PostMessage(&windMessage
);
2191 PostMessage(M_SKIP_NEXT
);
2195 PostMessage(M_SKIP_PREV
);
2199 if ((modifier
& B_COMMAND_KEY
) == 0) {
2206 if ((modifier
& B_COMMAND_KEY
) == 0) {
2207 _ZoomVideoView(-10);
2213 case 'd': // d for delete
2214 case 't': // t for Trash
2215 if ((modifiers() & B_COMMAND_KEY
) != 0) {
2216 BAutolock
_(fPlaylist
);
2217 BMessage
removeMessage(M_PLAYLIST_MOVE_TO_TRASH
);
2218 removeMessage
.AddInt32("playlist index",
2219 fPlaylist
->CurrentItemIndex());
2220 fPlaylistWindow
->PostMessage(&removeMessage
);
2227 case 0x3a: // numeric keypad +
2228 if ((modifier
& B_COMMAND_KEY
) == 0) {
2234 case 0x25: // numeric keypad -
2235 if ((modifier
& B_COMMAND_KEY
) == 0) {
2236 _ZoomVideoView(-10);
2241 case 0x38: // numeric keypad up arrow
2242 PostMessage(M_VOLUME_UP
);
2245 case 0x59: // numeric keypad down arrow
2246 PostMessage(M_VOLUME_DOWN
);
2249 case 0x39: // numeric keypad page up
2250 case 0x4a: // numeric keypad right arrow
2251 PostMessage(M_SKIP_NEXT
);
2254 case 0x5a: // numeric keypad page down
2255 case 0x48: // numeric keypad left arrow
2256 PostMessage(M_SKIP_PREV
);
2259 // Playback controls along the bottom of the keyboard:
2260 // Z X C (V) B for US International
2262 PostMessage(M_SKIP_PREV
);
2265 fController
->TogglePlaying();
2268 fController
->Pause();
2271 fController
->Stop();
2274 PostMessage(M_SKIP_NEXT
);
2286 MainWin::_ToggleFullscreen()
2288 printf("_ToggleFullscreen enter\n");
2291 printf("_ToggleFullscreen - ignoring, as we don't have a video\n");
2295 fIsFullscreen
= !fIsFullscreen
;
2297 if (fIsFullscreen
) {
2298 // switch to fullscreen
2300 fSavedFrame
= Frame();
2301 printf("saving current frame: %d %d %d %d\n", int(fSavedFrame
.left
),
2302 int(fSavedFrame
.top
), int(fSavedFrame
.right
),
2303 int(fSavedFrame
.bottom
));
2304 BScreen
screen(this);
2305 BRect
rect(screen
.Frame());
2308 MoveTo(rect
.left
, rect
.top
);
2309 ResizeTo(rect
.Width(), rect
.Height());
2313 // switch back from full screen mode
2314 _ShowFullscreenControls(false, false);
2317 MoveTo(fSavedFrame
.left
, fSavedFrame
.top
);
2318 ResizeTo(fSavedFrame
.Width(), fSavedFrame
.Height());
2322 fVideoView
->SetFullscreen(fIsFullscreen
);
2324 _MarkItem(fFileMenu
, M_TOGGLE_FULLSCREEN
, fIsFullscreen
);
2326 printf("_ToggleFullscreen leave\n");
2330 MainWin::_ToggleAlwaysOnTop()
2332 fAlwaysOnTop
= !fAlwaysOnTop
;
2333 SetFeel(fAlwaysOnTop
? B_FLOATING_ALL_WINDOW_FEEL
: B_NORMAL_WINDOW_FEEL
);
2335 _MarkItem(fFileMenu
, M_TOGGLE_ALWAYS_ON_TOP
, fAlwaysOnTop
);
2340 MainWin::_ToggleNoInterface()
2342 printf("_ToggleNoInterface enter\n");
2344 if (fIsFullscreen
|| !fHasVideo
) {
2345 // Fullscreen playback is always without interface and
2346 // audio playback is always with interface. So we ignore these
2348 printf("_ToggleNoControls leave, doing nothing, we are fullscreen\n");
2352 fNoInterface
= !fNoInterface
;
2353 _SetWindowSizeLimits();
2356 MoveBy(0, fMenuBarHeight
);
2357 ResizeBy(0, -(fControlsHeight
+ fMenuBarHeight
));
2358 SetLook(B_BORDERED_WINDOW_LOOK
);
2360 MoveBy(0, -fMenuBarHeight
);
2361 ResizeBy(0, fControlsHeight
+ fMenuBarHeight
);
2362 SetLook(B_TITLED_WINDOW_LOOK
);
2365 _MarkItem(fFileMenu
, M_TOGGLE_NO_INTERFACE
, fNoInterface
);
2367 printf("_ToggleNoInterface leave\n");
2372 MainWin::_ShowIfNeeded()
2374 // Only proceed if the window is already running
2375 if (find_thread(NULL
) != Thread())
2378 if (!fHasVideo
&& fNoVideoFrame
.IsValid()) {
2379 MoveTo(fNoVideoFrame
.LeftTop());
2380 ResizeTo(fNoVideoFrame
.Width(), fNoVideoFrame
.Height());
2381 } else if (fHasVideo
&& IsHidden())
2384 fNoVideoFrame
= BRect();
2394 MainWin::_ShowFullscreenControls(bool show
, bool animate
)
2396 if (fShowsFullscreenControls
== show
)
2399 fShowsFullscreenControls
= show
;
2400 fVideoView
->SetFullscreenControlsVisible(show
);
2403 fControls
->RemoveSelf();
2404 fControls
->MoveTo(fVideoView
->Bounds().left
,
2405 fVideoView
->Bounds().bottom
+ 1);
2406 fVideoView
->AddChild(fControls
);
2407 if (fScaleFullscreenControls
)
2408 fControls
->SetSymbolScale(1.5f
);
2410 while (fControls
->IsHidden())
2415 // Slide the controls into view. We need to do this with
2416 // messages, otherwise we block the video playback for the
2417 // time of the animation.
2418 const float kAnimationOffsets
[] = { 0.05, 0.2, 0.5, 0.2, 0.05 };
2419 const int32 steps
= sizeof(kAnimationOffsets
) / sizeof(float);
2420 float height
= fControls
->Bounds().Height();
2421 float moveDist
= show
? -height
: height
;
2422 float originalY
= fControls
->Frame().top
;
2423 for (int32 i
= 0; i
< steps
; i
++) {
2424 BMessage
message(M_SLIDE_CONTROLS
);
2425 message
.AddFloat("offset",
2426 floorf(moveDist
* kAnimationOffsets
[i
]));
2427 PostMessage(&message
, this);
2429 BMessage
finalMessage(M_FINISH_SLIDING_CONTROLS
);
2430 finalMessage
.AddFloat("offset", originalY
+ moveDist
);
2431 finalMessage
.AddBool("show", show
);
2432 PostMessage(&finalMessage
, this);
2434 fControls
->RemoveSelf();
2435 fControls
->MoveTo(fVideoView
->Frame().left
,
2436 fVideoView
->Frame().bottom
+ 1);
2437 fBackground
->AddChild(fControls
);
2438 fControls
->SetSymbolScale(1.0f
);
2440 while (!fControls
->IsHidden())
2450 MainWin::_Wind(bigtime_t howMuch
, int64 frames
)
2452 if (!fAllowWinding
|| !fController
->Lock())
2455 if (frames
!= 0 && fHasVideo
&& !fController
->IsPlaying()) {
2456 int64 newFrame
= fController
->CurrentFrame() + frames
;
2457 fController
->SetFramePosition(newFrame
);
2459 bigtime_t seekTime
= fController
->TimePosition() + howMuch
;
2461 fInitialSeekPosition
= seekTime
;
2462 PostMessage(M_SKIP_PREV
);
2463 } else if (seekTime
> fController
->TimeDuration()) {
2464 fInitialSeekPosition
= 0;
2465 PostMessage(M_SKIP_NEXT
);
2467 fController
->SetTimePosition(seekTime
);
2470 fController
->Unlock();
2471 fAllowWinding
= false;
2479 MainWin::_UpdatePlaylistItemFile()
2481 BAutolock
locker(fPlaylist
);
2482 const FilePlaylistItem
* item
2483 = dynamic_cast<const FilePlaylistItem
*>(fController
->Item());
2487 if (!fHasVideo
&& !fHasAudio
)
2490 BNode
node(&item
->Ref());
2491 if (node
.InitCheck())
2496 // Set some standard attributes of the currently played file.
2497 // This should only be a temporary solution.
2500 const char* kDurationAttrName
= "Media:Length";
2502 status_t status
= node
.GetAttrInfo(kDurationAttrName
, &info
);
2503 if (status
!= B_OK
|| info
.size
== 0) {
2504 bigtime_t duration
= fController
->TimeDuration();
2505 // TODO: Tracker does not seem to care about endian for scalar types
2506 node
.WriteAttr(kDurationAttrName
, B_INT64_TYPE
, 0, &duration
,
2510 // Write audio bitrate
2512 status
= node
.GetAttrInfo("Audio:Bitrate", &info
);
2513 if (status
!= B_OK
|| info
.size
== 0) {
2514 media_format format
;
2515 if (fController
->GetEncodedAudioFormat(&format
) == B_OK
2516 && format
.type
== B_MEDIA_ENCODED_AUDIO
) {
2517 int32 bitrate
= (int32
)(format
.u
.encoded_audio
.bit_rate
2520 snprintf(text
, sizeof(text
), "%" B_PRId32
" kbit", bitrate
);
2521 node
.WriteAttr("Audio:Bitrate", B_STRING_TYPE
, 0, text
,
2527 // Write video bitrate
2529 status
= node
.GetAttrInfo("Video:Bitrate", &info
);
2530 if (status
!= B_OK
|| info
.size
== 0) {
2531 media_format format
;
2532 if (fController
->GetEncodedVideoFormat(&format
) == B_OK
2533 && format
.type
== B_MEDIA_ENCODED_VIDEO
) {
2534 int32 bitrate
= (int32
)(format
.u
.encoded_video
.avg_bit_rate
2537 snprintf(text
, sizeof(text
), "%" B_PRId32
" kbit", bitrate
);
2538 node
.WriteAttr("Video:Bitrate", B_STRING_TYPE
, 0, text
,
2544 _UpdateAttributesMenu(node
);
2549 MainWin::_UpdateAttributesMenu(const BNode
& node
)
2554 status_t status
= node
.GetAttrInfo(kRatingAttrName
, &info
);
2555 if (status
== B_OK
&& info
.type
== B_INT32_TYPE
) {
2556 // Node has the Rating attribute.
2557 node
.ReadAttr(kRatingAttrName
, B_INT32_TYPE
, 0, &rating
,
2561 for (int32 i
= 0; BMenuItem
* item
= fRatingMenu
->ItemAt(i
); i
++)
2562 item
->SetMarked(i
+ 1 == rating
);
2567 MainWin::_SetRating(int32 rating
)
2569 BAutolock
locker(fPlaylist
);
2570 const FilePlaylistItem
* item
2571 = dynamic_cast<const FilePlaylistItem
*>(fController
->Item());
2575 BNode
node(&item
->Ref());
2576 if (node
.InitCheck())
2581 node
.WriteAttr(kRatingAttrName
, B_INT32_TYPE
, 0, &rating
, sizeof(rating
));
2583 // TODO: The whole mechnism should work like this:
2584 // * There is already an attribute API for PlaylistItem, flesh it out!
2585 // * FilePlaylistItem node-monitors it's file somehow.
2586 // * FilePlaylistItem keeps attributes in sync and sends notications.
2587 // * MainWin updates the menu according to FilePlaylistItem notifications.
2588 // * PlaylistWin shows columns with attribute and other info.
2589 // * PlaylistWin updates also upon FilePlaylistItem notifications.
2590 // * This keeps attributes in sync when another app changes them.
2592 _UpdateAttributesMenu(node
);
2597 MainWin::_UpdateControlsEnabledStatus()
2599 uint32 enabledButtons
= 0;
2600 if (fHasVideo
|| fHasAudio
) {
2601 enabledButtons
|= PLAYBACK_ENABLED
| SEEK_ENABLED
2602 | SEEK_BACK_ENABLED
| SEEK_FORWARD_ENABLED
;
2605 enabledButtons
|= VOLUME_ENABLED
;
2607 BAutolock
_(fPlaylist
);
2608 bool canSkipPrevious
, canSkipNext
;
2609 fPlaylist
->GetSkipInfo(&canSkipPrevious
, &canSkipNext
);
2610 if (canSkipPrevious
)
2611 enabledButtons
|= SKIP_BACK_ENABLED
;
2613 enabledButtons
|= SKIP_FORWARD_ENABLED
;
2615 fControls
->SetEnabled(enabledButtons
);
2617 fNoInterfaceMenuItem
->SetEnabled(fHasVideo
);
2618 fAttributesMenu
->SetEnabled(fHasAudio
|| fHasVideo
);
2623 MainWin::_UpdatePlaylistMenu()
2625 if (!fPlaylist
->Lock())
2628 fPlaylistMenu
->RemoveItems(0, fPlaylistMenu
->CountItems(), true);
2630 int32 count
= fPlaylist
->CountItems();
2631 for (int32 i
= 0; i
< count
; i
++) {
2632 PlaylistItem
* item
= fPlaylist
->ItemAtFast(i
);
2633 _AddPlaylistItem(item
, i
);
2635 fPlaylistMenu
->SetTargetForItems(this);
2637 _MarkPlaylistItem(fPlaylist
->CurrentItemIndex());
2639 fPlaylist
->Unlock();
2644 MainWin::_AddPlaylistItem(PlaylistItem
* item
, int32 index
)
2646 BMessage
* message
= new BMessage(M_SET_PLAYLIST_POSITION
);
2647 message
->AddInt32("index", index
);
2648 BMenuItem
* menuItem
= new BMenuItem(item
->Name().String(), message
);
2649 fPlaylistMenu
->AddItem(menuItem
, index
);
2654 MainWin::_RemovePlaylistItem(int32 index
)
2656 delete fPlaylistMenu
->RemoveItem(index
);
2661 MainWin::_MarkPlaylistItem(int32 index
)
2663 if (BMenuItem
* item
= fPlaylistMenu
->ItemAt(index
)) {
2664 item
->SetMarked(true);
2665 // ... and in case the menu is currently on screen:
2666 if (fPlaylistMenu
->LockLooper()) {
2667 fPlaylistMenu
->Invalidate();
2668 fPlaylistMenu
->UnlockLooper();
2675 MainWin::_MarkItem(BMenu
* menu
, uint32 command
, bool mark
)
2677 if (BMenuItem
* item
= menu
->FindItem(command
))
2678 item
->SetMarked(mark
);
2683 MainWin::_AdoptGlobalSettings()
2685 mpSettings settings
;
2686 Settings::Default()->Get(settings
);
2688 fCloseWhenDonePlayingMovie
= settings
.closeWhenDonePlayingMovie
;
2689 fCloseWhenDonePlayingSound
= settings
.closeWhenDonePlayingSound
;
2690 fLoopMovies
= settings
.loopMovie
;
2691 fLoopSounds
= settings
.loopSound
;
2692 fScaleFullscreenControls
= settings
.scaleFullscreenControls
;