1 /* 2 * MainWin.cpp - Media Player for the Haiku Operating System 3 * 4 * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de> 5 * Copyright (C) 2007-2008 Stephan Aßmus <superstippi@gmx.de> (GPL->MIT ok) 6 * Copyright (C) 2007-2008 Fredrik Modéen <fredrik@modeen.se> 7 * 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. 11 * 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. 16 * 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, 20 * USA. 21 * 22 */ 23 #include "MainWin.h" 24 25 #include <math.h> 26 #include <stdio.h> 27 #include <string.h> 28 29 #include <Alert.h> 30 #include <Application.h> 31 #include <Autolock.h> 32 #include <Debug.h> 33 #include <Menu.h> 34 #include <MenuBar.h> 35 #include <MenuItem.h> 36 #include <Messenger.h> 37 #include <PopUpMenu.h> 38 #include <RecentItems.h> 39 #include <Roster.h> 40 #include <Screen.h> 41 #include <String.h> 42 #include <View.h> 43 44 #include "AudioProducer.h" 45 #include "ControllerObserver.h" 46 #include "MainApp.h" 47 #include "PeakView.h" 48 #include "PlaylistObserver.h" 49 #include "PlaylistWindow.h" 50 #include "Settings.h" 51 52 #define NAME "MediaPlayer" 53 #define MIN_WIDTH 250 54 55 56 // XXX TODO: why is lround not defined? 57 #define lround(a) ((int)(0.99999 + (a))) 58 59 enum { 60 M_DUMMY = 0x100, 61 M_FILE_OPEN = 0x1000, 62 M_FILE_NEWPLAYER, 63 M_FILE_INFO, 64 M_FILE_PLAYLIST, 65 M_FILE_CLOSE, 66 M_FILE_QUIT, 67 M_VIEW_50, 68 M_VIEW_100, 69 M_VIEW_200, 70 M_VIEW_300, 71 M_VIEW_400, 72 M_TOGGLE_FULLSCREEN, 73 M_TOGGLE_NO_BORDER, 74 M_TOGGLE_NO_MENU, 75 M_TOGGLE_NO_CONTROLS, 76 M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS, 77 M_TOGGLE_ALWAYS_ON_TOP, 78 M_TOGGLE_KEEP_ASPECT_RATIO, 79 M_VOLUME_UP, 80 M_VOLUME_DOWN, 81 M_SKIP_NEXT, 82 M_SKIP_PREV, 83 M_ASPECT_100000_1, 84 M_ASPECT_106666_1, 85 M_ASPECT_109091_1, 86 M_ASPECT_141176_1, 87 M_ASPECT_720_576, 88 M_ASPECT_704_576, 89 M_ASPECT_544_576, 90 M_SELECT_AUDIO_TRACK = 0x00000800, 91 M_SELECT_AUDIO_TRACK_END = 0x00000fff, 92 M_SELECT_VIDEO_TRACK = 0x00010000, 93 M_SELECT_VIDEO_TRACK_END = 0x000fffff, 94 95 M_SET_PLAYLIST_POSITION 96 }; 97 98 //#define printf(a...) 99 100 101 MainWin::MainWin() 102 : BWindow(BRect(100,100,400,300), NAME, B_TITLED_WINDOW, 103 B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */), 104 fFilePanel(NULL), 105 fInfoWin(NULL), 106 fPlaylistWindow(NULL), 107 fHasFile(false), 108 fHasVideo(false), 109 fHasAudio(false), 110 fPlaylist(new Playlist), 111 fPlaylistObserver(new PlaylistObserver(this)), 112 fController(new Controller), 113 fControllerObserver(new ControllerObserver(this, 114 OBSERVE_FILE_CHANGES | OBSERVE_TRACK_CHANGES 115 | OBSERVE_PLAYBACK_STATE_CHANGES | OBSERVE_POSITION_CHANGES 116 | OBSERVE_VOLUME_CHANGES)), 117 fIsFullscreen(false), 118 fKeepAspectRatio(true), 119 fAlwaysOnTop(false), 120 fNoMenu(false), 121 fNoBorder(false), 122 fNoControls(false), 123 fSourceWidth(-1), 124 fSourceHeight(-1), 125 fWidthScale(1.0), 126 fHeightScale(1.0), 127 fMouseDownTracking(false), 128 fGlobalSettingsListener(this) 129 { 130 static int pos = 0; 131 MoveBy(pos * 25, pos * 25); 132 pos = (pos + 1) % 15; 133 134 BRect rect = Bounds(); 135 136 // background 137 fBackground = new BView(rect, "background", B_FOLLOW_ALL, 138 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE); 139 fBackground->SetViewColor(0,0,0); 140 AddChild(fBackground); 141 142 // menu 143 fMenuBar = new BMenuBar(fBackground->Bounds(), "menu"); 144 _CreateMenu(); 145 fBackground->AddChild(fMenuBar); 146 fMenuBar->ResizeToPreferred(); 147 fMenuBarWidth = (int)fMenuBar->Frame().Width() + 1; 148 fMenuBarHeight = (int)fMenuBar->Frame().Height() + 1; 149 fMenuBar->SetResizingMode(B_FOLLOW_NONE); 150 151 // video view 152 rect = BRect(0, fMenuBarHeight, fBackground->Bounds().right, 153 fMenuBarHeight + 10); 154 fVideoView = new VideoView(rect, "video display", B_FOLLOW_NONE); 155 fBackground->AddChild(fVideoView); 156 157 // controls 158 rect = BRect(0, fMenuBarHeight + 11, fBackground->Bounds().right, 159 fBackground->Bounds().bottom); 160 fControls = new ControllerView(rect, fController, fPlaylist); 161 fBackground->AddChild(fControls); 162 fControls->ResizeToPreferred(); 163 fControlsHeight = (int)fControls->Frame().Height() + 1; 164 fControlsWidth = (int)fControls->Frame().Width() + 1; 165 fControls->SetResizingMode(B_FOLLOW_BOTTOM | B_FOLLOW_LEFT_RIGHT); 166 // fControls->MoveTo(0, fBackground->Bounds().bottom - fControlsHeight + 1); 167 168 // fVideoView->ResizeTo(fBackground->Bounds().Width(), 169 // fBackground->Bounds().Height() - fMenuBarHeight - fControlsHeight); 170 171 fPlaylist->AddListener(fPlaylistObserver); 172 fController->SetVideoView(fVideoView); 173 fController->AddListener(fControllerObserver); 174 PeakView* peakView = fControls->GetPeakView(); 175 peakView->SetPeakNotificationWhat(MSG_PEAK_NOTIFICATION); 176 fController->SetPeakListener(peakView); 177 178 // printf("fMenuBarHeight %d\n", fMenuBarHeight); 179 // printf("fControlsHeight %d\n", fControlsHeight); 180 // printf("fControlsWidth %d\n", fControlsWidth); 181 182 _SetupWindow(); 183 184 // setup the playlist window now, we need to have it 185 // running for the undo/redo playlist editing 186 fPlaylistWindow = new PlaylistWindow(BRect(150, 150, 500, 600), fPlaylist, 187 fController); 188 fPlaylistWindow->Hide(); 189 fPlaylistWindow->Show(); 190 // this makes sure the window thread is running without 191 // showing the window just yet 192 193 Settings::Default()->AddListener(&fGlobalSettingsListener); 194 _AdoptGlobalSettings(); 195 196 Show(); 197 } 198 199 200 MainWin::~MainWin() 201 { 202 printf("MainWin::~MainWin\n"); 203 204 Settings::Default()->RemoveListener(&fGlobalSettingsListener); 205 fPlaylist->RemoveListener(fPlaylistObserver); 206 fController->RemoveListener(fControllerObserver); 207 fController->SetPeakListener(NULL); 208 209 // give the views a chance to detach from any notifiers 210 // before we delete them 211 fBackground->RemoveSelf(); 212 delete fBackground; 213 214 if (fInfoWin && fInfoWin->Lock()) 215 fInfoWin->Quit(); 216 217 if (fPlaylistWindow && fPlaylistWindow->Lock()) 218 fPlaylistWindow->Quit(); 219 220 delete fPlaylist; 221 delete fFilePanel; 222 223 // quit the Controller looper thread 224 thread_id controllerThread = fController->Thread(); 225 fController->PostMessage(B_QUIT_REQUESTED); 226 status_t exitValue; 227 wait_for_thread(controllerThread, &exitValue); 228 } 229 230 231 // #pragma mark - 232 233 234 void 235 MainWin::FrameResized(float newWidth, float newHeight) 236 { 237 if (newWidth != Bounds().Width() || newHeight != Bounds().Height()) { 238 debugger("size wrong\n"); 239 } 240 241 bool noMenu = fNoMenu || fIsFullscreen; 242 bool noControls = fNoControls || fIsFullscreen; 243 244 printf("FrameResized enter: newWidth %.0f, newHeight %.0f\n", 245 newWidth, newHeight); 246 247 int maxVideoWidth = int(newWidth) + 1; 248 int maxVideoHeight = int(newHeight) + 1 249 - (noMenu ? 0 : fMenuBarHeight) 250 - (noControls ? 0 : fControlsHeight); 251 252 ASSERT(maxVideoHeight >= 0); 253 254 int y = 0; 255 256 if (noMenu) { 257 if (!fMenuBar->IsHidden()) 258 fMenuBar->Hide(); 259 } else { 260 // fMenuBar->MoveTo(0, y); 261 fMenuBar->ResizeTo(newWidth, fMenuBarHeight - 1); 262 if (fMenuBar->IsHidden()) 263 fMenuBar->Show(); 264 y += fMenuBarHeight; 265 } 266 267 if (maxVideoHeight == 0) { 268 bool hidden = fVideoView->IsHidden(); 269 printf(" video view hidden: %d\n", hidden); 270 if (!hidden) 271 fVideoView->Hide(); 272 } else { 273 _ResizeVideoView(0, y, maxVideoWidth, maxVideoHeight); 274 if (fVideoView->IsHidden()) 275 fVideoView->Show(); 276 y += maxVideoHeight; 277 } 278 279 if (noControls) { 280 if (!fControls->IsHidden()) 281 fControls->Hide(); 282 } else { 283 fControls->MoveTo(0, y); 284 fControls->ResizeTo(newWidth, fControlsHeight - 1); 285 if (fControls->IsHidden()) 286 fControls->Show(); 287 // y += fControlsHeight; 288 } 289 290 printf("FrameResized leave\n"); 291 } 292 293 294 void 295 MainWin::Zoom(BPoint rec_position, float rec_width, float rec_height) 296 { 297 PostMessage(M_TOGGLE_FULLSCREEN); 298 } 299 300 301 void 302 MainWin::DispatchMessage(BMessage *msg, BHandler *handler) 303 { 304 if ((msg->what == B_MOUSE_DOWN) 305 && (handler == fBackground || handler == fVideoView 306 || handler == fControls)) 307 _MouseDown(msg, dynamic_cast<BView*>(handler)); 308 309 if ((msg->what == B_MOUSE_MOVED) 310 && (handler == fBackground || handler == fVideoView 311 || handler == fControls)) 312 _MouseMoved(msg, dynamic_cast<BView*>(handler)); 313 314 if ((msg->what == B_MOUSE_UP) 315 && (handler == fBackground || handler == fVideoView)) 316 _MouseUp(msg); 317 318 if ((msg->what == B_KEY_DOWN) 319 && (handler == fBackground || handler == fVideoView)) { 320 321 // special case for PrintScreen key 322 if (msg->FindInt32("key") == B_PRINT_KEY) { 323 fVideoView->OverlayScreenshotPrepare(); 324 BWindow::DispatchMessage(msg, handler); 325 fVideoView->OverlayScreenshotCleanup(); 326 return; 327 } 328 329 // every other key gets dispatched to our _KeyDown first 330 if (_KeyDown(msg) == B_OK) { 331 // it got handled, don't pass it on 332 return; 333 } 334 } 335 336 BWindow::DispatchMessage(msg, handler); 337 } 338 339 340 void 341 MainWin::MessageReceived(BMessage *msg) 342 { 343 // msg->PrintToStream(); 344 switch (msg->what) { 345 case B_REFS_RECEIVED: 346 printf("MainWin::MessageReceived: B_REFS_RECEIVED\n"); 347 _RefsReceived(msg); 348 break; 349 case B_SIMPLE_DATA: 350 printf("MainWin::MessageReceived: B_SIMPLE_DATA\n"); 351 if (msg->HasRef("refs")) { 352 // add to recent documents as it's not done with drag-n-drop 353 entry_ref ref; 354 for (int32 i = 0; msg->FindRef("refs", i, &ref) == B_OK; i++) { 355 be_roster->AddToRecentDocuments(&ref, kAppSig); 356 } 357 _RefsReceived(msg); 358 } 359 break; 360 361 case M_MEDIA_SERVER_STARTED: 362 printf("TODO: implement M_MEDIA_SERVER_STARTED\n"); 363 // fController->... 364 break; 365 366 case M_MEDIA_SERVER_QUIT: 367 printf("TODO: implement M_MEDIA_SERVER_QUIT\n"); 368 // fController->... 369 break; 370 371 // PlaylistObserver messages 372 case MSG_PLAYLIST_REF_ADDED: { 373 entry_ref ref; 374 int32 index; 375 if (msg->FindRef("refs", &ref) == B_OK 376 && msg->FindInt32("index", &index) == B_OK) { 377 _AddPlaylistItem(ref, index); 378 } 379 break; 380 } 381 case MSG_PLAYLIST_REF_REMOVED: { 382 int32 index; 383 if (msg->FindInt32("index", &index) == B_OK) { 384 _RemovePlaylistItem(index); 385 } 386 break; 387 } 388 case MSG_PLAYLIST_CURRENT_REF_CHANGED: { 389 BAutolock _(fPlaylist); 390 391 int32 index; 392 if (msg->FindInt32("index", &index) < B_OK 393 || index != fPlaylist->CurrentRefIndex()) 394 break; 395 entry_ref ref; 396 if (fPlaylist->GetRefAt(index, &ref) == B_OK) { 397 printf("open ref: %s\n", ref.name); 398 OpenFile(ref); 399 _MarkPlaylistItem(index); 400 } 401 break; 402 } 403 404 // ControllerObserver messages 405 case MSG_CONTROLLER_FILE_FINISHED: 406 { 407 bool hadNext = fPlaylist->SetCurrentRefIndex( 408 fPlaylist->CurrentRefIndex() + 1); 409 if (!hadNext) { 410 if (fHasVideo) { 411 if (fCloseWhenDonePlayingMovie) 412 PostMessage(B_QUIT_REQUESTED); 413 } else { 414 if (fCloseWhenDonePlayingSound) 415 PostMessage(B_QUIT_REQUESTED); 416 } 417 } 418 break; 419 } 420 case MSG_CONTROLLER_FILE_CHANGED: 421 // TODO: move all other GUI changes as a reaction to this 422 // notification 423 // _UpdatePlaylistMenu(); 424 break; 425 case MSG_CONTROLLER_VIDEO_TRACK_CHANGED: { 426 int32 index; 427 if (msg->FindInt32("index", &index) == B_OK) { 428 BMenuItem* item = fVideoTrackMenu->ItemAt(index); 429 if (item) 430 item->SetMarked(true); 431 } 432 break; 433 } 434 case MSG_CONTROLLER_AUDIO_TRACK_CHANGED: { 435 int32 index; 436 if (msg->FindInt32("index", &index) == B_OK) { 437 BMenuItem* item = fAudioTrackMenu->ItemAt(index); 438 if (item) 439 item->SetMarked(true); 440 } 441 break; 442 } 443 case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: { 444 uint32 state; 445 if (msg->FindInt32("state", (int32*)&state) == B_OK) 446 fControls->SetPlaybackState(state); 447 break; 448 } 449 case MSG_CONTROLLER_POSITION_CHANGED: { 450 float position; 451 if (msg->FindFloat("position", &position) == B_OK) 452 fControls->SetPosition(position); 453 break; 454 } 455 case MSG_CONTROLLER_VOLUME_CHANGED: { 456 float volume; 457 if (msg->FindFloat("volume", &volume) == B_OK) 458 fControls->SetVolume(volume); 459 break; 460 } 461 case MSG_CONTROLLER_MUTED_CHANGED: { 462 bool muted; 463 if (msg->FindBool("muted", &muted) == B_OK) 464 fControls->SetMuted(muted); 465 break; 466 } 467 468 // menu item messages 469 case M_FILE_NEWPLAYER: 470 gMainApp->NewWindow(); 471 break; 472 case M_FILE_OPEN: 473 if (!fFilePanel) { 474 fFilePanel = new BFilePanel(); 475 fFilePanel->SetTarget(BMessenger(0, this)); 476 fFilePanel->SetPanelDirectory("/boot/home/"); 477 } 478 fFilePanel->Show(); 479 break; 480 case M_FILE_INFO: 481 ShowFileInfo(); 482 break; 483 case M_FILE_PLAYLIST: 484 ShowPlaylistWindow(); 485 break; 486 case B_ABOUT_REQUESTED: 487 BAlert *alert; 488 alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen " 489 ", Stephan Aßmus and Frederik Modéen", "Thanks"); 490 if (fAlwaysOnTop) { 491 _ToggleAlwaysOnTop(); 492 alert->Go(NULL); // Asynchronous mode 493 _ToggleAlwaysOnTop(); 494 } else { 495 alert->Go(NULL); // Asynchronous mode 496 } 497 break; 498 case M_FILE_CLOSE: 499 PostMessage(B_QUIT_REQUESTED); 500 break; 501 case M_FILE_QUIT: 502 be_app->PostMessage(B_QUIT_REQUESTED); 503 break; 504 505 case M_TOGGLE_FULLSCREEN: 506 _ToggleFullscreen(); 507 break; 508 509 case M_TOGGLE_NO_MENU: 510 _ToggleNoMenu(); 511 break; 512 513 case M_TOGGLE_NO_CONTROLS: 514 _ToggleNoControls(); 515 break; 516 517 case M_TOGGLE_NO_BORDER: 518 _ToggleNoBorder(); 519 break; 520 521 case M_TOGGLE_ALWAYS_ON_TOP: 522 _ToggleAlwaysOnTop(); 523 break; 524 525 case M_TOGGLE_KEEP_ASPECT_RATIO: 526 _ToggleKeepAspectRatio(); 527 break; 528 529 case M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS: 530 _ToggleNoBorderNoMenu(); 531 break; 532 533 case M_VIEW_50: 534 if (!fHasVideo) 535 break; 536 if (fIsFullscreen) 537 _ToggleFullscreen(); 538 _ResizeWindow(50); 539 break; 540 541 case M_VIEW_100: 542 if (!fHasVideo) 543 break; 544 if (fIsFullscreen) 545 _ToggleFullscreen(); 546 _ResizeWindow(100); 547 break; 548 549 case M_VIEW_200: 550 if (!fHasVideo) 551 break; 552 if (fIsFullscreen) 553 _ToggleFullscreen(); 554 _ResizeWindow(200); 555 break; 556 557 case M_VIEW_300: 558 if (!fHasVideo) 559 break; 560 if (fIsFullscreen) 561 _ToggleFullscreen(); 562 _ResizeWindow(300); 563 break; 564 565 case M_VIEW_400: 566 if (!fHasVideo) 567 break; 568 if (fIsFullscreen) 569 _ToggleFullscreen(); 570 _ResizeWindow(400); 571 break; 572 573 /* 574 575 case B_ACQUIRE_OVERLAY_LOCK: 576 printf("B_ACQUIRE_OVERLAY_LOCK\n"); 577 fVideoView->OverlayLockAcquire(); 578 break; 579 580 case B_RELEASE_OVERLAY_LOCK: 581 printf("B_RELEASE_OVERLAY_LOCK\n"); 582 fVideoView->OverlayLockRelease(); 583 break; 584 585 case B_MOUSE_WHEEL_CHANGED: 586 { 587 printf("B_MOUSE_WHEEL_CHANGED\n"); 588 float dx = msg->FindFloat("be:wheel_delta_x"); 589 float dy = msg->FindFloat("be:wheel_delta_y"); 590 bool inv = modifiers() & B_COMMAND_KEY; 591 if (dx > 0.1) PostMessage(inv ? M_VOLUME_DOWN : M_SKIP_PREV); 592 if (dx < -0.1) PostMessage(inv ? M_VOLUME_UP : M_SKIP_NEXT); 593 if (dy > 0.1) PostMessage(inv ? M_SKIP_PREV : M_VOLUME_DOWN); 594 if (dy < -0.1) PostMessage(inv ? M_SKIP_NEXT : M_VOLUME_UP); 595 break; 596 } 597 */ 598 case M_SKIP_NEXT: 599 fControls->SkipForward(); 600 break; 601 602 case M_SKIP_PREV: 603 fControls->SkipBackward(); 604 break; 605 606 case M_VOLUME_UP: 607 fController->VolumeUp(); 608 break; 609 610 case M_VOLUME_DOWN: 611 fController->VolumeDown(); 612 break; 613 614 case M_ASPECT_100000_1: 615 VideoFormatChange(fSourceWidth, fSourceHeight, 1.0, 1.0); 616 break; 617 618 case M_ASPECT_106666_1: 619 VideoFormatChange(fSourceWidth, fSourceHeight, 1.06666, 1.0); 620 break; 621 622 case M_ASPECT_109091_1: 623 VideoFormatChange(fSourceWidth, fSourceHeight, 1.09091, 1.0); 624 break; 625 626 case M_ASPECT_141176_1: 627 VideoFormatChange(fSourceWidth, fSourceHeight, 1.41176, 1.0); 628 break; 629 630 case M_ASPECT_720_576: 631 VideoFormatChange(720, 576, 1.06666, 1.0); 632 break; 633 634 case M_ASPECT_704_576: 635 VideoFormatChange(704, 576, 1.09091, 1.0); 636 break; 637 638 case M_ASPECT_544_576: 639 VideoFormatChange(544, 576, 1.41176, 1.0); 640 break; 641 642 /* 643 default: 644 if (msg->what >= M_SELECT_CHANNEL 645 && msg->what <= M_SELECT_CHANNEL_END) { 646 SelectChannel(msg->what - M_SELECT_CHANNEL); 647 break; 648 } 649 if (msg->what >= M_SELECT_INTERFACE 650 && msg->what <= M_SELECT_INTERFACE_END) { 651 SelectInterface(msg->what - M_SELECT_INTERFACE - 1); 652 break; 653 } 654 */ 655 case M_SET_PLAYLIST_POSITION: { 656 int32 index; 657 if (msg->FindInt32("index", &index) == B_OK) 658 fPlaylist->SetCurrentRefIndex(index); 659 break; 660 } 661 662 case MSG_OBJECT_CHANGED: 663 // received from fGlobalSettingsListener 664 // TODO: find out which object, if we ever watch more than 665 // the global settings instance... 666 _AdoptGlobalSettings(); 667 break; 668 669 default: 670 // let BWindow handle the rest 671 BWindow::MessageReceived(msg); 672 } 673 } 674 675 676 void 677 MainWin::WindowActivated(bool active) 678 { 679 if (active) { 680 BScreen screen(this); 681 BRect screenFrame = screen.Frame(); 682 BRect frame = Frame(); 683 float diffX = 0.0; 684 float diffY = 0.0; 685 686 // If the frame is off the edge of the screen at all 687 // we will move it so all the window is on the screen. 688 if (frame.right > screenFrame.right) 689 // Move left 690 diffX = screenFrame.right - frame.right; 691 if (frame.bottom > screenFrame.bottom) 692 // Move up 693 diffY = screenFrame.bottom - frame.bottom; 694 if (frame.left < screenFrame.left) 695 // Move right 696 diffX = screenFrame.left - frame.left; 697 if (frame.top < screenFrame.top) 698 // Move down 699 diffY = screenFrame.top - frame.top; 700 701 MoveBy(diffX, diffY); 702 } 703 704 fController->PlayerActivated(active || gMainApp->PlayerCount() <= 1); 705 } 706 707 708 bool 709 MainWin::QuitRequested() 710 { 711 be_app->PostMessage(M_PLAYER_QUIT); 712 return true; 713 } 714 715 716 // #pragma mark - 717 718 719 void 720 MainWin::OpenFile(const entry_ref &ref) 721 { 722 printf("MainWin::OpenFile\n"); 723 724 status_t err = fController->SetTo(ref); 725 if (err != B_OK) { 726 if (fPlaylist->CountItems() == 1) { 727 // display error if this is the only file we're supposed to play 728 BString message; 729 message << "The file '"; 730 message << ref.name; 731 message << "' could not be opened.\n\n"; 732 733 if (err == B_MEDIA_NO_HANDLER) { 734 // give a more detailed message for the most likely of all 735 // errors 736 message << "There is no decoder installed to handle the " 737 "file format, or the decoder has trouble with the specific " 738 "version of the format."; 739 } else { 740 message << "Error: " << strerror(err); 741 } 742 (new BAlert("error", message.String(), "OK"))->Go(); 743 } else { 744 // just go to the next file and don't bother user 745 fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1); 746 } 747 fHasFile = false; 748 fHasVideo = false; 749 fHasAudio = false; 750 SetTitle(NAME); 751 } else { 752 fHasFile = true; 753 fHasVideo = fController->VideoTrackCount() != 0; 754 fHasAudio = fController->AudioTrackCount() != 0; 755 SetTitle(ref.name); 756 } 757 _SetupWindow(); 758 } 759 760 761 void 762 MainWin::ShowFileInfo() 763 { 764 if (!fInfoWin) 765 fInfoWin = new InfoWin(Frame().LeftTop(), fController); 766 767 if (fInfoWin->Lock()) { 768 if (fInfoWin->IsHidden()) 769 fInfoWin->Show(); 770 else 771 fInfoWin->Activate(); 772 fInfoWin->Unlock(); 773 } 774 } 775 776 777 void 778 MainWin::ShowPlaylistWindow() 779 { 780 if (fPlaylistWindow->Lock()) { 781 if (fPlaylistWindow->IsHidden()) 782 fPlaylistWindow->Show(); 783 else 784 fPlaylistWindow->Activate(); 785 fPlaylistWindow->Unlock(); 786 } 787 } 788 789 790 void 791 MainWin::VideoFormatChange(int width, int height, float width_scale, 792 float height_scale) 793 { 794 // called when video format or aspect ratio changes 795 796 printf("VideoFormatChange enter: width %d, height %d, width_scale %.6f, " 797 "height_scale %.6f\n", width, height, width_scale, height_scale); 798 799 if (width_scale < 1.0 && height_scale >= 1.0) { 800 width_scale = 1.0 / width_scale; 801 height_scale = 1.0 / height_scale; 802 printf("inverting! new values: width_scale %.6f, height_scale %.6f\n", 803 width_scale, height_scale); 804 } 805 806 fSourceWidth = width; 807 fSourceHeight = height; 808 fWidthScale = width_scale; 809 fHeightScale = height_scale; 810 811 FrameResized(Bounds().Width(), Bounds().Height()); 812 813 printf("VideoFormatChange leave\n"); 814 } 815 816 817 // #pragma mark - 818 819 820 void 821 MainWin::_RefsReceived(BMessage* msg) 822 { 823 // the playlist ist replaced by dropped files 824 // or the dropped files are appended to the end 825 // of the existing playlist if <shift> is pressed 826 int32 appendIndex = modifiers() & B_SHIFT_KEY ? 827 fPlaylist->CountItems() : -1; 828 msg->AddInt32("append_index", appendIndex); 829 830 // forward the message to the playlist window, 831 // so that undo/redo is used for modifying the playlist 832 fPlaylistWindow->PostMessage(msg); 833 } 834 835 836 void 837 MainWin::_SetupWindow() 838 { 839 printf("MainWin::_SetupWindow\n"); 840 // Populate the track menus 841 _SetupTrackMenus(); 842 // Enable both if a file was loaded 843 fAudioTrackMenu->SetEnabled(fHasFile); 844 fVideoTrackMenu->SetEnabled(fHasFile); 845 846 fVideoMenu->SetEnabled(fHasVideo); 847 fAudioMenu->SetEnabled(fHasAudio); 848 // fDebugMenu->SetEnabled(fHasVideo); 849 int previousSourceWidth = fSourceWidth; 850 int previousSourceHeight = fSourceHeight; 851 if (fHasVideo) { 852 fController->GetSize(&fSourceWidth, &fSourceHeight); 853 fWidthScale = 1.0; 854 fHeightScale = 1.0; 855 // TODO: implement aspect ratio 856 } else { 857 fSourceWidth = 0; 858 fSourceHeight = 0; 859 fWidthScale = 1.0; 860 fHeightScale = 1.0; 861 } 862 _UpdateControlsEnabledStatus(); 863 864 // adopt the size and window layout if necessary 865 if (!fIsFullscreen && (previousSourceWidth != fSourceWidth 866 || previousSourceHeight != fSourceHeight)) { 867 _ResizeWindow(100); 868 } 869 870 fVideoView->MakeFocus(); 871 } 872 873 874 void 875 MainWin::_CreateMenu() 876 { 877 fFileMenu = new BMenu(NAME); 878 fPlaylistMenu = new BMenu("Playlist"B_UTF8_ELLIPSIS); 879 fAudioMenu = new BMenu("Audio"); 880 fVideoMenu = new BMenu("Video"); 881 fSettingsMenu = new BMenu("Settings"); 882 fAudioTrackMenu = new BMenu("Track"); 883 fVideoTrackMenu = new BMenu("Track"); 884 // fDebugMenu = new BMenu("Debug"); 885 886 fMenuBar->AddItem(fFileMenu); 887 fMenuBar->AddItem(fAudioMenu); 888 fMenuBar->AddItem(fVideoMenu); 889 fMenuBar->AddItem(fSettingsMenu); 890 // fMenuBar->AddItem(fDebugMenu); 891 892 fFileMenu->AddItem(new BMenuItem("New Player"B_UTF8_ELLIPSIS, 893 new BMessage(M_FILE_NEWPLAYER), 'N')); 894 fFileMenu->AddSeparatorItem(); 895 896 // fFileMenu->AddItem(new BMenuItem("Open File"B_UTF8_ELLIPSIS, 897 // new BMessage(M_FILE_OPEN), 'O')); 898 // Add recent files 899 BRecentFilesList recentFiles(10, false, NULL, kAppSig); 900 BMenuItem *item = new BMenuItem(recentFiles.NewFileListMenu( 901 "Open File"B_UTF8_ELLIPSIS, new BMessage(B_REFS_RECEIVED), 902 NULL, this, 10, false, NULL, 0, kAppSig), new BMessage(M_FILE_OPEN)); 903 item->SetShortcut('O', 0); 904 fFileMenu->AddItem(item); 905 906 fFileMenu->AddItem(new BMenuItem("File Info"B_UTF8_ELLIPSIS, 907 new BMessage(M_FILE_INFO), 'I')); 908 fFileMenu->AddItem(fPlaylistMenu); 909 fPlaylistMenu->Superitem()->SetShortcut('P', B_COMMAND_KEY); 910 fPlaylistMenu->Superitem()->SetMessage(new BMessage(M_FILE_PLAYLIST)); 911 912 fFileMenu->AddSeparatorItem(); 913 fFileMenu->AddItem(new BMenuItem("About " NAME B_UTF8_ELLIPSIS, 914 new BMessage(B_ABOUT_REQUESTED))); 915 fFileMenu->AddSeparatorItem(); 916 fFileMenu->AddItem(new BMenuItem("Close", new BMessage(M_FILE_CLOSE), 'W')); 917 fFileMenu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q')); 918 919 fPlaylistMenu->SetRadioMode(true); 920 921 fAudioMenu->AddItem(fAudioTrackMenu); 922 923 fVideoMenu->AddItem(fVideoTrackMenu); 924 fVideoMenu->AddSeparatorItem(); 925 fVideoMenu->AddItem(new BMenuItem("50% scale", 926 new BMessage(M_VIEW_50), '0')); 927 fVideoMenu->AddItem(new BMenuItem("100% scale", 928 new BMessage(M_VIEW_100), '1')); 929 fVideoMenu->AddItem(new BMenuItem("200% scale", 930 new BMessage(M_VIEW_200), '2')); 931 fVideoMenu->AddItem(new BMenuItem("300% scale", 932 new BMessage(M_VIEW_300), '3')); 933 fVideoMenu->AddItem(new BMenuItem("400% scale", 934 new BMessage(M_VIEW_400), '4')); 935 fVideoMenu->AddSeparatorItem(); 936 fVideoMenu->AddItem(new BMenuItem("Full Screen", 937 new BMessage(M_TOGGLE_FULLSCREEN), 'F')); 938 fVideoMenu->AddItem(new BMenuItem("Keep Aspect Ratio", 939 new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K')); 940 941 fSettingsMenu->AddItem(new BMenuItem("No Menu", 942 new BMessage(M_TOGGLE_NO_MENU), 'M')); 943 fSettingsMenu->AddItem(new BMenuItem("No Border", 944 new BMessage(M_TOGGLE_NO_BORDER), 'B')); 945 fSettingsMenu->AddItem(new BMenuItem("No Controls", 946 new BMessage(M_TOGGLE_NO_CONTROLS), 'C')); 947 fSettingsMenu->AddItem(new BMenuItem("Always on Top", 948 new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T')); 949 fSettingsMenu->AddSeparatorItem(); 950 item = new BMenuItem("Settings"B_UTF8_ELLIPSIS, 951 new BMessage(M_SETTINGS), 'S'); 952 fSettingsMenu->AddItem(item); 953 item->SetTarget(be_app); 954 955 // fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", 956 // new BMessage(M_ASPECT_100000_1))); 957 // fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", 958 // new BMessage(M_ASPECT_106666_1))); 959 // fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", 960 // new BMessage(M_ASPECT_109091_1))); 961 // fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", 962 // new BMessage(M_ASPECT_141176_1))); 963 // fDebugMenu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", 964 // new BMessage(M_ASPECT_720_576))); 965 // fDebugMenu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", 966 // new BMessage(M_ASPECT_704_576))); 967 // fDebugMenu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", 968 // new BMessage(M_ASPECT_544_576))); 969 970 fAudioTrackMenu->SetRadioMode(true); 971 fVideoTrackMenu->SetRadioMode(true); 972 } 973 974 975 void 976 MainWin::_SetupTrackMenus() 977 { 978 fAudioTrackMenu->RemoveItems(0, fAudioTrackMenu->CountItems(), true); 979 fVideoTrackMenu->RemoveItems(0, fVideoTrackMenu->CountItems(), true); 980 981 char s[100]; 982 983 int count = fController->AudioTrackCount(); 984 int current = fController->CurrentAudioTrack(); 985 for (int i = 0; i < count; i++) { 986 sprintf(s, "Track %d", i + 1); 987 BMenuItem* item = new BMenuItem(s, 988 new BMessage(M_SELECT_AUDIO_TRACK + i)); 989 item->SetMarked(i == current); 990 fAudioTrackMenu->AddItem(item); 991 } 992 if (!count) { 993 fAudioTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY))); 994 fAudioTrackMenu->ItemAt(0)->SetMarked(true); 995 } 996 997 998 count = fController->VideoTrackCount(); 999 current = fController->CurrentVideoTrack(); 1000 for (int i = 0; i < count; i++) { 1001 sprintf(s, "Track %d", i + 1); 1002 BMenuItem* item = new BMenuItem(s, 1003 new BMessage(M_SELECT_VIDEO_TRACK + i)); 1004 item->SetMarked(i == current); 1005 fVideoTrackMenu->AddItem(item); 1006 } 1007 if (!count) { 1008 fVideoTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY))); 1009 fVideoTrackMenu->ItemAt(0)->SetMarked(true); 1010 } 1011 } 1012 1013 1014 void 1015 MainWin::_SetWindowSizeLimits() 1016 { 1017 int minWidth = fNoControls ? MIN_WIDTH : fControlsWidth; 1018 if (!fNoMenu) 1019 minWidth = max_c(minWidth, fMenuBarWidth); 1020 int minHeight = (fNoMenu ? 0 : fMenuBarHeight) 1021 + (fNoControls ? 0 : fControlsHeight); 1022 1023 SetSizeLimits(minWidth - 1, 32000, minHeight - 1, fHasVideo ? 1024 32000 : minHeight - 1); 1025 } 1026 1027 1028 void 1029 MainWin::_ResizeWindow(int percent) 1030 { 1031 // Get required window size 1032 int videoWidth = lround(fSourceWidth * fWidthScale); 1033 int videoHeight = lround(fSourceHeight * fHeightScale); 1034 1035 videoWidth = (videoWidth * percent) / 100; 1036 videoHeight = (videoHeight * percent) / 100; 1037 1038 // Calculate and set the initial window size 1039 int width = max_c(fControlsWidth, videoWidth); 1040 int height = (fNoControls ? 0 : fControlsHeight) + videoHeight; 1041 if (!fNoMenu) { 1042 width = max_c(width, fMenuBarWidth); 1043 height += fMenuBarHeight; 1044 } 1045 _SetWindowSizeLimits(); 1046 ResizeTo(width - 1, height - 1); 1047 } 1048 1049 1050 void 1051 MainWin::_ResizeVideoView(int x, int y, int width, int height) 1052 { 1053 printf("_ResizeVideoView: %d,%d, width %d, height %d\n", x, y, 1054 width, height); 1055 1056 if (fKeepAspectRatio) { 1057 // Keep aspect ratio, place video view inside 1058 // the background area (may create black bars). 1059 float scaledWidth = fSourceWidth * fWidthScale; 1060 float scaledHeight = fSourceHeight * fHeightScale; 1061 float factor = min_c(width / scaledWidth, height / scaledHeight); 1062 int renderWidth = lround(scaledWidth * factor); 1063 int renderHeight = lround(scaledHeight * factor); 1064 if (renderWidth > width) 1065 renderWidth = width; 1066 if (renderHeight > height) 1067 renderHeight = height; 1068 1069 int xOffset = x + (width - renderWidth) / 2; 1070 int yOffset = y + (height - renderHeight) / 2; 1071 1072 fVideoView->MoveTo(xOffset, yOffset); 1073 fVideoView->ResizeTo(renderWidth - 1, renderHeight - 1); 1074 1075 } else { 1076 fVideoView->MoveTo(x, y); 1077 fVideoView->ResizeTo(width - 1, height - 1); 1078 } 1079 } 1080 1081 1082 // #pragma mark - 1083 1084 1085 void 1086 MainWin::_MouseDown(BMessage *msg, BView* originalHandler) 1087 { 1088 BPoint screen_where; 1089 uint32 buttons = msg->FindInt32("buttons"); 1090 1091 // On Zeta, only "screen_where" is relyable, "where" and "be:view_where" 1092 // seem to be broken 1093 if (B_OK != msg->FindPoint("screen_where", &screen_where)) { 1094 // Workaround for BeOS R5, it has no "screen_where" 1095 if (!originalHandler || msg->FindPoint("where", &screen_where) < B_OK) 1096 return; 1097 originalHandler->ConvertToScreen(&screen_where); 1098 } 1099 1100 // msg->PrintToStream(); 1101 1102 // if (1 == msg->FindInt32("buttons") && msg->FindInt32("clicks") == 1) { 1103 1104 if (1 == buttons && msg->FindInt32("clicks") % 2 == 0) { 1105 BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, 1106 screen_where.y + 1); 1107 if (r.Contains(fMouseDownMousePos)) { 1108 PostMessage(M_TOGGLE_FULLSCREEN); 1109 return; 1110 } 1111 } 1112 1113 if (2 == buttons && msg->FindInt32("clicks") % 2 == 0) { 1114 BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, 1115 screen_where.y + 1); 1116 if (r.Contains(fMouseDownMousePos)) { 1117 PostMessage(M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS); 1118 return; 1119 } 1120 } 1121 1122 /* 1123 // very broken in Zeta: 1124 fMouseDownMousePos = fVideoView->ConvertToScreen( 1125 msg->FindPoint("where")); 1126 */ 1127 fMouseDownMousePos = screen_where; 1128 fMouseDownWindowPos = Frame().LeftTop(); 1129 1130 if (buttons == 1 && !fIsFullscreen) { 1131 // start mouse tracking 1132 fVideoView->SetMouseEventMask(B_POINTER_EVENTS | B_NO_POINTER_HISTORY 1133 /* | B_LOCK_WINDOW_FOCUS */); 1134 fMouseDownTracking = true; 1135 } 1136 1137 // pop up a context menu if right mouse button is down for 200 ms 1138 1139 if ((buttons & 2) == 0) 1140 return; 1141 bigtime_t start = system_time(); 1142 bigtime_t delay = 200000; 1143 BPoint location; 1144 do { 1145 fVideoView->GetMouse(&location, &buttons); 1146 if ((buttons & 2) == 0) 1147 break; 1148 snooze(1000); 1149 } while (system_time() - start < delay); 1150 1151 if (buttons & 2) 1152 _ShowContextMenu(screen_where); 1153 } 1154 1155 1156 void 1157 MainWin::_MouseMoved(BMessage *msg, BView* originalHandler) 1158 { 1159 // msg->PrintToStream(); 1160 1161 BPoint mousePos; 1162 uint32 buttons = msg->FindInt32("buttons"); 1163 1164 if (1 == buttons && fMouseDownTracking && !fIsFullscreen) { 1165 /* 1166 // very broken in Zeta: 1167 BPoint mousePos = msg->FindPoint("where"); 1168 printf("view where: %.0f, %.0f => ", mousePos.x, mousePos.y); 1169 fVideoView->ConvertToScreen(&mousePos); 1170 */ 1171 // On Zeta, only "screen_where" is relyable, "where" 1172 // and "be:view_where" seem to be broken 1173 if (B_OK != msg->FindPoint("screen_where", &mousePos)) { 1174 // Workaround for BeOS R5, it has no "screen_where" 1175 if (!originalHandler || msg->FindPoint("where", &mousePos) < B_OK) 1176 return; 1177 originalHandler->ConvertToScreen(&mousePos); 1178 } 1179 // printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y); 1180 float delta_x = mousePos.x - fMouseDownMousePos.x; 1181 float delta_y = mousePos.y - fMouseDownMousePos.y; 1182 float x = fMouseDownWindowPos.x + delta_x; 1183 float y = fMouseDownWindowPos.y + delta_y; 1184 // printf("move window to %.0f, %.0f\n", x, y); 1185 MoveTo(x, y); 1186 } 1187 } 1188 1189 1190 void 1191 MainWin::_MouseUp(BMessage *msg) 1192 { 1193 // msg->PrintToStream(); 1194 fMouseDownTracking = false; 1195 } 1196 1197 1198 void 1199 MainWin::_ShowContextMenu(const BPoint &screen_point) 1200 { 1201 printf("Show context menu\n"); 1202 BPopUpMenu *menu = new BPopUpMenu("context menu", false, false); 1203 BMenuItem *item; 1204 menu->AddItem(item = new BMenuItem("Full Screen", 1205 new BMessage(M_TOGGLE_FULLSCREEN), 'F')); 1206 item->SetMarked(fIsFullscreen); 1207 item->SetEnabled(fHasVideo); 1208 menu->AddItem(item = new BMenuItem("Keep Aspect Ratio", 1209 new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K')); 1210 item->SetMarked(fKeepAspectRatio); 1211 item->SetEnabled(fHasVideo); 1212 1213 menu->AddSeparatorItem(); 1214 menu->AddItem(item = new BMenuItem("No Menu", 1215 new BMessage(M_TOGGLE_NO_MENU), 'M')); 1216 item->SetMarked(fNoMenu); 1217 menu->AddItem(item = new BMenuItem("No Border", 1218 new BMessage(M_TOGGLE_NO_BORDER), 'B')); 1219 item->SetMarked(fNoBorder); 1220 menu->AddItem(item = new BMenuItem("Always on Top", 1221 new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T')); 1222 item->SetMarked(fAlwaysOnTop); 1223 1224 menu->AddSeparatorItem(); 1225 menu->AddItem(new BMenuItem("About " NAME B_UTF8_ELLIPSIS, 1226 new BMessage(B_ABOUT_REQUESTED))); 1227 menu->AddSeparatorItem(); 1228 menu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q')); 1229 1230 menu->AddSeparatorItem(); 1231 menu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", 1232 new BMessage(M_ASPECT_100000_1))); 1233 menu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", 1234 new BMessage(M_ASPECT_106666_1))); 1235 menu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", 1236 new BMessage(M_ASPECT_109091_1))); 1237 menu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", 1238 new BMessage(M_ASPECT_141176_1))); 1239 menu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", 1240 new BMessage(M_ASPECT_720_576))); 1241 menu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", 1242 new BMessage(M_ASPECT_704_576))); 1243 menu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", 1244 new BMessage(M_ASPECT_544_576))); 1245 1246 menu->SetTargetForItems(this); 1247 BRect r(screen_point.x - 5, screen_point.y - 5, screen_point.x + 5, 1248 screen_point.y + 5); 1249 menu->Go(screen_point, true, true, r, true); 1250 } 1251 1252 1253 /* Trap keys that are about to be send to background or renderer view. 1254 * Return B_OK if it shouldn't be passed to the view 1255 */ 1256 status_t 1257 MainWin::_KeyDown(BMessage *msg) 1258 { 1259 // msg->PrintToStream(); 1260 1261 uint32 key = msg->FindInt32("key"); 1262 uint32 raw_char = msg->FindInt32("raw_char"); 1263 uint32 modifiers = msg->FindInt32("modifiers"); 1264 1265 printf("key 0x%lx, raw_char 0x%lx, modifiers 0x%lx\n", key, raw_char, 1266 modifiers); 1267 1268 switch (raw_char) { 1269 case B_SPACE: 1270 fController->TogglePlaying(); 1271 return B_OK; 1272 1273 case B_ESCAPE: 1274 if (fIsFullscreen) { 1275 PostMessage(M_TOGGLE_FULLSCREEN); 1276 return B_OK; 1277 } else 1278 break; 1279 1280 case B_ENTER: // Enter / Return 1281 if (modifiers & B_COMMAND_KEY) { 1282 PostMessage(M_TOGGLE_FULLSCREEN); 1283 return B_OK; 1284 } else 1285 break; 1286 1287 case B_TAB: 1288 if ((modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY 1289 | B_MENU_KEY)) == 0) { 1290 PostMessage(M_TOGGLE_FULLSCREEN); 1291 return B_OK; 1292 } else 1293 break; 1294 1295 case B_UP_ARROW: 1296 if (modifiers & B_COMMAND_KEY) { 1297 PostMessage(M_SKIP_NEXT); 1298 } else { 1299 PostMessage(M_VOLUME_UP); 1300 } 1301 return B_OK; 1302 1303 case B_DOWN_ARROW: 1304 if (modifiers & B_COMMAND_KEY) { 1305 PostMessage(M_SKIP_PREV); 1306 } else { 1307 PostMessage(M_VOLUME_DOWN); 1308 } 1309 return B_OK; 1310 1311 case B_RIGHT_ARROW: 1312 if (modifiers & B_COMMAND_KEY) { 1313 PostMessage(M_VOLUME_UP); 1314 } else { 1315 PostMessage(M_SKIP_NEXT); 1316 } 1317 return B_OK; 1318 1319 case B_LEFT_ARROW: 1320 if (modifiers & B_COMMAND_KEY) { 1321 PostMessage(M_VOLUME_DOWN); 1322 } else { 1323 PostMessage(M_SKIP_PREV); 1324 } 1325 return B_OK; 1326 1327 case B_PAGE_UP: 1328 PostMessage(M_SKIP_NEXT); 1329 return B_OK; 1330 1331 case B_PAGE_DOWN: 1332 PostMessage(M_SKIP_PREV); 1333 return B_OK; 1334 } 1335 1336 switch (key) { 1337 case 0x3a: // numeric keypad + 1338 if ((modifiers & B_COMMAND_KEY) == 0) { 1339 printf("if\n"); 1340 PostMessage(M_VOLUME_UP); 1341 return B_OK; 1342 } else { 1343 printf("else\n"); 1344 break; 1345 } 1346 1347 case 0x25: // numeric keypad - 1348 if ((modifiers & B_COMMAND_KEY) == 0) { 1349 PostMessage(M_VOLUME_DOWN); 1350 return B_OK; 1351 } else { 1352 break; 1353 } 1354 1355 case 0x38: // numeric keypad up arrow 1356 PostMessage(M_VOLUME_UP); 1357 return B_OK; 1358 1359 case 0x59: // numeric keypad down arrow 1360 PostMessage(M_VOLUME_DOWN); 1361 return B_OK; 1362 1363 case 0x39: // numeric keypad page up 1364 case 0x4a: // numeric keypad right arrow 1365 PostMessage(M_SKIP_NEXT); 1366 return B_OK; 1367 1368 case 0x5a: // numeric keypad page down 1369 case 0x48: // numeric keypad left arrow 1370 PostMessage(M_SKIP_PREV); 1371 return B_OK; 1372 } 1373 1374 return B_ERROR; 1375 } 1376 1377 1378 // #pragma mark - 1379 1380 1381 void 1382 MainWin::_ToggleNoBorderNoMenu() 1383 { 1384 if (!fNoMenu && !fNoBorder && !fNoControls) { 1385 PostMessage(M_TOGGLE_NO_MENU); 1386 PostMessage(M_TOGGLE_NO_BORDER); 1387 PostMessage(M_TOGGLE_NO_CONTROLS); 1388 } else { 1389 if (!fNoMenu) 1390 PostMessage(M_TOGGLE_NO_MENU); 1391 if (!fNoBorder) 1392 PostMessage(M_TOGGLE_NO_BORDER); 1393 if (!fNoControls) 1394 PostMessage(M_TOGGLE_NO_CONTROLS); 1395 } 1396 } 1397 1398 1399 void 1400 MainWin::_ToggleFullscreen() 1401 { 1402 printf("_ToggleFullscreen enter\n"); 1403 1404 if (!fHasVideo) { 1405 printf("_ToggleFullscreen - ignoring, as we don't have a video\n"); 1406 return; 1407 } 1408 1409 fIsFullscreen = !fIsFullscreen; 1410 1411 if (fIsFullscreen) { 1412 // switch to fullscreen 1413 1414 fSavedFrame = Frame(); 1415 printf("saving current frame: %d %d %d %d\n", int(fSavedFrame.left), 1416 int(fSavedFrame.top), int(fSavedFrame.right), 1417 int(fSavedFrame.bottom)); 1418 BScreen screen(this); 1419 BRect rect(screen.Frame()); 1420 1421 Hide(); 1422 MoveTo(rect.left, rect.top); 1423 ResizeTo(rect.Width(), rect.Height()); 1424 Show(); 1425 1426 } else { 1427 // switch back from full screen mode 1428 1429 Hide(); 1430 MoveTo(fSavedFrame.left, fSavedFrame.top); 1431 ResizeTo(fSavedFrame.Width(), fSavedFrame.Height()); 1432 Show(); 1433 } 1434 1435 _MarkSettingsItem(M_TOGGLE_FULLSCREEN, fIsFullscreen); 1436 1437 printf("_ToggleFullscreen leave\n"); 1438 } 1439 1440 void 1441 MainWin::_ToggleNoControls() 1442 { 1443 printf("_ToggleNoControls enter\n"); 1444 1445 if (fIsFullscreen) { 1446 // fullscreen is always without menu 1447 printf("_ToggleNoControls leave, doing nothing, we are fullscreen\n"); 1448 return; 1449 } 1450 1451 fNoControls = !fNoControls; 1452 _SetWindowSizeLimits(); 1453 1454 if (fNoControls) { 1455 ResizeBy(0, - fControlsHeight); 1456 } else { 1457 ResizeBy(0, fControlsHeight); 1458 } 1459 1460 _MarkSettingsItem(M_TOGGLE_NO_CONTROLS, fNoControls); 1461 1462 printf("_ToggleNoControls leave\n"); 1463 } 1464 1465 void 1466 MainWin::_ToggleNoMenu() 1467 { 1468 printf("_ToggleNoMenu enter\n"); 1469 1470 if (fIsFullscreen) { 1471 // fullscreen is always without menu 1472 printf("_ToggleNoMenu leave, doing nothing, we are fullscreen\n"); 1473 return; 1474 } 1475 1476 fNoMenu = !fNoMenu; 1477 _SetWindowSizeLimits(); 1478 1479 if (fNoMenu) { 1480 MoveBy(0, fMenuBarHeight); 1481 ResizeBy(0, - fMenuBarHeight); 1482 } else { 1483 MoveBy(0, - fMenuBarHeight); 1484 ResizeBy(0, fMenuBarHeight); 1485 } 1486 1487 _MarkSettingsItem(M_TOGGLE_NO_MENU, fNoMenu); 1488 1489 printf("_ToggleNoMenu leave\n"); 1490 } 1491 1492 1493 void 1494 MainWin::_ToggleNoBorder() 1495 { 1496 fNoBorder = !fNoBorder; 1497 SetLook(fNoBorder ? B_BORDERED_WINDOW_LOOK : B_TITLED_WINDOW_LOOK); 1498 1499 _MarkSettingsItem(M_TOGGLE_NO_BORDER, fNoBorder); 1500 } 1501 1502 1503 void 1504 MainWin::_ToggleAlwaysOnTop() 1505 { 1506 fAlwaysOnTop = !fAlwaysOnTop; 1507 SetFeel(fAlwaysOnTop ? B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL); 1508 1509 _MarkSettingsItem(M_TOGGLE_ALWAYS_ON_TOP, fAlwaysOnTop); 1510 } 1511 1512 1513 void 1514 MainWin::_ToggleKeepAspectRatio() 1515 { 1516 fKeepAspectRatio = !fKeepAspectRatio; 1517 FrameResized(Bounds().Width(), Bounds().Height()); 1518 1519 _MarkSettingsItem(M_TOGGLE_KEEP_ASPECT_RATIO, fKeepAspectRatio); 1520 } 1521 1522 1523 // #pragma mark - 1524 1525 1526 void 1527 MainWin::_UpdateControlsEnabledStatus() 1528 { 1529 uint32 enabledButtons = 0; 1530 if (fHasVideo || fHasAudio) { 1531 enabledButtons |= PLAYBACK_ENABLED | SEEK_ENABLED 1532 | SEEK_BACK_ENABLED | SEEK_FORWARD_ENABLED; 1533 } 1534 if (fHasAudio) 1535 enabledButtons |= VOLUME_ENABLED; 1536 1537 bool canSkipPrevious, canSkipNext; 1538 fPlaylist->GetSkipInfo(&canSkipPrevious, &canSkipNext); 1539 if (canSkipPrevious) 1540 enabledButtons |= SKIP_BACK_ENABLED; 1541 if (canSkipNext) 1542 enabledButtons |= SKIP_FORWARD_ENABLED; 1543 1544 fControls->SetEnabled(enabledButtons); 1545 } 1546 1547 1548 void 1549 MainWin::_UpdatePlaylistMenu() 1550 { 1551 if (!fPlaylist->Lock()) 1552 return; 1553 1554 fPlaylistMenu->RemoveItems(0, fPlaylistMenu->CountItems(), true); 1555 1556 int32 count = fPlaylist->CountItems(); 1557 for (int32 i = 0; i < count; i++) { 1558 entry_ref ref; 1559 if (fPlaylist->GetRefAt(i, &ref) < B_OK) 1560 continue; 1561 _AddPlaylistItem(ref, i); 1562 } 1563 fPlaylistMenu->SetTargetForItems(this); 1564 1565 _MarkPlaylistItem(fPlaylist->CurrentRefIndex()); 1566 1567 fPlaylist->Unlock(); 1568 } 1569 1570 1571 void 1572 MainWin::_AddPlaylistItem(const entry_ref& ref, int32 index) 1573 { 1574 BMessage* message = new BMessage(M_SET_PLAYLIST_POSITION); 1575 message->AddInt32("index", index); 1576 BMenuItem* item = new BMenuItem(ref.name, message); 1577 fPlaylistMenu->AddItem(item, index); 1578 } 1579 1580 1581 void 1582 MainWin::_RemovePlaylistItem(int32 index) 1583 { 1584 delete fPlaylistMenu->RemoveItem(index); 1585 } 1586 1587 1588 void 1589 MainWin::_MarkPlaylistItem(int32 index) 1590 { 1591 if (BMenuItem* item = fPlaylistMenu->ItemAt(index)) { 1592 item->SetMarked(true); 1593 // ... and in case the menu is currently on screen: 1594 if (fPlaylistMenu->LockLooper()) { 1595 fPlaylistMenu->Invalidate(); 1596 fPlaylistMenu->UnlockLooper(); 1597 } 1598 } 1599 } 1600 1601 1602 void 1603 MainWin::_MarkSettingsItem(uint32 command, bool mark) 1604 { 1605 if (BMenuItem* item = fSettingsMenu->FindItem(command)) 1606 item->SetMarked(mark); 1607 } 1608 1609 1610 void 1611 MainWin::_AdoptGlobalSettings() 1612 { 1613 mpSettings settings = Settings::CurrentSettings(); 1614 // thread safe 1615 1616 fCloseWhenDonePlayingMovie = settings.closeWhenDonePlayingMovie; 1617 fCloseWhenDonePlayingSound = settings.closeWhenDonePlayingSound; 1618 } 1619 1620 1621